Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
name: Build Binaries (Reusable)

on:
workflow_call:
inputs:
version_name:
description: Version identifier used in archive names
required: true
type: string
is_nightly:
description: Whether this is a nightly build
type: boolean
default: false
revision:
description: Exact source revision to build (defaults to the caller's commit)
type: string
default: ''
pull_request:
paths:
- '.github/workflows/build.yml'
- '.github/workflows/release.yml'
- '.github/workflows/nightly.yml'
- 'Cargo.toml'
- 'Cargo.lock'
- 'rust-toolchain.toml'
- 'build.rs'
- 'src/**'
- 'docs/**'
- 'README.md'
- 'LICENSE'

permissions:
contents: read

env:
CARGO_TERM_COLOR: always

jobs:
build:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
- os: ubuntu-latest
target: aarch64-unknown-linux-musl
- os: macos-14
target: x86_64-apple-darwin
- os: macos-14
target: aarch64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-msvc
rust_flags: '-C target-feature=+crt-static'
- os: windows-latest
target: aarch64-pc-windows-msvc
rust_flags: '-C target-feature=+crt-static'
- os: ubuntu-latest
target: x86_64-unknown-freebsd
toolchain_target: x86_64-unknown-freebsd@14
steps:
- name: Checkout code
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
ref: ${{ inputs.revision || github.sha }}
persist-credentials: false

- name: Verify release version
if: github.ref_type == 'tag' && !inputs.is_nightly
shell: bash
run: |
VERSION=$(sed -nE 's/^version = "([^"]+)"/\1/p' Cargo.toml)
test "$GITHUB_REF_NAME" = "v$VERSION"

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable
with:
targets: ${{ matrix.target }}

- name: Install cross-compilation toolchain
if: runner.os == 'Linux'
uses: taiki-e/setup-cross-toolchain-action@12b7ad4acfa95a1476779d6c06699b96ec1691f8 # v1.42.0
with:
target: ${{ matrix.toolchain_target || matrix.target }}

- name: Cache Cargo dependencies
uses: swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
with:
key: ${{ matrix.target }}

- name: Build release binary
env:
RUSTFLAGS: ${{ matrix.rust_flags || '' }}
run: cargo build --locked --release --bin qmcp --target ${{ matrix.target }}

- name: Package archive (Linux, macOS and FreeBSD)
if: runner.os != 'Windows'
shell: bash
env:
VERSION_NAME: ${{ inputs.version_name || github.ref_name }}
TARGET: ${{ matrix.target }}
run: |
PKG="qmcp-${VERSION_NAME//\//-}-${TARGET}"
STAGING="dist/${PKG}"
mkdir -p "$STAGING"
cp "target/${TARGET}/release/qmcp" README.md LICENSE "$STAGING/"
cp -R docs "$STAGING/"
tar -czf "dist/${PKG}.tar.gz" -C dist "$PKG"
echo "ASSET_PATH=dist/${PKG}.tar.gz" >> "$GITHUB_ENV"

- name: Package archive (Windows)
if: runner.os == 'Windows'
shell: pwsh
env:
VERSION_NAME: ${{ inputs.version_name || github.ref_name }}
TARGET: ${{ matrix.target }}
run: |
$PKG = "qmcp-$($env:VERSION_NAME.Replace('/', '-'))-$($env:TARGET)"
$STAGING = Join-Path 'dist' $PKG
New-Item -ItemType Directory -Force -Path $STAGING | Out-Null
Copy-Item "target/$($env:TARGET)/release/qmcp.exe" -Destination $STAGING
Copy-Item README.md, LICENSE -Destination $STAGING
Copy-Item docs -Destination $STAGING -Recurse
$ZIP_PATH = "dist/${PKG}.zip"
Compress-Archive -Path (Join-Path $STAGING '*') -DestinationPath $ZIP_PATH -Force
"ASSET_PATH=${ZIP_PATH}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append

- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: qmcp-${{ matrix.target }}
path: ${{ env.ASSET_PATH }}
if-no-files-found: error
88 changes: 88 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Nightly

on:
schedule:
- cron: '0 3 * * *'
workflow_dispatch:

permissions:
contents: read

# Serialize publication so runs cannot race while replacing the nightly release.
concurrency:
group: nightly
cancel-in-progress: false

jobs:
check-changes:
name: Check for changes since last nightly
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
has_changes: ${{ steps.check.outputs.has_changes }}
revision: ${{ steps.check.outputs.revision }}
version_name: ${{ steps.check.outputs.version_name }}
steps:
- name: Checkout main
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
ref: main
persist-credentials: false

- name: Check for changes
id: check
env:
GH_TOKEN: ${{ github.token }}
run: |
LAST_NIGHTLY_SHA=$(gh release view nightly --repo "$GITHUB_REPOSITORY" --json targetCommitish --jq '.targetCommitish' 2>/dev/null || true)
CURRENT_SHA=$(git rev-parse HEAD)
if [ "$LAST_NIGHTLY_SHA" != "$CURRENT_SHA" ]; then
echo "has_changes=true" >> "$GITHUB_OUTPUT"
else
echo "has_changes=false" >> "$GITHUB_OUTPUT"
fi
echo "revision=$CURRENT_SHA" >> "$GITHUB_OUTPUT"
echo "version_name=nightly-$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"

build:
name: Build Nightly Binaries
needs: check-changes
if: needs.check-changes.outputs.has_changes == 'true' || github.event_name == 'workflow_dispatch'
uses: ./.github/workflows/build.yml
with:
version_name: ${{ needs.check-changes.outputs.version_name }}
is_nightly: true
revision: ${{ needs.check-changes.outputs.revision }}

release:
name: Create Nightly GitHub Release
needs: [check-changes, build]
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
steps:
- name: Download build artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: artifacts/
pattern: 'qmcp-*'
merge-multiple: true

- name: Replace nightly release
env:
GH_TOKEN: ${{ github.token }}
REVISION: ${{ needs.check-changes.outputs.revision }}
run: |
gh release delete nightly --repo "$GITHUB_REPOSITORY" --yes --cleanup-tag || true
gh release create nightly \
--repo "$GITHUB_REPOSITORY" \
--title "Nightly Build" \
--notes "**This is a pre-release build from the main branch.**

It is not intended for production use.

Commit: \`$REVISION\`" \
--prerelease \
--target "$REVISION" \
artifacts/*
90 changes: 12 additions & 78 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,94 +2,26 @@ name: Release

on:
push:
tags: ['v*.*.*']
pull_request:
paths: ['.github/workflows/release.yml']
tags:
- 'v*.*.*'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

jobs:
build:
name: Release build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
- os: ubuntu-latest
target: aarch64-unknown-linux-musl
- os: macos-14
target: x86_64-apple-darwin
- os: macos-14
target: aarch64-apple-darwin
steps:
- name: Checkout code
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false

- name: Verify release version
if: github.ref_type == 'tag'
env:
RELEASE_TAG: ${{ github.ref_name }}
run: |
VERSION=$(sed -nE 's/^version = "([^"]+)"/\1/p' Cargo.toml | head -n 1)
test "$RELEASE_TAG" = "v$VERSION"

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable
with:
targets: ${{ matrix.target }}

- name: Install cross-compilation toolchain
if: runner.os == 'Linux'
uses: taiki-e/setup-cross-toolchain-action@12b7ad4acfa95a1476779d6c06699b96ec1691f8 # v1.42.0
with:
target: ${{ matrix.target }}

- name: Cache Cargo dependencies
uses: swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
with:
key: ${{ matrix.target }}

- name: Build release binary
run: cargo build --locked --release --bin qmcp --target ${{ matrix.target }}

- name: Package archive
env:
RELEASE_REF: ${{ github.ref_name }}
TARGET: ${{ matrix.target }}
run: |
PKG="qmcp-${RELEASE_REF//\//-}-${TARGET}"
STAGING="dist/${PKG}"
mkdir -p "$STAGING"
cp "target/${TARGET}/release/qmcp" README.md LICENSE "$STAGING/"
cp -R docs "$STAGING/"
tar -czf "dist/${PKG}.tar.gz" -C dist "$PKG"
echo "ASSET_PATH=dist/${PKG}.tar.gz" >> "$GITHUB_ENV"

- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: qmcp-${{ matrix.target }}
path: ${{ env.ASSET_PATH }}
if-no-files-found: error
name: Build Release Binaries
uses: ./.github/workflows/build.yml
with:
version_name: ${{ github.ref_name }}

release:
name: GitHub Release
if: github.ref_type == 'tag'
needs: [build]
runs-on: ubuntu-latest
timeout-minutes: 10
Expand All @@ -106,8 +38,10 @@ jobs:
- name: Create GitHub Release
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
with:
tag_name: ${{ github.ref_name }}
target_commitish: ${{ github.sha }}
files: artifacts/*
fail_on_unmatched_files: true
generate_release_notes: true
draft: false
prerelease: false
fail_on_unmatched_files: true
draft: ${{ github.ref_type != 'tag' }}
prerelease: ${{ github.ref_type != 'tag' }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
Loading
Loading