From afe62e6592f458bcbaac34cee3014ede85c90587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Tue, 8 Sep 2026 19:39:17 +0200 Subject: [PATCH] :sparkles: Add force rebuild flag and adhoc ref builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a `force` input to Bundles Builder, Docker Images Builder and the admin-console dispatcher to bypass the existing S3/registry skip checks and overwrite artifacts unconditionally. Propagate it through _DEVELOP, _STAGING and _TAG (defaulting to false on non-dispatch triggers, since schedule/push events carry no inputs). Add a new _ADHOC workflow to build the full image set (bundle + all docker images + nitrate admin-console) from an arbitrary ref pair, for one-off builds of feature branches like test-bameda. Enrich the build/promote step summaries with the built version (`git describe --tags --always`), a link to the commit and the build timestamp. Add run-name to all `_`-prefixed workflows so the target ref (and, where reliable, the commit sha) is visible directly in the Actions run list. Signed-off-by: David BarragΓ‘n Merino --- .github/workflows/build-adhoc.yml | 44 +++++++++++++++++++ .github/workflows/build-bundle.yml | 36 ++++++++++++++- .github/workflows/build-develop.yml | 12 +++++ .../workflows/build-docker-admin-console.yml | 11 +++++ .github/workflows/build-docker.yml | 39 +++++++++++++++- .github/workflows/build-staging.yml | 12 +++++ .github/workflows/build-tag.yml | 12 +++++ 7 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/build-adhoc.yml diff --git a/.github/workflows/build-adhoc.yml b/.github/workflows/build-adhoc.yml new file mode 100644 index 0000000000..327c449fc4 --- /dev/null +++ b/.github/workflows/build-adhoc.yml @@ -0,0 +1,44 @@ +name: _ADHOC + +run-name: >- + _ADHOC (${{ inputs.gh_ref }}${{ inputs.nitrate_ref != '' && format(' / nitrate:{0}', inputs.nitrate_ref) || '' }}) + +on: + workflow_dispatch: + inputs: + gh_ref: + description: 'Branch/ref to build in penpot/penpot' + type: string + required: true + nitrate_ref: + description: 'Branch/ref to build admin-console in penpot/penpot-nitrate (defaults to gh_ref)' + type: string + required: false + force: + description: 'Rebuild and overwrite even if already built/promoted' + type: boolean + required: false + default: false + +jobs: + build-bundle: + uses: ./.github/workflows/build-bundle.yml + secrets: inherit + with: + gh_ref: ${{ inputs.gh_ref }} + force: ${{ inputs.force }} + + build-docker: + needs: build-bundle + uses: ./.github/workflows/build-docker.yml + secrets: inherit + with: + gh_ref: ${{ inputs.gh_ref }} + force: ${{ inputs.force }} + + build-docker-admin-console: + uses: ./.github/workflows/build-docker-admin-console.yml + secrets: inherit + with: + gh_ref: ${{ inputs.nitrate_ref || inputs.gh_ref }} + force: ${{ inputs.force }} diff --git a/.github/workflows/build-bundle.yml b/.github/workflows/build-bundle.yml index b31450ac60..493a3e44e8 100644 --- a/.github/workflows/build-bundle.yml +++ b/.github/workflows/build-bundle.yml @@ -9,6 +9,11 @@ on: type: string required: true default: 'develop' + force: + description: 'Rebuild and overwrite even if this version already exists in S3' + type: boolean + required: false + default: false workflow_call: inputs: gh_ref: @@ -16,6 +21,11 @@ on: type: string required: true default: 'develop' + force: + description: 'Rebuild and overwrite even if this version already exists in S3' + type: boolean + required: false + default: false # Literal group name: under `workflow_call`, `github.workflow` resolves to the # caller's workflow, which put this workflow and the other reusable one called @@ -34,6 +44,8 @@ jobs: outputs: gh_ref: ${{ steps.vars.outputs.gh_ref }} bundle_version: ${{ steps.vars.outputs.bundle_version }} + sha: ${{ steps.vars.outputs.sha }} + commit_title: ${{ steps.vars.outputs.commit_title }} exists: ${{ steps.check.outputs.exists }} steps: @@ -48,10 +60,12 @@ jobs: run: | echo "gh_ref=${{ inputs.gh_ref || github.ref_name }}" >> $GITHUB_OUTPUT echo "bundle_version=$(git describe --tags --always)" >> $GITHUB_OUTPUT + echo "sha=$(git rev-parse --short=12 HEAD)" >> $GITHUB_OUTPUT + echo "commit_title=$(git log -1 --pretty=%s)" >> $GITHUB_OUTPUT # The uploaded zip carries its version as S3 metadata. If the # existing object was already built from this same commit, the - # whole build job is skipped. + # whole build job is skipped. `force` bypasses this check entirely. - name: Check if this bundle is already built id: check env: @@ -59,6 +73,16 @@ jobs: AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }} run: | + if [ "${{ inputs.force }}" = "true" ]; then + echo "exists=false" >> $GITHUB_OUTPUT + { + echo "### πŸ” Bundle build forced" + echo "" + echo "\`force: true\` β€” skipping the S3 version check." + } >> "$GITHUB_STEP_SUMMARY" + exit 0 + fi + EXISTING_VERSION=$(aws s3api head-object \ --bucket ${{ secrets.S3_BUCKET }} \ --key "penpot-${{ steps.vars.outputs.gh_ref }}.zip" \ @@ -117,6 +141,16 @@ jobs: s3://${{ secrets.S3_BUCKET }}/penpot-${{ needs.check.outputs.gh_ref }}.zip \ --metadata bundle-version=${{ needs.check.outputs.bundle_version }} + - name: Write step summary + run: | + { + echo "### βœ… Bundle built" + echo "" + echo "- Version: \`${{ needs.check.outputs.bundle_version }}\` (\`git describe --tags --always\`)" + echo "- Commit: [\`${{ needs.check.outputs.sha }}\`](https://github.com/${{ github.repository }}/commit/${{ needs.check.outputs.sha }}) β€” ${{ needs.check.outputs.commit_title }}" + echo "- Built at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" + } >> "$GITHUB_STEP_SUMMARY" + # ── 3. Single failure notification for the whole workflow ───────────── notify: name: Notify failure diff --git a/.github/workflows/build-develop.yml b/.github/workflows/build-develop.yml index 961ad1dca9..7346450831 100644 --- a/.github/workflows/build-develop.yml +++ b/.github/workflows/build-develop.yml @@ -1,7 +1,16 @@ name: _DEVELOP +run-name: >- + _DEVELOP (develop @ ${{ github.sha }}) + on: workflow_dispatch: + inputs: + force: + description: 'Rebuild and overwrite even if already built/promoted' + type: boolean + required: false + default: false schedule: - cron: '16 5-20 * * 1-5' @@ -15,6 +24,7 @@ jobs: secrets: inherit with: gh_ref: "develop" + force: ${{ inputs.force || false }} build-docker: needs: build-bundle @@ -22,9 +32,11 @@ jobs: secrets: inherit with: gh_ref: "develop" + force: ${{ inputs.force || false }} build-docker-admin-console: uses: ./.github/workflows/build-docker-admin-console.yml secrets: inherit with: gh_ref: "develop" + force: ${{ inputs.force || false }} diff --git a/.github/workflows/build-docker-admin-console.yml b/.github/workflows/build-docker-admin-console.yml index b3f8384636..dbc28387b6 100644 --- a/.github/workflows/build-docker-admin-console.yml +++ b/.github/workflows/build-docker-admin-console.yml @@ -13,6 +13,11 @@ on: type: string required: false default: 'develop' + force: + description: 'Rebuild and overwrite even if already built' + type: boolean + required: false + default: false workflow_call: inputs: gh_ref: @@ -24,6 +29,11 @@ on: type: string required: false default: 'develop' + force: + description: 'Rebuild and overwrite even if already built' + type: boolean + required: false + default: false secrets: ORG_WORKFLOW_TOKEN: description: 'Token with Actions write access on penpot-nitrate' @@ -47,6 +57,7 @@ jobs: gh workflow run "$WORKFLOW" --repo "$REPO" --ref "$DISPATCH_REF" \ -f gh_ref="$GH_REF" \ + -f force="${{ inputs.force }}" \ -f caller_run_id="$DISTINCT_ID" \ -f caller_run_url="$CALLER_URL" diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index b7bb794776..ade22b78d1 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -8,6 +8,11 @@ on: type: string required: true default: 'develop' + force: + description: 'Rebuild and overwrite even if this sha is already promoted' + type: boolean + required: false + default: false workflow_call: inputs: gh_ref: @@ -15,6 +20,11 @@ on: type: string required: true default: 'develop' + force: + description: 'Rebuild and overwrite even if this sha is already promoted' + type: boolean + required: false + default: false # Literal group name: under `workflow_call`, `github.workflow` resolves to the # caller's workflow, which put this workflow and the other reusable one called @@ -42,6 +52,7 @@ jobs: gh_ref: ${{ steps.vars.outputs.gh_ref }} bundle_version: ${{ steps.vars.outputs.bundle_version }} sha: ${{ steps.vars.outputs.sha }} + commit_title: ${{ steps.vars.outputs.commit_title }} exists: ${{ steps.check.outputs.exists }} steps: @@ -60,6 +71,7 @@ jobs: GH_REF="${{ inputs.gh_ref || github.ref_name }}" echo "gh_ref=$GH_REF" >> $GITHUB_OUTPUT echo "sha=$(git rev-parse --short=12 HEAD)" >> $GITHUB_OUTPUT + echo "commit_title=$(git log -1 --pretty=%s)" >> $GITHUB_OUTPUT BUNDLE_VERSION=$(aws s3api head-object \ --bucket ${{ secrets.S3_BUCKET }} \ @@ -71,7 +83,8 @@ jobs: # The image set is a single block, so a single set-level check is # enough: `promote` drops a marker object in S3 only after every # image was built AND every branch tag was moved. Marker present - # means there is nothing at all to do for this commit. + # means there is nothing at all to do for this commit. `force` + # bypasses this check entirely. - name: Check if this image set is already built id: check env: @@ -79,6 +92,21 @@ jobs: AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }} run: | + if [ "${{ inputs.force }}" = "true" ]; then + echo "exists=false" >> $GITHUB_OUTPUT + mkdir -p "$BUNDLE_CACHE" + find "$BUNDLE_CACHE" -type f -mtime +1 -delete || true + ZIP="$BUNDLE_CACHE/penpot-${{ steps.vars.outputs.bundle_version }}.zip" + aws s3 cp "s3://${{ secrets.S3_BUCKET }}/penpot-${{ steps.vars.outputs.gh_ref }}.zip" "$ZIP.$$.tmp" + mv "$ZIP.$$.tmp" "$ZIP" + { + echo "### πŸ” Image set build forced" + echo "" + echo "\`force: true\` β€” skipping the S3 marker check." + } >> "$GITHUB_STEP_SUMMARY" + exit 0 + fi + if aws s3api head-object \ --bucket ${{ secrets.S3_BUCKET }} \ --key "markers/images-sha-${{ steps.vars.outputs.sha }}" \ @@ -138,7 +166,7 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - # To avoid the β€œ429 Too Many Requests” error when downloading + # To avoid the "429 Too Many Requests" error when downloading # images from DockerHub for unregistered users. # https://docs.docker.com/docker-hub/usage/ - name: Login to DockerHub Registry @@ -258,9 +286,16 @@ jobs: run: | echo "${{ github.run_id }}" | aws s3 cp - \ "s3://${{ secrets.S3_BUCKET }}/markers/images-sha-${{ needs.prepare.outputs.sha }}" + + - name: Write step summary + run: | { echo "### βœ… Image set promoted" echo "" + echo "- Version: \`${{ needs.prepare.outputs.bundle_version }}\` (\`git describe --tags --always\`)" + echo "- Commit: [\`${{ needs.prepare.outputs.sha }}\`](https://github.com/${{ github.repository }}/commit/${{ needs.prepare.outputs.sha }}) β€” ${{ needs.prepare.outputs.commit_title }}" + echo "- Built at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" + echo "" echo "All \`:${{ needs.prepare.outputs.gh_ref }}\` tags now point to \`sha-${{ needs.prepare.outputs.sha }}\`." } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/build-staging.yml b/.github/workflows/build-staging.yml index 1523e4d7df..c2e3dad823 100644 --- a/.github/workflows/build-staging.yml +++ b/.github/workflows/build-staging.yml @@ -1,7 +1,16 @@ name: _STAGING +run-name: >- + _STAGING (staging) + on: workflow_dispatch: + inputs: + force: + description: 'Rebuild and overwrite even if already built/promoted' + type: boolean + required: false + default: false schedule: - cron: '36 5-20 * * 1-5' @@ -15,6 +24,7 @@ jobs: secrets: inherit with: gh_ref: "staging" + force: ${{ inputs.force || false }} build-docker: needs: build-bundle @@ -22,9 +32,11 @@ jobs: secrets: inherit with: gh_ref: "staging" + force: ${{ inputs.force || false }} build-docker-admin-console: uses: ./.github/workflows/build-docker-admin-console.yml secrets: inherit with: gh_ref: "staging" + force: ${{ inputs.force || false }} diff --git a/.github/workflows/build-tag.yml b/.github/workflows/build-tag.yml index aa6a2b8357..bfa30fb67b 100644 --- a/.github/workflows/build-tag.yml +++ b/.github/workflows/build-tag.yml @@ -1,7 +1,16 @@ name: _TAG +run-name: >- + _TAG (${{ github.ref_name }} @ ${{ github.sha }}) + on: workflow_dispatch: + inputs: + force: + description: 'Rebuild and overwrite even if already built/promoted (manual re-releases only)' + type: boolean + required: false + default: false push: tags: - '*' @@ -18,6 +27,7 @@ jobs: secrets: inherit with: gh_ref: ${{ github.ref_name }} + force: ${{ inputs.force || false }} build-docker: needs: build-bundle @@ -25,12 +35,14 @@ jobs: secrets: inherit with: gh_ref: ${{ github.ref_name }} + force: ${{ inputs.force || false }} build-docker-admin-console: uses: ./.github/workflows/build-docker-admin-console.yml secrets: inherit with: gh_ref: ${{ github.ref_name }} + force: ${{ inputs.force || false }} notify: name: Notifications