Build A Runtime In GitHub Actions#
This tutorial takes a committed conda-ship project and builds runtime artifacts with the composite GitHub Action.
You will add a workflow that downloads released conda-ship build tools, verifies
them, runs cs build --dry-run, builds the runtime, and uploads the generated
dist directory as a workflow artifact.
Before You Start#
You need a repository that already contains one supported manifest and lockfile pair:
conda.tomlandconda.lockpixi.tomlandpixi.lockpyproject.tomlwith[tool.conda]andconda.lockpyproject.tomlwith[tool.pixi]andpixi.lock
The manifest must contain [tool.conda-ship] with at least:
[tool.conda-ship]
runtime = "demo"
runtime-version = "0.1.0"
delegate = "conda"
source-environment = "ship"
Run the local preflight before committing:
cs inspect
cs build --dry-run
Add The Workflow#
Create .github/workflows/build-runtime.yml:
name: Build runtime
on:
workflow_dispatch:
push:
branches: [main]
permissions:
contents: read
id-token: write
attestations: write
artifact-metadata: write
jobs:
build:
name: Build ${{ matrix.os }} ${{ matrix.layout }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
layout: online
install-method: standalone
- os: macos-15-intel
layout: embedded
install-method: homebrew
- os: macos-15
layout: embedded
install-method: homebrew
- os: windows-latest
layout: online
install-method: standalone
steps:
- uses: actions/checkout@v4
- uses: jezdez/conda-ship@0.2.1
id: cs
with:
layout: ${{ matrix.layout }}
install-method: ${{ matrix.install-method }}
- uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
with:
subject-path: ${{ steps.cs.outputs.dist-path }}/*
- uses: actions/upload-artifact@v4
with:
name: ${{ steps.cs.outputs.asset-name }}
path: ${{ steps.cs.outputs.dist-path }}
Pin the action to a conda-ship release tag. Branch refs do not have matching
release assets for cs and cs-template.
Warning
Use the latest reviewed actions/attest release in your workflow and pin it by
commit SHA. The SHA above is an example, not a recommendation to keep using that
exact revision indefinitely.
Run It#
Push the workflow and start it from the GitHub Actions tab, or wait for the next
push to main.
The action downloads these release assets for the current runner:
cs-<target>cs-template-<target>SHA256SUMS
It verifies GitHub artifact attestations and the checksums before running the
downloaded cs binary.
The workflow also attests the generated runtime output directory before
uploading it. That downstream attestation covers the runtime binary,
.runtime.lock, .packages.txt, .info.json, .sha256, and any external
bundle produced by that job.
Inspect The Artifact#
Each job uploads the full generated output directory. Download one artifact and inspect the files:
demo-x86_64-unknown-linux-gnu
demo-x86_64-unknown-linux-gnu.info.json
demo-x86_64-unknown-linux-gnu.packages.txt
demo-x86_64-unknown-linux-gnu.runtime.lock
demo-x86_64-unknown-linux-gnu.sha256
For an external build, the directory also contains
demo-<target>.bundle.tar.zst. For an embedded build, the runtime name gets
the z suffix, for example demoz-aarch64-apple-darwin.
Override Runtime Metadata#
Keep package and channel choices in the manifest and lockfile. Use action inputs for release-job metadata that may vary across a matrix:
- uses: jezdez/conda-ship@0.2.1
id: cs
with:
runtime: demo
delegate: conda
layout: ${{ matrix.layout }}
docs-url: https://example.com/demo/
install-scheme: conda-home
install-name: demo
install-method: ${{ matrix.install-method }}
The action does not validate those values itself. It passes them to
cs build --dry-run; invalid values fail in conda-ship before artifact files
are written.
What You Learned#
You added a release-style workflow that builds conda-ship runtime artifacts from committed project input. The solve still belongs to conda-workspaces or Pixi; the action consumes the committed lockfile and stamps a runtime with release-specific metadata.