Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
d2c4f5b
chore(beads): create epic for omnix template substitution and CI work…
cameronraysmith Feb 17, 2026
7b6d953
chore(beads): mark pnt-3zn epic in_progress
cameronraysmith Feb 17, 2026
f5bf4a4
feat(template): add camelCase omnix parameter for Nix variable names
cameronraysmith Feb 17, 2026
64d6b4c
fix(docs): replace Jinja placeholders with omnix literals in index.qmd
cameronraysmith Feb 17, 2026
ff10274
fix(docs): replace Jinja placeholders with omnix literals in _quarto.yml
cameronraysmith Feb 17, 2026
7bb0336
fix(docs): replace Jinja placeholder with omnix literal in about/inde…
cameronraysmith Feb 17, 2026
33050fb
fix(docs): replace Jinja placeholder with omnix literal in concepts/i…
cameronraysmith Feb 17, 2026
8196c28
fix(docs): replace Jinja placeholders with omnix literals in getting-…
cameronraysmith Feb 17, 2026
6b8d909
fix(docs): replace Jinja placeholders with omnix literals in installa…
cameronraysmith Feb 17, 2026
e28669b
fix(docs): replace Jinja placeholders with omnix literals in developm…
cameronraysmith Feb 17, 2026
ddcd59a
fix(docs): replace Jinja placeholder with omnix literal in developmen…
cameronraysmith Feb 17, 2026
14960dc
fix(docs): replace Jinja placeholder with omnix literal in context/in…
cameronraysmith Feb 17, 2026
e04604c
fix(docs): replace Jinja placeholder with omnix literal in context/co…
cameronraysmith Feb 17, 2026
1a9b101
fix(docs): replace Jinja placeholder with omnix literal in architectu…
cameronraysmith Feb 17, 2026
206b4bd
fix(docs): replace Jinja placeholder with omnix literal in architectu…
cameronraysmith Feb 17, 2026
3dd9d95
fix(docs): replace Jinja placeholder with omnix literal in requiremen…
cameronraysmith Feb 17, 2026
ae803dd
fix(docs): replace Jinja placeholder with omnix literal in requiremen…
cameronraysmith Feb 17, 2026
78a2e20
fix(docs): replace Jinja placeholder with omnix literal in traceabili…
cameronraysmith Feb 17, 2026
7fa820e
fix(docs): replace Jinja placeholder with omnix literal in traceabili…
cameronraysmith Feb 17, 2026
7d3990f
fix(docs): replace Jinja placeholder with omnix literal in work-items…
cameronraysmith Feb 17, 2026
c47395c
fix(template): align root package.json name and description with omni…
cameronraysmith Feb 17, 2026
aaeecef
fix(template): align pnt-cli package.json description with omnix plac…
cameronraysmith Feb 17, 2026
2f59dd1
fix(template): align pnt-functional package.json description with omn…
cameronraysmith Feb 17, 2026
03f56ac
fix(template): align python-nix-template package.json description wit…
cameronraysmith Feb 17, 2026
3ca68e0
feat(template): gate wheel workflow files on pyo3-package parameter
cameronraysmith Feb 17, 2026
ca37c27
feat(ci): add standalone wheel-release workflow for pyo3 packages
cameronraysmith Feb 17, 2026
c8258e6
refactor(ci): decouple wheel build from package-release workflow
cameronraysmith Feb 17, 2026
4554e94
refactor(ci): remove build-wheels from package discovery and release …
cameronraysmith Feb 17, 2026
fba3893
fix(ci): resolve SC2012 use find instead of ls in package discovery
cameronraysmith Feb 17, 2026
c79bc6a
fix(ci): resolve SC2086 and SC2129 in package-release.yaml
cameronraysmith Feb 17, 2026
4041977
fix(ci): resolve SC2001 use parameter expansion in wheel-release.yaml
cameronraysmith Feb 17, 2026
1feaf21
fix(ci): resolve SC2086 quote matrix.package.path in ci.yaml
cameronraysmith Feb 17, 2026
cc5b271
chore(beads): close pnt-3zn issues 1-5
cameronraysmith Feb 17, 2026
0d10d30
chore(pnt-functional): bump version to 0.2.2
cameronraysmith Feb 17, 2026
10e5dec
chore(pnt-cli): bump version to 0.1.3
cameronraysmith Feb 17, 2026
c1f5cd9
chore(python-nix-template): bump version to 0.2.1
cameronraysmith Feb 17, 2026
763c047
fix(ci): add camelCase param to template workflow test invocations
cameronraysmith Feb 17, 2026
82c2e1c
refactor(ci): remove redundant maximize-build-space step from deploy-…
cameronraysmith Feb 17, 2026
6fd27b9
chore(beads): add deploy-docs alignment issues pnt-3zn.6-10
cameronraysmith Feb 17, 2026
6e711e8
chore(beads): update pnt-3zn.6,7,10 descriptions for Quarto context
cameronraysmith Feb 17, 2026
6519167
chore(beads): add local verification requirement to pnt-3zn.7
cameronraysmith Feb 17, 2026
6020c6d
feat(deploy): align wrangler.jsonc with Workers static assets best pr…
cameronraysmith Feb 17, 2026
749599d
feat(docs): replace deploy recipes with sops-based credential pattern
cameronraysmith Feb 17, 2026
810efae
docs: update README recipe listing for renamed deploy recipes
cameronraysmith Feb 17, 2026
3cdafef
fix(docs): remove unsupported --limit flag from docs-versions recipe
cameronraysmith Feb 17, 2026
73a3fa4
fixup! docs: update README recipe listing for renamed deploy recipes
cameronraysmith Feb 17, 2026
0a291d9
chore(beads): close pnt-3zn.6 and pnt-3zn.7
cameronraysmith Feb 17, 2026
705484b
fix(docs): align deploy recipe output and error handling with referen…
cameronraysmith Feb 17, 2026
4089daa
refactor(ci): restructure deploy-docs to single-job direct deploy via…
cameronraysmith Feb 17, 2026
5880c8e
feat(ci): add sanitized_branch computation to set-variables job
cameronraysmith Feb 17, 2026
f0e96e2
feat(ci): pass deploy-docs inputs from preview-docs-deploy caller
cameronraysmith Feb 17, 2026
5bc8c88
feat(ci): pass deploy-docs inputs from production-docs-deploy caller
cameronraysmith Feb 17, 2026
921378c
feat(ci): add execution cache to deploy-docs workflow
cameronraysmith Feb 17, 2026
96d95ce
chore(beads): close pnt-3zn.8-10, epic 10/10 complete
cameronraysmith Feb 17, 2026
f637fb5
fix(docs): use recursive glob for quarto_ipynb gitignore pattern
cameronraysmith Feb 17, 2026
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
133 changes: 72 additions & 61 deletions .beads/issues.jsonl

