Skip to content

Commit 054000c

Browse files
ndbroadbentclaude
andcommitted
feat: add full GitHub Actions support with permissions, environment, concurrency, and matrix
Extended schema and models to support GitHub Actions-specific features: - Added permissions at workflow and job level - Added environment configuration for deployments - Added concurrency control - Added strategy/matrix with dynamic properties - Added step-level id and if conditionals - Updated job schema to accept native GitHub Actions step syntax All .github/workflows are now generated from .cigen/ config, including: - ci.yml (with job skipping) - docs.yml (with Pages deployment) - release.yml (with matrix builds) This makes cigen fully self-hosting and demonstrates 'write once, run anywhere' philosophy. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d113c55 commit 054000c

File tree

18 files changed

+801
-311
lines changed

18 files changed

+801
-311
lines changed

.cigen/workflows/docs.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
on:
2+
push:
3+
branches: [main]
4+
paths:
5+
- "docs/**"
6+
- ".github/workflows/docs.yml"
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: "pages"
15+
cancel-in-progress: false
16+
17+
jobs:
18+
ci_gate:
19+
build:
20+
requires:
21+
- ci_gate
22+
deploy:
23+
requires:
24+
- build
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
image: ubuntu-latest
2+
3+
steps:
4+
- uses: actions/checkout@v4
5+
6+
- name: Setup Node.js
7+
uses: actions/setup-node@v4
8+
with:
9+
node-version: "20"
10+
11+
- name: Setup pnpm
12+
uses: pnpm/action-setup@v4
13+
with:
14+
version: 10
15+
16+
- run:
17+
name: Install root deps (if any)
18+
command: |
19+
pnpm install --frozen-lockfile || pnpm install
20+
21+
- run:
22+
name: Build docs (if present)
23+
command: |
24+
set -e
25+
if [ -f docs/package.json ]; then
26+
cd docs
27+
pnpm install --frozen-lockfile || pnpm install
28+
if pnpm run -s build; then
29+
echo "Docs built with pnpm"
30+
elif npm run build; then
31+
echo "Docs built with npm"
32+
else
33+
echo "Docs build script not found" >&2
34+
exit 1
35+
fi
36+
if [ ! -d dist ]; then
37+
echo "Docs build output not found at dist/" >&2
38+
exit 1
39+
fi
40+
else
41+
echo "docs/package.json not found; docs site missing" >&2
42+
exit 1
43+
fi
44+
45+
- run:
46+
name: Verify docs output exists
47+
command: |
48+
if [ ! -d docs/dist ]; then
49+
echo "Docs build output not found at docs/dist" >&2
50+
exit 1
51+
fi
52+
53+
- name: Configure Pages
54+
uses: actions/configure-pages@v5
55+
56+
- name: Upload artifact
57+
uses: actions/upload-pages-artifact@v3
58+
with:
59+
path: docs/dist
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
image: ubuntu-latest
2+
3+
steps:
4+
- uses: actions/checkout@v4
5+
- name: Wait for CI checks to complete
6+
uses: actions/github-script@v7
7+
with:
8+
script: |
9+
const wait = require('./.github/wait-for-checks.js');
10+
await wait({ github, context, core, checks: ["test"] });
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
image: ubuntu-latest
2+
3+
environment:
4+
name: github-pages
5+
url: ${{ steps.deployment.outputs.page_url }}
6+
7+
steps:
8+
- name: Deploy to GitHub Pages
9+
id: deployment
10+
uses: actions/deploy-pages@v4

