mirror of
https://github.com/penpot/penpot.git
synced 2026-10-28 21:40:34 +00:00
👷 Include the version in the bundle and image build key
The bundle stamps the version into version.txt, so a commit that gets a new tag (2.18.1-RC1 -> 2.18.1) needs a new bundle and image set. Keying them by commit sha alone reused the RC artifacts for the final release. Signed-off-by: David Barragán Merino <david.barragan@kaleidos.net>
This commit is contained in:
parent
01e0b32850
commit
dbcd1e0d03
32
.github/workflows/build-bundle.yml
vendored
32
.github/workflows/build-bundle.yml
vendored
@ -61,6 +61,7 @@ jobs:
|
||||
outputs:
|
||||
gh_ref: ${{ steps.vars.outputs.gh_ref }}
|
||||
bundle_version: ${{ steps.vars.outputs.bundle_version }}
|
||||
build_key: ${{ steps.vars.outputs.build_key }}
|
||||
short_sha: ${{ steps.vars.outputs.short_sha }}
|
||||
sha: ${{ steps.vars.outputs.sha }}
|
||||
commit_title: ${{ steps.vars.outputs.commit_title }}
|
||||
@ -79,16 +80,22 @@ jobs:
|
||||
env:
|
||||
GH_REF: ${{ inputs.gh_ref || github.ref_name }}
|
||||
run: |
|
||||
# Same command the build uses to stamp version.txt, so the key
|
||||
# always matches what ends up inside the bundle.
|
||||
BUNDLE_VERSION=$(./manage.sh version)
|
||||
SHORT_SHA=$(git rev-parse --short=12 HEAD)
|
||||
echo "gh_ref=$GH_REF" >> $GITHUB_OUTPUT
|
||||
echo "bundle_version=$(git describe --tags --always)" >> $GITHUB_OUTPUT
|
||||
echo "short_sha=$(git rev-parse --short=12 HEAD)" >> $GITHUB_OUTPUT
|
||||
echo "bundle_version=$BUNDLE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "build_key=sha-${SHORT_SHA}-${BUNDLE_VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT
|
||||
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||
echo "commit_title=$(git log -1 --pretty=%s)" >> $GITHUB_OUTPUT
|
||||
|
||||
# Keyed by commit sha, same as build-docker.yml's marker check, so
|
||||
# both pipelines agree on what "already built" means: any ref that
|
||||
# points at an already-bundled commit skips the build, regardless of
|
||||
# which ref built it first. `force` bypasses this check entirely.
|
||||
# Keyed by commit sha AND version, same as build-docker.yml's marker
|
||||
# check, so both pipelines agree on what "already built" means. The
|
||||
# version is stamped into the bundle, so a new tag on an already
|
||||
# bundled commit (2.18.1-RC1 -> 2.18.1) must produce a new bundle.
|
||||
# `force` bypasses this check entirely.
|
||||
- name: Check if this bundle is already built
|
||||
id: check
|
||||
env:
|
||||
@ -97,8 +104,7 @@ jobs:
|
||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||
FORCE: ${{ inputs.force }}
|
||||
SHORT_SHA: ${{ steps.vars.outputs.short_sha }}
|
||||
BUNDLE_VERSION: ${{ steps.vars.outputs.bundle_version }}
|
||||
BUILD_KEY: ${{ steps.vars.outputs.build_key }}
|
||||
run: |
|
||||
if [ "$FORCE" = "true" ]; then
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
@ -112,7 +118,7 @@ jobs:
|
||||
|
||||
BUNDLE_EXISTS=$(aws s3api head-object \
|
||||
--bucket "$S3_BUCKET" \
|
||||
--key "penpot-sha-${SHORT_SHA}.zip" \
|
||||
--key "penpot-${BUILD_KEY}.zip" \
|
||||
> /dev/null 2>&1 && echo "true" || echo "false")
|
||||
|
||||
if [ "$BUNDLE_EXISTS" = "true" ]; then
|
||||
@ -120,7 +126,7 @@ jobs:
|
||||
{
|
||||
echo "### ⏭️ Bundle build skipped"
|
||||
echo ""
|
||||
echo "The bundle in S3 was already built from \`sha-${SHORT_SHA}\` (\`${BUNDLE_VERSION}\`)."
|
||||
echo "The bundle in S3 was already built for \`${BUILD_KEY}\`."
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
else
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
@ -164,11 +170,11 @@ jobs:
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||
SHORT_SHA: ${{ needs.check.outputs.short_sha }}
|
||||
BUILD_KEY: ${{ needs.check.outputs.build_key }}
|
||||
BUNDLE_VERSION: ${{ needs.check.outputs.bundle_version }}
|
||||
run: |
|
||||
aws s3 cp zips/penpot.zip \
|
||||
"s3://${S3_BUCKET}/penpot-sha-${SHORT_SHA}.zip" \
|
||||
"s3://${S3_BUCKET}/penpot-${BUILD_KEY}.zip" \
|
||||
--metadata "bundle-version=${BUNDLE_VERSION}"
|
||||
|
||||
- name: Write step summary
|
||||
@ -180,7 +186,7 @@ jobs:
|
||||
{
|
||||
echo "### ✅ Bundle built"
|
||||
echo ""
|
||||
echo "- Version: \`${BUNDLE_VERSION}\` (\`git describe --tags --always\`)"
|
||||
echo "- Version: \`${BUNDLE_VERSION}\` (\`./manage.sh version\`)"
|
||||
echo "- Commit: [\`${SHORT_SHA}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/${SHORT_SHA}) — ${COMMIT_TITLE}"
|
||||
echo "- Built at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
53
.github/workflows/build-docker.yml
vendored
53
.github/workflows/build-docker.yml
vendored
@ -85,6 +85,7 @@ jobs:
|
||||
bundle_version: ${{ steps.vars.outputs.bundle_version }}
|
||||
sha: ${{ steps.vars.outputs.sha }}
|
||||
short_sha: ${{ steps.vars.outputs.short_sha }}
|
||||
build_key: ${{ steps.vars.outputs.build_key }}
|
||||
commit_title: ${{ steps.vars.outputs.commit_title }}
|
||||
exists: ${{ steps.check.outputs.exists }}
|
||||
|
||||
@ -105,10 +106,14 @@ jobs:
|
||||
REF_SLUG=$(printf '%s' "$GH_REF" | tr -c 'A-Za-z0-9._-' '-' | cut -c1-100)
|
||||
echo "gh_ref=$GH_REF" >> $GITHUB_OUTPUT
|
||||
echo "ref_slug=$REF_SLUG" >> $GITHUB_OUTPUT
|
||||
# Must match the key computed by build-bundle.yml.
|
||||
BUNDLE_VERSION=$(./manage.sh version)
|
||||
SHORT_SHA=$(git rev-parse --short=12 HEAD)
|
||||
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||
echo "short_sha=$(git rev-parse --short=12 HEAD)" >> $GITHUB_OUTPUT
|
||||
echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT
|
||||
echo "commit_title=$(git log -1 --pretty=%s)" >> $GITHUB_OUTPUT
|
||||
echo "bundle_version=$(git describe --tags --always)" >> $GITHUB_OUTPUT
|
||||
echo "bundle_version=$BUNDLE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "build_key=sha-${SHORT_SHA}-${BUNDLE_VERSION}" >> $GITHUB_OUTPUT
|
||||
|
||||
# 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
|
||||
@ -123,14 +128,14 @@ jobs:
|
||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||
FORCE: ${{ inputs.force }}
|
||||
SHORT_SHA: ${{ steps.vars.outputs.short_sha }}
|
||||
BUILD_KEY: ${{ steps.vars.outputs.build_key }}
|
||||
run: |
|
||||
if [ "$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-sha-${SHORT_SHA}.zip"
|
||||
aws s3 cp "s3://${S3_BUCKET}/penpot-sha-${SHORT_SHA}.zip" "$ZIP.$$.tmp"
|
||||
ZIP="$BUNDLE_CACHE/penpot-${BUILD_KEY}.zip"
|
||||
aws s3 cp "s3://${S3_BUCKET}/penpot-${BUILD_KEY}.zip" "$ZIP.$$.tmp"
|
||||
mv "$ZIP.$$.tmp" "$ZIP"
|
||||
{
|
||||
echo "### 🔁 Image set build forced"
|
||||
@ -142,13 +147,13 @@ jobs:
|
||||
|
||||
if aws s3api head-object \
|
||||
--bucket "$S3_BUCKET" \
|
||||
--key "markers/images-sha-${SHORT_SHA}" \
|
||||
--key "markers/images-${BUILD_KEY}" \
|
||||
> /dev/null 2>&1; then
|
||||
echo "exists=true" >> $GITHUB_OUTPUT
|
||||
{
|
||||
echo "### ⏭️ Image set build skipped"
|
||||
echo ""
|
||||
echo "The whole set was already built and promoted for \`sha-${SHORT_SHA}\`."
|
||||
echo "The whole set was already built and promoted for \`${BUILD_KEY}\`."
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
else
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
@ -158,9 +163,9 @@ jobs:
|
||||
# prune stale bundles while at it.
|
||||
mkdir -p "$BUNDLE_CACHE"
|
||||
find "$BUNDLE_CACHE" -type f -mtime +1 -delete || true
|
||||
ZIP="$BUNDLE_CACHE/penpot-sha-${SHORT_SHA}.zip"
|
||||
ZIP="$BUNDLE_CACHE/penpot-${BUILD_KEY}.zip"
|
||||
if [ ! -f "$ZIP" ]; then
|
||||
aws s3 cp "s3://${S3_BUCKET}/penpot-sha-${SHORT_SHA}.zip" "$ZIP.$$.tmp"
|
||||
aws s3 cp "s3://${S3_BUCKET}/penpot-${BUILD_KEY}.zip" "$ZIP.$$.tmp"
|
||||
mv "$ZIP.$$.tmp" "$ZIP"
|
||||
fi
|
||||
fi
|
||||
@ -231,14 +236,14 @@ jobs:
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||
BUILD_KEY: ${{ needs.prepare.outputs.build_key }}
|
||||
IMAGE: ${{ matrix.image }}
|
||||
run: |
|
||||
ZIP="$BUNDLE_CACHE/penpot-sha-${SHORT_SHA}.zip"
|
||||
ZIP="$BUNDLE_CACHE/penpot-${BUILD_KEY}.zip"
|
||||
if [ ! -f "$ZIP" ]; then
|
||||
echo "Bundle not found in host cache; falling back to S3."
|
||||
mkdir -p "$BUNDLE_CACHE"
|
||||
aws s3 cp "s3://${S3_BUCKET}/penpot-sha-${SHORT_SHA}.zip" "$ZIP.$$.tmp"
|
||||
aws s3 cp "s3://${S3_BUCKET}/penpot-${BUILD_KEY}.zip" "$ZIP.$$.tmp"
|
||||
mv "$ZIP.$$.tmp" "$ZIP"
|
||||
fi
|
||||
# Extract only the bundle this job needs.
|
||||
@ -274,7 +279,7 @@ jobs:
|
||||
sbom: true
|
||||
# Immutable tag only; branch tags are moved atomically for the
|
||||
# whole image set by the `promote` job.
|
||||
tags: ${{ secrets.DOCKER_REGISTRY }}/${{ matrix.image }}:sha-${{ needs.prepare.outputs.short_sha }}
|
||||
tags: ${{ secrets.DOCKER_REGISTRY }}/${{ matrix.image }}:${{ needs.prepare.outputs.build_key }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=registry,ref=${{ secrets.DOCKER_REGISTRY }}/${{ matrix.image }}:buildcache
|
||||
cache-to: type=registry,ref=${{ secrets.DOCKER_REGISTRY }}/${{ matrix.image }}:buildcache,mode=max
|
||||
@ -305,13 +310,13 @@ jobs:
|
||||
env:
|
||||
DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
|
||||
REF_SLUG: ${{ needs.prepare.outputs.ref_slug }}
|
||||
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||
BUILD_KEY: ${{ needs.prepare.outputs.build_key }}
|
||||
run: |
|
||||
set -e
|
||||
for image in $ALL_IMAGES; do
|
||||
docker buildx imagetools create \
|
||||
-t "${DOCKER_REGISTRY}/${image}:${REF_SLUG}" \
|
||||
"${DOCKER_REGISTRY}/${image}:sha-${SHORT_SHA}"
|
||||
"${DOCKER_REGISTRY}/${image}:${BUILD_KEY}"
|
||||
done
|
||||
|
||||
# The marker is written LAST: its presence certifies that all five
|
||||
@ -322,26 +327,27 @@ jobs:
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||
BUILD_KEY: ${{ needs.prepare.outputs.build_key }}
|
||||
run: |
|
||||
echo "$GITHUB_RUN_ID" | aws s3 cp - \
|
||||
"s3://${S3_BUCKET}/markers/images-sha-${SHORT_SHA}"
|
||||
"s3://${S3_BUCKET}/markers/images-${BUILD_KEY}"
|
||||
|
||||
- name: Write step summary
|
||||
env:
|
||||
REF_SLUG: ${{ needs.prepare.outputs.ref_slug }}
|
||||
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||
BUILD_KEY: ${{ needs.prepare.outputs.build_key }}
|
||||
BUNDLE_VERSION: ${{ needs.prepare.outputs.bundle_version }}
|
||||
COMMIT_TITLE: ${{ needs.prepare.outputs.commit_title }}
|
||||
run: |
|
||||
{
|
||||
echo "### ✅ Image set promoted"
|
||||
echo ""
|
||||
echo "- Version: \`${BUNDLE_VERSION}\` (\`git describe --tags --always\`)"
|
||||
echo "- Version: \`${BUNDLE_VERSION}\` (\`./manage.sh version\`)"
|
||||
echo "- Commit: [\`${SHORT_SHA}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/${SHORT_SHA}) — ${COMMIT_TITLE}"
|
||||
echo "- Built at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||
echo ""
|
||||
echo "All \`:${REF_SLUG}\` tags now point to \`sha-${SHORT_SHA}\`."
|
||||
echo "All \`:${REF_SLUG}\` tags now point to \`${BUILD_KEY}\`."
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
# ── 3b. Skip path: make sure THIS ref's tags point to the existing
|
||||
@ -374,30 +380,31 @@ jobs:
|
||||
env:
|
||||
DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
|
||||
REF_SLUG: ${{ needs.prepare.outputs.ref_slug }}
|
||||
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||
BUILD_KEY: ${{ needs.prepare.outputs.build_key }}
|
||||
run: |
|
||||
set -e
|
||||
for image in $ALL_IMAGES; do
|
||||
docker buildx imagetools create \
|
||||
-t "${DOCKER_REGISTRY}/${image}:${REF_SLUG}" \
|
||||
"${DOCKER_REGISTRY}/${image}:sha-${SHORT_SHA}"
|
||||
"${DOCKER_REGISTRY}/${image}:${BUILD_KEY}"
|
||||
done
|
||||
|
||||
- name: Write step summary
|
||||
env:
|
||||
REF_SLUG: ${{ needs.prepare.outputs.ref_slug }}
|
||||
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||
BUILD_KEY: ${{ needs.prepare.outputs.build_key }}
|
||||
BUNDLE_VERSION: ${{ needs.prepare.outputs.bundle_version }}
|
||||
COMMIT_TITLE: ${{ needs.prepare.outputs.commit_title }}
|
||||
run: |
|
||||
{
|
||||
echo "### ✅ Image set already built (branch tags ensured)"
|
||||
echo ""
|
||||
echo "- Version: \`${BUNDLE_VERSION}\` (\`git describe --tags --always\`)"
|
||||
echo "- Version: \`${BUNDLE_VERSION}\` (\`./manage.sh version\`)"
|
||||
echo "- Commit: [\`${SHORT_SHA}\`](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/${SHORT_SHA}) — ${COMMIT_TITLE}"
|
||||
echo "- Checked at: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||
echo ""
|
||||
echo "All \`:${REF_SLUG}\` tags now point to \`sha-${SHORT_SHA}\`."
|
||||
echo "All \`:${REF_SLUG}\` tags now point to \`${BUILD_KEY}\`."
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
# ── 4. Single failure notification for the whole workflow ─────────────
|
||||
|
||||
22
.github/workflows/build-renovate.yml
vendored
22
.github/workflows/build-renovate.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
short_sha: ${{ steps.bundle.outputs.short_sha }}
|
||||
bundle_key: ${{ steps.bundle.outputs.bundle_key }}
|
||||
images: ${{ steps.changes.outputs.images }}
|
||||
devenv: ${{ steps.changes.outputs.devenv }}
|
||||
imagemagick: ${{ steps.changes.outputs.imagemagick }}
|
||||
@ -60,7 +60,9 @@ jobs:
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Renovate only changes Dockerfiles and package manager versions, so
|
||||
# the most recent develop bundle is enough to build the images.
|
||||
# the most recent develop bundle is enough to build the images. The
|
||||
# version part of the key does not matter here: take any bundle of
|
||||
# the commit.
|
||||
- name: Find the latest develop bundle
|
||||
id: bundle
|
||||
env:
|
||||
@ -72,10 +74,12 @@ jobs:
|
||||
run: |
|
||||
for SHA in $(git rev-list --first-parent --max-count=50 "$BASE_SHA"); do
|
||||
SHORT_SHA=$(git rev-parse --short=12 "$SHA")
|
||||
if aws s3api head-object --bucket "$S3_BUCKET" \
|
||||
--key "penpot-sha-${SHORT_SHA}.zip" > /dev/null 2>&1; then
|
||||
echo "short_sha=$SHORT_SHA" >> "$GITHUB_OUTPUT"
|
||||
echo "Using bundle \`penpot-sha-${SHORT_SHA}.zip\`" >> "$GITHUB_STEP_SUMMARY"
|
||||
BUNDLE_KEY=$(aws s3api list-objects-v2 --bucket "$S3_BUCKET" \
|
||||
--prefix "penpot-sha-${SHORT_SHA}-" \
|
||||
--query 'Contents[0].Key' --output text)
|
||||
if [ -n "$BUNDLE_KEY" ] && [ "$BUNDLE_KEY" != "None" ]; then
|
||||
echo "bundle_key=$BUNDLE_KEY" >> "$GITHUB_OUTPUT"
|
||||
echo "Using bundle \`${BUNDLE_KEY}\`" >> "$GITHUB_STEP_SUMMARY"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
@ -135,13 +139,13 @@ jobs:
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
|
||||
S3_BUCKET: ${{ secrets.S3_BUCKET }}
|
||||
SHORT_SHA: ${{ needs.prepare.outputs.short_sha }}
|
||||
BUNDLE_KEY: ${{ needs.prepare.outputs.bundle_key }}
|
||||
IMAGE: ${{ matrix.image }}
|
||||
run: |
|
||||
ZIP="$BUNDLE_CACHE/penpot-sha-${SHORT_SHA}.zip"
|
||||
ZIP="$BUNDLE_CACHE/${BUNDLE_KEY}"
|
||||
if [ ! -f "$ZIP" ]; then
|
||||
mkdir -p "$BUNDLE_CACHE"
|
||||
aws s3 cp "s3://${S3_BUCKET}/penpot-sha-${SHORT_SHA}.zip" "$ZIP.$$.tmp"
|
||||
aws s3 cp "s3://${S3_BUCKET}/${BUNDLE_KEY}" "$ZIP.$$.tmp"
|
||||
mv "$ZIP.$$.tmp" "$ZIP"
|
||||
fi
|
||||
pushd docker/images
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user