Skip to content

build: Bump version to 0.9.0 #14

build: Bump version to 0.9.0

build: Bump version to 0.9.0 #14

Workflow file for this run

# Builds release artifacts for Linux and macOS:
# - the GTK desktop app (`commedit`), one tarball per target, and
# - `commedit-plugin.zip`, a Claude Code plugin bundling the `commedit-mcp`
# server binary for every target (see plugin/README.md).
#
# The GTK app links dynamically against system GTK4 + GtkSourceView5, so those
# tarballs are NOT self-contained. The end user must have a compatible runtime
# (and `git` on PATH) installed — see the "Installing a binary release" section
# of README.md:
# - Linux: apt install git libgtk-4-1 libgtksourceview-5-0 libspelling-1-2 (or distro equivalent)
# - macOS: brew install git gtk4 gtksourceview5 libspelling
# The MCP server (and thus the plugin) only needs `git` on PATH.
#
# Push a tag like `v0.1.0` to cut a GitHub Release; or run manually via the
# Actions tab to just produce downloadable build artifacts.
#
# The build/plugin jobs only upload workflow artifacts; a final `release` job
# gathers them and publishes the release in one shot. It does so the way
# GitHub's *immutable releases* require: create a DRAFT, attach every asset to
# it, then flip it to published. A published immutable release is locked, so
# the old approach (each matrix job appending its own asset to an
# already-published release) cannot work — only the draft is still writable.
name: release
on:
push:
tags:
- "v*"
workflow_dispatch:
permissions:
contents: write
jobs:
build:
name: build (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
asset: commedit-linux-x86_64.tar.gz
mcp_asset: commedit-mcp-linux-x86_64
- os: ubuntu-24.04-arm
asset: commedit-linux-aarch64.tar.gz
mcp_asset: commedit-mcp-linux-aarch64
- os: macos-latest
asset: commedit-macos-aarch64.tar.gz
mcp_asset: commedit-mcp-macos-aarch64
steps:
- uses: actions/checkout@v6
# --- Linux: GTK from apt, Rust from rustup --------------------------
- name: Install GTK (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-4-dev libgtksourceview-5-dev libspelling-1-dev
# --- macOS: GTK from Homebrew, Rust from rustup ---------------------
# The runner image pre-taps third-party repos (aws/tap, azure/bicep) we
# never use. Opt into Homebrew's upcoming tap-trust default so it simply
# ignores untrusted taps instead of printing the transition warning;
# official taps are always trusted, so our formulae install unaffected.
- name: Install GTK (macOS)
if: runner.os == 'macOS'
env:
HOMEBREW_REQUIRE_TAP_TRUST: 1
run: brew install gtk4 gtksourceview5 libspelling pkg-config
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
# The MCP server has no GTK dependency, so building it alongside the app
# reuses the same toolchain and compile cache for free.
- name: Build
run: cargo build --release --locked -p commedit-gtk -p commedit-mcp
- name: Package app
run: tar -C target/release -czf "${{ matrix.asset }}" commedit
# Stage the MCP binary under its target-specific name, the name the
# plugin launcher (plugin/bin/launch.sh) resolves at runtime.
- name: Stage MCP binary
run: cp target/release/commedit-mcp "${{ matrix.mcp_asset }}"
# --- Publish --------------------------------------------------------
- name: Upload app artifact
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.asset }}
path: ${{ matrix.asset }}
# Consumed by the `plugin` job, not attached to the release on its own.
- name: Upload MCP binary artifact
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.mcp_asset }}
path: ${{ matrix.mcp_asset }}
# Bundle the per-target MCP binaries into a single Claude Code plugin zip.
plugin:
name: package plugin
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
# All three commedit-mcp-* binaries land directly in plugin/bin/, next to
# the launcher that dispatches between them.
- name: Download MCP binaries
uses: actions/download-artifact@v7
with:
pattern: commedit-mcp-*
path: plugin/bin
merge-multiple: true
# On a tagged release, pin the plugin version to the tag (v0.3.0 -> 0.3.0)
# so org-distributed installs see each release as a new version.
- name: Set plugin version from tag
if: startsWith(github.ref, 'refs/tags/')
run: |
version="${GITHUB_REF_NAME#v}"
tmp=$(mktemp)
jq --arg v "$version" '.version = $v' \
plugin/.claude-plugin/plugin.json > "$tmp"
mv "$tmp" plugin/.claude-plugin/plugin.json
# zip stores the +x bits we set here (the launcher self-heals the binary
# bit too, so the plugin still works if the channel drops permissions).
- name: Assemble plugin zip
run: |
chmod +x plugin/bin/launch.sh plugin/bin/commedit-mcp-*
(cd plugin && zip -r ../commedit-plugin.zip \
.claude-plugin .mcp.json bin skills agents README.md \
-x 'bin/.gitignore')
unzip -l commedit-plugin.zip
- name: Upload plugin artifact
uses: actions/upload-artifact@v7
with:
name: commedit-plugin.zip
path: commedit-plugin.zip
# Publish the release once, with every asset, via GitHub's immutable-release
# flow: a draft is the only writable state, so we attach all assets to a
# draft and then flip it to published (which locks it). Only on a tag.
release:
name: publish release
needs: [build, plugin]
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
# Pull every uploaded artifact flat into dist/. The bare MCP binaries
# land here too but are filtered out below — only tarballs + the plugin
# zip get attached, matching what the release carried before.
- name: Download release assets
uses: actions/download-artifact@v7
with:
path: dist
merge-multiple: true
- name: Create draft release with all assets
id: draft
uses: softprops/action-gh-release@v3
with:
draft: true
files: |
dist/*.tar.gz
dist/commedit-plugin.zip
fail_on_unmatched_files: true
# Flipping draft -> published is the point the release becomes immutable,
# with all assets already in place. This job has no checkout, so
# `gh release edit` would shell out to git to discover the repo and die
# with "not a git repository"; patch the release by its id (from the step
# above) via `gh api`, whose fully-qualified path needs neither a git
# checkout nor a tag lookup.
- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh api --method PATCH \
"/repos/${{ github.repository }}/releases/${{ steps.draft.outputs.id }}" \
-F draft=false