Large diffs are not rendered by default.

43 changes: 24 additions & 19 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ jobs:
checkout_ref: ${{ steps.set-variables.outputs.checkout_ref }}
checkout_rev: ${{ steps.set-variables.outputs.checkout_rev }}
has_docs: ${{ steps.check-docs.outputs.has_docs }}
sanitized_branch: ${{ steps.set-variables.outputs.sanitized_branch }}
packages: ${{ steps.discover-packages.outputs.packages }}
force_ci: ${{ steps.set-variables.outputs.force_ci }}

Expand Down Expand Up @@ -161,30 +162,30 @@ jobs:
CHECKOUT_REV="${{ github.sha }}"
fi

# Sanitize branch name for Cloudflare preview alias (must be valid subdomain component)
# - Replace / and other non-alphanumeric chars with -
# - Collapse consecutive hyphens, remove leading/trailing hyphens
# - Truncate to 40 chars (safe for subdomain label limit of 63)
SANITIZED_BRANCH=$(echo "$CHECKOUT_REF" | tr '/' '-' | tr -c 'a-zA-Z0-9-' '-' | sed 's/--*/-/g; s/^-//; s/-$//' | cut -c1-40)

{
echo "debug=$DEBUG"
echo "skip_ci=$SKIP_CI"
echo "skip_tests=$SKIP_TESTS"
echo "dry_run_release=$DRY_RUN_RELEASE"
echo "checkout_ref=$CHECKOUT_REF"
echo "checkout_rev=$CHECKOUT_REV"
echo "sanitized_branch=$SANITIZED_BRANCH"
echo "force_ci=$FORCE_CI"
} >> "$GITHUB_OUTPUT"

