Some checks failed
build-prerelease / Build cortex binary (push) Blocked by required conditions
CI / Clippy (push) Waiting to run
CI / Test (push) Waiting to run
build-prerelease / Resolve version stamps (push) Successful in 33s
CI / Format (push) Successful in 36s
build-prerelease / Build neuron-ampere (push) Has been cancelled
build-prerelease / Build neuron-ada (push) Has been cancelled
build-prerelease / Package cortex RPM (push) Has been cancelled
build-prerelease / Package helexa-neuron-ada RPM (push) Has been cancelled
build-prerelease / Package helexa-neuron-ampere RPM (push) Has been cancelled
build-prerelease / Package helexa-neuron-blackwell RPM (push) Has been cancelled
build-prerelease / Publish to rpm.lair.cafe (unstable) (push) Has been cancelled
CI / Build cortex SRPM (push) Has been cancelled
CI / Build neuron SRPM (push) Has been cancelled
CI / Publish cortex to COPR (push) Has been cancelled
CI / Publish neuron to COPR (push) Has been cancelled
CI / Bump version in source (push) Has been cancelled
build-prerelease / Build neuron-blackwell (push) Has been cancelled
The build-prerelease workflow was workflow_dispatch-only, which meant
every commit needed a manual run dispatch before any host could
upgrade. That left rolling fixes (e.g. f9f5fa4's StateDirectory fix)
sitting on main with no published RPM behind them, so deploy.sh
silently fell back to an older prerelease.
Add 'push: branches: [main]' alongside the existing workflow_dispatch
trigger; the unstable channel now tracks head automatically. The
concurrency group is keyed on ${{ github.ref }} with
cancel-in-progress so successive rapid-fire pushes coalesce to one
build (latest wins) rather than queueing every intermediate commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
327 lines
11 KiB
YAML
327 lines
11 KiB
YAML
name: build-prerelease
|
|
|
|
# Manually-dispatched workflow that builds CUDA-flavoured neuron binaries
|
|
# (and a single cortex binary), packages each as a Fedora RPM, signs
|
|
# them, and publishes to the `unstable` channel at rpm.lair.cafe.
|
|
#
|
|
# Trigger from the Gitea UI: Actions → build-prerelease → Run workflow.
|
|
# Optionally provide a `ref` to build from a non-default branch.
|
|
#
|
|
# The published packages are versioned as e.g.
|
|
# helexa-neuron-blackwell-0.1.16-0.1.20260518gitabcdef0.fc43.x86_64
|
|
# so they sort BELOW the eventual 0.1.16-1 stable release.
|
|
|
|
on:
|
|
# Auto-build on every push to main so the unstable channel tracks
|
|
# head without a manual dispatch step.
|
|
push:
|
|
branches: [main]
|
|
# Manual dispatch still available to build from a non-main ref.
|
|
workflow_dispatch:
|
|
inputs:
|
|
ref:
|
|
description: "Git ref to build (branch / tag / commit). Defaults to the workflow's branch."
|
|
required: false
|
|
default: ""
|
|
|
|
concurrency:
|
|
# Coalesce on branch+event so successive pushes don't pile up; the
|
|
# latest push wins.
|
|
group: prerelease-build-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
CARGO_INCREMENTAL: "0"
|
|
|
|
jobs:
|
|
prepare:
|
|
name: Resolve version stamps
|
|
runs-on: rust
|
|
outputs:
|
|
version: ${{ steps.info.outputs.version }}
|
|
release: ${{ steps.info.outputs.release }}
|
|
short_sha: ${{ steps.info.outputs.short_sha }}
|
|
commit_date: ${{ steps.info.outputs.commit_date }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.ref }}
|
|
fetch-depth: 0
|
|
|
|
- id: info
|
|
run: |
|
|
set -eux
|
|
VERSION=$(awk -F\" '/^version[[:space:]]*=/ { print $2; exit }' Cargo.toml)
|
|
SHORT_SHA=$(git rev-parse --short=7 HEAD)
|
|
COMMIT_DATE=$(git log -1 --format=%cd --date=format:%Y%m%d HEAD)
|
|
# Prerelease release stamp sorts before "1" (the stable release).
|
|
RELEASE="0.1.${COMMIT_DATE}git${SHORT_SHA}"
|
|
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
echo "release=${RELEASE}" >> "$GITHUB_OUTPUT"
|
|
echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
|
|
echo "commit_date=${COMMIT_DATE}" >> "$GITHUB_OUTPUT"
|
|
|
|
build-cortex:
|
|
name: Build cortex binary
|
|
needs: prepare
|
|
# runner-rust image already provides rust/cargo/clippy/rustfmt via
|
|
# dnf — no rustup install step needed.
|
|
runs-on: rust
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.ref }}
|
|
|
|
- name: Build cortex (release)
|
|
run: cargo build --release -p cortex-cli
|
|
|
|
- name: Stage binary
|
|
run: |
|
|
mkdir --parents artifacts
|
|
cp target/release/cortex artifacts/cortex
|
|
./artifacts/cortex --version || true
|
|
|
|
- uses: actions/upload-artifact@v3
|
|
with:
|
|
name: cortex-fc43
|
|
path: artifacts/cortex
|
|
retention-days: 1
|
|
|
|
build-neuron:
|
|
name: Build neuron-${{ matrix.flavour }}
|
|
needs: prepare
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- flavour: ampere
|
|
compute_cap: "86"
|
|
runner: cuda-13.0
|
|
cuda_home: /usr/local/cuda-13.0
|
|
build_jobs: 8
|
|
nvcc_threads: 4
|
|
cargo_features: "cuda cudnn flash-attn"
|
|
- flavour: ada
|
|
compute_cap: "89"
|
|
runner: cuda-13.0
|
|
cuda_home: /usr/local/cuda-13.0
|
|
build_jobs: 8
|
|
nvcc_threads: 4
|
|
cargo_features: "cuda cudnn flash-attn"
|
|
- flavour: blackwell
|
|
compute_cap: "120"
|
|
runner: cuda-13.0
|
|
cuda_home: /usr/local/cuda-13.0
|
|
build_jobs: 8
|
|
nvcc_threads: 4
|
|
cargo_features: "cuda cudnn flash-attn"
|
|
runs-on: ${{ matrix.runner }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.ref }}
|
|
|
|
- name: Build neuron with CUDA (${{ matrix.flavour }})
|
|
run: |
|
|
set -eux
|
|
export PATH="${{ matrix.cuda_home }}/bin:${PATH}"
|
|
export LD_LIBRARY_PATH="${{ matrix.cuda_home }}/targets/x86_64-linux/lib:${{ matrix.cuda_home }}/lib64:${LD_LIBRARY_PATH:-}"
|
|
export LIBRARY_PATH="${{ matrix.cuda_home }}/targets/x86_64-linux/lib:${{ matrix.cuda_home }}/lib64:${LIBRARY_PATH:-}"
|
|
cargo build --release -p neuron --features "${{ matrix.cargo_features }}"
|
|
env:
|
|
CUDA_COMPUTE_CAP: ${{ matrix.compute_cap }}
|
|
CARGO_BUILD_JOBS: ${{ matrix.build_jobs }}
|
|
NVCC_THREADS: ${{ matrix.nvcc_threads }}
|
|
|
|
- name: Stage binary
|
|
run: |
|
|
mkdir --parents artifacts
|
|
cp target/release/neuron artifacts/neuron-${{ matrix.flavour }}
|
|
file "artifacts/neuron-${{ matrix.flavour }}"
|
|
|
|
- uses: actions/upload-artifact@v3
|
|
with:
|
|
name: neuron-${{ matrix.flavour }}-fc43
|
|
path: artifacts/neuron-${{ matrix.flavour }}
|
|
retention-days: 1
|
|
|
|
package-cortex:
|
|
name: Package cortex RPM
|
|
needs: [prepare, build-cortex]
|
|
runs-on: rpm
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.ref }}
|
|
|
|
- uses: actions/download-artifact@v3
|
|
with:
|
|
name: cortex-fc43
|
|
path: artifacts/
|
|
|
|
- name: Build RPM
|
|
run: |
|
|
set -eux
|
|
rm -f ~/.rpmmacros
|
|
rpmdev-setuptree
|
|
cp artifacts/cortex ~/rpmbuild/SOURCES/
|
|
cp data/cortex.service ~/rpmbuild/SOURCES/
|
|
cp data/cortex-sysusers.conf ~/rpmbuild/SOURCES/
|
|
cp data/cortex-firewalld.xml ~/rpmbuild/SOURCES/
|
|
cp cortex.example.toml ~/rpmbuild/SOURCES/
|
|
cp models.example.toml ~/rpmbuild/SOURCES/
|
|
cp LICENSE ~/rpmbuild/SOURCES/
|
|
rpmbuild -bb rpm/cortex-prerelease.spec \
|
|
--define "cortex_version ${{ needs.prepare.outputs.version }}" \
|
|
--define "cortex_prerelease ${{ needs.prepare.outputs.release }}" \
|
|
--undefine dist \
|
|
--define "dist .fc43"
|
|
|
|
- uses: actions/upload-artifact@v3
|
|
with:
|
|
name: rpm-cortex-fc43
|
|
path: ~/rpmbuild/RPMS/x86_64/*.rpm
|
|
retention-days: 7
|
|
|
|
package-neuron:
|
|
name: Package helexa-neuron-${{ matrix.flavour }} RPM
|
|
needs: [prepare, build-neuron]
|
|
runs-on: rpm
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- flavour: ampere
|
|
- flavour: ada
|
|
- flavour: blackwell
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.ref }}
|
|
|
|
- uses: actions/download-artifact@v3
|
|
with:
|
|
name: neuron-${{ matrix.flavour }}-fc43
|
|
path: artifacts/
|
|
|
|
- name: Build RPM
|
|
run: |
|
|
set -eux
|
|
rm -f ~/.rpmmacros
|
|
rpmdev-setuptree
|
|
cp artifacts/neuron-${{ matrix.flavour }} ~/rpmbuild/SOURCES/
|
|
cp data/neuron.service ~/rpmbuild/SOURCES/
|
|
cp data/neuron-sysusers.conf ~/rpmbuild/SOURCES/
|
|
cp data/neuron-firewalld.xml ~/rpmbuild/SOURCES/
|
|
cp neuron.example.toml ~/rpmbuild/SOURCES/
|
|
cp LICENSE ~/rpmbuild/SOURCES/
|
|
rpmbuild -bb rpm/helexa-neuron-prerelease.spec \
|
|
--define "neuron_version ${{ needs.prepare.outputs.version }}" \
|
|
--define "neuron_flavour ${{ matrix.flavour }}" \
|
|
--define "neuron_prerelease ${{ needs.prepare.outputs.release }}" \
|
|
--undefine dist \
|
|
--define "dist .fc43"
|
|
|
|
- uses: actions/upload-artifact@v3
|
|
with:
|
|
name: rpm-neuron-${{ matrix.flavour }}-fc43
|
|
path: ~/rpmbuild/RPMS/x86_64/*.rpm
|
|
retention-days: 7
|
|
|
|
publish:
|
|
name: Publish to rpm.lair.cafe (unstable)
|
|
needs: [package-cortex, package-neuron]
|
|
runs-on: rpm
|
|
concurrency:
|
|
group: rpm-publish
|
|
cancel-in-progress: false
|
|
env:
|
|
RPM_REPO_HOST: oolon.kosherinata.internal
|
|
FEDORA_VERSION: "43"
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.ref }}
|
|
|
|
- name: Download all built RPMs
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
path: rpms/
|
|
pattern: rpm-*-fc43
|
|
|
|
- name: Flatten RPM artifacts
|
|
run: |
|
|
set -eux
|
|
find rpms/ -name '*.rpm' -exec mv --target-directory=rpms/ {} +
|
|
find rpms/ -mindepth 1 -type d -empty -delete
|
|
ls -la rpms/
|
|
|
|
- name: Check for sequoia-sq
|
|
run: |
|
|
if ! command -v sq &> /dev/null; then
|
|
echo "ERROR: sequoia-sq is not installed. Install with: sudo dnf install sequoia-sq"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Import signing key
|
|
env:
|
|
# Pass secrets via env so values stay out of the rendered shell
|
|
# script (which Gitea includes in step logs). Template
|
|
# expansion of ${{ secrets.X }} inside `run:` writes the literal
|
|
# value into the script and depends on Gitea's log masker to
|
|
# scrub it — fragile for multi-line keys.
|
|
RPM_SIGNING_KEY: ${{ secrets.RPM_SIGNING_KEY }}
|
|
RPM_SIGNING_KEY_ID: ${{ secrets.RPM_SIGNING_KEY_ID }}
|
|
run: |
|
|
echo "$RPM_SIGNING_KEY" | gpg --batch --import
|
|
fpr=$(gpg --batch --with-colons --list-keys "$RPM_SIGNING_KEY_ID" | awk -F: '/^fpr:/ { print $10; exit }')
|
|
echo "${fpr}:6:" | gpg --batch --import-ownertrust
|
|
sed "s/@GPG_NAME@/$RPM_SIGNING_KEY_ID/" rpm/rpmmacros > ~/.rpmmacros
|
|
|
|
- name: Sign RPMs
|
|
run: |
|
|
set -eux
|
|
for rpm in rpms/*.rpm; do
|
|
echo "signing ${rpm}..."
|
|
rpm --addsign "${rpm}"
|
|
done
|
|
|
|
- name: Set up SSH for rsync
|
|
run: |
|
|
install --directory --mode 700 ~/.ssh
|
|
echo "${RSYNC_SSH_KEY}" | install --mode 600 /dev/stdin ~/.ssh/id_ed25519
|
|
env:
|
|
RSYNC_SSH_KEY: ${{ secrets.RSYNC_SSH_KEY }}
|
|
|
|
- name: Test SSH connectivity
|
|
run: |
|
|
ssh -o StrictHostKeyChecking=accept-new "gitea_ci@${RPM_REPO_HOST}" exit
|
|
|
|
- name: Ensure unstable repo directory exists
|
|
run: |
|
|
ssh "gitea_ci@${RPM_REPO_HOST}" \
|
|
"mkdir --parents /var/www/rpm/fedora/${FEDORA_VERSION}/x86_64/unstable"
|
|
|
|
- name: Sync RPMs to unstable repo
|
|
run: |
|
|
rsync \
|
|
--archive \
|
|
--verbose \
|
|
--chmod D755,F644 \
|
|
rpms/*.rpm \
|
|
"gitea_ci@${RPM_REPO_HOST}:/var/www/rpm/fedora/${FEDORA_VERSION}/x86_64/unstable/"
|
|
|
|
- name: Update unstable repo metadata
|
|
run: |
|
|
ssh "gitea_ci@${RPM_REPO_HOST}" \
|
|
"cd /var/www/rpm/fedora/${FEDORA_VERSION}/x86_64/unstable && createrepo_c --update ."
|
|
|
|
- name: Generate packages.json manifest
|
|
run: |
|
|
scp script/generate-packages-json.py "gitea_ci@${RPM_REPO_HOST}:/tmp/"
|
|
ssh "gitea_ci@${RPM_REPO_HOST}" \
|
|
"python3 /tmp/generate-packages-json.py \
|
|
--repodata-dir /var/www/rpm/fedora/${FEDORA_VERSION}/x86_64/unstable/repodata \
|
|
--output /var/www/rpm/fedora/${FEDORA_VERSION}/x86_64/unstable/packages.json \
|
|
--base-url https://rpm.lair.cafe/fedora/${FEDORA_VERSION}/x86_64/unstable"
|