Sync from dist-$STACK-develop/ to dist-$STACK-stable/ #185
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Platform packages sync from -develop/ to -stable/ | |
| run-name: Sync${{ inputs.dry-run == true && ' dry-run' || '' }} from dist-$STACK-develop/ to dist-$STACK-stable/ | |
| env: | |
| src_path_suffix: "-develop/" | |
| dst_path_suffix: "-stable/" | |
| # ensure these are in sync with other relevant action/workflow yml files | |
| setup_php_php_version: "8.4" | |
| setup_php_composer_version: "2.9" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| stack-heroku-22-amd64: | |
| description: 'Sync heroku-22 (amd64) packages' | |
| type: boolean | |
| default: true | |
| required: false | |
| stack-heroku-24-amd64: | |
| description: 'Sync heroku-24 (amd64) packages' | |
| type: boolean | |
| default: true | |
| required: false | |
| stack-heroku-24-arm64: | |
| description: 'Sync heroku-24 (arm64) packages' | |
| type: boolean | |
| default: true | |
| required: false | |
| stack-heroku-26-amd64: | |
| description: 'Sync heroku-26 (amd64) packages' | |
| type: boolean | |
| default: true | |
| required: false | |
| stack-heroku-26-arm64: | |
| description: 'Sync heroku-26 (arm64) packages' | |
| type: boolean | |
| default: true | |
| required: false | |
| dry-run: | |
| description: 'Only list package changes, without syncing' | |
| type: boolean | |
| default: false | |
| required: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| stack-list: | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| stacks: ${{ steps.list-stacks.outputs.matrix }} | |
| steps: | |
| - id: list-stacks | |
| name: Generate list of stacks to sync based on input checkboxes | |
| run: | | |
| echo '## Stacks to sync' >> "$GITHUB_STEP_SUMMARY" | |
| set -o pipefail | |
| stacks=(${{ inputs.stack-heroku-22-amd64 == true && 'heroku-22-amd64' || ''}} ${{ inputs.stack-heroku-24-amd64 == true && 'heroku-24-amd64' || ''}} ${{ inputs.stack-heroku-24-arm64 == true && 'heroku-24-arm64' || ''}} ${{ inputs.stack-heroku-26-amd64 == true && 'heroku-26-amd64' || ''}} ${{ inputs.stack-heroku-26-arm64 == true && 'heroku-26-arm64' || ''}}) | |
| printf -- "- %s\n" "${stacks[@]}" >> "$GITHUB_STEP_SUMMARY" | |
| echo -n "matrix=" >> "$GITHUB_OUTPUT" | |
| printf "%s\n" "${stacks[@]}" | jq -jcRn '[inputs|select(length>0)]' >> "$GITHUB_OUTPUT" | |
| docker-build: | |
| needs: stack-list | |
| if: ${{ needs.stack-list.outputs.stacks != '[]' && needs.stack-list.outputs.stacks != '' }} | |
| runs-on: ${{ endsWith(matrix.stack, '-arm64') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} | |
| strategy: | |
| matrix: | |
| stack: ${{ fromJSON(needs.stack-list.outputs.stacks) }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Cache Docker build | |
| id: cache-docker | |
| uses: actions/cache@v5 | |
| with: | |
| key: docker-cache-heroku-php-build-${{matrix.stack}}.${{github.sha}} | |
| path: /tmp/docker-cache.tar.gz | |
| - name: Build Docker image | |
| if: steps.cache-docker.outputs.cache-hit != 'true' | |
| # our "input" stack might contain a "-amd64" or "-arm64" suffix, which we strip off for the Dockerfile name | |
| run: | | |
| shopt -s extglob | |
| stackname_with_architecture=${{matrix.stack}} | |
| docker build --tag heroku-php-build-${stackname_with_architecture}:${{github.sha}} --file support/build/docker/${stackname_with_architecture%-?(amd|arm)64}.Dockerfile . | |
| - name: Save built Docker image | |
| if: steps.cache-docker.outputs.cache-hit != 'true' | |
| run: docker save heroku-php-build-${{matrix.stack}}:${{github.sha}} | gzip -1 > /tmp/docker-cache.tar.gz | |
| sync: | |
| needs: [stack-list, docker-build] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| stack: ${{ fromJSON(needs.stack-list.outputs.stacks) }} | |
| runs-on: ${{ endsWith(matrix.stack, '-arm64') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} | |
| env: | |
| AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Restore cached Docker build | |
| uses: actions/cache/restore@v5 | |
| with: | |
| key: docker-cache-heroku-php-build-${{matrix.stack}}.${{github.sha}} | |
| path: /tmp/docker-cache.tar.gz | |
| fail-on-cache-miss: true | |
| - name: Load cached Docker image | |
| run: docker load -i /tmp/docker-cache.tar.gz | |
| - name: Perform platform repo snapshot checks | |
| id: platform-repo-snapshot-calc | |
| uses: ./.github/actions/platform-repo-snapshot-calc | |
| with: | |
| stacks-list-for-shell-expansion: ${{ matrix.stack }} | |
| repo-path-suffix: ${{ env.dst_path_suffix }} | |
| - name: ${{ inputs.dry-run == true && 'Dry-run sync of' || 'Sync' }} changed packages to stable bucket | |
| run: | | |
| # we want to fail if 'docker run' fails; without this, 'tee' would "eat" the failure status | |
| set -o pipefail | |
| # yes gets "n" to print for dry-runs so the sync aborts | |
| # errors are redirected to /dev/null, and we || true, to suppress SIGPIPE errors from 'docker run' exiting eventually | |
| # we need -i for Docker to accept input on stdin, but must not use -t for the pipeline to work | |
| (yes "${{ inputs.dry-run == true && 'n' || 'y' }}" 2>/dev/null || true) | docker run --rm -i --env-file=support/build/docker/env.default heroku-php-build-${{matrix.stack}}:${{github.sha}} sync.sh --no-remove -c "${{steps.platform-repo-snapshot-calc.outputs.snapshot-sha256}}" heroku-buildpack-php dist-${{matrix.stack}}${{env.dst_path_suffix}} 2>&1 | tee sync-${{matrix.stack}}.log || { | |
| result=$? | |
| case $result in | |
| 3) | |
| echo "::error title=Repository not in consistent state::Bucket contains manifests that are not listed in packages.json" | |
| ;; | |
| 4) | |
| echo "::error title=Repository snapshot outdated::The repository snapshot and packages.json differ; sync needs to be run against a branch whose manifests match the snapshot" | |
| ;; | |
| 9) | |
| echo "::error title=Snapshot already exists in destination::The destination already contains the same repository snapshot; overwrites of snapshots are not allowed" | |
| ;; | |
| *) | |
| echo "::error title=Repository sync failed::Check step output for details" | |
| ;; | |
| esac | |
| exit $result | |
| } | |
| - name: Upload sync log as artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: synclog-${{matrix.stack}} | |
| path: sync-${{matrix.stack}}.log | |
| - name: Output dry-run summary | |
| if: ${{ inputs.dry-run == true }} | |
| run: | | |
| echo '## Package changes available for syncing from `…${{matrix.stack}}${{env.src_path_suffix}}` to `…${{matrix.stack}}${{env.dst_path_suffix}}`' >> "$GITHUB_STEP_SUMMARY" | |
| echo '> [!IMPORTANT]' >> "$GITHUB_STEP_SUMMARY" | |
| echo '> **This is output from a dry-run**, no changes have been synced!' >> "$GITHUB_STEP_SUMMARY" | |
| echo >> "$GITHUB_STEP_SUMMARY" | |
| echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| sed -En '/^(The following packages will|Nothing to do except)/,/POTENTIALLY DESTRUCTIVE ACTION/{/POTENTIALLY DESTRUCTIVE ACTION/!p}' sync-${{matrix.stack}}.log >> "$GITHUB_STEP_SUMMARY" | |
| echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| - name: Output sync summary | |
| if: ${{ inputs.dry-run == false }} | |
| run: | | |
| echo '## Platform repository `…${{matrix.stack}}${{env.dst_path_suffix}}` updated' >> "$GITHUB_STEP_SUMMARY" | |
| echo '- Snapshot hash for formulae in source tree: `${{steps.platform-repo-snapshot-calc.outputs.snapshot-sha256}}`' >> "$GITHUB_STEP_SUMMARY" | |
| echo '- Snapshot repository URL: ${{steps.platform-repo-snapshot-calc.outputs.snapshot-urls}}' >> "$GITHUB_STEP_SUMMARY" | |
| echo '- "Head" repository URL: ${{steps.platform-repo-snapshot-calc.outputs.urls}}' >> "$GITHUB_STEP_SUMMARY" | |
| echo '## Package changes synced from `…${{matrix.stack}}${{env.src_path_suffix}}`' >> "$GITHUB_STEP_SUMMARY" | |
| echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| cat sync-${{matrix.stack}}.log >> "$GITHUB_STEP_SUMMARY" | |
| echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| changelog-generate: | |
| needs: sync | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Install PHP and Composer | |
| uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 | |
| with: | |
| php-version: "${{ env.setup_php_php_version }}" | |
| tools: "composer:${{ env.setup_php_composer_version }}" | |
| - name: Install Dev Center generator dependencies | |
| run: | | |
| composer install -d support/devcenter/ | |
| - name: Download all sync log artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: synclogs | |
| pattern: synclog-* | |
| merge-multiple: true | |
| - name: Generate Changelog markdown | |
| run: | | |
| set -o pipefail | |
| # concatenate all sync logs and feed them to changelog.php | |
| # immediately split changelog title and body (separated by a "----" line) for easier copy/paste | |
| # this also lets us detect if there even is anything to output in the next step (there won't be a changelog-01.md if the changelog is empty) | |
| # the '{*}' pattern works around a bug in older coreutils csplits: https://github.com/coreutils/coreutils/commit/7cf45f4f6a093a927d3139c87f52999dd2c750ec | |
| cat synclogs/sync-*.log | support/devcenter/changelog.php | csplit -s -z -f 'changelog-' -b '%02d.md' --suppress-matched - '/^----$/' '{*}' | |
| - name: Output Changelog markdown | |
| if: ${{ hashFiles('changelog-01.md') != '' }} | |
| run: | | |
| shopt -s extglob | |
| echo '## Markdown for package Changelog entry' >> "$GITHUB_STEP_SUMMARY" | |
| echo "${{ inputs.dry-run == true && '> [!WARNING]' || '-n' }}" >> "$GITHUB_STEP_SUMMARY" | |
| echo "${{ inputs.dry-run == true && '> **These changes have not been synced to the destination bucket**, the changelog entry is for reference only!' || '-n' }}" >> "$GITHUB_STEP_SUMMARY" | |
| echo "${{ inputs.dry-run == false && '-n' || '' }}" >> "$GITHUB_STEP_SUMMARY" | |
| echo '### Title' >> "$GITHUB_STEP_SUMMARY" | |
| echo '``````markdown' >> "$GITHUB_STEP_SUMMARY" # six instead of three backticks because our output is likely to also contain series of backticks | |
| cat changelog-00.md >> "$GITHUB_STEP_SUMMARY" | |
| echo '``````' >> "$GITHUB_STEP_SUMMARY" # six instead of three backticks because our output is likely to also contain series of backticks | |
| echo '### Content' >> "$GITHUB_STEP_SUMMARY" | |
| echo '``````markdown' >> "$GITHUB_STEP_SUMMARY" # six instead of three backticks because our output is likely to also contain series of backticks | |
| cat changelog-!(00).md >> "$GITHUB_STEP_SUMMARY" | |
| echo '``````' >> "$GITHUB_STEP_SUMMARY" # six instead of three backticks because our output is likely to also contain series of backticks |