From 1c87103bde1d8770c2648ed168c69d0661d5db2a Mon Sep 17 00:00:00 2001 From: radudiaconu Date: Tue, 16 Jun 2026 21:35:54 +0300 Subject: [PATCH 1/6] feat(php): wire release pipeline --- .github/actions/php/post-merge/action.yml | 227 ++++++++++ .github/config/publish.yml | 6 + .github/workflows/_build_php_extensions.yml | 466 ++++++++++++++++++++ .github/workflows/_common.yml | 9 + .github/workflows/post-merge.yml | 6 +- .github/workflows/publish.yml | 136 +++++- .pre-commit-config.yaml | 10 +- foreign/php/composer.json | 1 + scripts/ci/php-sdk-version-sync.sh | 109 +++++ scripts/extract-version.sh | 21 +- 10 files changed, 976 insertions(+), 15 deletions(-) create mode 100644 .github/actions/php/post-merge/action.yml create mode 100644 .github/workflows/_build_php_extensions.yml create mode 100755 scripts/ci/php-sdk-version-sync.sh diff --git a/.github/actions/php/post-merge/action.yml b/.github/actions/php/post-merge/action.yml new file mode 100644 index 0000000000..95a9ecdbde --- /dev/null +++ b/.github/actions/php/post-merge/action.yml @@ -0,0 +1,227 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: php-post-merge +description: PHP post-merge Packagist publishing with pre-built PIE extension archives + +inputs: + version: + description: "Version for publishing" + required: true + tag: + description: "Git tag that identifies this PHP SDK release" + required: true + commit: + description: "Commit SHA being published" + required: true + dry_run: + description: "Dry run mode" + required: false + default: "false" + packages_artifact: + description: "Name of the artifact containing PHP extension archives" + required: false + default: "php-extensions-all" + packages_path: + description: "Path where PHP packages should be downloaded" + required: false + default: "dist" + +runs: + using: "composite" + steps: + - name: Validate version format + run: | + VERSION="${{ inputs.version }}" + + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$'; then + echo "Invalid PHP SDK version format: $VERSION" + echo "Expected Composer/Cargo-compatible SemVer: X.Y.Z[-prerelease][+build]" + exit 1 + fi + + echo "Version format valid: $VERSION" + shell: bash + + - name: Download pre-built PHP packages + uses: actions/download-artifact@v8 + with: + name: ${{ inputs.packages_artifact }} + path: ${{ inputs.packages_path }} + + - name: Validate downloaded PHP packages + run: | + set -euo pipefail + + PACKAGES_PATH="${{ inputs.packages_path }}" + VERSION="${{ inputs.version }}" + + if [ ! -d "$PACKAGES_PATH" ]; then + echo "PHP packages directory not found: $PACKAGES_PATH" + exit 1 + fi + + expected=( + "php_iggy_php-${VERSION}_php8.3-x86_64-linux-glibc-nts.zip" + "php_iggy_php-${VERSION}_php8.4-x86_64-linux-glibc-nts.zip" + "php_iggy_php-${VERSION}_php8.3-aarch64-linux-glibc-nts.zip" + "php_iggy_php-${VERSION}_php8.4-aarch64-linux-glibc-nts.zip" + "php_iggy_php-${VERSION}_php8.3-x86_64-linux-musl-nts.zip" + "php_iggy_php-${VERSION}_php8.4-x86_64-linux-musl-nts.zip" + "php_iggy_php-${VERSION}_php8.3-aarch64-linux-musl-nts.zip" + "php_iggy_php-${VERSION}_php8.4-aarch64-linux-musl-nts.zip" + "php_iggy_php-${VERSION}_php8.3-x86_64-macos-bsdlibc-nts.zip" + "php_iggy_php-${VERSION}_php8.4-x86_64-macos-bsdlibc-nts.zip" + "php_iggy_php-${VERSION}_php8.3-aarch64-macos-bsdlibc-nts.zip" + "php_iggy_php-${VERSION}_php8.4-aarch64-macos-bsdlibc-nts.zip" + "apache-iggy-php-${VERSION}-source.tar.gz" + ) + + missing=0 + for filename in "${expected[@]}"; do + if [ ! -f "$PACKAGES_PATH/$filename" ]; then + echo "Missing expected package: $filename" + missing=1 + fi + done + if [ "$missing" -ne 0 ]; then + exit 1 + fi + + echo "Validating PHP extension archive contents:" + for archive in "$PACKAGES_PATH"/*.zip; do + filename="$(basename "$archive")" + echo " - $filename" + unzip -l "$archive" | awk '{ print $4 }' | grep -qx 'iggy_php.so' + unzip -l "$archive" | awk '{ print $4 }' | grep -qx 'LICENSE' + unzip -l "$archive" | awk '{ print $4 }' | grep -qx 'NOTICE' + unzip -l "$archive" | awk '{ print $4 }' | grep -qx 'LICENSE-binary' + done + + echo "" + echo "Packages ready for publishing:" + find "$PACKAGES_PATH" -maxdepth 1 -type f -print | sort | while IFS= read -r file; do + size="$(du -h "$file" | cut -f1)" + echo " - $(basename "$file") ($size)" + done + shell: bash + + - name: Display publishing information (dry run) + if: inputs.dry_run == 'true' + run: | + PACKAGES_PATH="${{ inputs.packages_path }}" + VERSION="${{ inputs.version }}" + TAG="${{ inputs.tag }}" + + echo "DRY RUN - Would publish PHP SDK:" + echo "" + echo "Package: apache/iggy-php" + echo "Version: $VERSION" + echo "Tag: $TAG" + echo "Registry: https://packagist.org/packages/apache/iggy-php" + echo "" + echo "Release assets that would be uploaded:" + find "$PACKAGES_PATH" -maxdepth 1 -type f -print | sort | sed 's|.*/| - |' + echo "" + echo "Packagist would be asked to refresh https://github.com/apache/iggy" + shell: bash + + - name: Publish GitHub release assets + if: inputs.dry_run == 'false' + run: | + set -euo pipefail + + PACKAGES_PATH="${{ inputs.packages_path }}" + VERSION="${{ inputs.version }}" + TAG="${{ inputs.tag }}" + COMMIT="${{ inputs.commit }}" + + if [ -z "$TAG" ]; then + echo "PHP release tag input is empty" + exit 1 + fi + if ! git ls-remote --tags --exit-code origin "refs/tags/${TAG}" >/dev/null 2>&1; then + echo "PHP release tag $TAG does not exist on origin" + echo "Create the annotated PHP SDK tag before publishing GitHub release assets or refreshing Packagist." + exit 1 + fi + + release_notes="$(mktemp)" + { + echo "Apache Iggy PHP SDK ${VERSION}" + echo "" + echo "This GitHub release contains downstream convenience binaries for the PHP extension." + echo "The canonical Apache source release remains the ASF release artifact." + } > "$release_notes" + + prerelease_flag=() + if [[ "$VERSION" == *-* ]]; then + prerelease_flag=(--prerelease) + fi + + if gh release view "$TAG" >/dev/null 2>&1; then + echo "GitHub release $TAG exists, uploading assets with clobber" + gh release upload "$TAG" "$PACKAGES_PATH"/* --clobber + else + echo "Creating GitHub release $TAG" + gh release create "$TAG" "$PACKAGES_PATH"/* \ + --target "$COMMIT" \ + --title "$TAG" \ + --notes-file "$release_notes" \ + "${prerelease_flag[@]}" + fi + shell: bash + env: + GH_TOKEN: ${{ github.token }} + + - name: Trigger Packagist update + if: inputs.dry_run == 'false' + run: | + set -euo pipefail + + if [ -z "${PACKAGIST_TOKEN:-}" ]; then + echo "PACKAGIST_TOKEN is not set" + exit 1 + fi + + if [[ "$PACKAGIST_TOKEN" != *:* ]]; then + echo "PACKAGIST_TOKEN must use Packagist bearer credentials in USERNAME:apiToken format" + exit 1 + fi + + response="$(mktemp)" + http_code="$(curl -sSL \ + -o "$response" \ + -w '%{http_code}' \ + -X POST \ + -H 'Content-Type: application/json' \ + -H "Authorization: Bearer ${PACKAGIST_TOKEN}" \ + 'https://packagist.org/api/update-package' \ + -d '{"repository":"https://github.com/apache/iggy"}')" + + if [ "$http_code" != "200" ]; then + echo "Packagist update failed with HTTP $http_code" + cat "$response" + exit 1 + fi + + cat "$response" + echo "" + echo "Packagist update requested for apache/iggy-php" + shell: bash + env: + PACKAGIST_TOKEN: ${{ env.PACKAGIST_TOKEN }} diff --git a/.github/config/publish.yml b/.github/config/publish.yml index 36376d34c6..3ff418354f 100644 --- a/.github/config/publish.yml +++ b/.github/config/publish.yml @@ -123,6 +123,12 @@ components: version_file: "foreign/python/pyproject.toml" version_regex: '(?m)^\s*version\s*=\s*"([^"]+)"' + sdk-php: + tag_pattern: "^php-sdk-([0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?)$" + registry: packagist + version_file: "foreign/php/composer.json" + version_regex: '"version"\s*:\s*"([^"]+)"' + sdk-node: tag_pattern: "^node-sdk-([0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?)$" registry: npm diff --git a/.github/workflows/_build_php_extensions.yml b/.github/workflows/_build_php_extensions.yml new file mode 100644 index 0000000000..53a204e718 --- /dev/null +++ b/.github/workflows/_build_php_extensions.yml @@ -0,0 +1,466 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: _build_php_extensions +on: + workflow_call: + inputs: + version: + type: string + required: false + default: "" + upload_artifacts: + type: boolean + required: false + default: true + use_latest_ci: + type: boolean + required: false + default: true + description: "Use latest CI configuration and scripts from master branch" + commit: + type: string + required: false + default: "" + description: "Specific commit to checkout for building PHP extensions" + outputs: + artifact_name: + description: "Name of the uploaded artifact containing PHP extension archives" + value: ${{ jobs.collect.outputs.artifact_name }} + +permissions: + contents: read + +jobs: + license-manifest: + name: Generate PHP binary license manifest + runs-on: ubuntu-latest + steps: + - name: Download latest copy script from master + if: inputs.use_latest_ci + run: | + curl -sSL "https://raw.githubusercontent.com/${{ github.repository }}/master/scripts/copy-latest-from-master.sh" \ + -o /tmp/copy-latest-from-master.sh + chmod +x /tmp/copy-latest-from-master.sh + + - uses: actions/checkout@v6.0.2 + with: + ref: ${{ inputs.commit }} + + - name: Save and apply latest CI from master + if: inputs.use_latest_ci + run: | + /tmp/copy-latest-from-master.sh save .github scripts + /tmp/copy-latest-from-master.sh apply + + - name: Install cargo-about + run: | + mkdir -p "$HOME/.cargo/bin" + TARGET="$(uname -m)-unknown-linux-musl" + curl -sSfL "https://github.com/EmbarkStudios/cargo-about/releases/download/0.9.0/cargo-about-0.9.0-${TARGET}.tar.gz" \ + | tar -xz -C "$HOME/.cargo/bin" --strip-components=1 "cargo-about-0.9.0-${TARGET}/cargo-about" + + - name: Generate third-party license manifest + run: ./scripts/ci/third-party-licenses.sh --generate --manifest foreign/php/Cargo.toml --output foreign/php/LICENSE-binary + + - name: Upload license manifest + uses: actions/upload-artifact@v7 + with: + name: php-license-binary + path: foreign/php/LICENSE-binary + retention-days: 7 + + linux: + name: PHP ${{ matrix.php }} ${{ matrix.arch }} linux-${{ matrix.libc }} + needs: license-manifest + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - php: "8.3" + arch: x86_64 + libc: glibc + runner: ubuntu-latest + image: php:8.3-cli-bookworm + - php: "8.4" + arch: x86_64 + libc: glibc + runner: ubuntu-latest + image: php:8.4-cli-bookworm + - php: "8.3" + arch: aarch64 + libc: glibc + runner: ubuntu-24.04-arm + image: php:8.3-cli-bookworm + - php: "8.4" + arch: aarch64 + libc: glibc + runner: ubuntu-24.04-arm + image: php:8.4-cli-bookworm + - php: "8.3" + arch: x86_64 + libc: musl + runner: ubuntu-latest + image: php:8.3-cli-alpine + - php: "8.4" + arch: x86_64 + libc: musl + runner: ubuntu-latest + image: php:8.4-cli-alpine + - php: "8.3" + arch: aarch64 + libc: musl + runner: ubuntu-24.04-arm + image: php:8.3-cli-alpine + - php: "8.4" + arch: aarch64 + libc: musl + runner: ubuntu-24.04-arm + image: php:8.4-cli-alpine + steps: + - name: Download latest copy script from master + if: inputs.use_latest_ci + run: | + curl -sSL "https://raw.githubusercontent.com/${{ github.repository }}/master/scripts/copy-latest-from-master.sh" \ + -o /tmp/copy-latest-from-master.sh + chmod +x /tmp/copy-latest-from-master.sh + + - uses: actions/checkout@v6.0.2 + with: + ref: ${{ inputs.commit }} + + - name: Save and apply latest CI from master + if: inputs.use_latest_ci + run: | + /tmp/copy-latest-from-master.sh save .github scripts + /tmp/copy-latest-from-master.sh apply + + - name: Download license manifest + uses: actions/download-artifact@v8 + with: + name: php-license-binary + path: foreign/php + + - name: Resolve version + id: ver + run: | + if [ -n "${{ inputs.version }}" ]; then + version="${{ inputs.version }}" + else + chmod +x scripts/extract-version.sh + version="$(scripts/extract-version.sh sdk-php)" + fi + echo "version=${version}" >> "$GITHUB_OUTPUT" + + - name: Build and package PHP extension + env: + VERSION: ${{ steps.ver.outputs.version }} + PHP_VERSION: ${{ matrix.php }} + PHP_ARCH: ${{ matrix.arch }} + PHP_LIBC: ${{ matrix.libc }} + PHP_IMAGE: ${{ matrix.image }} + run: | + set -euo pipefail + + mkdir -p foreign/php/dist + + docker run --rm \ + -e CARGO_TERM_COLOR=always \ + -e CARGO_TARGET_DIR=/workspace/target/php-release-${PHP_VERSION}-${PHP_ARCH}-${PHP_LIBC} \ + -e VERSION="${VERSION}" \ + -e PHP_VERSION="${PHP_VERSION}" \ + -e PHP_ARCH="${PHP_ARCH}" \ + -e PHP_LIBC="${PHP_LIBC}" \ + -v "$PWD:/workspace" \ + -w /workspace \ + "${PHP_IMAGE}" \ + sh -lc ' + set -eu + + if command -v apt-get >/dev/null 2>&1; then + apt-get update + apt-get install -y --no-install-recommends \ + build-essential \ + ca-certificates \ + clang \ + curl \ + git \ + libclang-dev \ + libhwloc-dev \ + libssl-dev \ + libudev-dev \ + pkg-config \ + zip + rm -rf /var/lib/apt/lists/* + else + apk add --no-cache \ + build-base \ + ca-certificates \ + clang \ + clang-dev \ + curl \ + eudev-dev \ + git \ + hwloc-dev \ + linux-headers \ + openssl-dev \ + pkgconf \ + zip + fi + + curl -sSf https://sh.rustup.rs -o /tmp/rustup-init.sh + sh /tmp/rustup-init.sh -y --profile minimal --default-toolchain none + . "$HOME/.cargo/env" + rustup show + + php --version + php-config --version + cargo build --release --manifest-path foreign/php/Cargo.toml + + extension="$(find "${CARGO_TARGET_DIR}/release" -maxdepth 1 -name "libiggy_php.so" -print -quit)" + if [ -z "$extension" ]; then + echo "PHP extension was not produced" + exit 1 + fi + + package_dir="$(mktemp -d)" + cp "$extension" "$package_dir/iggy_php.so" + cp foreign/php/LICENSE "$package_dir/LICENSE" + cp foreign/php/NOTICE "$package_dir/NOTICE" + cp foreign/php/LICENSE-binary "$package_dir/LICENSE-binary" + + archive="php_iggy_php-${VERSION}_php${PHP_VERSION}-${PHP_ARCH}-linux-${PHP_LIBC}-nts.zip" + (cd "$package_dir" && zip -9 "/workspace/foreign/php/dist/${archive}" iggy_php.so LICENSE NOTICE LICENSE-binary) + rm -rf "$package_dir" + ' + + ls -lh foreign/php/dist + + - name: Upload PHP extension archive + if: inputs.upload_artifacts + uses: actions/upload-artifact@v7 + with: + name: php-package-linux-${{ matrix.arch }}-${{ matrix.libc }}-php${{ matrix.php }} + path: foreign/php/dist/*.zip + retention-days: 7 + + macos: + name: PHP ${{ matrix.php }} ${{ matrix.arch }} macos + needs: license-manifest + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - php: "8.3" + arch: x86_64 + runner: macos-15-intel + - php: "8.4" + arch: x86_64 + runner: macos-15-intel + - php: "8.3" + arch: aarch64 + runner: macos-15 + - php: "8.4" + arch: aarch64 + runner: macos-15 + steps: + - name: Download latest copy script from master + if: inputs.use_latest_ci + run: | + curl -sSL "https://raw.githubusercontent.com/${{ github.repository }}/master/scripts/copy-latest-from-master.sh" \ + -o /tmp/copy-latest-from-master.sh + chmod +x /tmp/copy-latest-from-master.sh + + - uses: actions/checkout@v6.0.2 + with: + ref: ${{ inputs.commit }} + + - name: Save and apply latest CI from master + if: inputs.use_latest_ci + run: | + /tmp/copy-latest-from-master.sh save .github scripts + /tmp/copy-latest-from-master.sh apply + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: none + + - name: Setup Rust with cache + uses: ./.github/actions/utils/setup-rust-with-cache + with: + shared-key: php-release + save-cache: "false" + + - name: Download license manifest + uses: actions/download-artifact@v8 + with: + name: php-license-binary + path: foreign/php + + - name: Resolve version + id: ver + run: | + if [ -n "${{ inputs.version }}" ]; then + version="${{ inputs.version }}" + else + chmod +x scripts/extract-version.sh + version="$(scripts/extract-version.sh sdk-php)" + fi + echo "version=${version}" >> "$GITHUB_OUTPUT" + + - name: Build and package PHP extension + env: + VERSION: ${{ steps.ver.outputs.version }} + PHP_VERSION: ${{ matrix.php }} + PHP_ARCH: ${{ matrix.arch }} + CARGO_TARGET_DIR: ${{ github.workspace }}/target/php-release-${{ matrix.php }}-${{ matrix.arch }}-macos + run: | + set -euo pipefail + + php --version + php-config --version + cargo build --release --manifest-path foreign/php/Cargo.toml + + extension="$(find "${CARGO_TARGET_DIR}/release" -maxdepth 1 \( -name 'libiggy_php.so' -o -name 'libiggy_php.dylib' \) -print -quit)" + if [ -z "$extension" ]; then + echo "PHP extension was not produced" + exit 1 + fi + + mkdir -p foreign/php/dist + package_dir="$(mktemp -d)" + cp "$extension" "$package_dir/iggy_php.so" + cp foreign/php/LICENSE "$package_dir/LICENSE" + cp foreign/php/NOTICE "$package_dir/NOTICE" + cp foreign/php/LICENSE-binary "$package_dir/LICENSE-binary" + + archive="php_iggy_php-${VERSION}_php${PHP_VERSION}-${PHP_ARCH}-macos-bsdlibc-nts.zip" + (cd "$package_dir" && zip -9 "${{ github.workspace }}/foreign/php/dist/${archive}" iggy_php.so LICENSE NOTICE LICENSE-binary) + rm -rf "$package_dir" + + ls -lh foreign/php/dist + + - name: Upload PHP extension archive + if: inputs.upload_artifacts + uses: actions/upload-artifact@v7 + with: + name: php-package-macos-${{ matrix.arch }}-php${{ matrix.php }} + path: foreign/php/dist/*.zip + retention-days: 7 + + source: + name: Build PHP source archive + runs-on: ubuntu-latest + steps: + - name: Download latest copy script from master + if: inputs.use_latest_ci + run: | + curl -sSL "https://raw.githubusercontent.com/${{ github.repository }}/master/scripts/copy-latest-from-master.sh" \ + -o /tmp/copy-latest-from-master.sh + chmod +x /tmp/copy-latest-from-master.sh + + - uses: actions/checkout@v6.0.2 + with: + ref: ${{ inputs.commit }} + + - name: Save and apply latest CI from master + if: inputs.use_latest_ci + run: | + /tmp/copy-latest-from-master.sh save .github scripts + /tmp/copy-latest-from-master.sh apply + + - name: Resolve version + id: ver + run: | + if [ -n "${{ inputs.version }}" ]; then + version="${{ inputs.version }}" + else + chmod +x scripts/extract-version.sh + version="$(scripts/extract-version.sh sdk-php)" + fi + echo "version=${version}" >> "$GITHUB_OUTPUT" + + - name: Build source archive + run: | + set -euo pipefail + + version="${{ steps.ver.outputs.version }}" + mkdir -p foreign/php/dist + git archive \ + --format=tar.gz \ + --prefix="apache-iggy-php-${version}/" \ + --output="foreign/php/dist/apache-iggy-php-${version}-source.tar.gz" \ + HEAD + + ls -lh foreign/php/dist + + - name: Upload PHP source archive + if: inputs.upload_artifacts + uses: actions/upload-artifact@v7 + with: + name: php-package-source + path: foreign/php/dist/*.tar.gz + retention-days: 7 + + collect: + name: Collect PHP packages + needs: [linux, macos, source] + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + outputs: + artifact_name: ${{ steps.output.outputs.artifact_name }} + steps: + - name: Download PHP packages + uses: actions/download-artifact@v8 + with: + pattern: php-package-* + merge-multiple: true + path: dist + + - name: List PHP packages + run: | + echo "## Built PHP packages" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Kind | File |" >> $GITHUB_STEP_SUMMARY + echo "|------|------|" >> $GITHUB_STEP_SUMMARY + + while IFS= read -r package; do + filename="$(basename "$package")" + case "$filename" in + *.zip) kind="PIE binary" ;; + *.tar.gz) kind="Source" ;; + *) kind="Other" ;; + esac + echo "| $kind | \`$filename\` |" >> $GITHUB_STEP_SUMMARY + done < <(find dist -type f | sort) + + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Total packages built:** $(find dist -type f | wc -l)" >> $GITHUB_STEP_SUMMARY + + - name: Upload combined artifact + uses: actions/upload-artifact@v7 + with: + name: php-extensions-all + path: dist + retention-days: 30 + + - id: output + run: echo "artifact_name=php-extensions-all" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/_common.yml b/.github/workflows/_common.yml index 616008abcb..d220cadd78 100644 --- a/.github/workflows/_common.yml +++ b/.github/workflows/_common.yml @@ -42,6 +42,15 @@ jobs: - name: Check Python SDK versions are synchronized run: ./scripts/ci/python-sdk-version-sync.sh --check + php-versions: + name: Check PHP SDK versions sync + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6.0.2 + + - name: Check PHP SDK versions are synchronized + run: ./scripts/ci/php-sdk-version-sync.sh --check + python-interpreter-versions: name: Check Python interpreter versions sync runs-on: ubuntu-latest diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index 5de7a96ec1..b41176b2b8 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -16,7 +16,8 @@ # under the License. # Auto-publish: detects pre-release crate/SDK versions without tags -# and publishes them to crates.io, Docker Hub, PyPI, npm, Maven, NuGet. +# and publishes them to crates.io, Docker Hub, PyPI, Packagist, npm, Maven, +# NuGet. # Runs on every push to master. name: Post-merge @@ -107,7 +108,7 @@ jobs: # Check SDKs for pre-release versions without tags SDKS_TO_PUBLISH="" - for sdk in sdk-python sdk-node sdk-java sdk-csharp sdk-go; do + for sdk in sdk-python sdk-php sdk-node sdk-java sdk-csharp sdk-go; do VERSION=$(scripts/extract-version.sh "$sdk") TAG=$(scripts/extract-version.sh "$sdk" --tag) @@ -163,4 +164,3 @@ jobs: publish_other: ${{ needs.check-auto-publish.outputs.sdks_to_publish }} create_edge_docker_tag: true secrets: inherit - diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index aa28ccd10c..40bd186af0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -49,7 +49,7 @@ on: required: false default: "" publish_other: - description: "Other SDKs to publish (comma-separated: python, node, java, csharp, go)" + description: "Other SDKs to publish (comma-separated: python, php, node, java, csharp, go)" type: string required: false default: "" @@ -109,6 +109,8 @@ on: required: false NUGET_API_KEY: required: false + PACKAGIST_TOKEN: + required: false env: IGGY_CI_BUILD: true @@ -119,7 +121,7 @@ permissions: id-token: write # Static group so two concurrent release dispatches cannot race the -# crates.io / Maven Central / npm / NuGet / DockerHub / PyPI uploads. +# crates.io / Maven Central / npm / NuGet / DockerHub / PyPI / Packagist uploads. # `run_id` in the group was effectively a no-op because it is unique # per dispatch. `cancel-in-progress: false` keeps any in-flight upload # running to completion rather than leaving partial state in registries. @@ -264,6 +266,7 @@ jobs: docker_components: ${{ steps.mk.outputs.docker_components }} count: ${{ steps.mk.outputs.count }} has_python: ${{ steps.mk.outputs.has_python }} + has_php: ${{ steps.mk.outputs.has_php }} has_rust_crates: ${{ steps.mk.outputs.has_rust_crates }} has_docker: ${{ steps.mk.outputs.has_docker }} steps: @@ -327,7 +330,7 @@ jobs: // Parse other SDKs ('${{ inputs.publish_other }}').split(',').map(s => s.trim()).filter(Boolean).forEach(sdk => { - if (['python','node','java','csharp','go'].includes(sdk)) { + if (['python','php','node','java','csharp','go'].includes(sdk)) { wants.push(`sdk-${sdk}`); } else { core.warning(`Unknown SDK: ${sdk}`); @@ -338,6 +341,7 @@ jobs: dockerhub: 'docker', crates: 'rust', pypi: 'python', + packagist: 'php', npm: 'node', maven: 'java', nuget: 'csharp', @@ -428,6 +432,13 @@ jobs: core.setOutput('has_python', 'false'); } + const phpTarget = targets.find(t => t.key === 'sdk-php'); + if (phpTarget) { + core.setOutput('has_php', 'true'); + } else { + core.setOutput('has_php', 'false'); + } + check-tags: name: Check existing tags needs: [validate, plan] @@ -580,8 +591,8 @@ jobs: echo "| $NAME | $VERSION | $TAG | ℹ️ Already released ($SHORT_SHA) - :edge refresh only |" >> $GITHUB_STEP_SUMMARY # Fail-fast on wrong-target for MANUAL publish. A wrong-target tag # means create-git-tag would hard-fail 20-40 minutes later after - # publishing artifacts to crates.io / PyPI / npm / Maven / - # NuGet / DockerHub. Catching it at check-tags converts that + # publishing artifacts to crates.io / PyPI / Packagist / npm / + # Maven / NuGet / DockerHub. Catching it at check-tags converts that # into a fast, cheap failure at the top of the run. # Same-target is still benign (rerun convergence). # @@ -711,6 +722,18 @@ jobs: use_latest_ci: ${{ inputs.use_latest_ci }} commit: ${{ needs.validate.outputs.commit }} + build-php-extensions: + name: Build PHP extensions + needs: [validate, plan, check-tags] + if: | + needs.validate.outputs.has_targets == 'true' && + needs.plan.outputs.has_php == 'true' + uses: ./.github/workflows/_build_php_extensions.yml + with: + upload_artifacts: true + use_latest_ci: ${{ inputs.use_latest_ci }} + commit: ${{ needs.validate.outputs.commit }} + # Sequential Rust crate publishing to handle dependencies properly publish-rust-crates: name: Publish Rust crates @@ -731,13 +754,14 @@ jobs: # Docker publishing on native runners (no QEMU emulation) publish-docker: name: Docker ${{ matrix.name }} (${{ matrix.arch }}) - needs: [validate, plan, check-tags, build-python-wheels, publish-rust-crates] + needs: [validate, plan, check-tags, build-python-wheels, build-php-extensions, publish-rust-crates] if: | !cancelled() && needs.validate.outputs.has_targets == 'true' && needs.plan.outputs.has_docker == 'true' && fromJson(needs.plan.outputs.docker_matrix).include[0].key != 'noop' && (needs.build-python-wheels.result == 'success' || needs.build-python-wheels.result == 'skipped') && + (needs.build-php-extensions.result == 'success' || needs.build-php-extensions.result == 'skipped') && (needs.publish-rust-crates.result == 'success' || needs.publish-rust-crates.result == 'skipped') runs-on: ${{ matrix.runner }} timeout-minutes: 60 @@ -1034,16 +1058,17 @@ jobs: Commit: ${{ needs.validate.outputs.commit }} Released by: GitHub Actions (workflow ${{ github.run_id }}) - # Non-Docker, non-Rust publishing (Python, Node, Java, C#, Go SDKs) + # Non-Docker, non-Rust publishing (Python, PHP, Node, Java, C#, Go SDKs) # Note: This job runs in parallel with Docker publishing - no dependency between them publish: name: ${{ matrix.name }} - needs: [validate, plan, check-tags, build-python-wheels, publish-rust-crates] + needs: [validate, plan, check-tags, build-python-wheels, build-php-extensions, publish-rust-crates] if: | !cancelled() && needs.validate.outputs.has_targets == 'true' && fromJson(needs.plan.outputs.non_docker_targets).include[0].key != 'noop' && (needs.build-python-wheels.result == 'success' || needs.build-python-wheels.result == 'skipped') && + (needs.build-php-extensions.result == 'success' || needs.build-php-extensions.result == 'skipped') && (needs.publish-rust-crates.result == 'success' || needs.publish-rust-crates.result == 'skipped') runs-on: ubuntu-latest strategy: @@ -1058,6 +1083,7 @@ jobs: JAVA_GPG_SIGNING_KEY: ${{ secrets.JAVA_GPG_SIGNING_KEY }} JAVA_GPG_PASSWORD: ${{ secrets.JAVA_GPG_PASSWORD }} NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + PACKAGIST_TOKEN: ${{ secrets.PACKAGIST_TOKEN }} DRY_RUN: ${{ inputs.dry_run }} outputs: status: ${{ steps.status.outputs.status }} @@ -1163,6 +1189,39 @@ jobs: wheels_artifact: python-wheels-all wheels_path: dist + # ───────────────────────────────────────── + # PHP SDK Publishing + # ───────────────────────────────────────── + - name: Tag PHP SDK release (${{ matrix.key }}) + if: | + success() && + inputs.dry_run == false && + inputs.skip_tag_creation == false && + matrix.type == 'php' && + steps.ver.outputs.should_tag == 'true' + uses: ./.github/actions/utils/create-git-tag + with: + tag: ${{ steps.ver.outputs.tag }} + commit: ${{ needs.validate.outputs.commit }} + message: | + Release ${{ matrix.key }} ${{ steps.ver.outputs.version }} + + Component: ${{ matrix.key }} + Tag: ${{ steps.ver.outputs.tag }} + Commit: ${{ needs.validate.outputs.commit }} + Released by: GitHub Actions (workflow ${{ github.run_id }}) + + - name: Publish PHP SDK + if: matrix.type == 'php' + uses: ./.github/actions/php/post-merge + with: + version: ${{ steps.ver.outputs.version }} + tag: ${{ steps.ver.outputs.tag }} + commit: ${{ needs.validate.outputs.commit }} + dry_run: ${{ inputs.dry_run }} + packages_artifact: php-extensions-all + packages_path: dist + # ───────────────────────────────────────── # Node SDK Publishing # ───────────────────────────────────────── @@ -1238,6 +1297,52 @@ jobs: max_attempts: "15" initial_sleep_seconds: "3" + - name: Wait for Packagist availability + if: | + success() && + inputs.dry_run == false && + matrix.type == 'php' && + steps.ver.outputs.should_tag == 'true' + uses: ./.github/actions/utils/wait-for-url + with: + url: https://repo.packagist.org/p2/apache/iggy-php.json + description: apache/iggy-php metadata on Packagist + max_attempts: "20" + initial_sleep_seconds: "3" + + - name: Verify Packagist version + if: | + success() && + inputs.dry_run == false && + matrix.type == 'php' && + steps.ver.outputs.should_tag == 'true' + shell: bash + run: | + set -euo pipefail + version="${{ steps.ver.outputs.version }}" + + sleep_s=3 + for attempt in $(seq 1 20); do + if curl -sSL https://repo.packagist.org/p2/apache/iggy-php.json \ + | jq -e --arg version "$version" '.packages["apache/iggy-php"][] | select(.version == $version or .version == ("v" + $version))' >/dev/null; then + echo "apache/iggy-php ${version} is present in Packagist metadata" + exit 0 + fi + + if [ "$attempt" -eq 20 ]; then + break + fi + echo "Packagist metadata is available but ${version} is not listed yet (attempt ${attempt}/20, sleep ${sleep_s}s)" + sleep "$sleep_s" + sleep_s=$(( sleep_s * 2 )) + if [ "$sleep_s" -gt 30 ]; then + sleep_s=30 + fi + done + + echo "Timed out waiting for apache/iggy-php ${version} in Packagist metadata" + exit 1 + # Java publishes to ASF Nexus staging via `./gradlew publish` # (repository.apache.org/service/local/staging/deploy/maven2). The # staging -> Maven Central handoff requires a Nexus Close+Release @@ -1317,6 +1422,7 @@ jobs: if: | success() && inputs.dry_run == false && + matrix.type != 'php' && inputs.skip_tag_creation == false && steps.ver.outputs.should_tag == 'true' uses: ./.github/actions/utils/create-git-tag @@ -1345,6 +1451,7 @@ jobs: plan, check-tags, build-python-wheels, + build-php-extensions, publish-rust-crates, publish-docker, docker-manifests, @@ -1432,6 +1539,7 @@ jobs: crates) REGISTRY_DISPLAY="crates.io" ;; dockerhub) REGISTRY_DISPLAY="Docker Hub" ;; pypi) REGISTRY_DISPLAY="PyPI" ;; + packagist) REGISTRY_DISPLAY="Packagist" ;; npm) REGISTRY_DISPLAY="npm" ;; maven) REGISTRY_DISPLAY="Maven" ;; nuget) REGISTRY_DISPLAY="NuGet" ;; @@ -1477,6 +1585,17 @@ jobs: echo fi + # PHP extension building status + if [ "${{ needs.plan.outputs.has_php }}" = "true" ]; then + echo "### PHP Extension Building" + case "${{ needs.build-php-extensions.result }}" in + success) echo "✅ **PHP extension packages built successfully for all platforms**" ;; + failure) echo "❌ **PHP extension package building failed**" ;; + skipped) echo "⏭️ **PHP extension package building was skipped**" ;; + esac + echo + fi + # Rust crates publishing status if [ -n "${{ inputs.publish_crates }}" ]; then echo "### Rust Crates Publishing (Sequential)" @@ -1536,6 +1655,7 @@ jobs: validate, plan, build-python-wheels, + build-php-extensions, publish-rust-crates, publish-docker, docker-manifests, diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 67ecaaaa0e..5a50b43e54 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -103,6 +103,14 @@ repos: files: ^foreign/python/(Cargo\.toml|pyproject\.toml)$ pass_filenames: false + - id: php-sdk-version-sync + name: php sdk version sync + entry: ./scripts/ci/php-sdk-version-sync.sh + args: ["--fix"] + language: system + files: ^foreign/php/(Cargo\.toml|composer\.json)$ + pass_filenames: false + - id: python-interpreter-version-sync name: python interpreter version sync entry: ./scripts/ci/sync-python-interpreter-version.sh @@ -124,7 +132,7 @@ repos: entry: ./scripts/extract-version.sh args: ["--check"] language: system - files: (^Cargo\.toml$|^(core|foreign)/.*Cargo\.toml$|^foreign/node/package\.json$|^foreign/python/pyproject\.toml$|^foreign/csharp/.*\.csproj$|^foreign/java/gradle\.properties$|^foreign/go/contracts/version\.go$|^\.github/config/publish\.yml$) + files: (^Cargo\.toml$|^(core|foreign)/.*Cargo\.toml$|^foreign/node/package\.json$|^foreign/python/pyproject\.toml$|^foreign/php/composer\.json$|^foreign/csharp/.*\.csproj$|^foreign/java/gradle\.properties$|^foreign/go/contracts/version\.go$|^\.github/config/publish\.yml$) pass_filenames: false - id: trailing-whitespace diff --git a/foreign/php/composer.json b/foreign/php/composer.json index d711c646ae..429b0a016f 100644 --- a/foreign/php/composer.json +++ b/foreign/php/composer.json @@ -1,6 +1,7 @@ { "name": "apache/iggy-php", "description": "PHP extension bindings for Apache Iggy.", + "version": "0.1.0", "type": "php-ext", "license": "Apache-2.0", "homepage": "https://iggy.apache.org", diff --git a/scripts/ci/php-sdk-version-sync.sh b/scripts/ci/php-sdk-version-sync.sh new file mode 100755 index 0000000000..e78297b734 --- /dev/null +++ b/scripts/ci/php-sdk-version-sync.sh @@ -0,0 +1,109 @@ +#!/bin/bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +MODE="" + +while [[ $# -gt 0 ]]; do + case $1 in + --check) + MODE="check" + shift + ;; + --fix) + MODE="fix" + shift + ;; + --help|-h) + echo "Usage: $0 [--check|--fix]" + echo "" + echo "Sync PHP SDK version between Cargo.toml and composer.json" + echo "" + echo "Options:" + echo " --check Check if versions are synchronized" + echo " --fix Update composer.json to match Cargo.toml" + echo " --help Show this help message" + exit 0 + ;; + *) + echo -e "${RED}Error: Unknown option $1${NC}" + echo "Use --help for usage information" + exit 1 + ;; + esac +done + +if [ -z "$MODE" ]; then + echo -e "${RED}Error: Please specify either --check or --fix${NC}" + echo "Use --help for usage information" + exit 1 +fi + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$REPO_ROOT" + +CARGO_TOML="foreign/php/Cargo.toml" +COMPOSER_JSON="foreign/php/composer.json" + +CARGO_VERSION=$(grep '^version = ' "$CARGO_TOML" | head -1 | sed 's/version = "\(.*\)"/\1/') +COMPOSER_VERSION=$(perl -0777 -ne 'if (/"version"\s*:\s*"([^"]+)"/) { print $1; exit; }' "$COMPOSER_JSON") + +if [ -z "$CARGO_VERSION" ]; then + echo -e "${RED}Error: Could not extract version from $CARGO_TOML${NC}" + exit 1 +fi + +if [ -z "$COMPOSER_VERSION" ]; then + echo -e "${RED}Error: Could not extract version from $COMPOSER_JSON${NC}" + exit 1 +fi + +echo "PHP SDK version check:" +echo " Cargo.toml: $CARGO_VERSION" +echo " composer.json: $COMPOSER_VERSION" +echo "" + +if [ "$MODE" = "check" ]; then + if [ "$CARGO_VERSION" = "$COMPOSER_VERSION" ]; then + echo -e "${GREEN}✓ PHP SDK versions are synchronized${NC}" + exit 0 + fi + + echo -e "${RED}✗ PHP SDK versions are NOT synchronized${NC}" + echo "" + echo "Please ensure both files have the same version:" + echo " - $CARGO_TOML" + echo " - $COMPOSER_JSON" + echo "" + echo -e "${YELLOW}Run '$0 --fix' to update composer.json from Cargo.toml${NC}" + exit 1 +fi + +if [ "$CARGO_VERSION" = "$COMPOSER_VERSION" ]; then + echo -e "${GREEN}✓ PHP SDK versions are already synchronized${NC}" + exit 0 +fi + +perl -0pi -e "s/\"version\"\\s*:\\s*\"\\Q$COMPOSER_VERSION\\E\"/\"version\": \"$CARGO_VERSION\"/" "$COMPOSER_JSON" +echo -e "${GREEN}✓ Updated $COMPOSER_JSON: $COMPOSER_VERSION -> $CARGO_VERSION${NC}" diff --git a/scripts/extract-version.sh b/scripts/extract-version.sh index 6253db9342..51f965e4e1 100755 --- a/scripts/extract-version.sh +++ b/scripts/extract-version.sh @@ -260,6 +260,22 @@ handle_check() { echo "" + # --- Check 3: PHP dual-file sync --- + echo "=== PHP dual-file sync ===" + local php_script="$SCRIPT_DIR/ci/php-sdk-version-sync.sh" + if [[ -x "$php_script" ]]; then + if "$php_script" --check; then + passes=$((passes + 1)) + else + errors=$((errors + 1)) + fi + else + echo -e " ${RED}FAIL${NC} php-sdk-version-sync.sh not found or not executable" + errors=$((errors + 1)) + fi + + echo "" + # --- Summary --- local total=$((passes + errors)) echo "=== Summary ===" @@ -406,12 +422,11 @@ fi # version would be auto-published to PyPI but never git-tagged). # # Matches (any of): -# -edge[.N] (rust crates, docker, node SDK) -# -rc[.N] (all SDKs) +# - (rust crates, docker, node/PHP SDKs) # .devN (Python SDK PEP 440 development markers) # rcN$ (legacy bare rcN, retained for compatibility) if [[ "$RETURN_IS_PRE_RELEASE" == "true" ]]; then - if [[ "$VERSION" =~ -(edge|rc) ]] \ + if [[ "$VERSION" =~ -[0-9A-Za-z] ]] \ || [[ "$VERSION" =~ \.dev[0-9]+$ ]] \ || [[ "$VERSION" =~ rc[0-9]+$ ]]; then echo "true" From 0814756cea17145bc78fd03da2d69960d127f526 Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Fri, 19 Jun 2026 09:40:11 +0300 Subject: [PATCH 2/6] fix(php): address release workflow review nits --- .github/actions/php/post-merge/action.yml | 6 +- .github/workflows/_build_php_extensions.yml | 99 +++++++++++++++++++++ .github/workflows/publish.yml | 1 + 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/.github/actions/php/post-merge/action.yml b/.github/actions/php/post-merge/action.yml index 95a9ecdbde..0f18a93136 100644 --- a/.github/actions/php/post-merge/action.yml +++ b/.github/actions/php/post-merge/action.yml @@ -32,6 +32,10 @@ inputs: description: "Dry run mode" required: false default: "false" + packagist_token: + description: "Packagist bearer credential in USERNAME:apiToken format" + required: false + default: "" packages_artifact: description: "Name of the artifact containing PHP extension archives" required: false @@ -224,4 +228,4 @@ runs: echo "Packagist update requested for apache/iggy-php" shell: bash env: - PACKAGIST_TOKEN: ${{ env.PACKAGIST_TOKEN }} + PACKAGIST_TOKEN: ${{ inputs.packagist_token }} diff --git a/.github/workflows/_build_php_extensions.yml b/.github/workflows/_build_php_extensions.yml index 53a204e718..e577aeee92 100644 --- a/.github/workflows/_build_php_extensions.yml +++ b/.github/workflows/_build_php_extensions.yml @@ -156,6 +156,39 @@ jobs: name: php-license-binary path: foreign/php + - name: Setup yq + run: | + if command -v yq >/dev/null 2>&1; then + yq --version + exit 0 + fi + + YQ_VERSION="v4.47.1" + case "$(uname -s)-$(uname -m)" in + Linux-x86_64) YQ_BINARY="yq_linux_amd64" ;; + Linux-aarch64) YQ_BINARY="yq_linux_arm64" ;; + Darwin-x86_64) YQ_BINARY="yq_darwin_amd64" ;; + Darwin-arm64) YQ_BINARY="yq_darwin_arm64" ;; + *) + echo "Unsupported yq platform: $(uname -s)-$(uname -m)" + exit 1 + ;; + esac + + yq_tmp="$(mktemp -d)" + curl -sSL -o "${yq_tmp}/${YQ_BINARY}" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY}" + curl -sSL -o "${yq_tmp}/checksums" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/checksums" + if command -v sha256sum >/dev/null 2>&1; then + (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | sha256sum -c -) + else + (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | shasum -a 256 -c -) + fi + + mkdir -p "${RUNNER_TEMP}/yq-bin" + chmod +x "${yq_tmp}/${YQ_BINARY}" + mv "${yq_tmp}/${YQ_BINARY}" "${RUNNER_TEMP}/yq-bin/yq" + echo "${RUNNER_TEMP}/yq-bin" >> "$GITHUB_PATH" + - name: Resolve version id: ver run: | @@ -315,6 +348,39 @@ jobs: name: php-license-binary path: foreign/php + - name: Setup yq + run: | + if command -v yq >/dev/null 2>&1; then + yq --version + exit 0 + fi + + YQ_VERSION="v4.47.1" + case "$(uname -s)-$(uname -m)" in + Linux-x86_64) YQ_BINARY="yq_linux_amd64" ;; + Linux-aarch64) YQ_BINARY="yq_linux_arm64" ;; + Darwin-x86_64) YQ_BINARY="yq_darwin_amd64" ;; + Darwin-arm64) YQ_BINARY="yq_darwin_arm64" ;; + *) + echo "Unsupported yq platform: $(uname -s)-$(uname -m)" + exit 1 + ;; + esac + + yq_tmp="$(mktemp -d)" + curl -sSL -o "${yq_tmp}/${YQ_BINARY}" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY}" + curl -sSL -o "${yq_tmp}/checksums" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/checksums" + if command -v sha256sum >/dev/null 2>&1; then + (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | sha256sum -c -) + else + (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | shasum -a 256 -c -) + fi + + mkdir -p "${RUNNER_TEMP}/yq-bin" + chmod +x "${yq_tmp}/${YQ_BINARY}" + mv "${yq_tmp}/${YQ_BINARY}" "${RUNNER_TEMP}/yq-bin/yq" + echo "${RUNNER_TEMP}/yq-bin" >> "$GITHUB_PATH" + - name: Resolve version id: ver run: | @@ -387,6 +453,39 @@ jobs: /tmp/copy-latest-from-master.sh save .github scripts /tmp/copy-latest-from-master.sh apply + - name: Setup yq + run: | + if command -v yq >/dev/null 2>&1; then + yq --version + exit 0 + fi + + YQ_VERSION="v4.47.1" + case "$(uname -s)-$(uname -m)" in + Linux-x86_64) YQ_BINARY="yq_linux_amd64" ;; + Linux-aarch64) YQ_BINARY="yq_linux_arm64" ;; + Darwin-x86_64) YQ_BINARY="yq_darwin_amd64" ;; + Darwin-arm64) YQ_BINARY="yq_darwin_arm64" ;; + *) + echo "Unsupported yq platform: $(uname -s)-$(uname -m)" + exit 1 + ;; + esac + + yq_tmp="$(mktemp -d)" + curl -sSL -o "${yq_tmp}/${YQ_BINARY}" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY}" + curl -sSL -o "${yq_tmp}/checksums" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/checksums" + if command -v sha256sum >/dev/null 2>&1; then + (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | sha256sum -c -) + else + (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | shasum -a 256 -c -) + fi + + mkdir -p "${RUNNER_TEMP}/yq-bin" + chmod +x "${yq_tmp}/${YQ_BINARY}" + mv "${yq_tmp}/${YQ_BINARY}" "${RUNNER_TEMP}/yq-bin/yq" + echo "${RUNNER_TEMP}/yq-bin" >> "$GITHUB_PATH" + - name: Resolve version id: ver run: | diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 40bd186af0..af99d22ed8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1219,6 +1219,7 @@ jobs: tag: ${{ steps.ver.outputs.tag }} commit: ${{ needs.validate.outputs.commit }} dry_run: ${{ inputs.dry_run }} + packagist_token: ${{ env.PACKAGIST_TOKEN }} packages_artifact: php-extensions-all packages_path: dist From 8689752c47b4fd364ed63ee1e65f5c419bb4d892 Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Fri, 19 Jun 2026 10:03:05 +0300 Subject: [PATCH 3/6] fix(php): include sdk in version bump script --- scripts/bump-version.sh | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index aa4b086518..f65f32cf6f 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -53,6 +53,7 @@ Components: connectors-all runtime + all sink + all source crates --all All components (Rust + connectors + SDKs + web-ui) sdk-python foreign/python/Cargo.toml + foreign/python/pyproject.toml + sdk-php foreign/php/Cargo.toml + foreign/php/composer.json sdk-node foreign/node/package.json sdk-go foreign/go/contracts/version.go sdk-csharp foreign/csharp/Iggy_SDK/Iggy_SDK.csproj @@ -90,11 +91,11 @@ RUST_COMPONENTS="rust-sdk rust-common rust-binary-protocol rust-server rust-cli CONNECTOR_SINK_COMPONENTS="rust-connector-delta-sink rust-connector-elasticsearch-sink rust-connector-http-sink rust-connector-iceberg-sink rust-connector-influxdb-sink rust-connector-mongodb-sink rust-connector-postgres-sink rust-connector-quickwit-sink rust-connector-stdout-sink" CONNECTOR_SOURCE_COMPONENTS="rust-connector-elasticsearch-source rust-connector-influxdb-source rust-connector-postgres-source rust-connector-random-source" CONNECTOR_COMPONENTS="rust-connector-runtime ${CONNECTOR_SINK_COMPONENTS} ${CONNECTOR_SOURCE_COMPONENTS}" -SDK_COMPONENTS="sdk-python sdk-node sdk-go sdk-csharp sdk-java" +SDK_COMPONENTS="sdk-python sdk-php sdk-node sdk-go sdk-csharp sdk-java" ALL_COMPONENTS="${RUST_COMPONENTS} ${CONNECTOR_COMPONENTS} ${SDK_COMPONENTS} web-ui" # Returns "file:format" lines per component. -# Format keys: cargo, cargo-ws-dep:PKG, cargo-dep:PKG, python-cargo, pyproject, json, csproj, gradle, go +# Format keys: cargo, cargo-ws-dep:PKG, cargo-dep:PKG, python-cargo, pyproject, php-cargo, composer, json, csproj, gradle, go get_version_files() { local component="$1" case "$component" in @@ -152,6 +153,10 @@ get_version_files() { echo "foreign/python/Cargo.toml:python-cargo" echo "foreign/python/pyproject.toml:pyproject" ;; + sdk-php) + echo "foreign/php/Cargo.toml:php-cargo" + echo "foreign/php/composer.json:composer" + ;; sdk-node) echo "foreign/node/package.json:json" ;; @@ -257,6 +262,11 @@ translate_version() { edge) echo "${base}.dev${pre_num}" ;; stable) echo "$base" ;; esac ;; + php-cargo|composer) + case "$pre_type" in + edge) echo "${base}-dev${pre_num}" ;; + stable) echo "$base" ;; + esac ;; gradle) case "$pre_type" in edge) echo "${base}-SNAPSHOT" ;; @@ -288,6 +298,12 @@ canonicalize_version() { else echo "$raw" fi ;; + php-cargo|composer) + if [[ "$raw" =~ ^([0-9]+\.[0-9]+\.[0-9]+)-dev\.?([0-9]+)$ ]]; then + echo "${BASH_REMATCH[1]}-edge.${BASH_REMATCH[2]}" + else + echo "$raw" + fi ;; gradle) if [[ "$raw" =~ ^([0-9]+\.[0-9]+\.[0-9]+)-SNAPSHOT$ ]]; then echo "${BASH_REMATCH[1]}-edge.0" @@ -319,6 +335,10 @@ read_current_version() { grep '^version = ' "$abs_file" | head -1 | sed 's/version = "\(.*\)"/\1/' ;; pyproject) grep '^version = ' "$abs_file" | head -1 | sed 's/version = "\(.*\)"/\1/' ;; + php-cargo) + grep '^version = ' "$abs_file" | head -1 | sed 's/version = "\(.*\)"/\1/' ;; + composer) + grep '"version"' "$abs_file" | head -1 | sed 's/.*"version": *"\([^"]*\)".*/\1/' ;; json) grep '"version"' "$abs_file" | head -1 | sed 's/.*"version": *"\([^"]*\)".*/\1/' ;; csproj) @@ -363,6 +383,10 @@ write_version() { sedi "1,/^version = \".*\"/s/^version = \".*\"/version = \"${translated}\"/" "$abs_file" ;; pyproject) sedi '/^\[project\]/,/^\[/{s/^version = ".*"/version = "'"${translated}"'"/;}' "$abs_file" ;; + php-cargo) + sedi "1,/^version = \".*\"/s/^version = \".*\"/version = \"${translated}\"/" "$abs_file" ;; + composer) + sedi "1,/\"version\": *\"[^\"]*\"/{s/\"version\": *\"[^\"]*\"/\"version\": \"${translated}\"/;}" "$abs_file" ;; json) sedi "1,/\"version\": *\"[^\"]*\"/{s/\"version\": *\"[^\"]*\"/\"version\": \"${translated}\"/;}" "$abs_file" ;; csproj) From 58b20ccd0552cdda2a22b74e617a328cbe63daae Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Sun, 21 Jun 2026 15:09:09 +0300 Subject: [PATCH 4/6] chore(ci): rerun checks From d88a1507ec41e1ce9ea8119d86badf2d88efd066 Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Tue, 23 Jun 2026 13:36:00 +0300 Subject: [PATCH 5/6] fix(php): align release pipeline with review feedback --- .github/actions/php/post-merge/action.yml | 80 ++---- .../php/setup-release-tools/action.yml | 100 +++++++ .github/config/publish.yml | 6 +- .github/workflows/_build_php_extensions.yml | 190 ++++--------- .github/workflows/_common.yml | 14 +- .github/workflows/post-merge.yml | 4 +- .github/workflows/publish.yml | 253 +++++++++++------- foreign/php/composer.json | 1 - scripts/bump-version.sh | 20 +- scripts/ci/php-sdk-version-sync.sh | 54 ++-- scripts/extract-version.sh | 4 +- 11 files changed, 379 insertions(+), 347 deletions(-) create mode 100644 .github/actions/php/setup-release-tools/action.yml diff --git a/.github/actions/php/post-merge/action.yml b/.github/actions/php/post-merge/action.yml index 0f18a93136..740df528cf 100644 --- a/.github/actions/php/post-merge/action.yml +++ b/.github/actions/php/post-merge/action.yml @@ -16,7 +16,7 @@ # under the License. name: php-post-merge -description: PHP post-merge Packagist publishing with pre-built PIE extension archives +description: PHP post-merge GitHub release publishing with pre-built PIE extension archives inputs: version: @@ -32,10 +32,6 @@ inputs: description: "Dry run mode" required: false default: "false" - packagist_token: - description: "Packagist bearer credential in USERNAME:apiToken format" - required: false - default: "" packages_artifact: description: "Name of the artifact containing PHP extension archives" required: false @@ -82,16 +78,16 @@ runs: expected=( "php_iggy_php-${VERSION}_php8.3-x86_64-linux-glibc-nts.zip" "php_iggy_php-${VERSION}_php8.4-x86_64-linux-glibc-nts.zip" - "php_iggy_php-${VERSION}_php8.3-aarch64-linux-glibc-nts.zip" - "php_iggy_php-${VERSION}_php8.4-aarch64-linux-glibc-nts.zip" + "php_iggy_php-${VERSION}_php8.3-arm64-linux-glibc-nts.zip" + "php_iggy_php-${VERSION}_php8.4-arm64-linux-glibc-nts.zip" "php_iggy_php-${VERSION}_php8.3-x86_64-linux-musl-nts.zip" "php_iggy_php-${VERSION}_php8.4-x86_64-linux-musl-nts.zip" - "php_iggy_php-${VERSION}_php8.3-aarch64-linux-musl-nts.zip" - "php_iggy_php-${VERSION}_php8.4-aarch64-linux-musl-nts.zip" - "php_iggy_php-${VERSION}_php8.3-x86_64-macos-bsdlibc-nts.zip" - "php_iggy_php-${VERSION}_php8.4-x86_64-macos-bsdlibc-nts.zip" - "php_iggy_php-${VERSION}_php8.3-aarch64-macos-bsdlibc-nts.zip" - "php_iggy_php-${VERSION}_php8.4-aarch64-macos-bsdlibc-nts.zip" + "php_iggy_php-${VERSION}_php8.3-arm64-linux-musl-nts.zip" + "php_iggy_php-${VERSION}_php8.4-arm64-linux-musl-nts.zip" + "php_iggy_php-${VERSION}_php8.3-x86_64-darwin-bsdlibc-nts.zip" + "php_iggy_php-${VERSION}_php8.4-x86_64-darwin-bsdlibc-nts.zip" + "php_iggy_php-${VERSION}_php8.3-arm64-darwin-bsdlibc-nts.zip" + "php_iggy_php-${VERSION}_php8.4-arm64-darwin-bsdlibc-nts.zip" "apache-iggy-php-${VERSION}-source.tar.gz" ) @@ -110,10 +106,13 @@ runs: for archive in "$PACKAGES_PATH"/*.zip; do filename="$(basename "$archive")" echo " - $filename" - unzip -l "$archive" | awk '{ print $4 }' | grep -qx 'iggy_php.so' - unzip -l "$archive" | awk '{ print $4 }' | grep -qx 'LICENSE' - unzip -l "$archive" | awk '{ print $4 }' | grep -qx 'NOTICE' - unzip -l "$archive" | awk '{ print $4 }' | grep -qx 'LICENSE-binary' + members="$(unzip -Z1 "$archive")" + for member in iggy_php.so LICENSE NOTICE LICENSE-binary; do + if ! grep -qx "$member" <<< "$members"; then + echo "Archive $filename is missing $member" + exit 1 + fi + done done echo "" @@ -136,12 +135,12 @@ runs: echo "Package: apache/iggy-php" echo "Version: $VERSION" echo "Tag: $TAG" - echo "Registry: https://packagist.org/packages/apache/iggy-php" + echo "Registry: GitHub Releases" echo "" echo "Release assets that would be uploaded:" find "$PACKAGES_PATH" -maxdepth 1 -type f -print | sort | sed 's|.*/| - |' echo "" - echo "Packagist would be asked to refresh https://github.com/apache/iggy" + echo "Packagist publishing requires a split repository with composer.json at the repository root." shell: bash - name: Publish GitHub release assets @@ -160,11 +159,12 @@ runs: fi if ! git ls-remote --tags --exit-code origin "refs/tags/${TAG}" >/dev/null 2>&1; then echo "PHP release tag $TAG does not exist on origin" - echo "Create the annotated PHP SDK tag before publishing GitHub release assets or refreshing Packagist." + echo "Create the annotated PHP SDK tag before publishing GitHub release assets." exit 1 fi release_notes="$(mktemp)" + trap 'rm -f "$release_notes"' EXIT { echo "Apache Iggy PHP SDK ${VERSION}" echo "" @@ -173,7 +173,7 @@ runs: } > "$release_notes" prerelease_flag=() - if [[ "$VERSION" == *-* ]]; then + if [ "$(scripts/extract-version.sh sdk-php --is-pre-release)" = "true" ]; then prerelease_flag=(--prerelease) fi @@ -191,41 +191,3 @@ runs: shell: bash env: GH_TOKEN: ${{ github.token }} - - - name: Trigger Packagist update - if: inputs.dry_run == 'false' - run: | - set -euo pipefail - - if [ -z "${PACKAGIST_TOKEN:-}" ]; then - echo "PACKAGIST_TOKEN is not set" - exit 1 - fi - - if [[ "$PACKAGIST_TOKEN" != *:* ]]; then - echo "PACKAGIST_TOKEN must use Packagist bearer credentials in USERNAME:apiToken format" - exit 1 - fi - - response="$(mktemp)" - http_code="$(curl -sSL \ - -o "$response" \ - -w '%{http_code}' \ - -X POST \ - -H 'Content-Type: application/json' \ - -H "Authorization: Bearer ${PACKAGIST_TOKEN}" \ - 'https://packagist.org/api/update-package' \ - -d '{"repository":"https://github.com/apache/iggy"}')" - - if [ "$http_code" != "200" ]; then - echo "Packagist update failed with HTTP $http_code" - cat "$response" - exit 1 - fi - - cat "$response" - echo "" - echo "Packagist update requested for apache/iggy-php" - shell: bash - env: - PACKAGIST_TOKEN: ${{ inputs.packagist_token }} diff --git a/.github/actions/php/setup-release-tools/action.yml b/.github/actions/php/setup-release-tools/action.yml new file mode 100644 index 0000000000..257b01c364 --- /dev/null +++ b/.github/actions/php/setup-release-tools/action.yml @@ -0,0 +1,100 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: php-setup-release-tools +description: Install release helpers and resolve the PHP SDK version + +inputs: + version: + description: "Explicit PHP SDK version. When empty, the version is read from publish config." + required: false + default: "" + +outputs: + version: + description: "Resolved PHP SDK version" + value: ${{ steps.version.outputs.version }} + +runs: + using: "composite" + steps: + - name: Setup yq + shell: bash + run: | + set -euo pipefail + + if command -v yq >/dev/null 2>&1; then + yq --version + exit 0 + fi + + YQ_VERSION="v4.47.1" + case "$(uname -s)-$(uname -m)" in + Linux-x86_64) + YQ_BINARY="yq_linux_amd64" + YQ_CHECKSUM="0fb28c6680193c41b364193d0c0fc4a03177aecde51cfc04d506b1517158c2fb" + ;; + Linux-aarch64) + YQ_BINARY="yq_linux_arm64" + YQ_CHECKSUM="b7f7c991abe262b0c6f96bbcb362f8b35429cefd59c8b4c2daa4811f1e9df599" + ;; + Darwin-x86_64) + YQ_BINARY="yq_darwin_amd64" + YQ_CHECKSUM="a9b5ca36f7750576c6ace3cc7193349cd676b3a6bf30193fb2773ff45f5af5c2" + ;; + Darwin-arm64) + YQ_BINARY="yq_darwin_arm64" + YQ_CHECKSUM="99aae3a7c9ddfe76bb339f0e7acd8224324b6527436fb6a5d890079bf5fcc590" + ;; + *) + echo "Unsupported yq platform: $(uname -s)-$(uname -m)" + exit 1 + ;; + esac + + yq_tmp="$(mktemp -d)" + trap 'rm -rf "$yq_tmp"' EXIT + curl -sSL -o "${yq_tmp}/${YQ_BINARY}" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY}" + if command -v sha256sum >/dev/null 2>&1; then + echo "${YQ_CHECKSUM} ${yq_tmp}/${YQ_BINARY}" | sha256sum -c - + else + echo "${YQ_CHECKSUM} ${yq_tmp}/${YQ_BINARY}" | shasum -a 256 -c - + fi + + mkdir -p "${RUNNER_TEMP}/yq-bin" + chmod +x "${yq_tmp}/${YQ_BINARY}" + mv "${yq_tmp}/${YQ_BINARY}" "${RUNNER_TEMP}/yq-bin/yq" + echo "${RUNNER_TEMP}/yq-bin" >> "$GITHUB_PATH" + + - name: Resolve version + id: version + shell: bash + run: | + set -euo pipefail + + if [ -d "${RUNNER_TEMP}/yq-bin" ]; then + export PATH="${RUNNER_TEMP}/yq-bin:${PATH}" + fi + + if [ -n "${{ inputs.version }}" ]; then + version="${{ inputs.version }}" + else + chmod +x scripts/extract-version.sh + version="$(scripts/extract-version.sh sdk-php)" + fi + + echo "version=${version}" >> "$GITHUB_OUTPUT" diff --git a/.github/config/publish.yml b/.github/config/publish.yml index 3ff418354f..cae4893cde 100644 --- a/.github/config/publish.yml +++ b/.github/config/publish.yml @@ -125,9 +125,9 @@ components: sdk-php: tag_pattern: "^php-sdk-([0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?)$" - registry: packagist - version_file: "foreign/php/composer.json" - version_regex: '"version"\s*:\s*"([^"]+)"' + registry: github-release + version_file: "foreign/php/Cargo.toml" + version_regex: '(?m)^\s*version\s*=\s*"([^"]+)"' sdk-node: tag_pattern: "^node-sdk-([0-9]+\\.[0-9]+\\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?)$" diff --git a/.github/workflows/_build_php_extensions.yml b/.github/workflows/_build_php_extensions.yml index e577aeee92..fad80cd9ff 100644 --- a/.github/workflows/_build_php_extensions.yml +++ b/.github/workflows/_build_php_extensions.yml @@ -103,12 +103,12 @@ jobs: runner: ubuntu-latest image: php:8.4-cli-bookworm - php: "8.3" - arch: aarch64 + arch: arm64 libc: glibc runner: ubuntu-24.04-arm image: php:8.3-cli-bookworm - php: "8.4" - arch: aarch64 + arch: arm64 libc: glibc runner: ubuntu-24.04-arm image: php:8.4-cli-bookworm @@ -123,12 +123,12 @@ jobs: runner: ubuntu-latest image: php:8.4-cli-alpine - php: "8.3" - arch: aarch64 + arch: arm64 libc: musl runner: ubuntu-24.04-arm image: php:8.3-cli-alpine - php: "8.4" - arch: aarch64 + arch: arm64 libc: musl runner: ubuntu-24.04-arm image: php:8.4-cli-alpine @@ -156,53 +156,28 @@ jobs: name: php-license-binary path: foreign/php - - name: Setup yq - run: | - if command -v yq >/dev/null 2>&1; then - yq --version - exit 0 - fi - - YQ_VERSION="v4.47.1" - case "$(uname -s)-$(uname -m)" in - Linux-x86_64) YQ_BINARY="yq_linux_amd64" ;; - Linux-aarch64) YQ_BINARY="yq_linux_arm64" ;; - Darwin-x86_64) YQ_BINARY="yq_darwin_amd64" ;; - Darwin-arm64) YQ_BINARY="yq_darwin_arm64" ;; - *) - echo "Unsupported yq platform: $(uname -s)-$(uname -m)" - exit 1 - ;; - esac - - yq_tmp="$(mktemp -d)" - curl -sSL -o "${yq_tmp}/${YQ_BINARY}" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY}" - curl -sSL -o "${yq_tmp}/checksums" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/checksums" - if command -v sha256sum >/dev/null 2>&1; then - (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | sha256sum -c -) - else - (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | shasum -a 256 -c -) - fi - - mkdir -p "${RUNNER_TEMP}/yq-bin" - chmod +x "${yq_tmp}/${YQ_BINARY}" - mv "${yq_tmp}/${YQ_BINARY}" "${RUNNER_TEMP}/yq-bin/yq" - echo "${RUNNER_TEMP}/yq-bin" >> "$GITHUB_PATH" + - name: Setup PHP release tools + id: release + uses: ./.github/actions/php/setup-release-tools + with: + version: ${{ inputs.version }} - - name: Resolve version - id: ver - run: | - if [ -n "${{ inputs.version }}" ]; then - version="${{ inputs.version }}" - else - chmod +x scripts/extract-version.sh - version="$(scripts/extract-version.sh sdk-php)" - fi - echo "version=${version}" >> "$GITHUB_OUTPUT" + - name: Cache Linux PHP cargo state + uses: actions/cache@v5 + with: + path: | + target/php-cargo-home/registry + target/php-cargo-home/git + target/php-rustup-home + key: php-release-linux-${{ matrix.arch }}-${{ matrix.libc }}-php${{ matrix.php }}-${{ hashFiles('Cargo.lock', 'foreign/php/Cargo.toml') }} + restore-keys: | + php-release-linux-${{ matrix.arch }}-${{ matrix.libc }}-php${{ matrix.php }}- + php-release-linux-${{ matrix.arch }}-${{ matrix.libc }}- + php-release-linux-${{ matrix.arch }}- - name: Build and package PHP extension env: - VERSION: ${{ steps.ver.outputs.version }} + VERSION: ${{ steps.release.outputs.version }} PHP_VERSION: ${{ matrix.php }} PHP_ARCH: ${{ matrix.arch }} PHP_LIBC: ${{ matrix.libc }} @@ -214,7 +189,9 @@ jobs: docker run --rm \ -e CARGO_TERM_COLOR=always \ - -e CARGO_TARGET_DIR=/workspace/target/php-release-${PHP_VERSION}-${PHP_ARCH}-${PHP_LIBC} \ + -e CARGO_HOME=/workspace/target/php-cargo-home \ + -e RUSTUP_HOME=/workspace/target/php-rustup-home \ + -e "CARGO_TARGET_DIR=/workspace/target/php-release-${PHP_VERSION}-${PHP_ARCH}-${PHP_LIBC}" \ -e VERSION="${VERSION}" \ -e PHP_VERSION="${PHP_VERSION}" \ -e PHP_ARCH="${PHP_ARCH}" \ @@ -256,9 +233,12 @@ jobs: zip fi - curl -sSf https://sh.rustup.rs -o /tmp/rustup-init.sh - sh /tmp/rustup-init.sh -y --profile minimal --default-toolchain none - . "$HOME/.cargo/env" + mkdir -p "$CARGO_HOME" "$RUSTUP_HOME" + if [ ! -x "$CARGO_HOME/bin/rustup" ]; then + curl -sSf https://sh.rustup.rs -o /tmp/rustup-init.sh + sh /tmp/rustup-init.sh -y --profile minimal --default-toolchain none + fi + . "$CARGO_HOME/env" rustup show php --version @@ -307,10 +287,10 @@ jobs: arch: x86_64 runner: macos-15-intel - php: "8.3" - arch: aarch64 + arch: arm64 runner: macos-15 - php: "8.4" - arch: aarch64 + arch: arm64 runner: macos-15 steps: - name: Download latest copy script from master @@ -348,53 +328,15 @@ jobs: name: php-license-binary path: foreign/php - - name: Setup yq - run: | - if command -v yq >/dev/null 2>&1; then - yq --version - exit 0 - fi - - YQ_VERSION="v4.47.1" - case "$(uname -s)-$(uname -m)" in - Linux-x86_64) YQ_BINARY="yq_linux_amd64" ;; - Linux-aarch64) YQ_BINARY="yq_linux_arm64" ;; - Darwin-x86_64) YQ_BINARY="yq_darwin_amd64" ;; - Darwin-arm64) YQ_BINARY="yq_darwin_arm64" ;; - *) - echo "Unsupported yq platform: $(uname -s)-$(uname -m)" - exit 1 - ;; - esac - - yq_tmp="$(mktemp -d)" - curl -sSL -o "${yq_tmp}/${YQ_BINARY}" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY}" - curl -sSL -o "${yq_tmp}/checksums" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/checksums" - if command -v sha256sum >/dev/null 2>&1; then - (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | sha256sum -c -) - else - (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | shasum -a 256 -c -) - fi - - mkdir -p "${RUNNER_TEMP}/yq-bin" - chmod +x "${yq_tmp}/${YQ_BINARY}" - mv "${yq_tmp}/${YQ_BINARY}" "${RUNNER_TEMP}/yq-bin/yq" - echo "${RUNNER_TEMP}/yq-bin" >> "$GITHUB_PATH" - - - name: Resolve version - id: ver - run: | - if [ -n "${{ inputs.version }}" ]; then - version="${{ inputs.version }}" - else - chmod +x scripts/extract-version.sh - version="$(scripts/extract-version.sh sdk-php)" - fi - echo "version=${version}" >> "$GITHUB_OUTPUT" + - name: Setup PHP release tools + id: release + uses: ./.github/actions/php/setup-release-tools + with: + version: ${{ inputs.version }} - name: Build and package PHP extension env: - VERSION: ${{ steps.ver.outputs.version }} + VERSION: ${{ steps.release.outputs.version }} PHP_VERSION: ${{ matrix.php }} PHP_ARCH: ${{ matrix.arch }} CARGO_TARGET_DIR: ${{ github.workspace }}/target/php-release-${{ matrix.php }}-${{ matrix.arch }}-macos @@ -418,7 +360,7 @@ jobs: cp foreign/php/NOTICE "$package_dir/NOTICE" cp foreign/php/LICENSE-binary "$package_dir/LICENSE-binary" - archive="php_iggy_php-${VERSION}_php${PHP_VERSION}-${PHP_ARCH}-macos-bsdlibc-nts.zip" + archive="php_iggy_php-${VERSION}_php${PHP_VERSION}-${PHP_ARCH}-darwin-bsdlibc-nts.zip" (cd "$package_dir" && zip -9 "${{ github.workspace }}/foreign/php/dist/${archive}" iggy_php.so LICENSE NOTICE LICENSE-binary) rm -rf "$package_dir" @@ -453,61 +395,23 @@ jobs: /tmp/copy-latest-from-master.sh save .github scripts /tmp/copy-latest-from-master.sh apply - - name: Setup yq - run: | - if command -v yq >/dev/null 2>&1; then - yq --version - exit 0 - fi - - YQ_VERSION="v4.47.1" - case "$(uname -s)-$(uname -m)" in - Linux-x86_64) YQ_BINARY="yq_linux_amd64" ;; - Linux-aarch64) YQ_BINARY="yq_linux_arm64" ;; - Darwin-x86_64) YQ_BINARY="yq_darwin_amd64" ;; - Darwin-arm64) YQ_BINARY="yq_darwin_arm64" ;; - *) - echo "Unsupported yq platform: $(uname -s)-$(uname -m)" - exit 1 - ;; - esac - - yq_tmp="$(mktemp -d)" - curl -sSL -o "${yq_tmp}/${YQ_BINARY}" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/${YQ_BINARY}" - curl -sSL -o "${yq_tmp}/checksums" "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/checksums" - if command -v sha256sum >/dev/null 2>&1; then - (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | sha256sum -c -) - else - (cd "$yq_tmp" && grep " ${YQ_BINARY}$" checksums | shasum -a 256 -c -) - fi - - mkdir -p "${RUNNER_TEMP}/yq-bin" - chmod +x "${yq_tmp}/${YQ_BINARY}" - mv "${yq_tmp}/${YQ_BINARY}" "${RUNNER_TEMP}/yq-bin/yq" - echo "${RUNNER_TEMP}/yq-bin" >> "$GITHUB_PATH" - - - name: Resolve version - id: ver - run: | - if [ -n "${{ inputs.version }}" ]; then - version="${{ inputs.version }}" - else - chmod +x scripts/extract-version.sh - version="$(scripts/extract-version.sh sdk-php)" - fi - echo "version=${version}" >> "$GITHUB_OUTPUT" + - name: Setup PHP release tools + id: release + uses: ./.github/actions/php/setup-release-tools + with: + version: ${{ inputs.version }} - name: Build source archive run: | set -euo pipefail - version="${{ steps.ver.outputs.version }}" + version="${{ steps.release.outputs.version }}" mkdir -p foreign/php/dist git archive \ --format=tar.gz \ --prefix="apache-iggy-php-${version}/" \ --output="foreign/php/dist/apache-iggy-php-${version}-source.tar.gz" \ - HEAD + HEAD:foreign/php ls -lh foreign/php/dist diff --git a/.github/workflows/_common.yml b/.github/workflows/_common.yml index d220cadd78..f604744825 100644 --- a/.github/workflows/_common.yml +++ b/.github/workflows/_common.yml @@ -43,12 +43,12 @@ jobs: run: ./scripts/ci/python-sdk-version-sync.sh --check php-versions: - name: Check PHP SDK versions sync + name: Check PHP SDK Composer metadata runs-on: ubuntu-latest steps: - uses: actions/checkout@v6.0.2 - - name: Check PHP SDK versions are synchronized + - name: Check PHP SDK Composer metadata run: ./scripts/ci/php-sdk-version-sync.sh --check python-interpreter-versions: @@ -223,6 +223,7 @@ jobs: [ rust-versions, python-versions, + php-versions, python-interpreter-versions, python-lockfiles, version-consistency, @@ -249,6 +250,7 @@ jobs: # Always-run checks RUST_VERSIONS="${{ needs.rust-versions.result }}" PYTHON_VERSIONS="${{ needs.python-versions.result }}" + PHP_VERSIONS="${{ needs.php-versions.result }}" PYTHON_INTERPRETER_VERSIONS="${{ needs.python-interpreter-versions.result }}" PYTHON_LOCKFILES="${{ needs.python-lockfiles.result }}" VERSION_CONSISTENCY="${{ needs.version-consistency.result }}" @@ -272,6 +274,14 @@ jobs: echo "| ⏭️ Python SDK Versions | $PYTHON_VERSIONS | Check skipped |" >> "$GITHUB_STEP_SUMMARY" fi + if [ "$PHP_VERSIONS" = "success" ]; then + echo "| ✅ PHP SDK Composer Metadata | success | Composer versions are tag-derived |" >> "$GITHUB_STEP_SUMMARY" + elif [ "$PHP_VERSIONS" = "failure" ]; then + echo "| ❌ PHP SDK Composer Metadata | failure | composer.json declares a manual version |" >> "$GITHUB_STEP_SUMMARY" + else + echo "| ⏭️ PHP SDK Composer Metadata | $PHP_VERSIONS | Check skipped |" >> "$GITHUB_STEP_SUMMARY" + fi + if [ "$PYTHON_INTERPRETER_VERSIONS" = "success" ]; then echo "| ✅ Python Interpreter Versions | success | Python interpreter versions synchronized |" >> "$GITHUB_STEP_SUMMARY" elif [ "$PYTHON_INTERPRETER_VERSIONS" = "failure" ]; then diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index b41176b2b8..5625d0bb78 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -16,8 +16,8 @@ # under the License. # Auto-publish: detects pre-release crate/SDK versions without tags -# and publishes them to crates.io, Docker Hub, PyPI, Packagist, npm, Maven, -# NuGet. +# and publishes them to crates.io, Docker Hub, PyPI, npm, Maven, NuGet, +# and GitHub Releases. # Runs on every push to master. name: Post-merge diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index af99d22ed8..48621be3f9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -109,8 +109,6 @@ on: required: false NUGET_API_KEY: required: false - PACKAGIST_TOKEN: - required: false env: IGGY_CI_BUILD: true @@ -121,7 +119,7 @@ permissions: id-token: write # Static group so two concurrent release dispatches cannot race the -# crates.io / Maven Central / npm / NuGet / DockerHub / PyPI / Packagist uploads. +# crates.io / Maven Central / npm / NuGet / DockerHub / PyPI / GitHub release uploads. # `run_id` in the group was effectively a no-op because it is unique # per dispatch. `cancel-in-progress: false` keeps any in-flight upload # running to completion rather than leaving partial state in registries. @@ -262,6 +260,7 @@ jobs: targets: ${{ steps.mk.outputs.targets }} non_rust_targets: ${{ steps.mk.outputs.non_rust_targets }} non_docker_targets: ${{ steps.mk.outputs.non_docker_targets }} + php_targets: ${{ steps.mk.outputs.php_targets }} docker_matrix: ${{ steps.mk.outputs.docker_matrix }} docker_components: ${{ steps.mk.outputs.docker_components }} count: ${{ steps.mk.outputs.count }} @@ -341,7 +340,7 @@ jobs: dockerhub: 'docker', crates: 'rust', pypi: 'python', - packagist: 'php', + 'github-release': 'php', npm: 'node', maven: 'java', nuget: 'csharp', @@ -388,11 +387,13 @@ jobs: // Separate Docker targets from other non-Rust targets const dockerTargets = nonRustTargets.filter(t => t.type === 'docker'); const nonDockerTargets = nonRustTargets.filter(t => t.type !== 'docker'); + const phpTargets = nonDockerTargets.filter(t => t.type === 'php'); + const otherSdkTargets = nonDockerTargets.filter(t => t.type !== 'php'); console.log(`Publishing ${targets.length} components:`); targets.forEach(t => console.log(` - ${t.name} (${t.type}) -> ${t.registry || 'N/A'}`)); console.log(` (${nonRustTargets.length} non-Rust, ${targets.length - nonRustTargets.length} Rust crates)`); - console.log(` (${dockerTargets.length} Docker, ${nonDockerTargets.length} other SDKs)`); + console.log(` (${dockerTargets.length} Docker, ${otherSdkTargets.length} other SDKs, ${phpTargets.length} PHP SDK)`); // Output all targets for reference and tag creation core.setOutput('targets', JSON.stringify(targets.length ? { include: targets } : { include: [{ key: 'noop', type: 'noop' }] })); @@ -400,8 +401,10 @@ jobs: // Output only non-Rust targets for the parallel publish job core.setOutput('non_rust_targets', JSON.stringify(nonRustTargets.length ? { include: nonRustTargets } : { include: [{ key: 'noop', type: 'noop' }] })); - // Output non-Docker, non-Rust targets (SDKs only) - core.setOutput('non_docker_targets', JSON.stringify(nonDockerTargets.length ? { include: nonDockerTargets } : { include: [{ key: 'noop', type: 'noop' }] })); + // Output non-Docker, non-Rust, non-PHP targets. PHP needs its + // pre-built binary artifact, so it has a separate publish job. + core.setOutput('non_docker_targets', JSON.stringify(otherSdkTargets.length ? { include: otherSdkTargets } : { include: [{ key: 'noop', type: 'noop' }] })); + core.setOutput('php_targets', JSON.stringify(phpTargets.length ? { include: phpTargets } : { include: [{ key: 'noop', type: 'noop' }] })); // Build Docker matrix: components × platforms for native runner builds const platforms = [ @@ -548,7 +551,7 @@ jobs: # Versioned git tags require manual publish (workflow_dispatch). REGISTRY=$(_jq '.registry') if [ "${{ inputs.create_edge_docker_tag }}" = "true" ] && [ "$REGISTRY" = "dockerhub" ]; then - if [[ ! "$VERSION" =~ -(edge|rc) ]]; then + if [ "$(scripts/extract-version.sh "$KEY" --is-pre-release 2>/dev/null || echo false)" != "true" ]; then echo "⏭️ $NAME: Stable Docker version in auto-publish mode, tag will be skipped" echo "| $NAME | $VERSION | $TAG | ⏭️ Stable (manual publish only) |" >> $GITHUB_STEP_SUMMARY continue @@ -591,7 +594,7 @@ jobs: echo "| $NAME | $VERSION | $TAG | ℹ️ Already released ($SHORT_SHA) - :edge refresh only |" >> $GITHUB_STEP_SUMMARY # Fail-fast on wrong-target for MANUAL publish. A wrong-target tag # means create-git-tag would hard-fail 20-40 minutes later after - # publishing artifacts to crates.io / PyPI / Packagist / npm / + # publishing artifacts to crates.io / PyPI / npm / # Maven / NuGet / DockerHub. Catching it at check-tags converts that # into a fast, cheap failure at the top of the run. # Same-target is still benign (rerun convergence). @@ -754,14 +757,13 @@ jobs: # Docker publishing on native runners (no QEMU emulation) publish-docker: name: Docker ${{ matrix.name }} (${{ matrix.arch }}) - needs: [validate, plan, check-tags, build-python-wheels, build-php-extensions, publish-rust-crates] + needs: [validate, plan, check-tags, build-python-wheels, publish-rust-crates] if: | !cancelled() && needs.validate.outputs.has_targets == 'true' && needs.plan.outputs.has_docker == 'true' && fromJson(needs.plan.outputs.docker_matrix).include[0].key != 'noop' && (needs.build-python-wheels.result == 'success' || needs.build-python-wheels.result == 'skipped') && - (needs.build-php-extensions.result == 'success' || needs.build-php-extensions.result == 'skipped') && (needs.publish-rust-crates.result == 'success' || needs.publish-rust-crates.result == 'skipped') runs-on: ${{ matrix.runner }} timeout-minutes: 60 @@ -1006,13 +1008,13 @@ jobs: fi else # Manual publish: always push the versioned manifest, plus :latest - # for stable (non edge/rc) releases. + # for stable releases. docker buildx imagetools create \ -t "${IMAGE}:${VERSION}" \ $(printf "${IMAGE}@sha256:%s " *) echo "✅ Pushed manifest: ${IMAGE}:${VERSION}" - if [[ ! "$VERSION" =~ -(edge|rc) ]]; then + if [ "$(scripts/extract-version.sh "${{ matrix.key }}" --is-pre-release)" != "true" ]; then echo "Creating 'latest' manifest" docker buildx imagetools create \ -t "${IMAGE}:latest" \ @@ -1058,17 +1060,16 @@ jobs: Commit: ${{ needs.validate.outputs.commit }} Released by: GitHub Actions (workflow ${{ github.run_id }}) - # Non-Docker, non-Rust publishing (Python, PHP, Node, Java, C#, Go SDKs) + # Non-Docker, non-Rust publishing (Python, Node, Java, C#, Go SDKs) # Note: This job runs in parallel with Docker publishing - no dependency between them publish: name: ${{ matrix.name }} - needs: [validate, plan, check-tags, build-python-wheels, build-php-extensions, publish-rust-crates] + needs: [validate, plan, check-tags, build-python-wheels, publish-rust-crates] if: | !cancelled() && needs.validate.outputs.has_targets == 'true' && fromJson(needs.plan.outputs.non_docker_targets).include[0].key != 'noop' && (needs.build-python-wheels.result == 'success' || needs.build-python-wheels.result == 'skipped') && - (needs.build-php-extensions.result == 'success' || needs.build-php-extensions.result == 'skipped') && (needs.publish-rust-crates.result == 'success' || needs.publish-rust-crates.result == 'skipped') runs-on: ubuntu-latest strategy: @@ -1083,7 +1084,6 @@ jobs: JAVA_GPG_SIGNING_KEY: ${{ secrets.JAVA_GPG_SIGNING_KEY }} JAVA_GPG_PASSWORD: ${{ secrets.JAVA_GPG_PASSWORD }} NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} - PACKAGIST_TOKEN: ${{ secrets.PACKAGIST_TOKEN }} DRY_RUN: ${{ inputs.dry_run }} outputs: status: ${{ steps.status.outputs.status }} @@ -1189,40 +1189,6 @@ jobs: wheels_artifact: python-wheels-all wheels_path: dist - # ───────────────────────────────────────── - # PHP SDK Publishing - # ───────────────────────────────────────── - - name: Tag PHP SDK release (${{ matrix.key }}) - if: | - success() && - inputs.dry_run == false && - inputs.skip_tag_creation == false && - matrix.type == 'php' && - steps.ver.outputs.should_tag == 'true' - uses: ./.github/actions/utils/create-git-tag - with: - tag: ${{ steps.ver.outputs.tag }} - commit: ${{ needs.validate.outputs.commit }} - message: | - Release ${{ matrix.key }} ${{ steps.ver.outputs.version }} - - Component: ${{ matrix.key }} - Tag: ${{ steps.ver.outputs.tag }} - Commit: ${{ needs.validate.outputs.commit }} - Released by: GitHub Actions (workflow ${{ github.run_id }}) - - - name: Publish PHP SDK - if: matrix.type == 'php' - uses: ./.github/actions/php/post-merge - with: - version: ${{ steps.ver.outputs.version }} - tag: ${{ steps.ver.outputs.tag }} - commit: ${{ needs.validate.outputs.commit }} - dry_run: ${{ inputs.dry_run }} - packagist_token: ${{ env.PACKAGIST_TOKEN }} - packages_artifact: php-extensions-all - packages_path: dist - # ───────────────────────────────────────── # Node SDK Publishing # ───────────────────────────────────────── @@ -1298,52 +1264,6 @@ jobs: max_attempts: "15" initial_sleep_seconds: "3" - - name: Wait for Packagist availability - if: | - success() && - inputs.dry_run == false && - matrix.type == 'php' && - steps.ver.outputs.should_tag == 'true' - uses: ./.github/actions/utils/wait-for-url - with: - url: https://repo.packagist.org/p2/apache/iggy-php.json - description: apache/iggy-php metadata on Packagist - max_attempts: "20" - initial_sleep_seconds: "3" - - - name: Verify Packagist version - if: | - success() && - inputs.dry_run == false && - matrix.type == 'php' && - steps.ver.outputs.should_tag == 'true' - shell: bash - run: | - set -euo pipefail - version="${{ steps.ver.outputs.version }}" - - sleep_s=3 - for attempt in $(seq 1 20); do - if curl -sSL https://repo.packagist.org/p2/apache/iggy-php.json \ - | jq -e --arg version "$version" '.packages["apache/iggy-php"][] | select(.version == $version or .version == ("v" + $version))' >/dev/null; then - echo "apache/iggy-php ${version} is present in Packagist metadata" - exit 0 - fi - - if [ "$attempt" -eq 20 ]; then - break - fi - echo "Packagist metadata is available but ${version} is not listed yet (attempt ${attempt}/20, sleep ${sleep_s}s)" - sleep "$sleep_s" - sleep_s=$(( sleep_s * 2 )) - if [ "$sleep_s" -gt 30 ]; then - sleep_s=30 - fi - done - - echo "Timed out waiting for apache/iggy-php ${version} in Packagist metadata" - exit 1 - # Java publishes to ASF Nexus staging via `./gradlew publish` # (repository.apache.org/service/local/staging/deploy/maven2). The # staging -> Maven Central handoff requires a Nexus Close+Release @@ -1443,6 +1363,130 @@ jobs: if: always() run: echo "status=${{ job.status }}" >> "$GITHUB_OUTPUT" + publish-php: + name: PHP SDK + needs: [validate, plan, check-tags, build-php-extensions] + if: | + !cancelled() && + needs.validate.outputs.has_targets == 'true' && + needs.plan.outputs.has_php == 'true' && + fromJson(needs.plan.outputs.php_targets).include[0].key != 'noop' && + (needs.build-php-extensions.result == 'success' || needs.build-php-extensions.result == 'skipped') + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.plan.outputs.php_targets) }} + outputs: + status: ${{ steps.status.outputs.status }} + version: ${{ steps.ver.outputs.version }} + tag: ${{ steps.ver.outputs.tag }} + steps: + - name: Download latest copy script from master + if: inputs.use_latest_ci + run: | + curl -sSL "https://raw.githubusercontent.com/${{ github.repository }}/master/scripts/copy-latest-from-master.sh" \ + -o /tmp/copy-latest-from-master.sh + chmod +x /tmp/copy-latest-from-master.sh + echo "✅ Downloaded latest copy script from master" + + - name: Checkout at commit + uses: actions/checkout@v6.0.2 + with: + ref: ${{ needs.validate.outputs.commit }} + fetch-depth: 1 + + - name: Save and apply latest CI from master + if: inputs.use_latest_ci + run: | + /tmp/copy-latest-from-master.sh save \ + .github \ + scripts + + /tmp/copy-latest-from-master.sh apply + + - name: Ensure version extractor is executable + run: | + test -x scripts/extract-version.sh || chmod +x scripts/extract-version.sh + + - name: Extract version & tag + id: ver + shell: bash + env: + MATRIX_KEY: ${{ matrix.key }} + MATRIX_TAG_PATTERN: ${{ matrix.tag_pattern }} + CREATE_EDGE_DOCKER_TAG: ${{ inputs.create_edge_docker_tag }} + run: | + set -euo pipefail + VERSION=$(scripts/extract-version.sh "$MATRIX_KEY") + TAG=$(scripts/extract-version.sh "$MATRIX_KEY" --tag) + SHOULD_TAG=$(scripts/extract-version.sh "$MATRIX_KEY" --should-tag) + + if [ "$SHOULD_TAG" = "true" ] \ + && [ "$CREATE_EDGE_DOCKER_TAG" = "true" ] \ + && [ "$(scripts/extract-version.sh "$MATRIX_KEY" --is-pre-release)" != "true" ]; then + SHOULD_TAG=false + fi + + { + echo "version=$VERSION" + echo "tag=$TAG" + echo "should_tag=$SHOULD_TAG" + } >> "$GITHUB_OUTPUT" + echo "✅ Resolved $MATRIX_KEY -> version=$VERSION tag=$TAG should_tag=$SHOULD_TAG" + + - name: Tag PHP SDK release (${{ matrix.key }}) + if: | + success() && + inputs.dry_run == false && + inputs.skip_tag_creation == false && + steps.ver.outputs.should_tag == 'true' + uses: ./.github/actions/utils/create-git-tag + with: + tag: ${{ steps.ver.outputs.tag }} + commit: ${{ needs.validate.outputs.commit }} + message: | + Release ${{ matrix.key }} ${{ steps.ver.outputs.version }} + + Component: ${{ matrix.key }} + Tag: ${{ steps.ver.outputs.tag }} + Commit: ${{ needs.validate.outputs.commit }} + Released by: GitHub Actions (workflow ${{ github.run_id }}) + + - name: Publish PHP SDK + if: | + success() && + ( + inputs.dry_run == true || + ( + inputs.skip_tag_creation == false && + steps.ver.outputs.should_tag == 'true' + ) + ) + uses: ./.github/actions/php/post-merge + with: + version: ${{ steps.ver.outputs.version }} + tag: ${{ steps.ver.outputs.tag }} + commit: ${{ needs.validate.outputs.commit }} + dry_run: ${{ inputs.dry_run }} + packages_artifact: php-extensions-all + packages_path: dist + + - name: Skip PHP SDK publishing without tag + if: | + success() && + inputs.dry_run == false && + ( + inputs.skip_tag_creation == true || + steps.ver.outputs.should_tag != 'true' + ) + run: | + echo "PHP GitHub release publishing is skipped because it requires a taggable php-sdk version." + + - name: Set status output + id: status + if: always() + run: echo "status=${{ job.status }}" >> "$GITHUB_OUTPUT" + summary: name: Publish Summary needs: @@ -1457,6 +1501,7 @@ jobs: publish-docker, docker-manifests, publish, + publish-php, ] if: ${{ !cancelled() && needs.validate.outputs.has_targets == 'true' }} runs-on: ubuntu-latest @@ -1540,7 +1585,7 @@ jobs: crates) REGISTRY_DISPLAY="crates.io" ;; dockerhub) REGISTRY_DISPLAY="Docker Hub" ;; pypi) REGISTRY_DISPLAY="PyPI" ;; - packagist) REGISTRY_DISPLAY="Packagist" ;; + github-release) REGISTRY_DISPLAY="GitHub Releases" ;; npm) REGISTRY_DISPLAY="npm" ;; maven) REGISTRY_DISPLAY="Maven" ;; nuget) REGISTRY_DISPLAY="NuGet" ;; @@ -1597,6 +1642,17 @@ jobs: echo fi + if [ "${{ needs.plan.outputs.has_php }}" = "true" ]; then + echo "### PHP SDK Publishing" + case "${{ needs.publish-php.result }}" in + success) echo "✅ **PHP SDK GitHub release assets published successfully**" ;; + failure) echo "❌ **PHP SDK publishing failed - check logs for details**" ;; + cancelled) echo "🚫 **PHP SDK publishing was cancelled**" ;; + skipped) echo "⏭️ **PHP SDK publishing was skipped**" ;; + esac + echo + fi + # Rust crates publishing status if [ -n "${{ inputs.publish_crates }}" ]; then echo "### Rust Crates Publishing (Sequential)" @@ -1661,6 +1717,7 @@ jobs: publish-docker, docker-manifests, publish, + publish-php, summary, ] if: failure() && inputs.dry_run == false diff --git a/foreign/php/composer.json b/foreign/php/composer.json index 429b0a016f..d711c646ae 100644 --- a/foreign/php/composer.json +++ b/foreign/php/composer.json @@ -1,7 +1,6 @@ { "name": "apache/iggy-php", "description": "PHP extension bindings for Apache Iggy.", - "version": "0.1.0", "type": "php-ext", "license": "Apache-2.0", "homepage": "https://iggy.apache.org", diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index f65f32cf6f..66d288e882 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -53,7 +53,7 @@ Components: connectors-all runtime + all sink + all source crates --all All components (Rust + connectors + SDKs + web-ui) sdk-python foreign/python/Cargo.toml + foreign/python/pyproject.toml - sdk-php foreign/php/Cargo.toml + foreign/php/composer.json + sdk-php foreign/php/Cargo.toml sdk-node foreign/node/package.json sdk-go foreign/go/contracts/version.go sdk-csharp foreign/csharp/Iggy_SDK/Iggy_SDK.csproj @@ -95,7 +95,7 @@ SDK_COMPONENTS="sdk-python sdk-php sdk-node sdk-go sdk-csharp sdk-java" ALL_COMPONENTS="${RUST_COMPONENTS} ${CONNECTOR_COMPONENTS} ${SDK_COMPONENTS} web-ui" # Returns "file:format" lines per component. -# Format keys: cargo, cargo-ws-dep:PKG, cargo-dep:PKG, python-cargo, pyproject, php-cargo, composer, json, csproj, gradle, go +# Format keys: cargo, cargo-ws-dep:PKG, cargo-dep:PKG, python-cargo, pyproject, php-cargo, json, csproj, gradle, go get_version_files() { local component="$1" case "$component" in @@ -155,7 +155,6 @@ get_version_files() { ;; sdk-php) echo "foreign/php/Cargo.toml:php-cargo" - echo "foreign/php/composer.json:composer" ;; sdk-node) echo "foreign/node/package.json:json" @@ -250,7 +249,7 @@ translate_version() { read -r base pre_type pre_num <<< "$parsed" case "$format" in - cargo|cargo-ws-dep:*|cargo-dep:*|json|csproj|go) + cargo|cargo-ws-dep:*|cargo-dep:*|php-cargo|json|csproj|go) echo "$canonical" ;; python-cargo) case "$pre_type" in @@ -262,11 +261,6 @@ translate_version() { edge) echo "${base}.dev${pre_num}" ;; stable) echo "$base" ;; esac ;; - php-cargo|composer) - case "$pre_type" in - edge) echo "${base}-dev${pre_num}" ;; - stable) echo "$base" ;; - esac ;; gradle) case "$pre_type" in edge) echo "${base}-SNAPSHOT" ;; @@ -282,7 +276,7 @@ translate_version() { canonicalize_version() { local raw="$1" format="$2" case "$format" in - cargo|cargo-ws-dep:*|cargo-dep:*|json|csproj|go) + cargo|cargo-ws-dep:*|cargo-dep:*|php-cargo|json|csproj|go) echo "$raw" ;; python-cargo) # Handle both old (0.7.2-dev.1) and new (0.7.2-dev1) formats @@ -298,12 +292,6 @@ canonicalize_version() { else echo "$raw" fi ;; - php-cargo|composer) - if [[ "$raw" =~ ^([0-9]+\.[0-9]+\.[0-9]+)-dev\.?([0-9]+)$ ]]; then - echo "${BASH_REMATCH[1]}-edge.${BASH_REMATCH[2]}" - else - echo "$raw" - fi ;; gradle) if [[ "$raw" =~ ^([0-9]+\.[0-9]+\.[0-9]+)-SNAPSHOT$ ]]; then echo "${BASH_REMATCH[1]}-edge.0" diff --git a/scripts/ci/php-sdk-version-sync.sh b/scripts/ci/php-sdk-version-sync.sh index e78297b734..13d3e14d2e 100755 --- a/scripts/ci/php-sdk-version-sync.sh +++ b/scripts/ci/php-sdk-version-sync.sh @@ -38,11 +38,11 @@ while [[ $# -gt 0 ]]; do --help|-h) echo "Usage: $0 [--check|--fix]" echo "" - echo "Sync PHP SDK version between Cargo.toml and composer.json" + echo "Validate PHP SDK Cargo version and Composer metadata" echo "" echo "Options:" - echo " --check Check if versions are synchronized" - echo " --fix Update composer.json to match Cargo.toml" + echo " --check Check Cargo version and Composer version metadata" + echo " --fix Remove a manual Composer version field" echo " --help Show this help message" exit 0 ;; @@ -67,43 +67,55 @@ CARGO_TOML="foreign/php/Cargo.toml" COMPOSER_JSON="foreign/php/composer.json" CARGO_VERSION=$(grep '^version = ' "$CARGO_TOML" | head -1 | sed 's/version = "\(.*\)"/\1/') -COMPOSER_VERSION=$(perl -0777 -ne 'if (/"version"\s*:\s*"([^"]+)"/) { print $1; exit; }' "$COMPOSER_JSON") +COMPOSER_VERSION_LINE=$(grep '"version"' "$COMPOSER_JSON" | head -1 || true) +COMPOSER_VERSION="" +if [ -n "$COMPOSER_VERSION_LINE" ]; then + COMPOSER_VERSION=$(printf '%s\n' "$COMPOSER_VERSION_LINE" | sed 's/.*"version": *"\([^"]*\)".*/\1/') +fi if [ -z "$CARGO_VERSION" ]; then echo -e "${RED}Error: Could not extract version from $CARGO_TOML${NC}" exit 1 fi -if [ -z "$COMPOSER_VERSION" ]; then - echo -e "${RED}Error: Could not extract version from $COMPOSER_JSON${NC}" - exit 1 -fi - echo "PHP SDK version check:" echo " Cargo.toml: $CARGO_VERSION" -echo " composer.json: $COMPOSER_VERSION" +if [ -n "$COMPOSER_VERSION" ]; then + echo " composer.json: $COMPOSER_VERSION (must be removed)" +else + echo " composer.json: no manual version" +fi echo "" if [ "$MODE" = "check" ]; then - if [ "$CARGO_VERSION" = "$COMPOSER_VERSION" ]; then - echo -e "${GREEN}✓ PHP SDK versions are synchronized${NC}" + if [ -z "$COMPOSER_VERSION" ]; then + echo -e "${GREEN}✓ PHP SDK Composer metadata lets tags drive package versions${NC}" exit 0 fi - echo -e "${RED}✗ PHP SDK versions are NOT synchronized${NC}" + echo -e "${RED}✗ composer.json must not declare a manual version${NC}" echo "" - echo "Please ensure both files have the same version:" - echo " - $CARGO_TOML" - echo " - $COMPOSER_JSON" + echo "Packagist/Composer derive VCS package versions from tags." + echo "Remove the version field from $COMPOSER_JSON." echo "" - echo -e "${YELLOW}Run '$0 --fix' to update composer.json from Cargo.toml${NC}" + echo -e "${YELLOW}Run '$0 --fix' to remove the Composer version field${NC}" exit 1 fi -if [ "$CARGO_VERSION" = "$COMPOSER_VERSION" ]; then - echo -e "${GREEN}✓ PHP SDK versions are already synchronized${NC}" +if [ -z "$COMPOSER_VERSION" ]; then + echo -e "${GREEN}✓ PHP SDK Composer metadata already omits a manual version${NC}" exit 0 fi -perl -0pi -e "s/\"version\"\\s*:\\s*\"\\Q$COMPOSER_VERSION\\E\"/\"version\": \"$CARGO_VERSION\"/" "$COMPOSER_JSON" -echo -e "${GREEN}✓ Updated $COMPOSER_JSON: $COMPOSER_VERSION -> $CARGO_VERSION${NC}" +if sed --version 2>/dev/null | grep -q 'GNU'; then + sed -i '/^[[:space:]]*"version"[[:space:]]*:/d' "$COMPOSER_JSON" +else + sed -i '' '/^[[:space:]]*"version"[[:space:]]*:/d' "$COMPOSER_JSON" +fi + +if grep -q '"version"' "$COMPOSER_JSON"; then + echo -e "${RED}Error: Failed to remove version field from $COMPOSER_JSON${NC}" + exit 1 +fi + +echo -e "${GREEN}✓ Removed manual version field from $COMPOSER_JSON${NC}" diff --git a/scripts/extract-version.sh b/scripts/extract-version.sh index 51f965e4e1..ab06d457f3 100755 --- a/scripts/extract-version.sh +++ b/scripts/extract-version.sh @@ -260,8 +260,8 @@ handle_check() { echo "" - # --- Check 3: PHP dual-file sync --- - echo "=== PHP dual-file sync ===" + # --- Check 3: PHP Composer metadata --- + echo "=== PHP Composer metadata ===" local php_script="$SCRIPT_DIR/ci/php-sdk-version-sync.sh" if [[ -x "$php_script" ]]; then if "$php_script" --check; then From 78d8a8722be0b4e3b87c20edcff2e2c94cb0c350 Mon Sep 17 00:00:00 2001 From: Diaconu Radu-Mihai <52667211+countradooku@users.noreply.github.com> Date: Tue, 23 Jun 2026 13:41:01 +0300 Subject: [PATCH 6/6] fix(php): sync rust sdk dependency version --- .github/workflows/_common.yml | 10 +-- foreign/php/Cargo.toml | 2 +- scripts/bump-version.sh | 3 +- scripts/ci/php-sdk-version-sync.sh | 99 ++++++++++++++++++++++-------- scripts/extract-version.sh | 4 +- 5 files changed, 85 insertions(+), 33 deletions(-) diff --git a/.github/workflows/_common.yml b/.github/workflows/_common.yml index f604744825..f3071bb764 100644 --- a/.github/workflows/_common.yml +++ b/.github/workflows/_common.yml @@ -43,12 +43,12 @@ jobs: run: ./scripts/ci/python-sdk-version-sync.sh --check php-versions: - name: Check PHP SDK Composer metadata + name: Check PHP SDK metadata runs-on: ubuntu-latest steps: - uses: actions/checkout@v6.0.2 - - name: Check PHP SDK Composer metadata + - name: Check PHP SDK metadata run: ./scripts/ci/php-sdk-version-sync.sh --check python-interpreter-versions: @@ -275,11 +275,11 @@ jobs: fi if [ "$PHP_VERSIONS" = "success" ]; then - echo "| ✅ PHP SDK Composer Metadata | success | Composer versions are tag-derived |" >> "$GITHUB_STEP_SUMMARY" + echo "| ✅ PHP SDK Metadata | success | Rust SDK dependency and Composer metadata synchronized |" >> "$GITHUB_STEP_SUMMARY" elif [ "$PHP_VERSIONS" = "failure" ]; then - echo "| ❌ PHP SDK Composer Metadata | failure | composer.json declares a manual version |" >> "$GITHUB_STEP_SUMMARY" + echo "| ❌ PHP SDK Metadata | failure | PHP SDK metadata mismatch detected |" >> "$GITHUB_STEP_SUMMARY" else - echo "| ⏭️ PHP SDK Composer Metadata | $PHP_VERSIONS | Check skipped |" >> "$GITHUB_STEP_SUMMARY" + echo "| ⏭️ PHP SDK Metadata | $PHP_VERSIONS | Check skipped |" >> "$GITHUB_STEP_SUMMARY" fi if [ "$PYTHON_INTERPRETER_VERSIONS" = "success" ]; then diff --git a/foreign/php/Cargo.toml b/foreign/php/Cargo.toml index 0384b65633..554b47f4fc 100644 --- a/foreign/php/Cargo.toml +++ b/foreign/php/Cargo.toml @@ -32,7 +32,7 @@ crate-type = ["cdylib"] bytes = "1.11.1" futures = "0.3.32" ext-php-rs = "=0.15.14" -iggy = { path = "../../core/sdk" } +iggy = { path = "../../core/sdk", version = "0.10.1-edge.2" } tokio = "1.52.3" [profile.release] diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index 66d288e882..46c5a4d401 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -33,7 +33,7 @@ Usage: bump-version.sh --status [] Components: - rust-sdk core/sdk + workspace dep + python iggy dep + rust-sdk core/sdk + workspace dep + python/php iggy deps rust-common core/common + workspace dep rust-binary-protocol core/binary_protocol + workspace dep rust-server core/server @@ -103,6 +103,7 @@ get_version_files() { echo "core/sdk/Cargo.toml:cargo" echo "Cargo.toml:cargo-ws-dep:iggy" echo "foreign/python/Cargo.toml:cargo-dep:iggy" + echo "foreign/php/Cargo.toml:cargo-dep:iggy" ;; rust-common) echo "core/common/Cargo.toml:cargo" diff --git a/scripts/ci/php-sdk-version-sync.sh b/scripts/ci/php-sdk-version-sync.sh index 13d3e14d2e..9b93fc3089 100755 --- a/scripts/ci/php-sdk-version-sync.sh +++ b/scripts/ci/php-sdk-version-sync.sh @@ -38,11 +38,11 @@ while [[ $# -gt 0 ]]; do --help|-h) echo "Usage: $0 [--check|--fix]" echo "" - echo "Validate PHP SDK Cargo version and Composer metadata" + echo "Validate PHP SDK Cargo, Rust SDK dependency, and Composer metadata" echo "" echo "Options:" - echo " --check Check Cargo version and Composer version metadata" - echo " --fix Remove a manual Composer version field" + echo " --check Check Cargo dependency and Composer version metadata" + echo " --fix Sync the Rust SDK dependency and remove a manual Composer version field" echo " --help Show this help message" exit 0 ;; @@ -63,54 +63,95 @@ fi REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" cd "$REPO_ROOT" -CARGO_TOML="foreign/php/Cargo.toml" +RUST_SDK_CARGO_TOML="core/sdk/Cargo.toml" +PHP_CARGO_TOML="foreign/php/Cargo.toml" COMPOSER_JSON="foreign/php/composer.json" -CARGO_VERSION=$(grep '^version = ' "$CARGO_TOML" | head -1 | sed 's/version = "\(.*\)"/\1/') +PHP_CARGO_VERSION=$(grep '^version = ' "$PHP_CARGO_TOML" | head -1 | sed 's/version = "\(.*\)"/\1/') +RUST_SDK_VERSION=$(grep '^version = ' "$RUST_SDK_CARGO_TOML" | head -1 | sed 's/version = "\(.*\)"/\1/') +PHP_IGGY_DEP_LINE=$(grep '^iggy = ' "$PHP_CARGO_TOML" | head -1 || true) +PHP_IGGY_DEP_VERSION="" +if [[ "$PHP_IGGY_DEP_LINE" == *'version = "'* ]]; then + PHP_IGGY_DEP_VERSION=$(printf '%s\n' "$PHP_IGGY_DEP_LINE" | sed 's/.*version = "\([^"]*\)".*/\1/') +fi COMPOSER_VERSION_LINE=$(grep '"version"' "$COMPOSER_JSON" | head -1 || true) COMPOSER_VERSION="" if [ -n "$COMPOSER_VERSION_LINE" ]; then COMPOSER_VERSION=$(printf '%s\n' "$COMPOSER_VERSION_LINE" | sed 's/.*"version": *"\([^"]*\)".*/\1/') fi -if [ -z "$CARGO_VERSION" ]; then - echo -e "${RED}Error: Could not extract version from $CARGO_TOML${NC}" +if [ -z "$PHP_CARGO_VERSION" ]; then + echo -e "${RED}Error: Could not extract version from $PHP_CARGO_TOML${NC}" + exit 1 +fi + +if [ -z "$RUST_SDK_VERSION" ]; then + echo -e "${RED}Error: Could not extract version from $RUST_SDK_CARGO_TOML${NC}" exit 1 fi echo "PHP SDK version check:" -echo " Cargo.toml: $CARGO_VERSION" +echo " PHP Cargo.toml: $PHP_CARGO_VERSION" +echo " core/sdk Cargo.toml: $RUST_SDK_VERSION" +if [ -n "$PHP_IGGY_DEP_VERSION" ]; then + echo " PHP iggy dependency: $PHP_IGGY_DEP_VERSION" +else + echo " PHP iggy dependency: missing version" +fi if [ -n "$COMPOSER_VERSION" ]; then - echo " composer.json: $COMPOSER_VERSION (must be removed)" + echo " composer.json: $COMPOSER_VERSION (must be removed)" else - echo " composer.json: no manual version" + echo " composer.json: no manual version" fi echo "" if [ "$MODE" = "check" ]; then - if [ -z "$COMPOSER_VERSION" ]; then - echo -e "${GREEN}✓ PHP SDK Composer metadata lets tags drive package versions${NC}" + if [ "$PHP_IGGY_DEP_VERSION" = "$RUST_SDK_VERSION" ] && [ -z "$COMPOSER_VERSION" ]; then + echo -e "${GREEN}✓ PHP SDK metadata is synchronized${NC}" exit 0 fi - echo -e "${RED}✗ composer.json must not declare a manual version${NC}" + echo -e "${RED}✗ PHP SDK metadata is NOT synchronized${NC}" echo "" - echo "Packagist/Composer derive VCS package versions from tags." - echo "Remove the version field from $COMPOSER_JSON." + if [ "$PHP_IGGY_DEP_VERSION" != "$RUST_SDK_VERSION" ]; then + echo "The PHP iggy dependency must match $RUST_SDK_CARGO_TOML." + fi + if [ -n "$COMPOSER_VERSION" ]; then + echo "Packagist/Composer derive VCS package versions from tags." + echo "Remove the version field from $COMPOSER_JSON." + fi echo "" - echo -e "${YELLOW}Run '$0 --fix' to remove the Composer version field${NC}" + echo -e "${YELLOW}Run '$0 --fix' to sync PHP SDK metadata${NC}" exit 1 fi -if [ -z "$COMPOSER_VERSION" ]; then - echo -e "${GREEN}✓ PHP SDK Composer metadata already omits a manual version${NC}" - exit 0 +changed=0 + +sedi() { + if sed --version 2>/dev/null | grep -q 'GNU'; then + sed -i "$@" + else + sed -i '' "$@" + fi +} + +if [ "$PHP_IGGY_DEP_VERSION" != "$RUST_SDK_VERSION" ]; then + if grep -q '^iggy = .*version = ' "$PHP_CARGO_TOML"; then + sedi "s/^\(iggy = .*version = \"\)[^\"]*/\1${RUST_SDK_VERSION}/" "$PHP_CARGO_TOML" + else + sedi "s/^\(iggy = {[^}]*\) }/\1, version = \"${RUST_SDK_VERSION}\" }/" "$PHP_CARGO_TOML" + fi + changed=1 fi -if sed --version 2>/dev/null | grep -q 'GNU'; then - sed -i '/^[[:space:]]*"version"[[:space:]]*:/d' "$COMPOSER_JSON" -else - sed -i '' '/^[[:space:]]*"version"[[:space:]]*:/d' "$COMPOSER_JSON" +if [ -n "$COMPOSER_VERSION" ]; then + sedi '/^[[:space:]]*"version"[[:space:]]*:/d' "$COMPOSER_JSON" + changed=1 +fi + +if [ "$changed" -eq 0 ]; then + echo -e "${GREEN}✓ PHP SDK metadata already synchronized${NC}" + exit 0 fi if grep -q '"version"' "$COMPOSER_JSON"; then @@ -118,4 +159,14 @@ if grep -q '"version"' "$COMPOSER_JSON"; then exit 1 fi -echo -e "${GREEN}✓ Removed manual version field from $COMPOSER_JSON${NC}" +PHP_IGGY_DEP_LINE=$(grep '^iggy = ' "$PHP_CARGO_TOML" | head -1 || true) +PHP_IGGY_DEP_VERSION="" +if [[ "$PHP_IGGY_DEP_LINE" == *'version = "'* ]]; then + PHP_IGGY_DEP_VERSION=$(printf '%s\n' "$PHP_IGGY_DEP_LINE" | sed 's/.*version = "\([^"]*\)".*/\1/') +fi +if [ "$PHP_IGGY_DEP_VERSION" != "$RUST_SDK_VERSION" ]; then + echo -e "${RED}Error: Failed to sync PHP iggy dependency in $PHP_CARGO_TOML${NC}" + exit 1 +fi + +echo -e "${GREEN}✓ Synchronized PHP SDK metadata${NC}" diff --git a/scripts/extract-version.sh b/scripts/extract-version.sh index ab06d457f3..51548347dd 100755 --- a/scripts/extract-version.sh +++ b/scripts/extract-version.sh @@ -260,8 +260,8 @@ handle_check() { echo "" - # --- Check 3: PHP Composer metadata --- - echo "=== PHP Composer metadata ===" + # --- Check 3: PHP SDK metadata --- + echo "=== PHP SDK metadata ===" local php_script="$SCRIPT_DIR/ci/php-sdk-version-sync.sh" if [[ -x "$php_script" ]]; then if "$php_script" --check; then