- name: Discover packages
id: discover-packages
run: |
PACKAGES=$(ls -d packages/*/pyproject.toml | while read -r f; do
PACKAGES=$(find packages -maxdepth 2 -name pyproject.toml -path '*/*/pyproject.toml' | sort | while read -r f; do
d=$(dirname "$f")
n=$(basename "$d")

# Infer build-wheels from Cargo.toml presence (maturin/pyo3 package)
if [ -f "$d/Cargo.toml" ]; then
build_wheels="true"
else
build_wheels="false"
fi

# Read per-package CI metadata from .ci.json if present
ci_json="$d/.ci.json"
if [ -f "$ci_json" ]; then
Expand All @@ -198,10 +199,9 @@ jobs:
jq -nc \
--arg name "$n" \
--arg path "$d" \
--arg build_wheels "$build_wheels" \
--arg build_images "$build_images" \
--argjson images "$images" \
'{name: $name, path: $path, "build-wheels": $build_wheels, "build-images": $build_images, images: ($images | tojson)}'
'{name: $name, path: $path, "build-images": $build_images, images: ($images | tojson)}'
done | jq -sc '.')
echo "packages=$PACKAGES" >> "$GITHUB_OUTPUT"
echo "Discovered packages: $PACKAGES"
Expand Down Expand Up @@ -488,7 +488,7 @@ jobs:
if: steps.cache.outputs.should-run == 'true'
run: |
echo "::group::Preview semantic-release version"
OUTPUT=$(nix develop --accept-flake-config -c just preview-version main ${{ matrix.package.path }} 2>&1 | tee /dev/stderr)
OUTPUT=$(nix develop --accept-flake-config -c just preview-version main "${{ matrix.package.path }}" 2>&1 | tee /dev/stderr)
echo "::endgroup::"

# Strip ANSI escape codes before parsing (script outputs colored text)
Expand Down Expand Up @@ -557,10 +557,10 @@ jobs:
key: ${{ steps.cache.outputs.cache-key }}

# ---------------------------------------------------------------------------
# job 8: preview-docs
# job 8: preview-docs-deploy
# deploy docs to preview environment (PR only)
# ---------------------------------------------------------------------------
preview-docs:
preview-docs-deploy:
needs: set-variables
if: ${{ needs.set-variables.outputs.has_docs == 'true' && needs.set-variables.outputs.skip_ci != 'true' && ( contains(github.event.pull_request.labels.*.name, 'docs-preview') || (github.event_name == 'workflow_dispatch' && inputs.run_docs_preview) ) }}
uses: ./.github/workflows/deploy-docs.yaml
Expand All @@ -573,6 +573,9 @@ jobs:
with:
debug_enabled: ${{ needs.set-variables.outputs.debug }}
branch: ${{ needs.set-variables.outputs.checkout_ref }}
sanitized_branch: ${{ needs.set-variables.outputs.sanitized_branch }}
environment: preview
force_run: ${{ needs.set-variables.outputs.force_ci }}
secrets: inherit

# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -629,26 +632,28 @@ jobs:
checkout-ref: ${{ needs.set-variables.outputs.checkout_ref }}
build-images: ${{ matrix.package.build-images }}
images-to-build: ${{ matrix.package.images }}
build-wheels: ${{ matrix.package.build-wheels || 'false' }}
secrets: inherit

