Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 6 additions & 2 deletions .github/actions/setup-moon/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: Set up Moon
description: Install verified Node.js, Moon, and Bun binaries and optionally hydrate JavaScript workspace dependencies.

inputs:
cache-partition:
description: Stable task group or target; matrix jobs must keep independent cache writers.
required: false
default: "default"
task-cache:
description: Restore/save Moon task outputs; disable for planning and uncached finalizers.
required: false
Expand Down Expand Up @@ -99,9 +103,9 @@ runs:
path: |
.moon/cache/blobs
.moon/cache/manifests
key: moon-task-cache-v2-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}-${{ strategy.job-index }}-${{ hashFiles('.prototools', '.moon/toolchains.yml') }}-${{ github.sha }}
key: moon-task-cache-v3-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}-${{ inputs.cache-partition }}-${{ hashFiles('.prototools', '.moon/toolchains.yml') }}-${{ github.sha }}
restore-keys: |
moon-task-cache-v2-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}-${{ strategy.job-index }}-${{ hashFiles('.prototools', '.moon/toolchains.yml') }}-
moon-task-cache-v3-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}-${{ inputs.cache-partition }}-${{ hashFiles('.prototools', '.moon/toolchains.yml') }}-

- name: Hydrate Moon plugins
shell: bash
Expand Down
107 changes: 0 additions & 107 deletions .github/scripts/moon-producer-receipt.mts

This file was deleted.