.cigen/workflows/release.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
on:
2+
push:
3+
tags:
4+
- "v*" # Version tags like v1.2.3
5+
workflow_dispatch:
6+
7+
permissions:
8+
contents: write
9+
10+
jobs:
11+
release_build:
12+
release_create:
13+
requires:
14+
- release_build
15+
docker_image:
16+
requires:
17+
- release_create
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
image: ubuntu-latest
2+
3+
permissions:
4+
contents: read
5+
6+
env:
7+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
8+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
9+
10+
steps:
11+
- name: Checkout repository
12+
uses: actions/checkout@v4
13+
with:
14+
fetch-depth: 0
15+
16+
- run:
17+
name: Extract version
18+
command: |
19+
VERSION=$(grep -E '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
20+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
21+
22+
- name: Set up QEMU
23+
uses: docker/setup-qemu-action@v3
24+
25+
- name: Set up Docker Buildx
26+
uses: docker/setup-buildx-action@v3
27+
28+
- name: Log in to Docker Hub
29+
uses: docker/login-action@v3
30+
with:
31+
username: ${{ env.DOCKERHUB_USERNAME }}
32+
password: ${{ env.DOCKERHUB_TOKEN }}
33+
34+
- run:
35+
name: Build and push multi-arch image
36+
command: |
37+
set -euo pipefail
38+
VERSION="${{ steps.v.outputs.version }}"
39+
echo "Building docspringcom/cigen:${VERSION} and :latest"
40+
docker buildx build \
41+
--platform linux/amd64,linux/arm64 \
42+
-f Dockerfile \
43+
--build-arg CIGEN_VERSION="${VERSION}" \
44+
-t docspringcom/cigen:"${VERSION}" \
45+
-t docspringcom/cigen:latest \
46+
--push .
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Dynamic runs-on from matrix
2+
image: ${{ matrix.os }}
3+
4+
strategy:
5+
fail-fast: false
6+
matrix:
7+
include:
8+
# macOS builds
9+
- os: macos-latest
10+
target: x86_64-apple-darwin
11+
name: cigen-macos-amd64
12+
- os: macos-latest
13+
target: aarch64-apple-darwin
14+
name: cigen-macos-arm64
15+
# Linux builds
16+
- os: ubuntu-latest
17+
target: x86_64-unknown-linux-gnu
18+
name: cigen-linux-amd64
19+
- os: ubuntu-latest
20+
target: aarch64-unknown-linux-gnu
21+
name: cigen-linux-arm64
22+
use-cross: true
23+
24+
steps:
25+
- name: Checkout repository
26+
uses: actions/checkout@v4
27+
with:
28+
fetch-depth: 0
29+
fetch-tags: true
30+
31+
- name: Wait for required checks
32+
uses: actions/github-script@v7
33+
with:
34+
script: |
35+
const script = require('./.github/wait-for-checks.js');
36+
await script({ github, context, core });
37+
38+
- name: Install Rust
39+
uses: dtolnay/rust-toolchain@stable
40+
with:
41+
targets: ${{ matrix.target }}
42+
43+
- name: Install cross (for cross-compilation)
44+
if: matrix.use-cross
45+
run: cargo install cross --git https://github.com/cross-rs/cross
46+
47+
- run:
48+
name: Build binary
49+
command: |
50+
set -e
51+
if [ "${{ matrix.use-cross }}" = "true" ]; then
52+
cross build --release --target ${{ matrix.target }} --bin cigen
53+
else
54+
cargo build --release --target ${{ matrix.target }} --bin cigen
55+
fi
56+
57+
- run:
58+
name: Create archive
59+
command: |
60+
set -e
61+
cd "target/${{ matrix.target }}/release"
62+
tar czf "../../../${{ matrix.name }}.tar.gz" cigen
63+
cd ../../../
64+
echo "ASSET_PATH=${{ matrix.name }}.tar.gz" >> "$GITHUB_ENV"
65+
66+
- name: Upload artifact
67+
uses: actions/upload-artifact@v4
68+
with:
69+
name: ${{ matrix.name }}
70+
path: ${{ env.ASSET_PATH }}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
image: ubuntu-latest
2+
3+
steps:
4+
- name: Checkout repository
5+
uses: actions/checkout@v4
6+
with:
7+
fetch-depth: 0
8+
fetch-tags: true
9+
10+
- name: Download artifacts
11+
uses: actions/download-artifact@v4
12+
with:
13+
path: artifacts
14+
15+
- run:
16+
name: Get version from Cargo.toml
17+
command: |
18+
VERSION=$(grep -E '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
19+
{
20+
echo "version=$VERSION"
21+
} >> "$GITHUB_OUTPUT"
22+
23+
if [ "${{ github.event_name }}" = "push" ]; then
24+
TAG="${GITHUB_REF#refs/tags/}"
25+
EXPECTED_TAG="v$VERSION"
26+
if [ "$TAG" != "$EXPECTED_TAG" ]; then
27+
echo "Error: Tag $TAG doesn't match expected $EXPECTED_TAG from Cargo.toml" >&2
28+
exit 1
29+
fi
30+
{
31+
echo "tag=$TAG"
32+
} >> "$GITHUB_OUTPUT"
33+
else
34+
{
35+
echo "tag=v$VERSION"
36+
} >> "$GITHUB_OUTPUT"
37+
fi
38+
39+
- run:
40+
name: Generate checksums
41+
command: |
42+
set -e
43+
cd artifacts
44+
for dir in */; do
45+
cd "$dir"
46+
for file in *; do
47+
case "$file" in
48+
*.tar.gz|*.zip)
49+
if [ -f "$file" ]; then
50+
sha256sum "$file" > "${file}.sha256" || shasum -a 256 "$file" | awk '{print $1}' > "${file}.sha256"
51+
fi
52+
;;
53+
esac
54+
done
55+
cd ..
56+
done
57+
cd ..
58+
59+
- run:
60+
name: Generate changelog
61+
command: |
62+
cat > changelog.md <<EOF
63+
## Installation
64+
65+
### One-liner (Linux/macOS)
66+
curl -fsSL https://docspring.github.io/cigen/install.sh | sh
67+
68+
### Direct downloads
69+
- macOS (Intel): https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.tag }}/cigen-macos-amd64.tar.gz
70+
- macOS (Apple Silicon): https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.tag }}/cigen-macos-arm64.tar.gz
71+
- Linux (x86_64): https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.tag }}/cigen-linux-amd64.tar.gz
72+
- Linux (ARM64): https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.tag }}/cigen-linux-arm64.tar.gz
73+
EOF
74+
75+
- name: Create GitHub Release
76+
uses: softprops/action-gh-release@v2
77+
with:
78+
tag_name: ${{ steps.version.outputs.tag }}
79+
name: CIGen v${{ steps.version.outputs.version }}
80+
body_path: changelog.md
81+
draft: false
82+
prerelease: ${{ contains(steps.version.outputs.tag, '-') }}
83+
files: |
84+
artifacts/**/*.tar.gz
85+
artifacts/**/*.sha256

0 commit comments

Comments
 (0)