bulletin-deploy 0.6.9 → 0.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -66,6 +66,10 @@ Options:
66
66
  --playground Publish to the Playground remix registry
67
67
  --js-merkle Use pure-JS merkleization (no IPFS Kubo binary required)
68
68
  --pool-size N Number of pool accounts (default: 10)
69
+ --tag "..." Free-form label attached to the deploy span as deploy.tag
70
+ (see Telemetry section). Use to isolate test/benchmark/canary
71
+ runs from real-user traffic in Sentry dashboards. Also readable
72
+ from DEPLOY_TAG env var.
69
73
  --help Show help
70
74
  ```
71
75
 
@@ -247,9 +251,97 @@ What's tracked:
247
251
  - Source metadata (repo, branch, PR number, CI vs local)
248
252
  - Tool version (`deploy.tool_version`)
249
253
 
250
- Dashboard:
251
- - Bulletin Deploy Health: https://paritytech.sentry.io/dashboard/1669817/?project=4511093597405264
252
- - Deploy Failures Detail: https://paritytech.sentry.io/dashboard/1669818/?project=4511093597405264
254
+ ### Tagging test and benchmark runs
255
+
256
+ Real-user deploys and automated test/benchmark deploys share the same telemetry pipeline. Use `--tag` (or the `DEPLOY_TAG` env var) to label non-production runs so Sentry dashboards can filter them out:
257
+
258
+ ```bash
259
+ bulletin-deploy --tag e2e-ci-pr ./build my-app.dot
260
+ DEPLOY_TAG=load-test bulletin-deploy ./build my-app.dot
261
+ ```
262
+
263
+ The `tag` value is attached to the deploy span as `deploy.tag` (plus propagated through every child span).
264
+
265
+ Convention used in this repo:
266
+ - `e2e-ci-pr` / `e2e-ci-nightly` — CI-driven E2E runs (per-PR and nightly matrices).
267
+ - `e2e-local-smoke` / `e2e-local-pr` / `e2e-local-nightly` — maintainer-invoked E2E via `scripts/e2e-pass.sh`.
268
+ - Untagged — real-user deploys.
269
+
270
+ Sentry filter examples:
271
+ - Exclude all test traffic from a dashboard: `!has:deploy.tag`
272
+ - Only CI E2E: `deploy.tag:e2e-ci-*`
273
+ - Only nightly runs (local or CI): `deploy.tag:e2e-ci-nightly OR deploy.tag:e2e-local-nightly`
274
+
275
+ The shipped reusable workflow (`.github/workflows/deploy.yml`) exposes a `tag` input that feeds through to the CLI — pass it from caller workflows that do non-production deploys.
276
+
277
+ Dashboards:
278
+ - **Bulletin Deploy Health**: https://paritytech.sentry.io/dashboard/1669817/?project=4511093597405264 — overall deploy health across all consumer repos
279
+ - **Deploy Failures Detail**: https://paritytech.sentry.io/dashboard/1669818/?project=4511093597405264 — error drill-down
280
+ - **E2E Health (bulletin-deploy)**: https://paritytech.sentry.io/dashboard/1732713/?project=4511093597405264 — E2E suite pass rate, duration, and per-signer failure distribution (filtered by `deploy.tag:e2e-*`)
281
+
282
+ ## Testing
283
+
284
+ Three layers of coverage: offline unit tests for pure helpers, live-testnet end-to-end tests that exercise the shipped reusable workflow, and CI matrices that run both per-PR and nightly.
285
+
286
+ ### Offline unit tests
287
+
288
+ ```bash
289
+ npm test
290
+ ```
291
+
292
+ Runs `test/test.js` + `test/pool.test.js` + `test/helpers/e2e-helpers.test.js` via `node --test`. No network. ~5 seconds. Always runs on every PR via GitHub Actions.
293
+
294
+ ### Live-testnet E2E
295
+
296
+ Three scenarios land on Paseo Bulletin:
297
+
298
+ - **S1** — happy path on a stable label (`e2epool.dot` / `e2edirect.dot`)
299
+ - **S2** — fresh registration via commit-reveal (nightly only)
300
+ - **S3** — deploy to `e2eowned.dot` (owned by a different account), expects `EXIT_CODE_NO_RETRY` (78) and the "owned by a different account" error message
301
+
302
+ **Prerequisites** (one-time per testnet lifetime): see [`docs/e2e-bootstrap.md`](docs/e2e-bootstrap.md). Grants Alice PoP Full, funds+maps Bob, pre-registers `e2eowned.dot` to Bob via `dotns-cli`.
303
+
304
+ **Local launchers:**
305
+
306
+ ```bash
307
+ npm run test:e2e:smoke # 1 scenario (S1 pool/js) ~5 min
308
+ npm run test:e2e:pr # 3 scenarios (matches per-PR CI) ~15 min
309
+ npm run test:e2e:nightly # 7 scenarios (matches nightly CI) ~30–45 min
310
+ ```
311
+
312
+ All three run through to completion even if one fails; a colored summary prints at the end with per-scenario pass/fail, timing, JUnit report paths, and a pre-filtered Sentry trace link.
313
+
314
+ **Agent-friendly / quiet mode** — `E2E_QUIET=1` suppresses the live streaming output (`node:test` spec reporter + bulletin-deploy stdio + build logs) while still printing the summary and writing structured reports. Works with every mode:
315
+
316
+ ```bash
317
+ E2E_QUIET=1 npm run test:e2e:smoke
318
+ E2E_QUIET=1 npm run test:e2e:pr
319
+ E2E_QUIET=1 npm run test:e2e:nightly
320
+ ```
321
+
322
+ Equivalent flag form: `bash scripts/e2e-pass.sh --quiet <mode>`.
323
+
324
+ **JUnit reports** — every scenario writes one to `e2e-reports/<scenario>-<signer>-<merkle>.xml` regardless of quiet mode. Consume via any JUnit-compatible tool, or just `cat` the XML — `<failure>` blocks carry the assertion message and stack.
325
+
326
+ ### CI matrices (`.github/workflows/e2e.yml`)
327
+
328
+ The CI workflow **calls the shipped reusable `.github/workflows/deploy.yml`** for every scenario — so each E2E job runs exactly the code path real consumers hit. Per-PR tests HEAD via `bulletin-deploy-version: "git+https://...#<sha>"` (the `prepare` npm script builds `dist/` during install). Nightly leaves the version empty so it tests the latest published release.
329
+
330
+ - **Per-PR** (3 jobs): on `pull_request` and `push` to `main`. S1 pool/js + S1 direct/kubo + S3 negative. Posts a sticky comment on the PR with results and updates in place on re-runs.
331
+ - **Nightly** (11 jobs): scheduled `0 3 * * *` UTC. Full S1 signer×merkle×runner cube + S2 pool/direct fresh-registration + S3. Failures auto-open a GitHub issue.
332
+
333
+ Every deploy job passes `tag: e2e-ci-pr` or `tag: e2e-ci-nightly` through to the CLI, so the E2E traffic is tagged in Sentry and can be filtered out of real-user dashboards (see Telemetry → Tagging test and benchmark runs above).
334
+
335
+ ### Tag convention in this repo
336
+
337
+ | Trigger | `deploy.tag` |
338
+ |---|---|
339
+ | `npm run test:e2e:smoke` | `e2e-local-smoke` |
340
+ | `npm run test:e2e:pr` | `e2e-local-pr` |
341
+ | `npm run test:e2e:nightly` | `e2e-local-nightly` |
342
+ | E2E workflow per-PR | `e2e-ci-pr` |
343
+ | E2E workflow nightly | `e2e-ci-nightly` |
344
+ | Real-user deploys | _none_ (`!has:deploy.tag`) |
253
345
 
254
346
  ## Troubleshooting
255
347
 
@@ -20,6 +20,7 @@ for (let i = 0; i < args.length; i++) {
20
20
  else if (args[i] === "--password") { flags.password = args[++i]; }
21
21
  else if (args[i] === "--playground") { flags.playground = true; }
22
22
  else if (args[i] === "--js-merkle") { flags.jsMerkle = true; }
23
+ else if (args[i] === "--tag") { flags.tag = args[++i]; }
23
24
  else if (args[i] === "--version" || args[i] === "-V") { flags.version = true; }
24
25
  else if (args[i] === "--help" || args[i] === "-h") { flags.help = true; }
25
26
  else { positional.push(args[i]); }
@@ -45,6 +46,7 @@ Options:
45
46
  --password "..." Encrypt SPA content (users will be prompted to decrypt)
46
47
  --playground Publish to the playground remix registry
47
48
  --js-merkle Use pure-JS merkleization (no IPFS Kubo binary required)
49
+ --tag "..." Label deploy in telemetry (or set DEPLOY_TAG env var); see Telemetry in README
48
50
  --version Show version
49
51
  --help Show this help`);
