Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
* text=auto eol=lf

/.github export-ignore
/docs export-ignore
/scripts export-ignore
/tests export-ignore
/.editorconfig export-ignore
/.gitattributes export-ignore
Expand Down
292 changes: 289 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: PHP ${{ matrix.php }}
runs-on: ubuntu-24.04
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
Expand All @@ -29,10 +30,10 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v7
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Set up PHP
uses: shivammathur/setup-php@v2
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2
with:
php-version: ${{ matrix.php }}
coverage: none
Expand All @@ -47,10 +48,295 @@ jobs:
- name: Unit tests
run: composer test

- name: Security audit
if: matrix.php == '8.4'
run: composer audit --no-interaction

- name: Coding standard
if: matrix.php == '8.4'
run: composer style

- name: Static analysis
if: matrix.php == '8.4'
run: composer analyse

lowest:
name: Lowest supported dependencies
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Set up PHP
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2
with:
php-version: "8.2"
coverage: none
tools: composer:v2

- name: Resolve lowest supported dependencies
run: >-
composer update
--no-interaction
--prefer-lowest
--prefer-stable
--ignore-platform-req=ext-getbiblesword

- name: Unit tests
run: composer test

coverage:
name: Coverage inventory
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Set up PHP
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2
with:
php-version: "8.4"
coverage: xdebug
tools: composer:v2

- name: Install dependencies
run: composer install --no-interaction --prefer-dist --ignore-platform-req=ext-getbiblesword

- name: Build coverage report
env:
XDEBUG_MODE: coverage
run: composer coverage

- name: Build coverage inventory
run: composer coverage-inventory

- name: Retain coverage evidence
if: always() && hashFiles('build/coverage*') != ''
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-${{ github.sha }}
path: build/coverage*
if-no-files-found: error
retention-days: 30

distribution:
name: Composer distribution
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0

- name: Set up PHP
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2
with:
php-version: "8.4"
coverage: none
tools: composer:v2

- name: Build Composer archive
shell: bash
run: |
set -euo pipefail
version="$(tr -d '\r\n' < VERSION)"
mkdir -p build/dist
COMPOSER_ROOT_VERSION="$version" composer archive \
--format=zip \
--dir=build/dist \
--file="getbible-scripture-${version}"

- name: Install clean distribution
shell: bash
run: |
set -euo pipefail
archive="build/dist/getbible-scripture-$(tr -d '\r\n' < VERSION).zip"
test -s "$archive"
mkdir -p build/extracted
unzip -q "$archive" -d build/extracted
package_composer="$(
find build/extracted -maxdepth 2 -type f -name composer.json \
-print -quit
)"
test -n "$package_composer"
package_root="$(dirname "$package_composer")"
composer validate --strict --working-dir="$package_root"
composer install \
--working-dir="$package_root" \
--no-dev \
--no-interaction \
--prefer-dist \
--ignore-platform-req=ext-getbiblesword
php -r '
require $argv[1];
exit(
interface_exists(
GetBible\Scripture\Service\ScriptureInterface::class
) ? 0 : 1
);
' "$package_root/vendor/autoload.php"

