189 lines
6.3 KiB
YAML
189 lines
6.3 KiB
YAML
name: Distribute Release Assets
|
|
|
|
# Triggered after a GitHub Release is officially published.
|
|
# Mirrors installer assets to the configured distribution endpoint for external download.
|
|
#
|
|
# Why `published` (not `released`)?
|
|
# - `released` is supposed to fire when a non-prerelease release is published,
|
|
# but GitHub sometimes only emits `published` (not `released`) when a pre-existing
|
|
# draft is publicly released, causing the workflow to be silently skipped.
|
|
# - `published` reliably fires on every draft → public transition, including
|
|
# prereleases. The `if` guard on the job filters out prereleases explicitly.
|
|
#
|
|
# All credentials / identifiers are read from repository secrets:
|
|
# - AWS_REGION
|
|
# - AWS_ROLE_ARN
|
|
# - AWS_S3_BUCKET
|
|
# Do NOT hardcode these values in this file.
|
|
|
|
on:
|
|
release:
|
|
types: [published]
|
|
# Manual trigger for smoke testing or for retrying a missed release:
|
|
# pick any existing release tag to re-run the distribution against.
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: 'Existing release tag to redistribute (e.g. v1.9.21)'
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
id-token: write # required for OIDC token
|
|
contents: read
|
|
|
|
env:
|
|
S3_RELEASE_PREFIX: releases
|
|
|
|
jobs:
|
|
distribute:
|
|
name: Distribute release assets
|
|
runs-on: ubuntu-latest
|
|
# Skip prereleases: manual dispatch always runs, automatic event runs only when not a prerelease.
|
|
if: github.event_name == 'workflow_dispatch' || github.event.release.prerelease == false
|
|
steps:
|
|
- name: Extract version from tag
|
|
id: version
|
|
env:
|
|
EVENT_TAG: ${{ github.event.release.tag_name }}
|
|
INPUT_TAG: ${{ github.event.inputs.tag }}
|
|
run: |
|
|
TAG="${EVENT_TAG:-$INPUT_TAG}"
|
|
if [ -z "$TAG" ]; then
|
|
echo "::error::No tag provided (event did not supply one)."
|
|
exit 1
|
|
fi
|
|
VERSION="${TAG#v}"
|
|
echo "tag=$TAG" >> $GITHUB_OUTPUT
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "Tag: $TAG / Version: $VERSION"
|
|
|
|
- name: Configure AWS credentials (OIDC)
|
|
uses: aws-actions/configure-aws-credentials@v4
|
|
with:
|
|
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
|
|
aws-region: ${{ secrets.AWS_REGION }}
|
|
|
|
- name: Guard against same-version overwrite
|
|
env:
|
|
S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
|
VERSION: ${{ steps.version.outputs.version }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
PREFIX="${S3_RELEASE_PREFIX}/${VERSION}/"
|
|
DEST="s3://${S3_BUCKET}/${PREFIX}"
|
|
COUNT=$(aws s3api list-objects-v2 \
|
|
--bucket "$S3_BUCKET" \
|
|
--prefix "$PREFIX" \
|
|
--no-paginate \
|
|
--query 'KeyCount' \
|
|
--output text)
|
|
if [ "$COUNT" -gt 0 ]; then
|
|
echo "::error::Version directory already contains $COUNT file(s). Refusing to overwrite."
|
|
echo "::error::Same-version re-publish is not allowed (downstream caches would serve stale files). Release a new version instead."
|
|
aws s3 ls "$DEST"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Download release assets from GitHub
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
mkdir -p dist
|
|
gh release download "${{ steps.version.outputs.tag }}" \
|
|
--repo "${{ github.repository }}" \
|
|
--dir dist \
|
|
--pattern "*.dmg" \
|
|
--pattern "*.exe" \
|
|
--pattern "*.msi" \
|
|
--pattern "*.deb" \
|
|
--pattern "*.zip" \
|
|
--pattern "latest*.yml"
|
|
echo "Downloaded files:"
|
|
ls -la dist
|
|
|
|
- name: Validate updater metadata
|
|
id: metadata
|
|
env:
|
|
VERSION: ${{ steps.version.outputs.version }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
metadata_files=(
|
|
dist/latest.yml
|
|
dist/latest-win-arm64.yml
|
|
dist/latest-mac.yml
|
|
dist/latest-arm64-mac.yml
|
|
dist/latest-linux.yml
|
|
dist/latest-linux-arm64.yml
|
|
)
|
|
|
|
for file in "${metadata_files[@]}"; do
|
|
if [ ! -f "$file" ]; then
|
|
echo "::error::Missing updater metadata file: $file."
|
|
exit 1
|
|
fi
|
|
|
|
metadata_version=$(grep -E "^version:" "$file" | head -n 1 | sed -E "s/^version:[[:space:]]*['\"]?([^'\"]+).*/\1/")
|
|
if [ "$metadata_version" != "$VERSION" ]; then
|
|
echo "::error::$file version is $metadata_version, expected $VERSION."
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
{
|
|
echo "files<<EOF"
|
|
for file in "${metadata_files[@]}"; do
|
|
basename "$file"
|
|
done
|
|
echo "EOF"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Upload assets
|
|
env:
|
|
S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
|
VERSION: ${{ steps.version.outputs.version }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
aws s3 cp dist/ "s3://${S3_BUCKET}/${S3_RELEASE_PREFIX}/${VERSION}/" \
|
|
--recursive
|
|
echo "Uploaded release ${VERSION}"
|
|
|
|
- name: Upload updater metadata
|
|
env:
|
|
S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
aws s3 cp dist/ "s3://${S3_BUCKET}/${S3_RELEASE_PREFIX}/" \
|
|
--recursive \
|
|
--exclude "*" \
|
|
--include "latest*.yml" \
|
|
--content-type "text/yaml" \
|
|
--cache-control "public, max-age=60"
|
|
echo "Uploaded updater metadata"
|
|
|
|
- name: Summary
|
|
env:
|
|
VERSION: ${{ steps.version.outputs.version }}
|
|
TAG: ${{ steps.version.outputs.tag }}
|
|
FILES: ${{ steps.metadata.outputs.files }}
|
|
run: |
|
|
{
|
|
echo "### Release assets distributed"
|
|
echo ""
|
|
echo "- Tag: \`${TAG}\`"
|
|
echo "- Version: \`${VERSION}\`"
|
|
echo "- Asset prefix: \`${S3_RELEASE_PREFIX}/${VERSION}/\`"
|
|
echo "- Metadata prefix: \`${S3_RELEASE_PREFIX}/\`"
|
|
echo ""
|
|
echo "Uploaded metadata:"
|
|
while IFS= read -r file; do
|
|
[ -n "$file" ] && echo "- \`${S3_RELEASE_PREFIX}/$file\`"
|
|
done <<< "$FILES"
|
|
} >> $GITHUB_STEP_SUMMARY
|