50
52
  process.exit(0);
@@ -80,6 +82,7 @@ try {
80
82
  poolSize: flags.poolSize,
81
83
  password: flags.password,
82
84
  jsMerkle: flags.jsMerkle,
85
+ tag: flags.tag,
83
86
  });
84
87
 
85
88
  const output = process.env.GITHUB_OUTPUT;
@@ -2,10 +2,10 @@ import {
2
2
  classifyErrorArea,
3
3
  isInteractive,
4
4
  promptYesNo
5
- } from "./chunk-TF4MTBZF.js";
5
+ } from "./chunk-PRT3B52H.js";
6
6
  import {
7
7
  VERSION
8
- } from "./chunk-BUAELY3G.js";
8
+ } from "./chunk-2FXONN6K.js";
9
9
  import "./chunk-QGM4M3NI.js";
10
10
 
11
11
  // src/bug-report.ts
@@ -7,7 +7,7 @@ import * as path from "path";
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "bulletin-deploy",
10
- version: "0.6.9",
10
+ version: "0.6.10",
11
11
  private: false,
12
12
  repository: {
13
13
  type: "git",
@@ -36,7 +36,12 @@ var package_default = {
36
36
  ],
37
37
  scripts: {
38
38
  build: "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/merkle.ts src/version-check.ts src/bug-report.ts --format esm --dts --clean --target node22",
39
- test: "npm run build && node --test test/test.js",
39
+ prepare: "npm run build",
40
+ test: "npm run build && node --test test/test.js test/pool.test.js test/helpers/e2e-helpers.test.js",
41
+ "test:e2e": "npm run build && node --test test/e2e.test.js",
42
+ "test:e2e:smoke": "bash scripts/e2e-pass.sh smoke",
43
+ "test:e2e:pr": "bash scripts/e2e-pass.sh pr",
44
+ "test:e2e:nightly": "bash scripts/e2e-pass.sh nightly",
40
45
  benchmark: "npm run build && node benchmark.js"
41
46
  },
42
47
  dependencies: {
@@ -5,7 +5,7 @@ import {
5
5
  fetchNonce,
6
6
  popStatusName,
7
7
  validateDomainLabel
8
- } from "./chunk-CE67XAQY.js";
8
+ } from "./chunk-H4HN4RRK.js";
9
9
  import {
10
10
  merkleizeJS
11
11
  } from "./chunk-GZ5UUECB.js";
@@ -27,7 +27,7 @@ import {
27
27
  truncateAddress,
28
28
  withDeploySpan,
29
29
  withSpan
30
- } from "./chunk-BUAELY3G.js";
30
+ } from "./chunk-2FXONN6K.js";
31
31
 