8 changes: 5 additions & 3 deletions .github/scripts/moon-task-capabilities.mts
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,14 @@ export function groupTargets(targets, { maxTargets = MAX_TARGETS_PER_JOB } = {})
byCapabilities.set(key, [...(byCapabilities.get(key) ?? []), target]);
}
const groups = [];
for (const targetsWithSameSetup of [...byCapabilities.values()]) {
const rows = [];
for (const [key, targetsWithSameSetup] of byCapabilities) {
for (let index = 0; index < targetsWithSameSetup.length; index += maxTargets) {
groups.push(targetsWithSameSetup.slice(index, index + maxTargets));
const batch = targetsWithSameSetup.slice(index, index + maxTargets);
groups.push(batch);
rows.push({ ...groupRow(batch), cache_partition: `${key}-${index / maxTargets}` });
}
}
const rows = groups.map(groupRow);
return rows.map((row, index) => {
if (rows.filter(({ label }) => label === row.label).length === 1) return row;
// A component may have separate setup profiles or span multiple batches.
Expand Down
18 changes: 18 additions & 0 deletions .github/scripts/moon-task-capabilities.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,24 @@ describe('Moon task capabilities', () => {
assert.equal(new Set(labels(targets)).size, labels(targets).length);
});

test('keeps cache partitions stable across unrelated groups and separates batch writers', () => {
const taskMap = tasks(
{ target: 'a:check' },
{ target: 'rust:first', tags: ['requires-rust'] },
{ target: 'rust:second', tags: ['requires-rust'] },
);
const targets = [...taskMap.values()].map((task) => matrixTarget(task, 'deep', taskMap));
const rustOnly = groupTargets(targets.slice(1), { maxTargets: 1 });
const withUnrelated = groupTargets(targets, { maxTargets: 1 }).filter(
({ requires_rust }) => requires_rust,
);
assert.deepEqual(
withUnrelated.map(({ cache_partition }) => cache_partition),
rustOnly.map(({ cache_partition }) => cache_partition),
);
assert.equal(new Set(withUnrelated.map(({ cache_partition }) => cache_partition)).size, 2);
});

test('rejects duplicate targets and invalid shard limits', () => {
const row = {
target: 'repo:check',
Expand Down
59 changes: 0 additions & 59 deletions .github/scripts/release-candidate-lib.mts
Original file line number Diff line number Diff line change
Expand Up @@ -352,65 +352,6 @@ export function assertCandidateBindingShape(candidate) {
candidate?.schemaVersion === 2,
`release candidate schemaVersion must be 2, got ${candidate?.schemaVersion}`,
);
if (candidate.producers !== undefined) {
assert(Array.isArray(candidate.producers), 'candidate producers must be a list');
const targets = new Set();
for (const receipt of candidate.producers) {
assert(
typeof receipt.target === 'string' && !targets.has(receipt.target),
'duplicate or invalid producer',
);
targets.add(receipt.target);
positiveInteger(candidate.runAttempt, 'candidate runAttempt');
positiveInteger(receipt.producer?.runAttempt, 'producer receipt runAttempt');
// Failed-job reruns retain successful producers from earlier attempts.
assert(
receipt.producer?.sha === candidate.sha &&
receipt.producer?.runId === candidate.runId &&
receipt.producer.runAttempt <= candidate.runAttempt,
'producer receipt must match the qualification SHA/run and not exceed its attempt',
);
assert(
Number.isSafeInteger(receipt.artifact?.id) &&
receipt.artifact.id > 0 &&
Number.isSafeInteger(receipt.artifact.size) &&
receipt.artifact.size > 0 &&
/^sha256:[0-9a-f]{64}$/.test(receipt.artifact.digest),
'producer artifact identity is invalid',
);
assert(
receipt.toolchain?.moon &&
receipt.toolchain?.bun &&
receipt.toolchain?.typescript &&
receipt.toolchain.target === 'portable-typescript',
'producer toolchain identity is incomplete',
);
assert(typeof receipt.eligible === 'boolean', 'producer eligibility is missing');
if (!receipt.eligible) {
assert(
typeof receipt.reason === 'string' && receipt.reason.length > 0,
'ineligible producer requires a reason',
);
continue;
}
assert(
typeof receipt.cacheHit === 'boolean' && Array.isArray(receipt.hashes),
'producer execution evidence is missing',
);
const hashes = new Map(receipt.hashes.map((entry) => [entry.target, entry.hash]));
assert(
/^[0-9a-f]{64}$/.test(receipt.taskHash ?? '') &&
hashes.size === receipt.hashes.length &&
hashes.get(receipt.target) === receipt.taskHash,
'producer hash chain is inconsistent',
);
for (const entry of receipt.hashes) {
assert(/^[0-9a-f]{64}$/.test(entry.hash), 'producer hash is invalid');
for (const [dependency, hash] of Object.entries(entry.dependencies))
assert(hashes.get(dependency) === hash, 'producer dependency hash is incomplete');
}
}
}
assert(
candidate.affectedPlan !== null && typeof candidate.affectedPlan === 'object',
'release candidate affectedPlan is missing',
Expand Down
2 changes: 2 additions & 0 deletions .github/scripts/require-workflow-success.sh
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ while true; do
fi
if [[ "$status" -eq 75 ]]; then
echo "transient GitHub read budget exhausted while inspecting $workflow run $run_id; the waiter remains active"
# An unread candidate is unknown, so absence cannot authorize a dispatch.
inventory_ready=false
continue
fi
echo "$workflow run $run_id does not satisfy the required job/artifact gate"
Expand Down
1 change: 0 additions & 1 deletion .github/scripts/write-release-candidate.mts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ const candidate = {
ref: requiredEnv('GITHUB_REF'),
sha: checkedOutSha,
tree,
producers: JSON.parse(process.env.PRODUCER_RECEIPTS_JSON || '[]'),
affectedPlan,
evidenceRequirements: {
wasixReleaseRegression: wasixRequired,
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/broker-runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ jobs:

- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: broker-${{ matrix.target }}

- name: Set up Rust
uses: ./.github/actions/setup-rust
Expand Down
34 changes: 14 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ jobs:
- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: ${{ matrix.cache_partition }}
install-workspace: ${{ matrix.requires_workspace && 'true' || 'false' }}

- name: Set up Rust
Expand Down Expand Up @@ -435,6 +436,7 @@ jobs:
- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: ${{ matrix.cache_partition }}
install-workspace: ${{ matrix.requires_workspace && 'true' || 'false' }}

- name: Set up Rust
Expand Down Expand Up @@ -595,6 +597,8 @@ jobs:

- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: ${{ matrix.target }}

- name: Set up Rust
uses: ./.github/actions/setup-rust
Expand Down Expand Up @@ -782,6 +786,8 @@ jobs:

- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: ${{ matrix.target }}

- name: Set up Rust
uses: ./.github/actions/setup-rust
Expand Down Expand Up @@ -873,6 +879,8 @@ jobs:

- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: ${{ matrix.target }}

- name: Set up Apple
uses: ./.github/actions/setup-apple
Expand Down Expand Up @@ -1295,6 +1303,8 @@ jobs:

- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: ${{ matrix.target }}

- name: Set up Rust
uses: ./.github/actions/setup-rust
Expand Down Expand Up @@ -1679,11 +1689,6 @@ jobs:

js-sdk-package:
name: Packages / JavaScript SDK + ICU
permissions:
contents: read
actions: read
outputs:
producer_receipt: ${{ steps.query_producer_receipt.outputs.receipt }}
needs:
- affected
- checks
Expand Down Expand Up @@ -1743,27 +1748,13 @@ jobs:
if-no-files-found: error

- name: Upload shared TypeScript query package
id: query_package_artifact
if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['js-sdk-package'], 'oliphaunt-query-ts:package') }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: oliphaunt-query-ts-sdk-package-artifacts
path: target/sdk-artifacts/oliphaunt-query-ts
if-no-files-found: error

- name: Record TypeScript query producer evidence
id: query_producer_receipt
if: ${{ steps.query_package_artifact.outcome == 'success' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CI_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
PRODUCER_ARTIFACT_ID: ${{ steps.query_package_artifact.outputs.artifact-id }}
PRODUCER_ARTIFACT_DIGEST: ${{ steps.query_package_artifact.outputs.artifact-digest }}
run: |
PRODUCER_MOON_VERSION="$(moon --version)"
export PRODUCER_MOON_VERSION
bun .github/scripts/moon-producer-receipt.mts oliphaunt-query-ts:package oliphaunt-query-ts-sdk-package-artifacts src/query/ts

native-consumers:
name: Tests / Native Consumers
needs: [affected, js-sdk-package, rust-sdk-package, liboliphaunt-native-desktop-linux, broker-runtime-linux, node-direct]
Expand Down Expand Up @@ -2445,6 +2436,8 @@ jobs:

- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: ${{ matrix.target_id }}

- name: Set up Rust
uses: ./.github/actions/setup-rust
Expand Down Expand Up @@ -2582,6 +2575,7 @@ jobs:
- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: shard-${{ matrix.shard }}
install-workspace: "false"

- name: Set up Deno for packed native tools smoke
Expand Down Expand Up @@ -2879,6 +2873,7 @@ jobs:
- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: ${{ matrix.target }}
install-workspace: "true"

- name: Set up Android
Expand Down Expand Up @@ -3496,7 +3491,6 @@ jobs:
WASIX_RELEASE_REGRESSION_REQUIRED: ${{ needs.affected.outputs.wasix_release_regression_required }}
WASIX_EVIDENCE_ROOT: target/qualification/wasix-release-regression-evidence
NATIVE_EVIDENCE_ROOT: target/qualification/native-extension-lifecycle-evidence
PRODUCER_RECEIPTS_JSON: ${{ format('[{0}]', needs.js-sdk-package.outputs.producer_receipt || '') }}
run: bash .github/scripts/release-candidate.sh write

- name: Upload exact-SHA qualification record
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/extension-artifacts-native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ jobs:

- name: Set up Moon
uses: ./.github/actions/setup-moon
with:
cache-partition: extensions-${{ matrix.target }}

- name: Set up Apple
if: ${{ runner.os == 'macOS' }}
Expand Down
Loading
Loading