Skip to content

v0.0.22

v0.0.22 #31

Workflow file for this run

name: Release
on:
release:
types: [published]
workflow_dispatch:
inputs:
release_tag:
description: "Existing release tag to rebuild and publish, for example v0.0.17"
required: false
type: string
# Skip beta/prerelease tags — handled by release-beta.yml
permissions:
contents: write
id-token: write
attestations: write
env:
CARGO_TERM_COLOR: always
concurrency:
group: release-${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref }}
cancel-in-progress: true
jobs:
build:
name: Build ${{ matrix.name }}
if: github.event_name == 'workflow_dispatch' || !github.event.release.prerelease
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- name: aarch64-macos
runner: macos-14
target: aarch64-apple-darwin
bottle_tag: arm64_sonoma
archive: tar.gz
- name: x86_64-linux
runner: ubuntu-22.04
target: x86_64-unknown-linux-gnu
bottle_tag: x86_64_linux
archive: tar.gz
- name: aarch64-linux
runner: ubuntu-22.04-arm
target: aarch64-unknown-linux-gnu
archive: tar.gz
- name: x86_64-windows
runner: windows-latest
target: x86_64-pc-windows-msvc
archive: zip
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref }}
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: dashboard/package-lock.json
- name: Build dashboard assets
working-directory: dashboard
run: |
npm ci
npm run build
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Use lld-link
if: runner.os == 'Windows'
shell: pwsh
run: |
where.exe lld-link
lld-link --version
"RUSTFLAGS=-C linker=lld-link.exe" >> $env:GITHUB_ENV
- name: Cache Rust build
uses: Swatinem/rust-cache@v2
with:
shared-key: release-${{ matrix.target }}
cache-on-failure: true
- name: Build release binary
run: cargo build --release --target ${{ matrix.target }}
- name: Get version
id: version
shell: bash
run: |
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ] && [ -n "${{ inputs.release_tag }}" ]; then
TAG="${{ inputs.release_tag }}"
VERSION="${TAG#v}"
elif [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
TAG="dry-run-${GITHUB_SHA::7}"
VERSION="${TAG#v}"
else
TAG="${GITHUB_REF_NAME}"
VERSION="${GITHUB_REF_NAME#v}"
fi
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
# --- Binary archive (all platforms) ---
- name: Package binary (unix)
if: matrix.archive == 'tar.gz'
run: |
cd target/${{ matrix.target }}/release
tar czf ../../../tracedecay-${{ steps.version.outputs.tag }}-${{ matrix.name }}.tar.gz tracedecay
cd ../../..
- name: Generate archive attestation (unix)
if: matrix.archive == 'tar.gz' && github.event_name == 'release'
uses: actions/attest@v4
with:
subject-path: tracedecay-${{ steps.version.outputs.tag }}-${{ matrix.name }}.${{ matrix.archive }}
- name: Upload binary archive artifact (unix)
if: matrix.archive == 'tar.gz'
uses: actions/upload-artifact@v6
with:
name: binary-${{ matrix.name }}
path: tracedecay-${{ steps.version.outputs.tag }}-${{ matrix.name }}.${{ matrix.archive }}
- name: Package binary (windows)
if: matrix.archive == 'zip'
shell: pwsh
run: |
Compress-Archive -Path target/${{ matrix.target }}/release/tracedecay.exe -DestinationPath tracedecay-${{ steps.version.outputs.tag }}-${{ matrix.name }}.zip -Force
- name: Generate archive attestation (windows)
if: matrix.archive == 'zip' && github.event_name == 'release'
uses: actions/attest@v4
with:
subject-path: tracedecay-${{ steps.version.outputs.tag }}-${{ matrix.name }}.${{ matrix.archive }}
- name: Upload binary archive artifact (windows)
if: matrix.archive == 'zip'
uses: actions/upload-artifact@v6
with:
name: binary-${{ matrix.name }}
path: tracedecay-${{ steps.version.outputs.tag }}-${{ matrix.name }}.${{ matrix.archive }}
# --- Homebrew bottle (only for platforms with bottle_tag) ---
- name: Package Homebrew bottle
if: matrix.bottle_tag
run: |
VERSION="${{ steps.version.outputs.version }}"
BOTTLE_TAG="${{ matrix.bottle_tag }}"
mkdir -p tracedecay/${VERSION}/bin
cp target/${{ matrix.target }}/release/tracedecay tracedecay/${VERSION}/bin/tracedecay
chmod +x tracedecay/${VERSION}/bin/tracedecay
tar czf "tracedecay-${VERSION}.${BOTTLE_TAG}.bottle.tar.gz" tracedecay/
- name: Generate bottle attestation
if: matrix.bottle_tag && github.event_name == 'release'
uses: actions/attest@v4
with:
subject-path: tracedecay-${{ steps.version.outputs.version }}.${{ matrix.bottle_tag }}.bottle.tar.gz
- name: Upload bottle artifact
if: matrix.bottle_tag
uses: actions/upload-artifact@v6
with:
name: bottle-${{ matrix.bottle_tag }}
path: "tracedecay-*.bottle.tar.gz"
publish-assets:
name: Publish release assets
if: |
needs.build.result == 'success' &&
(
(github.event_name == 'release' && !github.event.release.prerelease) ||
(github.event_name == 'workflow_dispatch' && inputs.release_tag != '')
)
needs: build
runs-on: ubuntu-latest
steps:
- name: Get release tag
id: release
run: |
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
TAG="${{ inputs.release_tag }}"
else
TAG="${GITHUB_REF_NAME}"
fi
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
- name: Download binary artifacts
uses: actions/download-artifact@v7
with:
pattern: binary-*
path: binaries
merge-multiple: true
- name: Upload binaries to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
find binaries -type f -name 'tracedecay-*' -print -exec \
gh release upload "${{ steps.release.outputs.tag }}" {} --repo "${{ github.repository }}" --clobber \;
update-homebrew:
name: Update Homebrew tap
if: |
needs.build.result == 'success' &&
(
(github.event_name == 'release' && !github.event.release.prerelease) ||
(github.event_name == 'workflow_dispatch' && inputs.release_tag != '')
)
needs: [build, publish-assets]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get version
id: version
run: |
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
TAG="${{ inputs.release_tag }}"
else
TAG="${GITHUB_REF_NAME}"
fi
VERSION="${TAG#v}"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Download bottle artifacts
uses: actions/download-artifact@v7
with:
pattern: bottle-*
path: bottles
merge-multiple: true
- name: Upload bottles to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
for f in bottles/tracedecay-*.bottle.tar.gz; do
gh release upload "${{ steps.version.outputs.tag }}" "$f" --clobber
done
- name: Download source tarball
run: |
curl -sL "https://github.com/${{ github.repository }}/archive/refs/tags/${{ steps.version.outputs.tag }}.tar.gz" -o "source.tar.gz"
- name: Compute SHA256 hashes
id: hashes
run: |
VERSION="${{ steps.version.outputs.version }}"
SOURCE_SHA=$(sha256sum source.tar.gz | awk '{print $1}')
echo "source_sha=${SOURCE_SHA}" >> "$GITHUB_OUTPUT"
for f in bottles/tracedecay-*.bottle.tar.gz; do
tag=$(basename "$f" | sed "s/tracedecay-${VERSION}\.\(.*\)\.bottle\.tar\.gz/\1/")
sha=$(sha256sum "$f" | awk '{print $1}')
echo "${tag}_sha=${sha}" >> "$GITHUB_OUTPUT"
done
# NOTE: the Homebrew tap (ScriptedAlchemy/homebrew-tap) is an external
# repo — the previous formula there must be removed/renamed
# separately; this step only writes the new Formula/tracedecay.rb.
- name: Update formula
env:
TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
run: |
VERSION="${{ steps.version.outputs.version }}"
SOURCE_SHA="${{ steps.hashes.outputs.source_sha }}"
ARM64_SONOMA_SHA="${{ steps.hashes.outputs.arm64_sonoma_sha }}"
X86_64_LINUX_SHA="${{ steps.hashes.outputs.x86_64_linux_sha }}"
git clone "https://x-access-token:${TAP_GITHUB_TOKEN}@github.com/ScriptedAlchemy/homebrew-tap.git" tap
mkdir -p tap/Formula
cat > tap/Formula/tracedecay.rb << EOF
class Tracedecay < Formula
desc "Code intelligence tool that builds semantic knowledge graphs from source code"
homepage "https://github.com/ScriptedAlchemy/tracedecay"
url "https://github.com/ScriptedAlchemy/tracedecay/archive/refs/tags/v${VERSION}.tar.gz"
sha256 "${SOURCE_SHA}"
license "MIT"
bottle do
root_url "https://github.com/ScriptedAlchemy/tracedecay/releases/download/v${VERSION}"
sha256 cellar: :any_skip_relocation, arm64_sonoma: "${ARM64_SONOMA_SHA}"
sha256 cellar: :any_skip_relocation, x86_64_linux: "${X86_64_LINUX_SHA}"
end
depends_on "rust" => :build
def install
system "cargo", "install", *std_cargo_args
end
test do
system "#{bin}/tracedecay", "--help"
end
end
EOF
cd tap
# Clean up the legacy pre-rebrand formula if it still exists.
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/tracedecay.rb
git diff --cached --quiet || git commit -m "tracedecay ${VERSION}"
git push
update-scoop:
name: Update Scoop bucket
if: |
needs.build.result == 'success' &&
(
(github.event_name == 'release' && !github.event.release.prerelease) ||
(github.event_name == 'workflow_dispatch' && inputs.release_tag != '')
)
needs: [build, publish-assets]
runs-on: ubuntu-latest
steps:
- name: Get release info
id: release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
TAG="${{ inputs.release_tag }}"
else
TAG="${GITHUB_REF_NAME}"
fi
VERSION="${TAG#v}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
gh release download "${TAG}" \
--repo "${{ github.repository }}" \
--pattern "tracedecay-${TAG}-x86_64-windows.zip" \
--dir .
SHA256=$(sha256sum "tracedecay-${TAG}-x86_64-windows.zip" | cut -d' ' -f1)
echo "sha256_win64=${SHA256}" >> "$GITHUB_OUTPUT"
# NOTE: the Scoop bucket (ScriptedAlchemy/scoop-bucket) is an external
# repo — the previous bucket manifest there must be removed separately;
# this step only writes the new bucket/tracedecay.json.
- name: Update Scoop manifest
env:
SCOOP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
run: |
VERSION="${{ steps.release.outputs.version }}"
TAG="${{ steps.release.outputs.tag }}"
SHA256="${{ steps.release.outputs.sha256_win64 }}"
cat > tracedecay.json << EOF
{
"version": "${VERSION}",
"description": "Code intelligence tool that builds semantic knowledge graphs from source code",
"homepage": "https://github.com/ScriptedAlchemy/tracedecay",
"license": "MIT",
"architecture": {
"64bit": {
"url": "https://github.com/ScriptedAlchemy/tracedecay/releases/download/${TAG}/tracedecay-${TAG}-x86_64-windows.zip",
"hash": "${SHA256}"
}
},
"bin": "tracedecay.exe",
"checkver": {
"github": "https://github.com/ScriptedAlchemy/tracedecay"
},
"autoupdate": {
"architecture": {
"64bit": {
"url": "https://github.com/ScriptedAlchemy/tracedecay/releases/download/v\$version/tracedecay-v\$version-x86_64-windows.zip"
}
}
}
}
EOF
git clone "https://x-access-token:${SCOOP_GITHUB_TOKEN}@github.com/ScriptedAlchemy/scoop-bucket.git" scoop-repo
cd scoop-repo
mkdir -p bucket
cp ../tracedecay.json bucket/tracedecay.json
# Clean up legacy pre-rebrand manifests (root-level and bucket/).
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add bucket/tracedecay.json
git diff --cached --quiet || git commit -m "tracedecay ${VERSION}"
git push
# Rewrites the MCP registry manifest (server.json) from the actual release
# artifacts so the version, download URLs, and fileSha256 digests always
# describe real uploaded assets. Skips (with a warning) when the release has
# no MCPB packages, since those are not yet produced by the build matrix.
update-server-json:
name: Update server.json manifest
if: |
needs.build.result == 'success' &&
(
(github.event_name == 'release' && !github.event.release.prerelease) ||
(github.event_name == 'workflow_dispatch' && inputs.release_tag != '')
)
needs: [build, publish-assets]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: master
- name: Rewrite server.json from release artifacts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
TAG="${{ inputs.release_tag }}"
else
TAG="${GITHUB_REF_NAME}"
fi
VERSION="${TAG#v}"
REPO="${{ github.repository }}"
PLATFORMS="aarch64-macos:mcp.tar.gz x86_64-linux:mcp.tar.gz aarch64-linux:mcp.tar.gz x86_64-windows:mcp.zip"
mkdir -p assets
missing=0
for entry in $PLATFORMS; do
platform="${entry%%:*}"
ext="${entry#*:}"
asset="tracedecay-${TAG}-${platform}.${ext}"
if ! gh release download "$TAG" --repo "$REPO" --pattern "$asset" --dir assets; then
echo "::warning::release asset ${asset} not found"
missing=1
fi
done
if [ "$missing" -ne 0 ]; then
echo "::warning::server.json not updated — this release has no complete MCPB package set"
exit 0
fi
printf '[' > sha-map.json
sep=""
for entry in $PLATFORMS; do
platform="${entry%%:*}"
ext="${entry#*:}"
asset="tracedecay-${TAG}-${platform}.${ext}"
sha=$(sha256sum "assets/${asset}" | cut -d' ' -f1)
printf '%s{"platform":"%s","ext":"%s","sha":"%s"}' "$sep" "$platform" "$ext" "$sha" >> sha-map.json
sep=","
done
printf ']' >> sha-map.json
jq --arg v "$VERSION" --arg tag "$TAG" --arg repo "$REPO" --slurpfile map sha-map.json '
.version = $v
| .packages = ($map[0] | map(
{
"registryType": "mcpb",
"identifier": "https://github.com/\($repo)/releases/download/\($tag)/tracedecay-\($tag)-\(.platform).\(.ext)",
"version": $v,
"fileSha256": .sha,
"packageArguments": [
{
"type": "positional",
"valueHint": "serve"
}
],
"transport": {
"type": "stdio"
}
}
)
)
' server.json > server.json.tmp
mv server.json.tmp server.json
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add server.json
git diff --cached --quiet || git commit -m "chore(release): update server.json for ${VERSION}"
git push