32
32
  // src/deploy.ts
33
33
  import { Buffer } from "buffer";
@@ -884,12 +884,15 @@ async function deploy(content, domainName = null, options = {}) {
884
884
  const rawName = domainName ? domainName.replace(".dot", "") : `test-domain-${Date.now().toString(36)}${randomSuffix}`;
885
885
  const name = validateDomainLabel(rawName);
886
886
  return withDeploySpan(name, async () => {
887
+ const deployTag = options.tag ?? process.env.DEPLOY_TAG;
888
+ if (deployTag) setDeployAttribute("deploy.tag", deployTag);
887
889
  let cid;
888
890
  let ipfsCid;
889
891
  console.log("\n" + "=".repeat(60));
890
892
  console.log(`DEPLOYING TO TESTNET v${VERSION}`);
891
893
  console.log("=".repeat(60));
892
894
  console.log(` Domain: ${name}.dot`);
895
+ if (deployTag) console.log(` Tag: ${deployTag}`);
893
896
  if (typeof content === "string") console.log(` Build dir: ${path.resolve(content)}`);
894
897
  if (process.env.CI) console.log(` Runner: ${resolveRunner()} (${resolveRunnerType()})`);
895
898
  if (options.password) console.log(` Encrypted: yes`);
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  captureWarning,
6
6
  withSpan
7
- } from "./chunk-BUAELY3G.js";
7
+ } from "./chunk-2FXONN6K.js";
8
8
 
9
9
  // src/dotns.ts
10
10
  import crypto from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-BUAELY3G.js";
3
+ } from "./chunk-2FXONN6K.js";
4
4
 
5
5
  // src/version-check.ts
6
6
  import { execSync, execFileSync } from "child_process";
