Skip to content

Release 1.5.0

Release 1.5.0 #116

Workflow file for this run

name: Release
on:
push:
tags:
- "*.*.*"
workflow_dispatch:
inputs:
tag:
description: "Release tag (example: 1.2.3 or 1.2.3-rc.1)"
required: true
type: string
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.resolve_version.outputs.version }}
is_prerelease: ${{ steps.resolve_version.outputs.is_prerelease }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
cache-dependency-path: go.sum
- name: Resolve release version
id: resolve_version
run: |
if [ "${{ github.event_name }}" = "push" ]; then
VERSION="${GITHUB_REF#refs/tags/}"
else
VERSION="${{ github.event.inputs.tag }}"
fi
if [ -z "${VERSION}" ]; then
echo "Error: VERSION is empty"
exit 1
fi
if [[ "${VERSION}" == v* ]]; then
echo "Error: tags must not use 'v' prefix (got: ${VERSION})"
exit 1
fi
if ! [[ "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
echo "Error: VERSION must be SemVer-like (got: ${VERSION})"
exit 1
fi
BASE_VERSION="${VERSION%%+*}"
if [[ "${BASE_VERSION}" == *-* ]]; then
IS_PRERELEASE=true
else
IS_PRERELEASE=false
fi
echo "VERSION=${VERSION}" >> "${GITHUB_ENV}"
echo "VERSION_SEMVER=${VERSION}" >> "${GITHUB_ENV}"
echo "IS_PRERELEASE=${IS_PRERELEASE}" >> "${GITHUB_ENV}"
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
echo "is_prerelease=${IS_PRERELEASE}" >> "${GITHUB_OUTPUT}"
- name: Download dependencies
run: go mod download
- name: Verify dependencies
run: go mod verify
- name: Sync VERSION file with tag
run: echo "${{ env.VERSION_SEMVER }}" > VERSION
- name: Run tests
run: make test-ci
- name: Run linter
uses: golangci/golangci-lint-action@v9
with:
version: v2.10.1
args: --timeout=5m
- name: Build release artifacts
env:
VERSION: ${{ env.VERSION }}
run: |
make VERSION="${VERSION}" release
ls -la dist/
- name: Optional release signing and notarization
env:
RELEASE_SIGN: ${{ vars.RELEASE_SIGN }}
RELEASE_NOTARIZE: ${{ vars.RELEASE_NOTARIZE }}
SIGN_IDENTITY: ${{ secrets.APPLE_SIGN_IDENTITY }}
run: |
make release-sign
make notarize-release
- name: Create macOS Universal Binary
run: |
sudo apt-get update && sudo apt-get install -y llvm
if ! command -v llvm-lipo &> /dev/null; then
LIPO_PATH=$(find /usr/bin -name "llvm-lipo-*" | head -n 1)
if [ -n "$LIPO_PATH" ]; then
sudo ln -s "$LIPO_PATH" /usr/bin/llvm-lipo
else
echo "Error: llvm-lipo not found"
exit 1
fi
fi
llvm-lipo -create -output dist/construct dist/construct-darwin-amd64 dist/construct-darwin-arm64
file dist/construct
tar -czf dist/construct-cli-macos-universal.tar.gz -C dist construct
rm dist/construct
- name: Prepare Linux Artifacts
run: |
mkdir -p dist/linux-amd64 dist/linux-arm64
cp dist/construct-linux-amd64 dist/linux-amd64/construct
cp dist/construct-linux-arm64 dist/linux-arm64/construct
tar -czf dist/construct-cli-linux-amd64.tar.gz -C dist/linux-amd64 construct
tar -czf dist/construct-cli-linux-arm64.tar.gz -C dist/linux-arm64 construct
rm -rf dist/linux-amd64 dist/linux-arm64
- name: Generate checksums
env:
VERSION: ${{ env.VERSION }}
run: |
cd dist
sha256sum \
"construct-darwin-arm64-${VERSION}.tar.gz" \
"construct-darwin-amd64-${VERSION}.tar.gz" \
"construct-linux-amd64-${VERSION}.tar.gz" \
"construct-linux-arm64-${VERSION}.tar.gz" \
"construct-cli-macos-universal.tar.gz" \
"construct-cli-linux-amd64.tar.gz" \
"construct-cli-linux-arm64.tar.gz" \
> checksums.txt
- name: Verify release outputs
env:
VERSION: ${{ env.VERSION }}
run: |
set -e
expected_files=(
"dist/construct-darwin-arm64-${VERSION}.tar.gz"
"dist/construct-darwin-amd64-${VERSION}.tar.gz"
"dist/construct-linux-amd64-${VERSION}.tar.gz"
"dist/construct-linux-arm64-${VERSION}.tar.gz"
"dist/construct-cli-macos-universal.tar.gz"
"dist/construct-cli-linux-amd64.tar.gz"
"dist/construct-cli-linux-arm64.tar.gz"
"dist/checksums.txt"
)
for file in "${expected_files[@]}"; do
if [ -f "${file}" ]; then
size=$(stat -c%s "${file}")
echo "OK ${file} (size: ${size} bytes)"
else
echo "Missing expected artifact: ${file}"
exit 1
fi
done
- name: Extract release notes from CHANGELOG.md
env:
VERSION_SEMVER: ${{ env.VERSION_SEMVER }}
run: |
set -euo pipefail
changelog_file="CHANGELOG.md"
notes_file="release_notes.md"
start_marker="<!-- RELEASE:START ${VERSION_SEMVER} -->"
end_marker="<!-- RELEASE:END ${VERSION_SEMVER} -->"
if [ -f "${changelog_file}" ]; then
awk -v start="${start_marker}" -v end="${end_marker}" '
$0 == start { in_section = 1; next }
$0 == end { in_section = 0; exit }
in_section { print }
' "${changelog_file}" > "${notes_file}"
else
: > "${notes_file}"
fi
if ! grep -q '[^[:space:]]' "${notes_file}"; then
prev_tag=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || true)
if [ -n "${prev_tag}" ]; then
echo "**Full changelog:** ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/compare/${prev_tag}...${VERSION_SEMVER}" > "${notes_file}"
else
echo "**Full changelog:** ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${VERSION_SEMVER}" > "${notes_file}"
fi
fi
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ env.VERSION }}
name: The Construct CLI ${{ env.VERSION }}
body_path: release_notes.md
draft: false
prerelease: ${{ steps.resolve_version.outputs.is_prerelease == 'true' }}
files: |
dist/construct-darwin-arm64-${{ env.VERSION }}.tar.gz
dist/construct-darwin-amd64-${{ env.VERSION }}.tar.gz
dist/construct-linux-amd64-${{ env.VERSION }}.tar.gz
dist/construct-linux-arm64-${{ env.VERSION }}.tar.gz
dist/construct-cli-macos-universal.tar.gz
dist/construct-cli-linux-amd64.tar.gz
dist/construct-cli-linux-arm64.tar.gz
dist/checksums.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update release marker file
env:
VERSION: ${{ env.VERSION }}
IS_PRERELEASE: ${{ env.IS_PRERELEASE }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if [ "$IS_PRERELEASE" = "true" ]; then
echo "$VERSION" > VERSION-BETA
git add VERSION-BETA
git commit -m "chore: update VERSION-BETA to $VERSION" || echo "No changes to commit"
else
echo "$VERSION" > VERSION
git add VERSION
git commit -m "chore: update VERSION to $VERSION" || echo "No changes to commit"
fi
git push origin HEAD:main || echo "Failed to push release marker update"
update-tap:
needs: release
if: ${{ needs.release.outputs.is_prerelease != 'true' }}
runs-on: ubuntu-latest
steps:
- name: Trigger Homebrew Tap Update
uses: actions/github-script@v8
with:
github-token: ${{ secrets.TAP_GITHUB_TOKEN }}
script: |
await github.rest.actions.createWorkflowDispatch({
owner: 'EstebanForge',
repo: 'homebrew-tap',
workflow_id: 'update-formula.yml',
ref: 'main',
inputs: {
formula: 'construct-cli',
tag: '${{ needs.release.outputs.version }}',
repository: '${{ github.repository }}'
}
})