Skip to content

Sync from dist-$STACK-develop/ to dist-$STACK-stable/ #185

Sync from dist-$STACK-develop/ to dist-$STACK-stable/

Sync from dist-$STACK-develop/ to dist-$STACK-stable/ #185

Workflow file for this run

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