package/dist/deploy.d.ts CHANGED
@@ -68,6 +68,12 @@ interface DeployOptions {
68
68
  password?: string;
69
69
  /** Use pure-JS merkleization instead of Kubo CLI. Required for WebContainer environments. */
70
70
  jsMerkle?: boolean;
71
+ /**
72
+ * Free-form label attached to the deploy span as `deploy.tag`. Used to separate
73
+ * test/benchmark/canary runs from real-user traffic in Sentry dashboards
74
+ * (e.g. "e2e-ci-pr", "load-test-a"). Falls back to DEPLOY_TAG env var.
75
+ */
76
+ tag?: string;
71
77
  /** Custom telemetry attributes, merged into the deploy span. Overrides auto-detected values. */
72
78
  attributes?: Record<string, string>;
73
79
  }
package/dist/deploy.js CHANGED
@@ -23,11 +23,11 @@ import {
23
23
  storeChunkedContent,
24
24
  storeDirectory,
25
25
  storeFile
26
- } from "./chunk-INDAKTSG.js";
27
- import "./chunk-CE67XAQY.js";
26
+ } from "./chunk-6QG2QJV4.js";
27
+ import "./chunk-H4HN4RRK.js";
28
28
  import "./chunk-GZ5UUECB.js";
29
29
  import "./chunk-JHNW2EKY.js";
30
- import "./chunk-BUAELY3G.js";
30
+ import "./chunk-2FXONN6K.js";
31
31
  import "./chunk-QGM4M3NI.js";
32
32
  export {
33
33
  DEFAULT_BULLETIN_RPC,
package/dist/dotns.js CHANGED
@@ -24,9 +24,9 @@ import {
24
24
  simulateUserStatus,
25
25
  stripTrailingDigits,
26
26
  validateDomainLabel
27
- } from "./chunk-CE67XAQY.js";
27
+ } from "./chunk-H4HN4RRK.js";
28
28
  import "./chunk-JHNW2EKY.js";
29
- import "./chunk-BUAELY3G.js";
29
+ import "./chunk-2FXONN6K.js";
30
30
  import "./chunk-QGM4M3NI.js";
31
31
  export {
32
32
  CONNECTION_TIMEOUT_MS,
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  deploy
3
- } from "./chunk-INDAKTSG.js";
3
+ } from "./chunk-6QG2QJV4.js";
4
4
  import {
5
5
  DotNS
6
- } from "./chunk-CE67XAQY.js";
6
+ } from "./chunk-H4HN4RRK.js";
7
7
  import {
8
8
  merkleizeJS
9
9
  } from "./chunk-GZ5UUECB.js";
@@ -14,7 +14,7 @@ import {
14
14
  fetchPoolAuthorizations,
15
15
  selectAccount
16
16
  } from "./chunk-JHNW2EKY.js";
17
- import "./chunk-BUAELY3G.js";
17
+ import "./chunk-2FXONN6K.js";
18
18
  import "./chunk-QGM4M3NI.js";
19
19
  export {
20
20
  DotNS,
package/dist/telemetry.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  truncateAddress,
18
18
  withDeploySpan,
19
19
  withSpan
20
- } from "./chunk-BUAELY3G.js";
20
+ } from "./chunk-2FXONN6K.js";
21
21
  import "./chunk-QGM4M3NI.js";
22
22
  export {
23
23
  VERSION,
@@ -8,8 +8,8 @@ import {
8
8
  isPreReleaseVersion,
9
9
  preReleaseWarning,
10
10
  promptYesNo
11
- } from "./chunk-TF4MTBZF.js";
12
- import "./chunk-BUAELY3G.js";
11
+ } from "./chunk-PRT3B52H.js";
12
+ import "./chunk-2FXONN6K.js";
13
13
  import "./chunk-QGM4M3NI.js";
14
14
  export {
15
15
  assessVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulletin-deploy",
3
- "version": "0.6.9",
3
+ "version": "0.6.10",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,7 +29,12 @@
29
29
  ],
30
30
  "scripts": {
31
31
  "build": "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/merkle.ts src/version-check.ts src/bug-report.ts --format esm --dts --clean --target node22",
32
- "test": "npm run build && node --test test/test.js",
32
+ "prepare": "npm run build",
33
+ "test": "npm run build && node --test test/test.js test/pool.test.js test/helpers/e2e-helpers.test.js",
34
+ "test:e2e": "npm run build && node --test test/e2e.test.js",
35
+ "test:e2e:smoke": "bash scripts/e2e-pass.sh smoke",
36
+ "test:e2e:pr": "bash scripts/e2e-pass.sh pr",
37
+ "test:e2e:nightly": "bash scripts/e2e-pass.sh nightly",
33
38
  "benchmark": "npm run build && node benchmark.js"
34
39
  },
35
40
  "dependencies": {