- name: Retain package evidence
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: composer-package-${{ github.sha }}
path: build/dist/*
if-no-files-found: error
retention-days: 30

integration:
name: Released extension and local SWORD fixture
runs-on: ubuntu-24.04
timeout-minutes: 90
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Set up PHP
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2
with:
php-version: "8.4"
coverage: none
tools: composer:v2

- name: Install native build dependencies
run: |
sudo apt-get update
sudo apt-get install --yes \
autoconf automake binutils build-essential cmake curl git \
libbz2-dev libcurl4-openssl-dev libicu-dev liblzma-dev \
libsword-utils libtool pkg-config unzip zlib1g-dev

- name: Install published getbible/sword source through PIE
shell: bash
run: |
set -euo pipefail
sword_version="0.1.0"
sword_archive="php_getbiblesword-${sword_version}-src.tgz"
sword_release="https://github.com/getbible/sword/releases/download/v${sword_version}"
curl \
--fail \
--location \
--proto '=https' \
--retry 3 \
--show-error \
--silent \
--tlsv1.2 \
--output "$RUNNER_TEMP/pie.phar" \
https://github.com/php/pie/releases/download/1.4.9/pie.phar
echo \
'19a31ddd4bfd08b9eb5eaad2e5f63e76e7919cae7683852da41c80da704ad6c0 '"$RUNNER_TEMP"'/pie.phar' \
| sha256sum --check --strict
curl \
--fail \
--location \
--proto '=https' \
--retry 3 \
--show-error \
--silent \
--tlsv1.2 \
--output "$RUNNER_TEMP/$sword_archive" \
"$sword_release/$sword_archive"
curl \
--fail \
--location \
--proto '=https' \
--retry 3 \
--show-error \
--silent \
--tlsv1.2 \
--output "$RUNNER_TEMP/$sword_archive.sha256" \
"$sword_release/$sword_archive.sha256"
(
cd "$RUNNER_TEMP"
sha256sum --check --strict "$sword_archive.sha256"
)
mkdir -p "$RUNNER_TEMP/getbiblesword"
tar \
--extract \
--gzip \
--file "$RUNNER_TEMP/$sword_archive" \
--directory "$RUNNER_TEMP/getbiblesword"
sword_root="$RUNNER_TEMP/getbiblesword/php_getbiblesword-${sword_version}"
test -f "$sword_root/composer.json"
test -f "$sword_root/vendor/getbiblesword/src/c_api.cpp"
sudo env COMPOSER_ALLOW_SUPERUSER=1 \
php "$RUNNER_TEMP/pie.phar" repository:add path "$sword_root"
sudo env COMPOSER_ALLOW_SUPERUSER=1 \
php "$RUNNER_TEMP/pie.phar" install \
--no-cache \
'getbible/sword:*@dev'
php --ri getbiblesword
extension_path="$(
php -r '
echo rtrim((string) ini_get("extension_dir"), DIRECTORY_SEPARATOR)
. DIRECTORY_SEPARATOR
. "getbiblesword."
. PHP_SHLIB_SUFFIX;
'
)"
test -f "$extension_path"
if ldd "$extension_path" \
| grep -E 'lib(getbible)?sword[^[:space:]]*\.so'; then
echo 'The extension unexpectedly depends on a SWORD shared library.' >&2
exit 1
fi

- name: Install Composer dependencies
run: composer install --no-interaction --prefer-dist

- name: Create deterministic SWORD fixture
id: fixture
shell: bash
run: |
set -euo pipefail
sword_utils_version="$(
dpkg-query --show --showformat='${Version}' libsword-utils
)"
if [[ "$sword_utils_version" != 1.9.0+dfsg-* ]]; then
echo "Unexpected libsword-utils version: $sword_utils_version" >&2
exit 1
fi
bash scripts/create-native-fixture.sh "$RUNNER_TEMP/sword"
fixture_tree_sha256="$(
find "$RUNNER_TEMP/sword" -type f -printf '%P\0' \
| sort --zero-terminated \
| while IFS= read -r -d '' relative_path; do
printf '%s\0' "$relative_path"
sha256sum "$RUNNER_TEMP/sword/$relative_path" \
| cut --delimiter=' ' --fields=1 \
| tr --delete '\n'
printf '\0'
done \
| sha256sum \
| cut --delimiter=' ' --fields=1
)"
{
printf 'source_sha256=%s\n' \
'7ceaa7330fd234669dfc58c67294639a0a58a5a75c70efb4320a3f7adfc428a5'
printf 'tree_sha256=%s\n' "$fixture_tree_sha256"
printf 'sword_utils_version=%s\n' "$sword_utils_version"
} >> "$GITHUB_OUTPUT"

- name: Run installed-module integration
env:
FIXTURE_SOURCE_SHA256: ${{ steps.fixture.outputs.source_sha256 }}
FIXTURE_TREE_SHA256: ${{ steps.fixture.outputs.tree_sha256 }}
SWORD_UTILS_VERSION: ${{ steps.fixture.outputs.sword_utils_version }}
run: >-
php scripts/integration-native.php
"$RUNNER_TEMP/sword"
"$RUNNER_TEMP/cache"
"build/integration-evidence.json"

- name: Retain integration evidence
if: always() && hashFiles('build/integration-evidence.json') != ''
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: native-integration-${{ github.sha }}
path: build/integration-evidence.json
if-no-files-found: error
retention-days: 90
Loading