Skip to content

Release

Release #67

Workflow file for this run

name: Release
on:
workflow_dispatch:
push:
tags:
- "v*"
concurrency:
group: release-${{ github.ref_name }}
cancel-in-progress: false
permissions:
contents: write
packages: write
jobs:
agent:
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- goos: linux
goarch: amd64
runner: blacksmith-2vcpu-ubuntu-2404
- goos: linux
goarch: arm64
runner: blacksmith-2vcpu-ubuntu-2404-arm
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version-file: agent/go.mod
cache-dependency-path: agent/go.sum
- name: Build
working-directory: agent
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: 0
run: |
go build -ldflags="-s -w -X techulus/cloud-agent/internal/agent.Version=${{ github.ref_name }}" -o agent-${{ matrix.goos }}-${{ matrix.goarch }} ./cmd/agent
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: agent-${{ matrix.goos }}-${{ matrix.goarch }}
path: agent/agent-${{ matrix.goos }}-${{ matrix.goarch }}
retention-days: 1
cli:
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- goos: darwin
goarch: amd64
runner: blacksmith-2vcpu-ubuntu-2404
- goos: darwin
goarch: arm64
runner: blacksmith-2vcpu-ubuntu-2404-arm
- goos: linux
goarch: amd64
runner: blacksmith-2vcpu-ubuntu-2404
- goos: linux
goarch: arm64
runner: blacksmith-2vcpu-ubuntu-2404-arm
- goos: windows
goarch: amd64
runner: blacksmith-2vcpu-ubuntu-2404
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version-file: cli/go.mod
cache-dependency-path: cli/go.sum
- name: Build
working-directory: cli
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: 0
run: |
ext=""
if [ "${{ matrix.goos }}" = "windows" ]; then ext=".exe"; fi
binary="tc-${{ matrix.goos }}-${{ matrix.goarch }}$ext"
go build -ldflags="-s -w -X main.version=${{ github.ref_name }}" -o "$binary" ./cmd/tc
if [ "${{ matrix.goos }}" != "windows" ]; then
version="${GITHUB_REF_NAME#v}"
version="${version//\//-}"
package_dir=$(mktemp -d)
cp "$binary" "$package_dir/tc"
tar -czf "tc_${version}_${{ matrix.goos }}_${{ matrix.goarch }}.tar.gz" -C "$package_dir" tc
rm -rf "$package_dir"
fi
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: tc-${{ matrix.goos }}-${{ matrix.goarch }}
path: |
cli/tc-${{ matrix.goos }}-${{ matrix.goarch }}*
cli/tc_*_${{ matrix.goos }}_${{ matrix.goarch }}.tar.gz
retention-days: 1
release:
needs: [agent, cli, containers]
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download agent artifacts
uses: actions/download-artifact@v8
with:
path: binaries
pattern: agent-*
merge-multiple: true
- name: Download CLI artifacts
uses: actions/download-artifact@v8
with:
path: binaries
pattern: tc-*
merge-multiple: true
- name: Download image digests
uses: actions/download-artifact@v8
with:
path: image-digests
pattern: release-digest-*
merge-multiple: true
- name: Generate SHA256 checksums
run: |
cd binaries
sha256sum agent-* tc-* tc_* > checksums.txt
- name: Generate release manifest
env:
RELEASE_VERSION: ${{ github.ref_name }}
RELEASE_COMMIT: ${{ github.sha }}
run: |
sha256_pattern='^[0-9a-f]{64}$'
digest_pattern='^sha256:[0-9a-f]{64}$'
agent_amd64=$(sha256sum binaries/agent-linux-amd64 | awk '{print $1}')
agent_arm64=$(sha256sum binaries/agent-linux-arm64 | awk '{print $1}')
compose_production=$(sha256sum deployment/compose.production.yml | awk '{print $1}')
compose_postgres=$(sha256sum deployment/compose.postgres.yml | awk '{print $1}')
web_digest=$(cat image-digests/web)
registry_digest=$(cat image-digests/registry)
updater_digest=$(cat image-digests/updater)
for checksum in "$agent_amd64" "$agent_arm64" "$compose_production" "$compose_postgres"; do
[[ "$checksum" =~ $sha256_pattern ]]
done
for digest in "$web_digest" "$registry_digest" "$updater_digest"; do
[[ "$digest" =~ $digest_pattern ]]
done
[[ "$RELEASE_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]
[[ "$RELEASE_COMMIT" =~ ^[0-9a-f]{40}$ ]]
jq -n \
--arg version "$RELEASE_VERSION" \
--arg commit "$RELEASE_COMMIT" \
--arg agent_amd64 "$agent_amd64" \
--arg agent_arm64 "$agent_arm64" \
--arg compose_production "$compose_production" \
--arg compose_postgres "$compose_postgres" \
--arg web_digest "$web_digest" \
--arg registry_digest "$registry_digest" \
--arg updater_digest "$updater_digest" \
'{
version: $version,
commit: $commit,
binaries: {
"agent-linux-amd64": $agent_amd64,
"agent-linux-arm64": $agent_arm64
},
composeFiles: {
"deployment/compose.production.yml": $compose_production,
"deployment/compose.postgres.yml": $compose_postgres
},
images: {
web: $web_digest,
registry: $registry_digest,
updater: $updater_digest
}
}' > binaries/release-manifest.json
- name: Create GitHub release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "${{ github.ref_name }}" \
--repo ${{ github.repository }} \
--title "${{ github.ref_name }}" \
--generate-notes \
binaries/agent-* binaries/tc-* binaries/tc_* binaries/checksums.txt binaries/release-manifest.json
homebrew:
needs: release
if: startsWith(github.ref, 'refs/tags/v')
runs-on: blacksmith-2vcpu-ubuntu-2404
concurrency:
group: homebrew-tap
cancel-in-progress: false
steps:
- name: Download CLI artifacts
uses: actions/download-artifact@v8
with:
path: binaries
pattern: tc-*
merge-multiple: true
- name: Checkout Homebrew tap
uses: actions/checkout@v6
with:
repository: techulus/homebrew-tap
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
path: homebrew-tap
- name: Update Homebrew formula
run: |
version="${GITHUB_REF_NAME#v}"
darwin_amd64_sha=$(sha256sum "binaries/tc_${version}_darwin_amd64.tar.gz" | awk '{print $1}')
darwin_arm64_sha=$(sha256sum "binaries/tc_${version}_darwin_arm64.tar.gz" | awk '{print $1}')
linux_amd64_sha=$(sha256sum "binaries/tc_${version}_linux_amd64.tar.gz" | awk '{print $1}')
linux_arm64_sha=$(sha256sum "binaries/tc_${version}_linux_arm64.tar.gz" | awk '{print $1}')
cat > homebrew-tap/Formula/tc.rb <<EOF
# typed: false
# frozen_string_literal: true
# This file was generated by the Techulus Cloud release workflow. DO NOT EDIT.
class Tc < Formula
desc "Techulus Cloud CLI"
homepage "https://github.com/${GITHUB_REPOSITORY}"
version "${version}"
license "AGPL-3.0-only"
on_macos do
if Hardware::CPU.intel?
url "https://github.com/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/tc_${version}_darwin_amd64.tar.gz"
sha256 "${darwin_amd64_sha}"
define_method(:install) do
bin.install "tc"
end
end
if Hardware::CPU.arm?
url "https://github.com/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/tc_${version}_darwin_arm64.tar.gz"
sha256 "${darwin_arm64_sha}"
define_method(:install) do
bin.install "tc"
end
end
end
on_linux do
if Hardware::CPU.intel? && Hardware::CPU.is_64_bit?
url "https://github.com/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/tc_${version}_linux_amd64.tar.gz"
sha256 "${linux_amd64_sha}"
define_method(:install) do
bin.install "tc"
end
end
if Hardware::CPU.arm? && Hardware::CPU.is_64_bit?
url "https://github.com/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/tc_${version}_linux_arm64.tar.gz"
sha256 "${linux_arm64_sha}"
define_method(:install) do
bin.install "tc"
end
end
end
test do
assert_match version.to_s, shell_output("#{bin}/tc version")
end
end
EOF
cd homebrew-tap
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Formula/tc.rb
if git diff --cached --quiet; then
echo "Homebrew formula is already up to date."
exit 0
fi
git commit -m "Brew formula update for tc version ${GITHUB_REF_NAME}"
for attempt in 1 2 3; do
if git push; then
exit 0
fi
if [ "$attempt" -eq 3 ]; then
echo "Failed to push the Homebrew formula after $attempt attempts." >&2
exit 1
fi
git pull --rebase origin main
done
container:
name: Build ${{ matrix.image }} (${{ matrix.arch }})
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- image: web
context: web
arch: amd64
platform: linux/amd64
runner: blacksmith-2vcpu-ubuntu-2404
- image: web
context: web
arch: arm64
platform: linux/arm64
runner: blacksmith-2vcpu-ubuntu-2404-arm
- image: registry
context: registry
arch: amd64
platform: linux/amd64
runner: blacksmith-2vcpu-ubuntu-2404
- image: registry
context: registry
arch: arm64
platform: linux/arm64
runner: blacksmith-2vcpu-ubuntu-2404-arm
- image: updater
context: deployment/updater
arch: amd64
platform: linux/amd64
runner: blacksmith-2vcpu-ubuntu-2404
- image: updater
context: deployment/updater
arch: arm64
platform: linux/arm64
runner: blacksmith-2vcpu-ubuntu-2404-arm
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Docker builder
uses: useblacksmith/setup-docker-builder@v1
- name: Login to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
id: build
uses: useblacksmith/build-push-action@v2
with:
context: ${{ matrix.context }}
tags: ghcr.io/${{ github.repository }}/${{ matrix.image }}
platforms: ${{ matrix.platform }}
build-args: ${{ matrix.image == 'web' && format('APP_VERSION={0}', github.ref_name) || '' }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p /tmp/digests
touch "/tmp/digests/${DIGEST#sha256:}"
env:
DIGEST: ${{ steps.build.outputs.digest }}
- name: Upload digest
uses: actions/upload-artifact@v7
with:
name: digest-${{ matrix.image }}-${{ matrix.arch }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
containers:
name: Publish ${{ matrix.image }} manifest
needs: container
runs-on: blacksmith-2vcpu-ubuntu-2404
strategy:
matrix:
image: [web, registry, updater]
steps:
- name: Download digests
uses: actions/download-artifact@v8
with:
path: /tmp/digests
pattern: digest-${{ matrix.image }}-*
merge-multiple: true
- name: Login to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push multi-platform manifest
working-directory: /tmp/digests
run: |
image="ghcr.io/${{ github.repository }}/${{ matrix.image }}"
docker buildx imagetools create \
--tag "$image:${{ github.ref_name }}" \
--tag "$image:tip" \
$(printf "$image@sha256:%s " *)
- name: Export multi-platform manifest digest
run: |
image="ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ github.ref_name }}"
mkdir -p /tmp/release-digests
docker buildx imagetools inspect "$image" --format '{{json .Manifest}}' \
| jq -er '.digest | select(test("^sha256:[0-9a-f]{64}$"))' \
> "/tmp/release-digests/${{ matrix.image }}"
- name: Upload multi-platform manifest digest
uses: actions/upload-artifact@v7
with:
name: release-digest-${{ matrix.image }}
path: /tmp/release-digests/${{ matrix.image }}
if-no-files-found: error
retention-days: 1