mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
chore(nix): streamline pnpm deps hash maintenance (#2919)
* chore(nix): streamline pnpm deps hash maintenance Generated-By: looper 0.9.0 (runner=worker, agent=opencode) * fix(ci): satisfy actionlint in nix hash autofix Generated-By: looper 0.9.0 (runner=fixer, agent=opencode) * fix(ci): allow nix hash autofix on fork PRs Generated-By: looper 0.9.0 (runner=fixer, agent=opencode) * fix(ci): follow up nix hash review Generated-By: looper 0.9.0 (runner=fixer, agent=opencode) * fix(ci): tolerate nix hash bot token failures Generated-By: looper 0.9.0 (runner=fixer, agent=opencode)
This commit is contained in:
parent
fb1e0c819f
commit
d5659d82d4
9 changed files with 369 additions and 46 deletions
91
.github/workflows/ci.yml
vendored
91
.github/workflows/ci.yml
vendored
|
|
@ -80,7 +80,8 @@ jobs:
|
|||
tools_dev_tests_required=true
|
||||
tools_pack_tests_required=true
|
||||
fi
|
||||
if [[ "$file" == "package.json" || "$file" == "apps/"*/"package.json" || "$file" == "packages/"*/"package.json" || "$file" == "tools/"*/"package.json" || "$file" == "e2e/package.json" || "$file" == "pnpm-lock.yaml" || "$file" == "pnpm-workspace.yaml" || "$file" == "flake.nix" || "$file" == "flake.lock" || "$file" == "nix/"* || "$file" == ".github/workflows/ci.yml" || "$file" == ".github/workflows/nix-check.yml" ]]; then
|
||||
# Keep this filter in sync with flake.nix daemonWorkspacePaths / webWorkspacePaths.
|
||||
if [[ "$file" == "package.json" || "$file" == "pnpm-lock.yaml" || "$file" == "pnpm-workspace.yaml" || "$file" == "flake.nix" || "$file" == "flake.lock" || "$file" == "nix/"* || "$file" == ".github/workflows/ci.yml" || "$file" == ".github/workflows/nix-check.yml" || "$file" == ".github/workflows/nix-hash-autofix.yml" || "$file" == "apps/daemon/"* || "$file" == "apps/web/"* || "$file" == "packages/contracts/"* || "$file" == "packages/registry-protocol/"* || "$file" == "packages/agui-adapter/"* || "$file" == "packages/plugin-runtime/"* || "$file" == "packages/sidecar-proto/"* || "$file" == "packages/sidecar/"* || "$file" == "packages/platform/"* || "$file" == "packages/diagnostics/"* || "$file" == "packages/host/"* || "$file" == "assets/"* || "$file" == "plugins/"* || "$file" == "skills/"* || "$file" == "design-systems/"* || "$file" == "design-templates/"* || "$file" == "craft/"* || "$file" == "prompt-templates/"* || "$file" == "scripts/update-nix-pnpm-deps-hash.ts" ]]; then
|
||||
nix_validation_required=true
|
||||
fi
|
||||
case "$file" in
|
||||
|
|
@ -151,9 +152,97 @@ jobs:
|
|||
experimental-features = nix-command flakes
|
||||
accept-flake-config = true
|
||||
|
||||
- name: Setup Node for Nix hash refresh
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: package.json
|
||||
|
||||
- name: nix flake check
|
||||
id: flake_check
|
||||
continue-on-error: true
|
||||
run: nix flake check --print-build-logs --keep-going
|
||||
|
||||
- name: Generate Nix hash refresh patch
|
||||
id: hash_refresh
|
||||
if: ${{ github.event_name == 'pull_request' && steps.flake_check.outcome == 'failure' }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
out_dir="$RUNNER_TEMP/nix-hash-refresh"
|
||||
mkdir -p "$out_dir"
|
||||
|
||||
status="update-failed"
|
||||
if node --experimental-strip-types ./scripts/update-nix-pnpm-deps-hash.ts >"$out_dir/update.log" 2>&1; then
|
||||
if git diff --quiet --exit-code -- nix/pnpm-deps.nix; then
|
||||
status="no-change"
|
||||
else
|
||||
git diff -- nix/pnpm-deps.nix >"$out_dir/nix-pnpm-deps.patch"
|
||||
cp nix/pnpm-deps.nix "$out_dir/pnpm-deps.nix"
|
||||
status="patch-generated"
|
||||
fi
|
||||
fi
|
||||
|
||||
printf '{"status":"%s","runId":%s,"prNumber":%s,"headSha":"%s"}\n' \
|
||||
"$status" \
|
||||
'${{ github.run_id }}' \
|
||||
'${{ github.event.pull_request.number }}' \
|
||||
'${{ github.event.pull_request.head.sha }}' >"$out_dir/metadata.json"
|
||||
|
||||
echo "status=$status" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload Nix hash refresh artifact
|
||||
if: ${{ github.event_name == 'pull_request' && steps.flake_check.outcome == 'failure' && steps.hash_refresh.outputs.status != 'no-change' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nix-hash-refresh
|
||||
path: ${{ runner.temp }}/nix-hash-refresh
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
- name: Summarize Nix hash refresh guidance
|
||||
if: ${{ github.event_name == 'pull_request' && steps.flake_check.outcome == 'failure' }}
|
||||
env:
|
||||
HASH_REFRESH_STATUS: ${{ steps.hash_refresh.outputs.status }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
case "${HASH_REFRESH_STATUS:-not-run}" in
|
||||
patch-generated)
|
||||
cat >> "$GITHUB_STEP_SUMMARY" <<'EOF'
|
||||
## Generated Nix hash refresh
|
||||
|
||||
CI regenerated a patch for `nix/pnpm-deps.nix` and uploaded it as the
|
||||
`nix-hash-refresh` artifact for this run.
|
||||
|
||||
- same-repo PRs: the follow-up `nix-hash-autofix` workflow will try to
|
||||
push the hash-only patch back to the PR branch automatically;
|
||||
- fork PRs: a PR comment will include the patch and artifact guidance.
|
||||
EOF
|
||||
;;
|
||||
no-change)
|
||||
cat >> "$GITHUB_STEP_SUMMARY" <<'EOF'
|
||||
## Nix hash refresh unavailable
|
||||
|
||||
`nix flake check` failed, but `nix/pnpm-deps.nix` did not change after
|
||||
running the hash refresh helper. Inspect the Nix build logs for a
|
||||
non-hash failure.
|
||||
EOF
|
||||
;;
|
||||
*)
|
||||
cat >> "$GITHUB_STEP_SUMMARY" <<'EOF'
|
||||
## Nix hash refresh failed
|
||||
|
||||
`nix flake check` failed and the helper could not generate a hash-only
|
||||
patch. See the `nix-hash-refresh` artifact for `update.log`.
|
||||
EOF
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Fail when Nix validation fails
|
||||
if: ${{ steps.flake_check.outcome == 'failure' }}
|
||||
run: exit 1
|
||||
|
||||
preflight:
|
||||
name: Preflight
|
||||
needs: [change_scopes]
|
||||
|
|
|
|||
205
.github/workflows/nix-hash-autofix.yml
vendored
Normal file
205
.github/workflows/nix-hash-autofix.yml
vendored
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
name: nix-hash-autofix
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [ci]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
autofix:
|
||||
if: ${{ github.repository == 'nexu-io/open-design' && github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'failure' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check for Nix hash refresh artifact
|
||||
id: artifact
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
RUN_ID: ${{ github.event.workflow_run.id }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
artifact_id="$(gh api "repos/$REPO/actions/runs/$RUN_ID/artifacts" --jq '.artifacts[] | select(.name == "nix-hash-refresh") | .id' | head -n 1 || true)"
|
||||
if [ -z "$artifact_id" ]; then
|
||||
echo "present=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "present=true" >> "$GITHUB_OUTPUT"
|
||||
echo "artifact_id=$artifact_id" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Download Nix hash refresh artifact
|
||||
if: ${{ steps.artifact.outputs.present == 'true' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
ARTIFACT_ID: ${{ steps.artifact.outputs.artifact_id }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "$RUNNER_TEMP/nix-hash-refresh"
|
||||
gh api \
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
"repos/$REPO/actions/artifacts/$ARTIFACT_ID/zip" > "$RUNNER_TEMP/nix-hash-refresh.zip"
|
||||
unzip -q "$RUNNER_TEMP/nix-hash-refresh.zip" -d "$RUNNER_TEMP/nix-hash-refresh"
|
||||
|
||||
- name: Read PR and patch metadata
|
||||
if: ${{ steps.artifact.outputs.present == 'true' }}
|
||||
id: meta
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
WORKFLOW_PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number || '' }}
|
||||
WORKFLOW_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
status="$(python3 -c 'import json, sys; data = json.load(open(sys.argv[1], "r", encoding="utf-8")); print(data.get("status", "missing"))' "$RUNNER_TEMP/nix-hash-refresh/metadata.json")"
|
||||
artifact_head_sha="$(python3 -c 'import json, sys; data = json.load(open(sys.argv[1], "r", encoding="utf-8")); print(data.get("headSha", ""))' "$RUNNER_TEMP/nix-hash-refresh/metadata.json")"
|
||||
|
||||
pr_number="$WORKFLOW_PR_NUMBER"
|
||||
if [ -z "$pr_number" ]; then
|
||||
pr_number="$(gh api "repos/$REPO/commits/$WORKFLOW_HEAD_SHA/pulls" --jq '.[0].number // empty')"
|
||||
fi
|
||||
if ! [[ "$pr_number" =~ ^[0-9]+$ ]]; then
|
||||
echo "Unable to derive PR number for workflow head $WORKFLOW_HEAD_SHA." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pr_json="$(gh api "repos/$REPO/pulls/$pr_number")"
|
||||
head_repo="$(printf '%s' "$pr_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["head"]["repo"]["full_name"])')"
|
||||
head_ref="$(printf '%s' "$pr_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["head"]["ref"])')"
|
||||
head_sha="$(printf '%s' "$pr_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["head"]["sha"])')"
|
||||
{
|
||||
echo "status=$status"
|
||||
echo "artifact_head_sha=$artifact_head_sha"
|
||||
echo "pr_number=$pr_number"
|
||||
echo "head_repo=$head_repo"
|
||||
echo "head_ref=$head_ref"
|
||||
echo "head_sha=$head_sha"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
if [ -n "$artifact_head_sha" ] && [ "$artifact_head_sha" = "$head_sha" ]; then
|
||||
echo "head_sha_matches=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "head_sha_matches=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
if [ "$head_repo" = "$REPO" ] && [ "$status" = "patch-generated" ] && [ "$artifact_head_sha" = "$head_sha" ]; then
|
||||
echo "can_autopush=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "can_autopush=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Detect bot credentials
|
||||
if: ${{ steps.meta.outputs.can_autopush == 'true' }}
|
||||
id: bot-secrets
|
||||
env:
|
||||
BOT_APP_ID: ${{ secrets.BOT_APP_ID }}
|
||||
BOT_APP_PRIVATE_KEY: ${{ secrets.BOT_APP_PRIVATE_KEY }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ -n "${BOT_APP_ID}" ] && [ -n "${BOT_APP_PRIVATE_KEY}" ]; then
|
||||
echo "present=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "present=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Generate Open Design bot token
|
||||
if: ${{ steps.meta.outputs.can_autopush == 'true' && steps.bot-secrets.outputs.present == 'true' }}
|
||||
id: bot-token
|
||||
continue-on-error: true
|
||||
uses: actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: ${{ secrets.BOT_APP_ID }}
|
||||
private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }}
|
||||
owner: nexu-io
|
||||
repositories: open-design
|
||||
permission-contents: write
|
||||
|
||||
- name: Checkout PR branch for auto-apply
|
||||
if: ${{ steps.meta.outputs.can_autopush == 'true' && steps.bot-token.outcome == 'success' }}
|
||||
uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
repository: ${{ steps.meta.outputs.head_repo }}
|
||||
ref: ${{ steps.meta.outputs.head_ref }}
|
||||
token: ${{ steps.bot-token.outputs.token }}
|
||||
|
||||
- name: Apply generated hash patch
|
||||
if: ${{ steps.meta.outputs.can_autopush == 'true' && steps.bot-token.outcome == 'success' }}
|
||||
id: apply
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
patch_path="$RUNNER_TEMP/nix-hash-refresh/nix-pnpm-deps.patch"
|
||||
if [ ! -f "$patch_path" ]; then
|
||||
echo "applied=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
git apply --check "$patch_path"
|
||||
git apply "$patch_path"
|
||||
changed_files="$(git diff --name-only)"
|
||||
if [ "$changed_files" != "nix/pnpm-deps.nix" ]; then
|
||||
echo "Unexpected files changed after applying hash patch:" >&2
|
||||
printf '%s\n' "$changed_files" >&2
|
||||
exit 1
|
||||
fi
|
||||
if git diff --quiet --exit-code; then
|
||||
echo "applied=false" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "applied=true" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Commit and push generated hash refresh
|
||||
if: ${{ steps.meta.outputs.can_autopush == 'true' && steps.bot-token.outcome == 'success' && steps.apply.outputs.applied == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git config user.name 'open-design-bot[bot]'
|
||||
git config user.email '282769551+open-design-bot[bot]@users.noreply.github.com'
|
||||
git add nix/pnpm-deps.nix
|
||||
git commit -m 'chore(nix): refresh pnpm deps hash'
|
||||
git push origin "HEAD:${{ steps.meta.outputs.head_ref }}"
|
||||
|
||||
- name: Upsert fork/manual patch comment
|
||||
if: ${{ steps.artifact.outputs.present == 'true' && steps.meta.outputs.head_sha_matches == 'true' && (steps.meta.outputs.can_autopush != 'true' || steps.bot-token.outcome != 'success' || steps.apply.outputs.applied != 'true') }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
PR_NUMBER: ${{ steps.meta.outputs.pr_number }}
|
||||
HASH_REFRESH_STATUS: ${{ steps.meta.outputs.status }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
body_file="$RUNNER_TEMP/nix-hash-refresh-comment.md"
|
||||
patch_file="$RUNNER_TEMP/nix-hash-refresh/nix-pnpm-deps.patch"
|
||||
marker='<!-- nix-hash-refresh -->'
|
||||
|
||||
{
|
||||
printf '%s\n' "$marker"
|
||||
if [ "${HASH_REFRESH_STATUS}" = 'patch-generated' ]; then
|
||||
printf "A generated Nix hash refresh is available for this PR.\n\n"
|
||||
printf "Apply the patch from the \`nix-hash-refresh\` artifact attached to the failed \`ci\` run, or paste the diff below into \`git apply\`:\n\n"
|
||||
printf '```diff\n'
|
||||
if [ -f "$patch_file" ]; then
|
||||
cat "$patch_file"
|
||||
else
|
||||
printf '(artifact did not include nix-pnpm-deps.patch)\n'
|
||||
fi
|
||||
printf '\n```\n'
|
||||
else
|
||||
printf "The failed \`ci\` run attempted to refresh \`nix/pnpm-deps.nix\`, but it could not produce a hash-only patch.\n\n"
|
||||
printf "Download the \`nix-hash-refresh\` artifact from that run and inspect \`update.log\` for details.\n"
|
||||
fi
|
||||
} > "$body_file"
|
||||
|
||||
comment_id="$(gh api --paginate "repos/$REPO/issues/$PR_NUMBER/comments" --jq ".[] | select(.body | contains(\"$marker\")) | .id" | tail -n 1 || true)"
|
||||
if [ -n "$comment_id" ]; then
|
||||
gh api --method PATCH "repos/$REPO/issues/comments/$comment_id" --field body="$(cat "$body_file")" >/dev/null
|
||||
else
|
||||
gh api --method POST "repos/$REPO/issues/$PR_NUMBER/comments" --field body="$(cat "$body_file")" >/dev/null
|
||||
fi
|
||||
|
|
@ -167,7 +167,7 @@ root `pnpm tools-pr` script without a new explicit maintainer decision.
|
|||
## Validation strategy
|
||||
|
||||
- After package, workspace, or command-entry changes, run `pnpm install` so workspace links and generated dist entries stay fresh.
|
||||
- Treat every `pnpm-lock.yaml` change as requiring a Nix pnpm deps hash refresh check. Use `pnpm nix:update-hash` to regenerate `nix/pnpm-deps.nix`, then re-run `nix flake check --print-build-logs --keep-going` (or rely on the PR `Validate workspace` gate if Nix is unavailable locally).
|
||||
- Treat every `pnpm-lock.yaml` change as requiring a Nix pnpm deps hash refresh check. `nix/pnpm-deps.nix` is a generated lock artifact; use `pnpm nix:update-hash` only when intentionally maintaining Nix packaging, then re-run `nix flake check --print-build-logs --keep-going`. Contributors without Nix can rely on the PR `Validate workspace` gate, which now uploads or auto-applies the generated hash-only fix when possible.
|
||||
- Before marking regular work ready, run at least `pnpm guard` and `pnpm typecheck`, plus the package-scoped tests/builds that match the files changed. Do not use or add root `pnpm test`/`pnpm build` aliases.
|
||||
- For local web runtime loops, prefer `pnpm tools-dev run web --daemon-port <port> --web-port <port>`.
|
||||
- On a GUI-capable machine, validate desktop by running `pnpm tools-dev`, then `pnpm tools-dev inspect desktop status`.
|
||||
|
|
|
|||
44
flake.nix
44
flake.nix
|
|
@ -40,12 +40,34 @@
|
|||
perSystem = flake-utils.lib.eachDefaultSystem (system: let
|
||||
pkgs = import nixpkgs {inherit system;};
|
||||
nodejs = pkgs.nodejs_24;
|
||||
daemonSrc = filterProjectSource [
|
||||
# Keep in sync with .github/workflows/ci.yml change_scopes
|
||||
# nix_validation_required filter.
|
||||
daemonWorkspacePaths = [
|
||||
"packages/contracts"
|
||||
"packages/registry-protocol"
|
||||
"packages/agui-adapter"
|
||||
"packages/plugin-runtime"
|
||||
"packages/sidecar-proto"
|
||||
"packages/sidecar"
|
||||
"packages/platform"
|
||||
"packages/diagnostics"
|
||||
"apps/daemon"
|
||||
];
|
||||
# Keep in sync with .github/workflows/ci.yml change_scopes
|
||||
# nix_validation_required filter.
|
||||
webWorkspacePaths = [
|
||||
"packages/contracts"
|
||||
"packages/host"
|
||||
"packages/platform"
|
||||
"packages/sidecar"
|
||||
"packages/sidecar-proto"
|
||||
"apps/web"
|
||||
];
|
||||
daemonSrc = filterProjectSource ([
|
||||
"package.json"
|
||||
"pnpm-lock.yaml"
|
||||
"pnpm-workspace.yaml"
|
||||
"tsconfig.json"
|
||||
"scripts"
|
||||
"assets"
|
||||
"plugins"
|
||||
"skills"
|
||||
|
|
@ -53,21 +75,15 @@
|
|||
"design-templates"
|
||||
"craft"
|
||||
"prompt-templates"
|
||||
"apps/daemon"
|
||||
"packages"
|
||||
];
|
||||
webSrc = filterProjectSource [
|
||||
]
|
||||
++ daemonWorkspacePaths);
|
||||
webSrc = filterProjectSource ([
|
||||
"package.json"
|
||||
"pnpm-lock.yaml"
|
||||
"pnpm-workspace.yaml"
|
||||
"tsconfig.json"
|
||||
"apps/web"
|
||||
"packages/contracts"
|
||||
"packages/host"
|
||||
"packages/platform"
|
||||
"packages/sidecar"
|
||||
"packages/sidecar-proto"
|
||||
];
|
||||
]
|
||||
++ webWorkspacePaths);
|
||||
|
||||
# nixpkgs ships pnpm 10.33.0; the repo's package.json declares
|
||||
# `engines.pnpm: ">=10.33.2 <11"` and pnpm refuses to install
|
||||
|
|
@ -92,10 +108,12 @@
|
|||
daemon = pkgs.callPackage ./nix/package-daemon.nix {
|
||||
inherit dream2nix nixpkgs system nodejs pnpm_10;
|
||||
src = daemonSrc;
|
||||
workspacePaths = daemonWorkspacePaths;
|
||||
};
|
||||
web = pkgs.callPackage ./nix/package-web.nix {
|
||||
inherit dream2nix nixpkgs system nodejs pnpm_10;
|
||||
src = webSrc;
|
||||
workspacePaths = webWorkspacePaths;
|
||||
};
|
||||
in {
|
||||
packages = {
|
||||
|
|
|
|||
|
|
@ -220,27 +220,42 @@ Never inline a secret with `pkgs.writeText` or `home.file`.
|
|||
|
||||
## First-build hash pinning
|
||||
|
||||
`nix/pnpm-deps.nix` is the single source of truth for the vendored pnpm
|
||||
store hash used by both `nix/package-daemon.nix` and
|
||||
`nix/package-web.nix`. If `pnpm-lock.yaml` changes, run:
|
||||
`nix/pnpm-deps.nix` is the generated single source of truth for the
|
||||
vendored pnpm store hash used by both `nix/package-daemon.nix` and
|
||||
`nix/package-web.nix`. Treat it like a lock artifact, not a hand-edited
|
||||
source file. If `pnpm-lock.yaml` changes and you are intentionally
|
||||
maintaining the Nix packaging, run:
|
||||
|
||||
```bash
|
||||
pnpm nix:update-hash
|
||||
```
|
||||
|
||||
The script temporarily swaps one consumer to `lib.fakeHash`, runs
|
||||
`nix build .#web --print-build-logs`, extracts the expected hash from the
|
||||
failure output, writes it back into `nix/pnpm-deps.nix`, and restores the
|
||||
consumer file.
|
||||
The script temporarily swaps one consumer to `lib.fakeHash`, runs the
|
||||
matching `nix build .#<consumer> --print-build-logs`, extracts the
|
||||
expected hash from the failure output, writes it back into
|
||||
`nix/pnpm-deps.nix`, and restores the consumer file. The script runs via
|
||||
`node --experimental-strip-types`, so CI can invoke it without first
|
||||
installing the workspace.
|
||||
|
||||
## CI
|
||||
|
||||
`.github/workflows/nix-check.yml` runs `nix flake check` on pushes to
|
||||
`main` and can also be started manually with `workflow_dispatch`.
|
||||
|
||||
Pull requests that touch Nix or dependency inputs are validated earlier in
|
||||
Pull requests that touch Nix inputs, daemon/web Nix build closures, or the
|
||||
generated hash maintenance workflows are validated earlier in
|
||||
`.github/workflows/ci.yml` via the required `Validate workspace` gate.
|
||||
That PR path runs `nix flake check` when `pnpm-lock.yaml`, package
|
||||
manifests, `flake.*`, `nix/**`, or the Nix workflows change, so fixed-
|
||||
output hash drift is caught before merge while keeping unrelated PRs off
|
||||
the slower Nix path.
|
||||
That PR path runs `nix flake check` for `flake.*`, `nix/**`, root lock and
|
||||
workspace manifests, and files that are actually in the daemon/web Nix
|
||||
closures. The flake also filters each derivation down to only the workspace
|
||||
packages it actually installs, so unrelated package/tool changes stay off the
|
||||
slower Nix path and do not churn the other derivation's pnpm store hash.
|
||||
|
||||
When a PR run fails because `nix/pnpm-deps.nix` is stale, the CI job also
|
||||
tries to regenerate a hash-only patch:
|
||||
|
||||
- same-repo PRs get a bot-authored commit pushed back to the PR branch when
|
||||
the generated patch only touches `nix/pnpm-deps.nix`;
|
||||
- fork PRs get a PR comment plus a workflow artifact containing the patch;
|
||||
- the failing run still stays red until the generated patch lands and a
|
||||
fresh validation run passes.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
fetchPnpmDeps,
|
||||
pnpmConfigHook,
|
||||
src,
|
||||
workspacePaths,
|
||||
makeWrapper,
|
||||
python3,
|
||||
gnumake,
|
||||
|
|
@ -40,10 +41,13 @@ let
|
|||
version = (lib.importJSON ../package.json).version;
|
||||
|
||||
pnpmDepsHash = (import ./pnpm-deps.nix).daemonHash;
|
||||
pnpmWorkspaceFilters = map (workspacePath: "./${workspacePath}") workspacePaths;
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
inherit pname version src;
|
||||
|
||||
pnpmWorkspaces = pnpmWorkspaceFilters;
|
||||
|
||||
nativeBuildInputs = [
|
||||
nodejs
|
||||
pnpm_10
|
||||
|
|
@ -60,6 +64,7 @@ in
|
|||
pnpmDeps = fetchPnpmDeps {
|
||||
inherit (finalAttrs) pname version src;
|
||||
hash = pnpmDepsHash;
|
||||
pnpmWorkspaces = pnpmWorkspaceFilters;
|
||||
fetcherVersion = 3;
|
||||
};
|
||||
|
||||
|
|
@ -128,17 +133,7 @@ in
|
|||
exit 1
|
||||
fi
|
||||
|
||||
for target in \
|
||||
packages/contracts \
|
||||
packages/registry-protocol \
|
||||
packages/agui-adapter \
|
||||
packages/plugin-runtime \
|
||||
packages/sidecar-proto \
|
||||
packages/sidecar \
|
||||
packages/platform \
|
||||
packages/diagnostics \
|
||||
apps/daemon
|
||||
do
|
||||
for target in ${lib.escapeShellArgs workspacePaths}; do
|
||||
pnpm -C "$target" run --if-present build
|
||||
done
|
||||
runHook postBuild
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
fetchPnpmDeps,
|
||||
pnpmConfigHook,
|
||||
src,
|
||||
workspacePaths,
|
||||
}:
|
||||
# Builds the @open-design/web Next.js static export.
|
||||
#
|
||||
|
|
@ -27,10 +28,14 @@ let
|
|||
version = (lib.importJSON ../package.json).version;
|
||||
|
||||
pnpmDepsHash = (import ./pnpm-deps.nix).webHash;
|
||||
pnpmWorkspaceFilters = map (workspacePath: "./${workspacePath}") workspacePaths;
|
||||
dependencyBuildPaths = lib.filter (workspacePath: workspacePath != "apps/web") workspacePaths;
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
inherit pname version src;
|
||||
|
||||
pnpmWorkspaces = pnpmWorkspaceFilters;
|
||||
|
||||
nativeBuildInputs = [
|
||||
nodejs
|
||||
pnpm_10
|
||||
|
|
@ -40,6 +45,7 @@ in
|
|||
pnpmDeps = fetchPnpmDeps {
|
||||
inherit (finalAttrs) pname version src;
|
||||
hash = pnpmDepsHash;
|
||||
pnpmWorkspaces = pnpmWorkspaceFilters;
|
||||
fetcherVersion = 3;
|
||||
};
|
||||
|
||||
|
|
@ -50,13 +56,7 @@ in
|
|||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
for target in \
|
||||
packages/contracts \
|
||||
packages/host \
|
||||
packages/sidecar-proto \
|
||||
packages/sidecar \
|
||||
packages/platform
|
||||
do
|
||||
for target in ${lib.escapeShellArgs dependencyBuildPaths}; do
|
||||
pnpm -C "$target" run --if-present build
|
||||
done
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
# Vendored pnpm store hashes for the workspace packages built by the flake.
|
||||
# Generated lock artifact; do not hand-edit outside intentional Nix maintenance.
|
||||
#
|
||||
# The daemon and web derivations now build from different filtered source
|
||||
# trees, so each fetchPnpmDeps invocation needs its own fixed-output hash.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"tools-dev": "pnpm exec tools-dev",
|
||||
"tools-pack": "pnpm exec tools-pack",
|
||||
"tools-serve": "pnpm exec tools-serve",
|
||||
"nix:update-hash": "tsx ./scripts/update-nix-pnpm-deps-hash.ts",
|
||||
"nix:update-hash": "node --experimental-strip-types ./scripts/update-nix-pnpm-deps-hash.ts",
|
||||
"guard": "tsx ./scripts/guard.ts && node --import tsx --test scripts/style-policy.test.ts scripts/approve-fork-pr-workflows.test.ts",
|
||||
"i18n:check": "tsx ./scripts/i18n-check.ts",
|
||||
"i18n:coverage": "tsx ./scripts/i18n-coverage-report.ts",
|
||||
|
|
|
|||
Loading…
Reference in a new issue