# ---------------------------------------------------------------------------
# job 11: deploy-docs
# job 11: production-docs-deploy
# production docs deployment on push to main/beta
# ---------------------------------------------------------------------------
deploy-docs:
production-docs-deploy:
needs: [set-variables, test-python, nix]
if: ${{ needs.set-variables.outputs.has_docs == 'true' && github.repository_owner == 'sciexp' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') }}
uses: ./.github/workflows/deploy-docs.yaml
permissions:
contents: read
deployments: write
concurrency:
group: deploy-docs-${{ github.workflow }}-${{ github.ref_name }}
group: production-docs-deploy-${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
with:
debug_enabled: "false"
branch: ${{ github.ref_name }}
debug_enabled: ${{ needs.set-variables.outputs.debug }}
branch: ${{ needs.set-variables.outputs.checkout_ref }}
sanitized_branch: ${{ needs.set-variables.outputs.sanitized_branch }}
environment: production
force_run: ${{ needs.set-variables.outputs.force_ci }}
secrets: inherit

# ---------------------------------------------------------------------------
Expand Down
142 changes: 78 additions & 64 deletions .github/workflows/deploy-docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,54 @@ on:
inputs:
debug_enabled:
description: "Run with tmate.io debugging enabled"
required: true
required: false
type: string
default: "false"
branch:
description: "Git branch or ref to checkout"
required: true
type: string
sanitized_branch:
description: "URL-safe branch name for preview alias (auto-computed if empty)"
required: false
type: string
default: ""
environment:
description: "Deployment environment (preview or production)"
required: false
type: string
default: "preview"
force_run:
description: "Force execution even if already successful"
required: false
type: string
default: "false"
workflow_call:
inputs:
debug_enabled:
description: "Run with tmate.io debugging enabled"
required: false
type: string
default: "false"
branch:
description: "Git branch or ref to checkout"
required: true
type: string
sanitized_branch:
description: "URL-safe branch name for preview alias (auto-computed if empty)"
required: false
type: string
default: ""
environment:
description: "Deployment environment (preview or production)"
required: false
type: string
default: "production"
force_run:
description: "Force execution even if already successful"
required: false
type: string
default: "false"

defaults:
run:
Expand All @@ -32,88 +63,71 @@ permissions:
deployments: write

jobs:
build-docs:
deploy-docs:
runs-on: ubuntu-latest
environment:
name: ${{ inputs.environment }}
url: ${{ inputs.environment == 'preview' && format('https://b-{0}-python-nix-template.sciexp.workers.dev', inputs.sanitized_branch || inputs.branch) || 'https://python-nix-template.scientistexperience.net' }}
permissions:
contents: read
deployments: write
steps:
# https://github.com/easimon/maximize-build-space/blob/v10/action.yml#L121-L137
- name: Maximize build space
run: |
echo "Available storage before removing unused software:"
sudo df -h
echo
sudo rm -rf /usr/local/lib/android
echo "Available storage after removing android:"
sudo df -h
echo
sudo rm -rf /opt/hostedtoolcache/CodeQL
echo "Available storage after removing codeql:"
sudo df -h
echo

- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ inputs.branch }}
fetch-depth: 0 # for git diff in composite action

- name: Check execution cache
id: cache
uses: ./.github/actions/cached-ci-job
with:
check-name: preview-docs-deploy
hash-sources: 'docs/**/* .github/actions/setup-nix/action.yml .github/workflows/deploy-docs.yaml justfile'
force-run: ${{ inputs.force_run }}

- name: Setup Nix
if: steps.cache.outputs.should-run == 'true'
uses: ./.github/actions/setup-nix
with:
installer: quick
system: x86_64-linux
enable-cachix: true
cachix-name: ${{ vars.CACHIX_CACHE_NAME }}
cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }}

- name: Setup tmate debug session
if: inputs.debug_enabled == 'true' && steps.cache.outputs.should-run == 'true'
uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3
if: ${{ inputs.debug_enabled == 'true' }}

- name: Build docs
- name: Deploy docs
if: steps.cache.outputs.should-run == 'true'
env:
SOPS_AGE_KEY: ${{ secrets.CI_AGE_KEY }}
run: |
df -h
nix develop --accept-flake-config -c just docs-build
df -h

- name: Upload docs
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: docs-site
path: |
docs/_site
wrangler.jsonc

deploy-docs:
needs: build-docs
runs-on: ubuntu-latest
steps:
- name: Download docs
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
name: docs-site

- name: Site artifact tree
run: |
if command -v tree &> /dev/null; then
tree --du -alh
if [ "${{ inputs.environment }}" = "preview" ]; then
nix develop --accept-flake-config -c just docs-deploy-preview "${{ inputs.sanitized_branch || inputs.branch }}"
else
echo "tree command not found, skipping file tree display"
nix develop --accept-flake-config -c just docs-deploy-production
fi

- name: Deploy preview
id: deployment
uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65 # ratchet:cloudflare/wrangler-action@v3
with:
wranglerVersion: "4.37.1"
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: versions upload --preview-alias b-${{ inputs.branch }}
gitHubToken: ${{ secrets.GITHUB_TOKEN }}

- name: Preview rollout command
env:
WRANGLER_OUTPUT: ${{ steps.deployment.outputs.command-output }}
- name: Create job result marker
if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none'
shell: bash
run: |
WRANGLER_VERSION_ID=$(echo "$WRANGLER_OUTPUT" | grep -oP 'Version ID: \K[a-f0-9-]+')
echo "WRANGLER_VERSION_ID=$WRANGLER_VERSION_ID"
echo "bunx wrangler versions deploy ${WRANGLER_VERSION_ID}@100 --yes --dry-run"
mkdir -p "${{ steps.cache.outputs.cache-path }}"
cat > "${{ steps.cache.outputs.cache-path }}/marker" <<EOF
{
"success": true,
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"commit": "${{ github.sha }}",
"cache_key": "${{ steps.cache.outputs.cache-key }}",
"workflow_run_id": "${{ github.run_id }}",
"environment": "${{ inputs.environment }}",
"branch": "${{ inputs.branch }}"
}
EOF

- name: Save job result to cache
if: success() && steps.cache.outputs.should-run == 'true' && steps.cache.outputs.cache-source == 'none'
uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5
with:
path: ${{ steps.cache.outputs.cache-path }}
key: ${{ steps.cache.outputs.cache-key }}
Loading
Loading