Skip to content

fix: allow legacy release commit subject (#134) #580

fix: allow legacy release commit subject (#134)

fix: allow legacy release commit subject (#134) #580

Workflow file for this run

name: Binaries
on:
push:
branches:
- "**"
tags:
- "v*"
workflow_dispatch:
inputs:
tag:
description: "Optional release tag to build and attach assets for, for example v0.2.0"
required: false
type: string
channel:
description: "Override artifact channel for manual branch builds"
required: false
default: auto
type: choice
options:
- auto
- stable
- next
- beta
permissions:
contents: write
concurrency:
group: binaries-${{ github.ref }}-${{ github.event.inputs.tag || 'branch' }}
cancel-in-progress: false
env:
UV_VERSION: "0.11.8"
jobs:
build:
name: Build ${{ matrix.label }}
runs-on: ${{ matrix.os }}
outputs:
artifact_version: ${{ steps.release-target.outputs.artifact_version }}
branch: ${{ steps.release-target.outputs.branch }}
channel: ${{ steps.release-target.outputs.channel }}
is_stable: ${{ steps.release-target.outputs.is_stable }}
publish_to_release: ${{ steps.release-target.outputs.publish_to_release }}
release_ref: ${{ steps.release-target.outputs.release_ref }}
release_tag: ${{ steps.release-target.outputs.release_tag }}
short_sha: ${{ steps.release-target.outputs.short_sha }}
strategy:
fail-fast: false
matrix:
include:
- os: macos-14
label: macOS Apple Silicon
asset_suffix: macos-arm64
extension: ""
- os: windows-latest
label: Windows
asset_suffix: windows-x64
extension: ".exe"
steps:
- name: Resolve checkout ref
id: ref
shell: bash
env:
INPUT_TAG: ${{ github.event.inputs.tag }}
run: |
set -euo pipefail
release_ref=""
checkout_ref="${GITHUB_REF_NAME}"
ref_name="${GITHUB_REF_NAME}"
if [ -n "${INPUT_TAG}" ]; then
release_ref="${INPUT_TAG}"
checkout_ref="${INPUT_TAG}"
ref_name="${INPUT_TAG}"
elif [ "${GITHUB_REF_TYPE}" = "tag" ]; then
release_ref="${GITHUB_REF_NAME}"
fi
echo "checkout_ref=${checkout_ref}" >> "$GITHUB_OUTPUT"
echo "release_ref=${release_ref}" >> "$GITHUB_OUTPUT"
echo "ref_name=${ref_name}" >> "$GITHUB_OUTPUT"
- name: Check out repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ steps.ref.outputs.checkout_ref }}
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
with:
python-version-file: ".python-version"
- name: Set up uv
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true
- name: Install packaging dependencies
shell: bash
run: uv sync --locked --python "$(cat .python-version)" --all-extras --group dev
- name: Detect semantic tag candidate
id: semantic
shell: bash
env:
RELEASE_REF: ${{ steps.ref.outputs.release_ref }}
run: |
set -euo pipefail
tag="${RELEASE_REF}"
if [ -z "$tag" ]; then
set +e
tag="$(
uv run --locked --no-sync semantic-release --noop version --print-tag 2>/tmp/semantic-release-preview.log \
| grep -E '^v[0-9]+(\.[0-9]+){2}([-.+][0-9A-Za-z.-]+)?$' \
| tail -n 1
)"
set -e
fi
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
- name: Compute artifact version
id: plan
shell: bash
env:
RELEASE_REF: ${{ steps.ref.outputs.release_ref }}
REF_NAME: ${{ steps.ref.outputs.ref_name }}
SEMANTIC_TAG: ${{ steps.semantic.outputs.tag }}
CHANNEL: ${{ github.event.inputs.channel }}
run: |
set -euo pipefail
args=(
--semantic-tag "$SEMANTIC_TAG"
--release-ref "$RELEASE_REF"
--ref-name "$REF_NAME"
--format github
)
if [ -n "${CHANNEL}" ] && [ "${CHANNEL}" != "auto" ]; then
args+=(--channel "$CHANNEL")
fi
uv run --locked --no-sync python scripts/release/version_plan.py "${args[@]}"
- name: Resolve release target
id: release-target
shell: bash
env:
ARTIFACT_VERSION: ${{ steps.plan.outputs.artifact_version }}
BRANCH: ${{ steps.plan.outputs.branch }}
CHANNEL: ${{ steps.plan.outputs.channel }}
IS_STABLE: ${{ steps.plan.outputs.is_stable }}
RELEASE_REF: ${{ steps.plan.outputs.release_ref }}
SHORT_SHA: ${{ steps.plan.outputs.short_sha }}
ATTACH_TO_RELEASE: ${{ steps.plan.outputs.attach_to_release }}
run: |
set -euo pipefail
publish_to_release=false
if [ "${ATTACH_TO_RELEASE}" = "true" ]; then
publish_to_release=true
elif [ "${GITHUB_EVENT_NAME}" = "push" ] && [ "${GITHUB_REF_TYPE}" = "branch" ] && [ "${IS_STABLE}" != "true" ]; then
publish_to_release=true
fi
echo "artifact_version=${ARTIFACT_VERSION}" >> "$GITHUB_OUTPUT"
echo "branch=${BRANCH}" >> "$GITHUB_OUTPUT"
echo "channel=${CHANNEL}" >> "$GITHUB_OUTPUT"
echo "is_stable=${IS_STABLE}" >> "$GITHUB_OUTPUT"
echo "publish_to_release=${publish_to_release}" >> "$GITHUB_OUTPUT"
echo "release_ref=${RELEASE_REF}" >> "$GITHUB_OUTPUT"
echo "release_tag=${RELEASE_REF:-$ARTIFACT_VERSION}" >> "$GITHUB_OUTPUT"
echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
- name: Build CLI binary
shell: bash
run: uv run --locked --no-sync pyinstaller --clean --noconfirm agentic-trader.spec
- name: Smoke-test CLI binary
shell: bash
run: "./dist/agentic-trader${{ matrix.extension }} doctor --json"
- name: Package binary asset
id: package
shell: bash
run: |
set -euo pipefail
mkdir -p release
asset_base="agentic-trader-${{ matrix.asset_suffix }}-${{ steps.plan.outputs.artifact_version }}"
binary="dist/agentic-trader${{ matrix.extension }}"
staged="release/${asset_base}${{ matrix.extension }}"
cp "$binary" "$staged"
if [ "${{ runner.os }}" = "Windows" ]; then
archive="release/${asset_base}.zip"
7z a "$archive" "$staged"
else
archive="release/${asset_base}.tar.gz"
tar -czf "$archive" -C release "$(basename "$staged")"
fi
echo "archive=$archive" >> "$GITHUB_OUTPUT"
- name: Upload workflow artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ${{ matrix.asset_suffix }}-${{ steps.plan.outputs.artifact_version }}
path: ${{ steps.package.outputs.archive }}
if-no-files-found: error
retention-days: 30
publish-release:
name: Publish GitHub Release
runs-on: ubuntu-latest
needs: build
if: ${{ needs.build.outputs.publish_to_release == 'true' }}
permissions:
contents: write
steps:
- name: Check out repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ needs.build.outputs.release_ref || github.sha }}
fetch-depth: 0
- name: Download packaged binary artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: "*-${{ needs.build.outputs.artifact_version }}"
path: release-assets
merge-multiple: true
- name: Publish release with assets
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ needs.build.outputs.release_tag }}
RELEASE_REF: ${{ needs.build.outputs.release_ref }}
CHANNEL: ${{ needs.build.outputs.channel }}
BRANCH: ${{ needs.build.outputs.branch }}
SHORT_SHA: ${{ needs.build.outputs.short_sha }}
RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
shopt -s nullglob
assets=(release-assets/*)
if [ "${#assets[@]}" -eq 0 ]; then
echo "No release assets were downloaded." >&2
exit 1
fi
if gh release view "$TAG" >/dev/null 2>&1; then
asset_count="$(gh release view "$TAG" --json assets --jq '.assets | length')"
if [ "$asset_count" -gt 0 ]; then
echo "Release ${TAG} already exists with ${asset_count} asset(s); skipping publish."
exit 0
fi
echo "Release ${TAG} already exists without assets; immutable releases cannot be repaired automatically." >&2
exit 1
fi
notes="$(mktemp)"
if [ -n "${RELEASE_REF}" ]; then
python3 scripts/release/release_notes.py \
--version "$TAG" \
--output "$notes" \
--stable \
--run-url "$RUN_URL" \
--repo-url "https://github.com/${GITHUB_REPOSITORY}"
gh release create "$TAG" "${assets[@]}" \
--verify-tag \
--title "Agentic Trader ${TAG}" \
--notes-file "$notes"
else
python3 scripts/release/release_notes.py \
--version "$TAG" \
--output "$notes" \
--channel "$CHANNEL" \
--branch "$BRANCH" \
--short-sha "$SHORT_SHA" \
--run-url "$RUN_URL" \
--repo-url "https://github.com/${GITHUB_REPOSITORY}"
gh release create "$TAG" "${assets[@]}" \
--target "$GITHUB_SHA" \
--title "Agentic Trader ${TAG}" \
--notes-file "$notes" \
--prerelease \
--latest=false
fi