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
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ jobs:
run: |
npm ci
npm run build
# `npm run build` runs codegen + ncc and outputs dist/gate/index.js.
# `npm run build` runs codegen + ncc and outputs gate.js + import.js.

- name: Package ado-script bundle
run: |
set -euo pipefail
cd scripts
zip -r ../ado-script.zip ado-script/dist
zip -r ../ado-script.zip ado-script/gate.js ado-script/import.js

- name: Upload release assets
env:
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ Every compiled pipeline runs as three sequential jobs:
├── scripts/ # Supporting scripts shipped as release artifacts
│ └── ado-script/ # TypeScript workspace for bundled gate.js, import.js, and future bundles
│ └── src/
│ ├── gate/ # Gate evaluator source (bundled to dist/gate/index.js)
│ ├── import/ # Runtime prompt resolver source (bundled to dist/import/index.js)
│ ├── gate/ # Gate evaluator source (bundled to gate.js)
│ ├── import/ # Runtime prompt resolver source (bundled to import.js)
│ └── shared/ # Shared modules across bundles (auth, ado-client, env-facts, types.gen.ts)
├── tests/ # Integration tests and fixtures
├── docs/ # Per-concept reference documentation (see index below)
Expand Down
26 changes: 13 additions & 13 deletions docs/ado-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ because the compiler always embeds an absolute marker path and
`import.js` is single-pass (nested markers inside the inlined body are
not re-expanded).

The bundle lives at `dist/import/index.js` and ships in the same
The bundle lives at `import.js` and ships in the same
`ado-script.zip` release asset as `gate.js`, so pipelines download it
through the same Setup-job asset flow. `import.js` uses only the Node
standard library, so the ncc bundle is small (~1.5 KB) and carries no
Expand Down Expand Up @@ -137,7 +137,7 @@ job.
## Runtime env-var contract

The compiler injects these environment variables on the
`bash: node gate/index.js` step. `gate.js` reads them via
`bash: node gate.js` step. `gate.js` reads them via
`process.env`:

| Env var | Source | Purpose |
Expand Down Expand Up @@ -187,13 +187,13 @@ scripts/ado-script/
│ ├── index.ts # main(): expand runtime-import markers in place
│ └── __tests__/ # marker, path-resolution, and single-pass coverage
├── test/ # End-to-end smoke tests
└── dist/ # ncc bundle output (gitignored)
├── gate/index.js
└── import/index.js
├── gate.js # ncc bundle output (gitignored)
└── import.js # ncc bundle output (gitignored)
```

The release workflow (`.github/workflows/release.yml`) runs
`npm ci && npm run build`, then zips `scripts/ado-script/dist/` into
`npm ci && npm run build`, then zips `scripts/ado-script/gate.js` and
`scripts/ado-script/import.js` into
the `ado-script.zip` release asset. Pipelines download that asset at
runtime by URL pinned to the compiler's `CARGO_PKG_VERSION`, verify
its SHA-256 against the `checksums.txt` asset, then extract.
Expand Down Expand Up @@ -250,7 +250,7 @@ three step strings into the Setup job:
`CARGO_PKG_VERSION`, verifies the zip's SHA-256, then
`unzip -o /tmp/ado-aw-scripts/ado-script.zip -d /tmp/ado-aw-scripts/`.
Also capped at `timeoutInMinutes: 5`.
3. **`bash: node '/tmp/ado-aw-scripts/ado-script/dist/gate/index.js'`** —
3. **`bash: node '/tmp/ado-aw-scripts/ado-script/gate.js'`** —
runs the gate with `GATE_SPEC` and the env-var contract documented
above.

Expand All @@ -263,7 +263,7 @@ the Agent job's existing `{{ prepare_steps }}` block:
1. **`NodeTool@0`** — same shape as above.
2. **`curl` download + verify + extract** — same artefact, same
verification.
3. **`bash: node '/tmp/ado-aw-scripts/ado-script/dist/import/index.js'`** —
3. **`bash: node '/tmp/ado-aw-scripts/ado-script/import.js'`** —
expands `{{#runtime-import …}}` markers in
`/tmp/awf-tools/agent-prompt.md` in place. See
[`runtime-imports.md`](runtime-imports.md) for marker syntax.
Expand Down Expand Up @@ -324,16 +324,16 @@ The IR-to-bash codegen that produces the gate step is
`scripts/ado-script/src/poll/`. Reuse anything in `src/shared/`.
2. Add a build script to `package.json`:
```json
"build:poll": "ncc build src/poll/index.ts -o dist/poll -m -t"
"build:poll": "ncc build src/poll/index.ts -o .ado-build/poll -m -t && node -e \"const fs=require('node:fs'); fs.copyFileSync('.ado-build/poll/index.js','poll.js'); fs.rmSync('.ado-build/poll',{recursive:true,force:true});\""
```
and extend `build` to also run it.
3. Add vitest tests under `src/poll/__tests__/`.
4. Wire from a new `CompilerExtension` (or extend an existing one)
that downloads `ado-script.zip` (already a release asset) and
invokes `node /tmp/ado-aw-scripts/ado-script/dist/poll/index.js`
invokes `node /tmp/ado-aw-scripts/ado-script/poll.js`
as a runtime step.
5. No release-workflow change is needed — `zip -r ado-script/dist`
picks up the new bundle automatically.
5. Update release packaging to include `scripts/ado-script/poll.js`
in `ado-script.zip` alongside other bundles.

### Local development loop

Expand All @@ -344,7 +344,7 @@ npm ci # one-time
npm run codegen # regenerate types.gen.ts (compiles ado-aw first)
npm test # vitest unit tests
npm run typecheck # strict tsc --noEmit
npm run build # ncc-bundle to dist/gate/index.js
npm run build # ncc-bundle to gate.js
npm run test:smoke # build + smoke test the bundle end-to-end
```

Expand Down
14 changes: 7 additions & 7 deletions docs/filter-ir.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ require heuristic analysis and could produce false positives.

Produces a complete ADO pipeline step (`- bash: |`) with a **data-driven
architecture**: bash is a thin ADO-macro shim, all filter logic lives in
the bundled Node.js gate evaluator (`scripts/ado-script/dist/gate/index.js`) that reads a JSON
the bundled Node.js gate evaluator (`scripts/ado-script/gate.js`) that reads a JSON
gate spec.

#### Generated Step Structure
Expand All @@ -257,7 +257,7 @@ gate spec.
export ADO_SYSTEM_ACCESS_TOKEN="$SYSTEM_ACCESSTOKEN"

# 4. Run the bundled Node evaluator (downloaded by the Setup job)
node '/tmp/ado-aw-scripts/ado-script/dist/gate/index.js'
node '/tmp/ado-aw-scripts/ado-script/gate.js'
name: prGate
displayName: "Evaluate PR filters"
env:
Expand Down Expand Up @@ -304,7 +304,7 @@ acquisition logic.
#### Bundled Gate Evaluator (`scripts/ado-script/src/gate/`)

The evaluator is a TypeScript program ncc-bundled to a single
self-contained `scripts/ado-script/dist/gate/index.js` (~1.1 MB) that ships as part of the
self-contained `scripts/ado-script/gate.js` (~1.1 MB) that ships as part of the
`ado-script.zip` release asset. See [`ado-script.md`](ado-script.md) for the
full design and codegen pipeline. It handles:

Expand Down Expand Up @@ -364,9 +364,9 @@ For the gate path it controls:
LTS so `gate.js` has a runtime.
2. **Download step** — fetches `ado-script.zip` from the ado-aw release
artifacts, verifies its SHA256 checksum via `checksums.txt`, then
extracts `gate.js` to `/tmp/ado-aw-scripts/ado-script/dist/gate/index.js`.
extracts `gate.js` to `/tmp/ado-aw-scripts/ado-script/gate.js`.
3. **Gate step** — calls `compile_gate_step_external()` to generate a step
that runs `node /tmp/ado-aw-scripts/ado-script/dist/gate/index.js` (no inline heredoc).
that runs `node /tmp/ado-aw-scripts/ado-script/gate.js` (no inline heredoc).
4. **Validation** — runs `validate_pr_filters()` / `validate_pipeline_filters()`
during compilation via the `validate()` trait method.

Expand Down Expand Up @@ -416,7 +416,7 @@ The `expression` escape hatch is also ANDed if present.

The `gate.js` bundle is built from the TypeScript workspace at
`scripts/ado-script/` (see [`ado-script.md`](ado-script.md)) and emitted to
`scripts/ado-script/dist/gate/index.js` by the release workflow's build step. It ships inside
`scripts/ado-script/gate.js` by the release workflow's build step. It ships inside
the `ado-script.zip` release asset, alongside any future bundled helpers
(e.g. `poll.js`, `stats.js`). The download URL is deterministic based on
the ado-aw version:
Expand All @@ -425,7 +425,7 @@ the ado-aw version:
A `checksums.txt` file is also published at the same URL base and used to
verify the SHA256 integrity of `ado-script.zip` before extraction.

The Setup-job download step pulls the zip, extracts `ado-script/dist/gate/index.js`,
The Setup-job download step pulls the zip, extracts `ado-script/gate.js`,
and discards the rest. New per-use-site bundles follow the same pattern
(per-bundle ncc entry + per-bundle download step).

Expand Down
2 changes: 1 addition & 1 deletion docs/runtime-imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ compile time instead of on the pipeline runner.

## Implementation notes

- **Runtime**: `dist/import/index.js` is ncc-bundled into `ado-script.zip`.
- **Runtime**: `import.js` is ncc-bundled into `ado-script.zip`.
The always-on `AdoScriptExtension`'s `prepare_steps()` injects three
steps into the Agent job's existing `{{ prepare_steps }}` block:
`NodeTool@0` install, the `ado-script.zip` download/verify/extract,
Expand Down
4 changes: 3 additions & 1 deletion scripts/ado-script/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
node_modules
dist
.ado-build
gate.js
import.js
schema
*.tsbuildinfo
2 changes: 1 addition & 1 deletion scripts/ado-script/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ This invokes `cargo run -- export-gate-schema` to write the JSON Schema, then ru
- `src/shared/` — modules shared across all bundles (auth, ado-client, vso-logger, env-facts, policy state machine)
- `src/gate/` — gate evaluator entry point and per-concern modules
- `src/import/` — runtime-import resolver entry point
- `dist/` — ncc bundle output (gitignored); `npm run build` writes `dist/gate/index.js` and `dist/import/index.js`, both of which ship in `ado-script.zip`
- `gate.js` / `import.js` — ncc bundle outputs (gitignored); `npm run build` writes both at the workspace root, and both ship in `ado-script.zip`

## See also

Expand Down
9 changes: 5 additions & 4 deletions scripts/ado-script/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
"node": ">=20.0.0"
},
"scripts": {
"build": "npm run codegen && npm run build:gate && npm run build:import",
"build:gate": "ncc build src/gate/index.ts -o dist/gate -m -t",
"build:import": "ncc build src/import/index.ts -o dist/import -m -t",
"build:check": "ls -lh dist/gate/index.js && wc -c dist/gate/index.js",
"build": "npm run codegen && npm run clean && npm run build:gate && npm run build:import",
"clean": "node -e \"const fs=require('node:fs'); fs.rmSync('.ado-build',{recursive:true,force:true}); fs.rmSync('gate.js',{force:true}); fs.rmSync('import.js',{force:true});\"",
"build:gate": "ncc build src/gate/index.ts -o .ado-build/gate -m -t && node -e \"const fs=require('node:fs'); fs.copyFileSync('.ado-build/gate/index.js','gate.js'); fs.rmSync('.ado-build/gate',{recursive:true,force:true});\"",
"build:import": "ncc build src/import/index.ts -o .ado-build/import -m -t && node -e \"const fs=require('node:fs'); fs.copyFileSync('.ado-build/import/index.js','import.js'); fs.rmSync('.ado-build/import',{recursive:true,force:true});\"",
"build:check": "ls -lh gate.js && wc -c gate.js",
"codegen": "node -e \"require('node:fs').mkdirSync('schema', { recursive: true })\" && cargo run --quiet --manifest-path ../../Cargo.toml -- export-gate-schema --output schema/gate-spec.schema.json && npx json2ts schema/gate-spec.schema.json -o src/shared/types.gen.ts --bannerComment \"// AUTO-GENERATED from Rust IR via cargo run -- export-gate-schema. Do not edit; run npm run codegen.\"",
"test": "vitest run",
"test:smoke": "npm run build:gate && npm run build:import && vitest run -c vitest.config.smoke.ts",
Expand Down
2 changes: 1 addition & 1 deletion scripts/ado-script/src/gate/predicates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export function evaluatePredicate(p: PredicateSpec, facts: Map<string, unknown>)
const unknownType = (p as { type?: unknown }).type;
logWarning(
`Unknown predicate type '${String(unknownType)}'; failing closed. ` +
"Update scripts/ado-script/dist/gate/index.js (or the bundled ado-script.zip) to a " +
"Update scripts/ado-script/gate.js (or the bundled ado-script.zip) to a " +
"release that supports this predicate.",
);
return false;
Expand Down
2 changes: 1 addition & 1 deletion scripts/ado-script/src/shared/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* (e.g. a manual build that hits the bypass branch in `bypass.ts`, or
* a pipeline whose facts are all pipeline variables). The dynamic
* `import()` below is statically analysable by ncc, so the SDK is
* still bundled into `dist/gate/index.js` — only its module-evaluation
* still bundled into `gate.js` — only its module-evaluation
* cost is deferred until the first `getWebApi()` call.
*
* Env-var contract (set by the compiler in
Expand Down
2 changes: 1 addition & 1 deletion scripts/ado-script/src/shared/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export type PredicateSpec =

/**
* Serializable gate specification — the JSON document consumed by the
* Node gate evaluator (`scripts/ado-script/dist/gate/index.js`) at pipeline runtime.
* Node gate evaluator (`scripts/ado-script/gate.js`) at pipeline runtime.
*/
export interface GateSpec {
checks: CheckSpec[];
Expand Down
8 changes: 4 additions & 4 deletions scripts/ado-script/test/smoke.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* End-to-end smoke tests of bundled ado-script programs.
*
* The gate smoke test validates the existing dist/gate/index.js bundle.
* The import smoke test builds dist/import/index.js and verifies it expands
* The gate smoke test validates the existing gate.js bundle.
* The import smoke test builds import.js and verifies it expands
* a prompt fixture in place.
*/
import { spawnSync } from "node:child_process";
Expand All @@ -14,8 +14,8 @@ import { describe, expect, it } from "vitest";

const __dirname = dirname(fileURLToPath(import.meta.url));
const workspaceDir = resolve(__dirname, "..");
const gateBundlePath = resolve(__dirname, "../dist/gate/index.js");
const importBundlePath = resolve(__dirname, "../dist/import/index.js");
const gateBundlePath = resolve(__dirname, "../gate.js");
const importBundlePath = resolve(__dirname, "../import.js");
const gateFixturePath = resolve(
__dirname,
"fixtures/gate-spec-pr-title-match.json",
Expand Down
2 changes: 1 addition & 1 deletion scripts/ado-script/vitest.config.smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
// Smoke-test config: targets bundled ado-script programs end-to-end.
// The suite must run AFTER `npm run build` produces dist/*/index.js.
// The suite must run AFTER `npm run build` produces gate.js/import.js.
include: ["test/**/*.test.ts"],
},
});
3 changes: 1 addition & 2 deletions scripts/ado-script/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
// Default suite covers source-side tests under src/. The smoke test
// under test/ depends on dist/*/index.js existing, so it runs via a
// under test/ depends on gate.js/import.js existing, so it runs via a
// separate config — see vitest.config.smoke.ts and `npm run test:smoke`.
include: ["src/**/*.test.ts"],
},
});


12 changes: 6 additions & 6 deletions site/src/content/docs/reference/filter-ir.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ require heuristic analysis and could produce false positives.

Produces a complete ADO pipeline step (`- bash: |`) with a **data-driven
architecture**: bash is a thin ADO-macro shim, all filter logic lives in
the bundled Node.js gate evaluator (`scripts/ado-script/dist/gate/index.js`) that reads a JSON
the bundled Node.js gate evaluator (`scripts/ado-script/gate.js`) that reads a JSON
gate spec.

#### Generated Step Structure
Expand All @@ -258,7 +258,7 @@ gate spec.
export ADO_SYSTEM_ACCESS_TOKEN="$SYSTEM_ACCESSTOKEN"

# 4. Run the bundled Node evaluator (downloaded by the Setup job)
node '/tmp/ado-aw-scripts/ado-script/dist/gate/index.js'
node '/tmp/ado-aw-scripts/ado-script/gate.js'
name: prGate
displayName: "Evaluate PR filters"
env:
Expand Down Expand Up @@ -305,7 +305,7 @@ acquisition logic.
#### Bundled Gate Evaluator (`scripts/ado-script/src/gate/`)

The evaluator is a TypeScript program ncc-bundled to a single
self-contained `scripts/ado-script/dist/gate/index.js` (~1.1 MB) that ships as part of the
self-contained `scripts/ado-script/gate.js` (~1.1 MB) that ships as part of the
`ado-script.zip` release asset. It handles:

1. **Bypass logic** -- reads `ADO_BUILD_REASON` and exits early for non-matching
Expand Down Expand Up @@ -364,9 +364,9 @@ For the gate path it controls:
LTS so the gate evaluator has a runtime.
2. **Download step** -- fetches `ado-script.zip` from the ado-aw release
artifacts, verifies its SHA256 checksum via `checksums.txt`, then
extracts `gate.js` to `/tmp/ado-aw-scripts/ado-script/dist/gate/index.js`.
extracts `gate.js` to `/tmp/ado-aw-scripts/ado-script/gate.js`.
3. **Gate step** -- calls `compile_gate_step_external()` to generate a step
that runs `node /tmp/ado-aw-scripts/ado-script/dist/gate/index.js` (no inline heredoc).
that runs `node /tmp/ado-aw-scripts/ado-script/gate.js` (no inline heredoc).
4. **Validation** -- runs `validate_pr_filters()` / `validate_pipeline_filters()`
during compilation via the `validate()` trait method.

Expand Down Expand Up @@ -408,7 +408,7 @@ The `expression` escape hatch is also ANDed if present.
### Scripts Distribution

The `gate.js` bundle is built from the TypeScript workspace at
`scripts/ado-script/` and emitted to `scripts/ado-script/dist/gate/index.js`
`scripts/ado-script/` and emitted to `scripts/ado-script/gate.js`
by the release workflow's build step. It ships inside the `ado-script.zip`
release asset alongside any future bundled helpers. The download URL is
deterministic based on the ado-aw version:
Expand Down
2 changes: 1 addition & 1 deletion site/src/content/docs/reference/runtime-imports.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ compile time instead of on the pipeline runner.

## Implementation notes

- **Runtime**: `dist/import/index.js` is ncc-bundled into `ado-script.zip`.
- **Runtime**: `import.js` is ncc-bundled into `ado-script.zip`.
The always-on `AdoScriptExtension`'s `prepare_steps()` injects three
steps into the Agent job's existing `{{ prepare_steps }}` block:
`NodeTool@0` install, the `ado-script.zip` download/verify/extract,
Expand Down
8 changes: 4 additions & 4 deletions src/compile/extensions/ado_script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use crate::compile::filter_ir::{
};
use crate::compile::types::{PipelineFilters, PrFilters};

const GATE_EVAL_PATH: &str = "/tmp/ado-aw-scripts/ado-script/dist/gate/index.js";
pub(crate) const IMPORT_EVAL_PATH: &str = "/tmp/ado-aw-scripts/ado-script/dist/import/index.js";
const GATE_EVAL_PATH: &str = "/tmp/ado-aw-scripts/ado-script/gate.js";
pub(crate) const IMPORT_EVAL_PATH: &str = "/tmp/ado-aw-scripts/ado-script/import.js";
const RELEASE_BASE_URL: &str = "https://github.com/githubnext/ado-aw/releases/download";

/// Single always-on extension that owns all `ado-script` bundle wiring.
Expand Down Expand Up @@ -424,7 +424,7 @@ mod tests {
assert!(!steps[0].contains("for gate evaluator"));
assert!(steps[1].contains("Download ado-aw scripts"));
assert!(steps[1].contains("sha256sum -c -"));
assert!(steps[2].contains("node '/tmp/ado-aw-scripts/ado-script/dist/gate/index.js'"));
assert!(steps[2].contains("node '/tmp/ado-aw-scripts/ado-script/gate.js'"));
}

#[test]
Expand All @@ -444,7 +444,7 @@ mod tests {
assert_eq!(steps.len(), 3, "install + download + resolver");
assert!(steps[0].contains("NodeTool@0"));
assert!(steps[1].contains("Download ado-aw scripts"));
assert!(steps[2].contains("node '/tmp/ado-aw-scripts/ado-script/dist/import/index.js'"));
assert!(steps[2].contains("node '/tmp/ado-aw-scripts/ado-script/import.js'"));
assert!(steps[2].contains("Resolve runtime imports (agent prompt)"));
// The resolver receives `--base "$(Build.SourcesDirectory)"` so
// the compiler-emitted trigger-repo-relative marker path
Expand Down
Loading
Loading