Skip to content

Release CLI

Release CLI #3

Workflow file for this run

name: Release CLI
on:
workflow_dispatch:
inputs:
release_type:
description: 'Release type'
required: true
default: 'auto'
type: choice
options:
- auto
- patch
- minor
- major
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
env:
OPENTAINT_DEPENDENCIES_VERSION: 2026.03.19.adeb616
jobs:
release:
runs-on: ubuntu-latest
container: ghcr.io/catthehacker/ubuntu:act-latest
defaults:
run:
shell: bash
permissions:
contents: write
packages: write
steps:
-
name: Install GitHub CLI
run: |
(type -p wget >/dev/null || apt-get install -yqq wget) \
&& mkdir -p -m 755 /etc/apt/keyrings \
&& out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \
&& cat $out | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& apt-get update \
&& apt-get install -yqq gh
-
name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
-
name: Manual release
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_type != 'auto' }}
id: manual_release
uses: ./.github/actions/manual-version-bump
with:
tag-prefix: 'v'
bump-type: ${{ github.event.inputs.release_type }}
-
name: Write manual release version
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_type != 'auto' }}
run: |
echo "${{ steps.manual_release.outputs.new-version }}" > cli/release_version.txt
-
name: Create release tag (manual)
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_type != 'auto' }}
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag "v${{ steps.manual_release.outputs.new-version }}"
git push origin "v${{ steps.manual_release.outputs.new-version }}"
-
name: Force-update tags
run: git fetch --tags --force
-
name: 'Release (auto)'
if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.release_type == 'auto' }}
id: semantic_release
uses: cycjimmy/semantic-release-action@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
semantic_version: 23.0.0
working_directory: cli
extra_plugins: |
@semantic-release/commit-analyzer@11.1.0
@semantic-release/exec@6.0.3
conventional-changelog-conventionalcommits@7.0.2
-
name: 'Get release_version and pass to next job'
id: release_version
working-directory: cli
run: |
if [ -f release_version.txt ]; then
echo "status=succeeded" >>"$GITHUB_OUTPUT"
echo "RELEASE_VERSION=$(cat release_version.txt)" >> $GITHUB_OUTPUT
else
echo "status=skipped" >>"$GITHUB_OUTPUT"
fi
rm -f release_version.txt
-
name: Login to GitHub Container Registry
if: ${{ steps.release_version.outputs.status == 'succeeded' }}
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.SEQRA_GITHUB_ACTOR }}
password: ${{ secrets.SEQRA_GITHUB_TOKEN }}
-
name: Set up QEMU
if: ${{ steps.release_version.outputs.status == 'succeeded' }}
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
if: ${{ steps.release_version.outputs.status == 'succeeded' }}
uses: docker/setup-buildx-action@v3
-
name: Set up Go
if: ${{ steps.release_version.outputs.status == 'succeeded' }}
uses: actions/setup-go@v5
with:
go-version: '>=1.25.0'
-
name: Docker meta
id: meta
if: ${{ steps.release_version.outputs.status == 'succeeded' }}
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ github.repository }}
tags: |
type=semver,pattern={{version}},value=${{ steps.release_version.outputs.RELEASE_VERSION }}
-
name: Download bundled artifacts
if: ${{ steps.release_version.outputs.status == 'succeeded' }}
working-directory: cli
env:
GH_TOKEN: ${{ secrets.SEQRA_GITHUB_TOKEN }}
run: |
ANALYZER_TAG=$(grep '^analyzer:' internal/globals/versions.yaml | awk '{print $2}' | tr -d '"')
AUTOBUILDER_TAG=$(grep '^autobuilder:' internal/globals/versions.yaml | awk '{print $2}' | tr -d '"')
RULES_TAG=$(grep '^rules:' internal/globals/versions.yaml | awk '{print $2}' | tr -d '"')
mkdir -p lib
echo "Downloading analyzer ${ANALYZER_TAG}..."
gh release download "$ANALYZER_TAG" \
--repo ${{ github.repository }} \
--pattern "opentaint-project-analyzer.jar" \
--dir lib
echo "Downloading autobuilder ${AUTOBUILDER_TAG}..."
gh release download "$AUTOBUILDER_TAG" \
--repo ${{ github.repository }} \
--pattern "opentaint-project-auto-builder.jar" \
--dir lib
echo "Downloading rules ${RULES_TAG}..."
gh release download "$RULES_TAG" \
--repo ${{ github.repository }} \
--pattern "opentaint-rules.tar.gz" \
--dir /tmp
mkdir -p lib/rules
tar -xzf /tmp/opentaint-rules.tar.gz -C lib/rules
echo "Bundled artifacts:"
ls -la lib/
-
name: Run GoReleaser
if: ${{ steps.release_version.outputs.status == 'succeeded' }}
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: '~> v2'
args: release --clean
workdir: cli
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_CURRENT_TAG: v${{ steps.release_version.outputs.RELEASE_VERSION }}
HOMEBREW_TAP_OWNER: ${{ github.repository_owner }}
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
-
name: Bundle JREs into release archives
if: ${{ steps.release_version.outputs.status == 'succeeded' }}
working-directory: cli
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
bash scripts/bundle-jre.sh dist
RELEASE_TAG="v${{ steps.release_version.outputs.RELEASE_VERSION }}"
for archive in dist/opentaint-full_*.tar.gz dist/opentaint-full_*.zip; do
[ -f "$archive" ] || continue
echo "Re-uploading $archive..."
gh release upload "$RELEASE_TAG" "$archive" --clobber
done
# Regenerate checksums covering all three variants
cd dist
sha256sum opentaint-cli_*.{tar.gz,zip} opentaint_*.{tar.gz,zip} opentaint-full_*.{tar.gz,zip} 2>/dev/null > checksums.txt
cd ..
if [ -s dist/checksums.txt ]; then
gh release upload "$RELEASE_TAG" dist/checksums.txt --clobber
else
echo "No checksums to upload"
fi
-
name: Check Homebrew token availability
if: ${{ steps.release_version.outputs.status == 'succeeded' }}
id: check_homebrew
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
if [ -n "$HOMEBREW_TAP_TOKEN" ]; then
echo "available=true" >> "$GITHUB_OUTPUT"
else
echo "available=false" >> "$GITHUB_OUTPUT"
fi
-
name: Update package manager manifests
if: ${{ steps.check_homebrew.outputs.available == 'true' && steps.release_version.outputs.status == 'succeeded' && (steps.semantic_release.outputs.new_release_channel == '' || steps.manual_release.outputs.new-version != '') }}
working-directory: cli
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
HOMEBREW_TAP_OWNER: ${{ github.repository_owner }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
run: |
RELEASE_TAG="v${{ steps.release_version.outputs.RELEASE_VERSION }}"
# Import GPG key for signed commits
echo "$GPG_PRIVATE_KEY" | gpg --batch --import
# Fix SHA256 values in GoReleaser-generated cask file
CASK_FILE="dist/homebrew/Casks/opentaint.rb"
for f in dist/opentaint-full_*.tar.gz dist/opentaint-full_*.zip; do
[ -f "$f" ] || continue
name="$(basename "$f")"
sha="$(sha256sum "$f" | awk '{print $1}')"
escaped_name="${name//./\\.}"
sed -i "/${escaped_name}/{ n; s/sha256 \"[a-f0-9]\{64\}\"/sha256 \"${sha}\"/; }" "$CASK_FILE"
done
# Push updated cask to Homebrew tap
git clone "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/${{ github.repository_owner }}/homebrew-tap.git" /tmp/homebrew-tap
mkdir -p /tmp/homebrew-tap/Casks
cp "$CASK_FILE" /tmp/homebrew-tap/Casks/opentaint.rb
cd /tmp/homebrew-tap
git config user.name "seqradev"
git config user.email "seqradev@gmail.com"
git config user.signingkey "6000887370B8C08E"
git config commit.gpgsign true
git add -A
if ! git diff --cached --quiet; then
git commit -m "Update opentaint to ${RELEASE_TAG}"
git push
fi
cd -
-
name: Build and push Docker image
if: ${{ steps.release_version.outputs.status == 'succeeded' && (steps.semantic_release.outputs.new_release_channel == '' || steps.manual_release.outputs.new-version != '') }}
uses: docker/build-push-action@v6
with:
context: cli
build-contexts: |
opentaint-dependencies:latest=docker-image://ghcr.io/${{ github.repository_owner }}/opentaint/infra:${{ env.OPENTAINT_DEPENDENCIES_VERSION }}
platforms: linux/amd64, linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
secrets: |
github_token=${{ secrets.SEQRA_GITHUB_TOKEN }}
build-args: |
OPENTAINT_OWNER=${{ github.repository_owner }}
OPENTAINT_BUILD_FLAGS=-s -w -X github.com/${{ github.repository_owner }}/opentaint/internal/version.Version=${{ steps.release_version.outputs.RELEASE_VERSION }}
-
name: Update floating version tags
if: ${{ steps.release_version.outputs.status == 'succeeded' }}
uses: ./.github/actions/update-floating-tags
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
release-version: ${{ steps.release_version.outputs.RELEASE_VERSION }}
tag-prefix: ''
component-name: 'CLI'
copy-assets-from: v${{ steps.release_version.outputs.RELEASE_VERSION }}
outputs:
release_version: ${{ steps.release_version.outputs.RELEASE_VERSION }}