@parity/product-deploy 0.7.28-rc.0
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/LICENSE +201 -0
- package/README.md +233 -0
- package/assets/environments.json +313 -0
- package/bin/bulletin-bootstrap +84 -0
- package/bin/bulletin-deploy +429 -0
- package/dist/bug-report.d.ts +29 -0
- package/dist/bug-report.js +27 -0
- package/dist/chunk-2VAUMZB2.js +284 -0
- package/dist/chunk-43HLT335.js +232 -0
- package/dist/chunk-5VZQ2KSU.js +231 -0
- package/dist/chunk-ADNBLFDP.js +225 -0
- package/dist/chunk-BMAEWZYV.js +24 -0
- package/dist/chunk-C2TS5MER.js +64 -0
- package/dist/chunk-DNXH4QTI.js +2336 -0
- package/dist/chunk-FZWJV5AD.js +231 -0
- package/dist/chunk-GZD2UFLR.js +8 -0
- package/dist/chunk-HOTQDYHD.js +219 -0
- package/dist/chunk-IDYGYIMH.js +207 -0
- package/dist/chunk-KHVTYIIX.js +146 -0
- package/dist/chunk-KJH2T5TQ.js +172 -0
- package/dist/chunk-KOSF5FDO.js +49 -0
- package/dist/chunk-LZJMVPYW.js +156 -0
- package/dist/chunk-MFTODIIT.js +725 -0
- package/dist/chunk-MMAZFJDG.js +91 -0
- package/dist/chunk-NF2FL4ZO.js +164 -0
- package/dist/chunk-OITUIM2E.js +524 -0
- package/dist/chunk-P6CHOMN3.js +2368 -0
- package/dist/chunk-QMYW3D6E.js +316 -0
- package/dist/chunk-QTZNULSH.js +185 -0
- package/dist/chunk-RI3ZLNPN.js +71 -0
- package/dist/chunk-S7EM5VMW.js +108 -0
- package/dist/chunk-T7EEVWNU.js +32 -0
- package/dist/chunk-UPWEOGLQ.js +37 -0
- package/dist/chunk-ZOC4GITL.js +13 -0
- package/dist/chunk-ZYVGHDMU.js +117 -0
- package/dist/chunk-probe.d.ts +37 -0
- package/dist/chunk-probe.js +18 -0
- package/dist/chunker.d.ts +8 -0
- package/dist/chunker.js +10 -0
- package/dist/deploy.d.ts +299 -0
- package/dist/deploy.js +96 -0
- package/dist/dotns.d.ts +506 -0
- package/dist/dotns.js +101 -0
- package/dist/environments.d.ts +104 -0
- package/dist/environments.js +23 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +8 -0
- package/dist/gh-pages-mirror.d.ts +76 -0
- package/dist/gh-pages-mirror.js +30 -0
- package/dist/incremental-stats.d.ts +69 -0
- package/dist/incremental-stats.js +10 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +146 -0
- package/dist/manifest/byte-budget.d.ts +46 -0
- package/dist/manifest/byte-budget.js +14 -0
- package/dist/manifest/config-load.d.ts +36 -0
- package/dist/manifest/config-load.js +10 -0
- package/dist/manifest/publish.d.ts +54 -0
- package/dist/manifest/publish.js +23 -0
- package/dist/manifest/schema.d.ts +29 -0
- package/dist/manifest/schema.js +10 -0
- package/dist/manifest/types.d.ts +90 -0
- package/dist/manifest/types.js +6 -0
- package/dist/manifest-embed.d.ts +18 -0
- package/dist/manifest-embed.js +9 -0
- package/dist/manifest-fetch.d.ts +32 -0
- package/dist/manifest-fetch.js +21 -0
- package/dist/manifest-roundtrip.d.ts +15 -0
- package/dist/manifest-roundtrip.js +55 -0
- package/dist/manifest.d.ts +44 -0
- package/dist/manifest.js +20 -0
- package/dist/memory-report.d.ts +95 -0
- package/dist/memory-report.js +17 -0
- package/dist/merkle.d.ts +50 -0
- package/dist/merkle.js +33 -0
- package/dist/personhood/bind-paid-alias.d.ts +43 -0
- package/dist/personhood/bind-paid-alias.js +10 -0
- package/dist/personhood/bind-personal-id.d.ts +55 -0
- package/dist/personhood/bind-personal-id.js +12 -0
- package/dist/personhood/bootstrap.d.ts +85 -0
- package/dist/personhood/bootstrap.js +245 -0
- package/dist/personhood/claim-pgas.d.ts +61 -0
- package/dist/personhood/claim-pgas.js +12 -0
- package/dist/personhood/constants.d.ts +23 -0
- package/dist/personhood/constants.js +22 -0
- package/dist/personhood/encoding.d.ts +49 -0
- package/dist/personhood/encoding.js +24 -0
- package/dist/personhood/hashing.d.ts +4 -0
- package/dist/personhood/hashing.js +8 -0
- package/dist/personhood/member-key.d.ts +12 -0
- package/dist/personhood/member-key.js +10 -0
- package/dist/personhood/people-client.d.ts +14 -0
- package/dist/personhood/people-client.js +48 -0
- package/dist/personhood/reprove.d.ts +43 -0
- package/dist/personhood/reprove.js +225 -0
- package/dist/pool.d.ts +51 -0
- package/dist/pool.js +30 -0
- package/dist/run-state.d.ts +22 -0
- package/dist/run-state.js +20 -0
- package/dist/telemetry.d.ts +56 -0
- package/dist/telemetry.js +71 -0
- package/dist/version-check.d.ts +38 -0
- package/dist/version-check.js +30 -0
- package/docs/bootstrap.md +49 -0
- package/docs/e2e-bootstrap.md +154 -0
- package/docs/telemetry.md +62 -0
- package/docs/testing.md +44 -0
- package/package.json +82 -0
- package/tools/release-retry-wrapper.mjs +74 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# E2E test setup
|
|
2
|
+
|
|
3
|
+
The E2E suite (`test/e2e.test.js`, driven by `.github/workflows/e2e.yml`) deploys real content to Paseo Bulletin testnet via `bulletin-deploy` and verifies the on-chain round-trip. It consumes the **shared default pool** (derived from `DEV_PHRASE` — the same pool real users hit in production) for Bulletin chunk upload, so no pool bootstrapping is required.
|
|
4
|
+
|
|
5
|
+
Three one-time setup items are needed before the workflow can pass. Do them once per testnet lifetime (redo if testnet is wiped).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Paseo (stable testnet)
|
|
10
|
+
|
|
11
|
+
### Prerequisites
|
|
12
|
+
|
|
13
|
+
- `bulletin-deploy` built locally (`npm run build`).
|
|
14
|
+
- Network access to Paseo Bulletin RPC (`wss://paseo-bulletin-rpc.polkadot.io`) and Asset Hub Paseo (DotNS).
|
|
15
|
+
- Alice's dev mnemonic: `bottom drive obey lake curtain smoke basket hold race lonely fit walk`.
|
|
16
|
+
|
|
17
|
+
### 1. Verify Alice Personhood status
|
|
18
|
+
|
|
19
|
+
Both happy-path scenarios (S1, S2) deploy as Alice via DotNS. Registering a new un-reserved base name requires Personhood status from the chain's Personhood precompile:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
node tools/check-pop-status.mjs
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Re-run if the check cannot read Alice's status. Self-attestation is no longer available; ask the DotNS team to whitelist the signer if Alice needs a higher status for a label class.
|
|
26
|
+
|
|
27
|
+
### 2. Fund and map Bob on Asset Hub Paseo
|
|
28
|
+
|
|
29
|
+
Bob (`//Bob` from the dev phrase) is the owner of `e2eowned.dot` (see item 3). He needs:
|
|
30
|
+
|
|
31
|
+
- **Balance** on Asset Hub Paseo for his on-chain fees. Request ~1 PAS from the Paseo faucet at [https://faucet.polkadot.io/](https://faucet.polkadot.io/) sending to Bob's SS58 address `5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty`.
|
|
32
|
+
- **Revive mapping** so he can sign EVM transactions. `check-pop-status` reports Bob's deterministic H160 and Personhood status without submitting transactions. A later Bob-signed registration or transfer triggers mapping when the chain supports automatic mapping.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
node tools/check-pop-status.mjs "bottom drive obey lake curtain smoke basket hold race lonely fit walk//Bob"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Expected output: Bob's SS58, his H160 (`0x41dccbd49b26c50d34355ed86ff0fa9e489d1e01`), and PoP status (`NoStatus (0)` initially). Idempotent.
|
|
39
|
+
|
|
40
|
+
### 3. Register `e2eowned.dot` directly as Bob
|
|
41
|
+
|
|
42
|
+
The S3 negative scenario asserts that `bulletin-deploy` refuses to deploy to a domain owned by a different account (exit 78 with transfer guidance). Have Bob register the label with a DotNS registration tool outside `bulletin-deploy` — no Alice intermediary, no Bulletin content needed (S3 never reads content).
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
node tools/register-test-fixture-paseo-next-v2.mjs e2eowned
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Expected: `e2eowned.dot` is owned by Bob's H160 `0x41dccbd49b26c50d34355ed86ff0fa9e489d1e01`. The `e2eowned.dot` label requires PoP Full status and a mature commitment (the tool waits 30s after the minimum commitment age). The tool is idempotent: it exits 0 immediately if Bob already owns it, and transfers the label from Alice back to Bob if fixture drift is detected.
|
|
49
|
+
|
|
50
|
+
If S3 ever fails because `e2eowned.dot` was transferred back to Alice by mistake, re-run this step to restore Bob's ownership.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Paseo Next v2 (`--env paseo-next-v2`)
|
|
55
|
+
|
|
56
|
+
Paseo Next v2 uses a separate Asset Hub (`wss://paseo-asset-hub-next-rpc.polkadot.io`) and Bulletin chain (`wss://paseo-bulletin-next-rpc.polkadot.io`) with different contract addresses. The `map_account` extrinsic does not exist on this chain — account mapping is triggered automatically when an account submits its first on-chain transaction.
|
|
57
|
+
|
|
58
|
+
> **Note on PoP grants:** The paseo-next-v2 `POP_RULES` contract (`0x2002C1c15b88632Ad01c7770f6EbE1Ca05c8472E`) is **not permissionless** — `setUserPopStatus` can only be called by the contract owner (`0x4a519c30da0ec16aa9a73c26ea6ca6f701cce099`). `bulletin-deploy` itself cannot upgrade a signer; the chain team flips the Personhood precompile out of band. CI scenarios pick labels via `pickStableLabel`/`pickDirectLabel`/`pickIncLabel`/`pickRotLabel`, which auto-select between a PoP-Full base name (e.g. `e2epool.dot`) and a NoStatus fallback (e.g. `e2epoolns01.dot`) based on what `Personhood.personhoodStatus(<signer>)` returns at test start. The setup below covers both modes.
|
|
59
|
+
|
|
60
|
+
> **⚠ Testnet wipes reset everything.** When paseo-next-v2 is reset (which happens periodically), Alice's Personhood precompile status drops to NoStatus *and* every `e2e*.dot` registration is gone. Re-run the relevant steps below after each wipe — there is no on-chain self-recovery. Issue #381 traces back to exactly this: Alice's status came back as Full but `e2epool.dot` was unregistered, so `setContenthash` reverted with `ERC721NonexistentToken`. As long as ownership stays in lockstep with Alice's PoP grade (Full ↔ PoP-Full labels registered; NoStatus ↔ NoStatus labels auto-register on first deploy), the nightly stays green.
|
|
61
|
+
|
|
62
|
+
### Prerequisites
|
|
63
|
+
|
|
64
|
+
- `bulletin-deploy` built locally (`npm run build`).
|
|
65
|
+
- Alice (`5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV`) funded on paseo-next-v2 Asset Hub. The chain team must send funds manually — there is no public faucet for this chain.
|
|
66
|
+
|
|
67
|
+
### 1. Authorize pool accounts on Bulletin Next
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
bulletin-bootstrap --env paseo-next-v2
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This grants each pool account `TransactionStorage` quota on Bulletin Next. Alice (`//Alice`) must be funded and mapped on Asset Hub Next for this to succeed (Alice's mapping is triggered automatically by her first on-chain tx, so funding alone is sufficient).
|
|
74
|
+
|
|
75
|
+
### 2. Verify Alice PoP status
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
node tools/check-pop-status.mjs --env paseo-next-v2
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
What you see decides which labels need pre-registration:
|
|
82
|
+
|
|
83
|
+
- **`NoStatus (0)`** → no extra work. The tests pick the NoStatus fallback labels (`e2epoolns01`, `e2edirect01`, `e2eincpool01`, `e2erotpool01`) which auto-register on first deploy because their shape (base length ≥ 9 with two trailing digits) bypasses the `Requires Full personhood verification` gate.
|
|
84
|
+
- **`ProofOfPersonhoodFull (2)`** → the chain team has flipped Alice on the Personhood precompile. The tests will now pick the PoP-Full stable labels (`e2epool`, `e2edirect`, `e2einc`, `e2erot`), and those **must already be registered to Alice** before the matrix runs. Register them once:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Pre-built fixture is fine — it's the contenthash, not the content, that the tests overwrite.
|
|
88
|
+
for label in e2epool e2edirect e2einc e2erot; do
|
|
89
|
+
node bin/bulletin-deploy test/fixtures/e2e-spa "${label}.dot" --env paseo-next-v2 --js-merkle
|
|
90
|
+
done
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Skipping this leaves `setContenthash` reverting with `ERC721NonexistentToken` on whichever PoP-Full label the scenario picks (issue #381).
|
|
94
|
+
|
|
95
|
+
### 3. Fund Bob and trigger his account mapping
|
|
96
|
+
|
|
97
|
+
Bob (`5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty`) needs PAS on paseo-next-v2 Asset Hub so he can pay fees for the `e2eowned.dot` registration. Have the chain team send ~1 PAS to his SS58 address. His H160 mapping (`0x41dccbd49b26c50d34355ed86ff0fa9e489d1e01`) is triggered automatically when he submits his first on-chain tx.
|
|
98
|
+
|
|
99
|
+
Verify his mapping:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
node tools/check-pop-status.mjs --env paseo-next-v2 \
|
|
103
|
+
"bottom drive obey lake curtain smoke basket hold race lonely fit walk//Bob"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Expected output: Bob's SS58, his H160 (`0x41dccbd49b26c50d34355ed86ff0fa9e489d1e01`), and PoP status.
|
|
107
|
+
|
|
108
|
+
### 4. Verify Bob PoP status
|
|
109
|
+
|
|
110
|
+
Bob owns both `e2eownedns02.dot` (NoStatus, used by S3 when Alice is NoStatus) and `e2eowned.dot` (PoP-Full, used by S3 when the Personhood precompile has flipped Alice to Full). The NoStatus branch needs no admin help; the PoP-Full branch needed Bob to register it back when the chain team granted him Full status once. After that one-shot registration the label persists until expiry, so Bob can stay NoStatus going forward — ownership and PoP-grade are decoupled after registration.
|
|
111
|
+
|
|
112
|
+
### 5. Register `e2eownedns02.dot` directly as Bob
|
|
113
|
+
|
|
114
|
+
Register the domain using the dedicated tool:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
node tools/register-test-fixture-paseo-next-v2.mjs e2eownedns02
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Expected: `e2eownedns02.dot` is owned by Bob (`0x41dccbd49b26c50d34355ed86ff0fa9e489d1e01`).
|
|
121
|
+
The tool is idempotent: it leaves Bob-owned state alone and transfers the label back to Bob if a failed S3 fixture run accidentally left it owned by Alice.
|
|
122
|
+
|
|
123
|
+
### 6. Ensure Bob owns `e2eowned.dot` on paseo-next-v2
|
|
124
|
+
|
|
125
|
+
S3 picks `e2eowned.dot` when Alice is PoP-Full at test start. If the label is unregistered, Alice's deploy gets routed through the full register flow and her own H160 lands as owner — at which point every subsequent S3 run on the Full path "succeeds" cleanly (`exit 0`) instead of being rejected (`exit 78`), and the test fails. Bob must own this label.
|
|
126
|
+
|
|
127
|
+
If Bob already owns it (`ownerOf` on `DOTNS_REGISTRAR` returns `0x41dccbd…`), skip. Otherwise:
|
|
128
|
+
|
|
129
|
+
- **If nobody owns it yet:** registration needs Bob to hold Full PoP. Coordinate with the chain team to flip Bob's Personhood precompile to Full, then run `node tools/register-e2eowned-paseo-next-v2.mjs` (the script targets Bob via `//Bob`). After registration Bob can drop back to NoStatus.
|
|
130
|
+
- **If Alice (or anyone other than Bob) is squatting:** the owner can call `transferFrom(<current>, Bob, tokenId)` on `DOTNS_REGISTRAR`. ERC721 transfer is unconditional on the recipient (no PoP check) and doesn't need Bob's signer. `tools/transfer-e2eowned-to-bob.mjs` does this for Alice → Bob in one shot (was added to recover from a botched PR-CI run on 2026-05-17, see issue #381 thread).
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## No pre-registration needed for `e2epoolns01.dot` / direct NoStatus labels
|
|
135
|
+
|
|
136
|
+
The stable happy-path labels auto-register to the selected test signer on first deploy. Subsequent runs exercise the update path (new contenthash under existing ownership). On paseo-next-v2 these labels must remain NoStatus-compatible because DotNS self-attestation is no longer available.
|
|
137
|
+
|
|
138
|
+
## Verifying locally
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Paseo
|
|
142
|
+
E2E=1 E2E_SIGNER=pool E2E_MERKLE=js E2E_SCENARIO=s1 \
|
|
143
|
+
BULLETIN_RPC=wss://paseo-bulletin-rpc.polkadot.io \
|
|
144
|
+
npm run test:e2e
|
|
145
|
+
|
|
146
|
+
# Paseo Next v2
|
|
147
|
+
E2E=1 E2E_SIGNER=pool E2E_MERKLE=js E2E_SCENARIO=s1 \
|
|
148
|
+
BULLETIN_RPC=wss://paseo-bulletin-next-rpc.polkadot.io \
|
|
149
|
+
BULLETIN_DEPLOY_ENV=paseo-next-v2 \
|
|
150
|
+
npm run test:e2e
|
|
151
|
+
# Previously named DOTNS_ENV; kept as deprecated alias for one release.
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Vary `E2E_SCENARIO` (`s1`, `s2`, `s3`), `E2E_SIGNER` (`pool`, `direct`), and `E2E_MERKLE` (`js`, `kubo`) to cover the full CI matrix.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Telemetry
|
|
2
|
+
|
|
3
|
+
Telemetry is **off by default for external users**. It is enabled automatically for known internal Parity contexts and can also be controlled explicitly.
|
|
4
|
+
|
|
5
|
+
## Opt in / opt out
|
|
6
|
+
|
|
7
|
+
- `BULLETIN_DEPLOY_TELEMETRY=1`: explicit opt-in
|
|
8
|
+
- `BULLETIN_DEPLOY_TELEMETRY=0`: force off
|
|
9
|
+
|
|
10
|
+
Internal detection signals are OR'd together:
|
|
11
|
+
|
|
12
|
+
1. `GITHUB_REPOSITORY` matches a known internal org
|
|
13
|
+
2. `RUNNER_NAME` starts with `parity-`
|
|
14
|
+
3. `git remote get-url origin` points at a known internal org
|
|
15
|
+
|
|
16
|
+
## What is tracked
|
|
17
|
+
|
|
18
|
+
- deploy duration and success/failure
|
|
19
|
+
- storage phase timing
|
|
20
|
+
- DotNS phase timing
|
|
21
|
+
- pool account selection
|
|
22
|
+
- source metadata such as repo, branch, and CI vs local
|
|
23
|
+
- tool version
|
|
24
|
+
|
|
25
|
+
## Ambient Sentry mode
|
|
26
|
+
|
|
27
|
+
If another app embeds `bulletin-deploy` and already owns Sentry initialization, set these before importing or invoking the library:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
BULLETIN_DEPLOY_USE_AMBIENT_SENTRY=1
|
|
31
|
+
BULLETIN_DEPLOY_HOST_APP=<your-app-name>
|
|
32
|
+
BULLETIN_DEPLOY_HOST_APP_VERSION=<your-app-version>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`BULLETIN_DEPLOY_HOST_APP_VERSION` is optional but recommended — it populates `deploy.host_app_version` on every span, enabling version-correlated triage in the dashboard.
|
|
36
|
+
|
|
37
|
+
That makes `bulletin-deploy` reuse the existing Sentry client instead of calling its own `Sentry.init()`.
|
|
38
|
+
|
|
39
|
+
Requirements:
|
|
40
|
+
|
|
41
|
+
- the host app must initialize Sentry first
|
|
42
|
+
- Sentry SDK compatibility still matters
|
|
43
|
+
- quotas and issue grouping remain owned by the host project
|
|
44
|
+
|
|
45
|
+
## Tagging test traffic
|
|
46
|
+
|
|
47
|
+
Use `--tag` or `DEPLOY_TAG` to separate test and benchmark traffic from real deploys.
|
|
48
|
+
|
|
49
|
+
Examples:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
bulletin-deploy --tag e2e-ci-pr ./build my-app.dot
|
|
53
|
+
DEPLOY_TAG=load-test bulletin-deploy ./build my-app.dot
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Common tags in this repo:
|
|
57
|
+
|
|
58
|
+
- `e2e-ci-pr`
|
|
59
|
+
- `e2e-ci-nightly`
|
|
60
|
+
- `e2e-local-smoke`
|
|
61
|
+
- `e2e-local-pr`
|
|
62
|
+
- `e2e-local-nightly`
|
package/docs/testing.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Testing
|
|
2
|
+
|
|
3
|
+
The repo has three practical test layers: offline unit tests, live-testnet E2E coverage, and GitHub Actions matrices that exercise the shipped reusable workflow.
|
|
4
|
+
|
|
5
|
+
## Offline tests
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm test
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This runs the local Node test suite without network access.
|
|
12
|
+
|
|
13
|
+
## Live-testnet E2E
|
|
14
|
+
|
|
15
|
+
The E2E suite deploys real content to Paseo Bulletin and verifies the on-chain round-trip.
|
|
16
|
+
|
|
17
|
+
Local launchers:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm run test:e2e:smoke
|
|
21
|
+
npm run test:e2e:pr
|
|
22
|
+
npm run test:e2e:nightly
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Quiet mode:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
E2E_QUIET=1 npm run test:e2e:smoke
|
|
29
|
+
E2E_QUIET=1 npm run test:e2e:pr
|
|
30
|
+
E2E_QUIET=1 npm run test:e2e:nightly
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Each scenario writes a JUnit XML report under `e2e-reports/`.
|
|
34
|
+
|
|
35
|
+
For one-time chain setup, see [E2E test setup](./e2e-bootstrap.md).
|
|
36
|
+
|
|
37
|
+
## CI matrices
|
|
38
|
+
|
|
39
|
+
`.github/workflows/e2e.yml` calls the shipped reusable `.github/workflows/deploy.yml` so the E2E jobs exercise the same path consumers use.
|
|
40
|
+
|
|
41
|
+
- per-PR: stable happy-path coverage plus negative ownership coverage
|
|
42
|
+
- nightly: broader signer, merkleization, and mirror-path coverage
|
|
43
|
+
|
|
44
|
+
E2E deploys are tagged so telemetry can distinguish them from real-user traffic. See [Telemetry](./telemetry.md).
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@parity/product-deploy",
|
|
3
|
+
"version": "0.7.28-rc.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/paritytech/bulletin-deploy.git"
|
|
8
|
+
},
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"registry": "https://registry.npmjs.org",
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"bin": {
|
|
17
|
+
"bulletin-deploy": "./bin/bulletin-deploy",
|
|
18
|
+
"bulletin-bootstrap": "./bin/bulletin-bootstrap"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./deploy": {
|
|
26
|
+
"types": "./dist/deploy.d.ts",
|
|
27
|
+
"import": "./dist/deploy.js"
|
|
28
|
+
},
|
|
29
|
+
"./manifest-roundtrip": {
|
|
30
|
+
"types": "./dist/manifest-roundtrip.d.ts",
|
|
31
|
+
"import": "./dist/manifest-roundtrip.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"bin",
|
|
37
|
+
"docs",
|
|
38
|
+
"assets",
|
|
39
|
+
"tools/release-retry-wrapper.mjs"
|
|
40
|
+
],
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsup src/index.ts src/deploy.ts src/dotns.ts src/pool.ts src/telemetry.ts src/memory-report.ts src/merkle.ts src/gh-pages-mirror.ts src/version-check.ts src/bug-report.ts src/run-state.ts src/environments.ts src/errors.ts src/manifest.ts src/chunk-probe.ts src/manifest-embed.ts src/manifest-fetch.ts src/manifest-roundtrip.ts src/incremental-stats.ts src/chunker.ts src/personhood/encoding.ts src/personhood/hashing.ts src/personhood/constants.ts src/personhood/member-key.ts src/personhood/people-client.ts src/personhood/reprove.ts src/personhood/bind-personal-id.ts src/personhood/claim-pgas.ts src/personhood/bind-paid-alias.ts src/personhood/bootstrap.ts src/manifest/types.ts src/manifest/schema.ts src/manifest/byte-budget.ts src/manifest/config-load.ts src/manifest/publish.ts --format esm --dts --clean --target node22",
|
|
43
|
+
"refresh-environments": "node scripts/refresh-environments.mjs",
|
|
44
|
+
"check:watched-dependencies": "node tools/check-watched-dependencies.mjs",
|
|
45
|
+
"prepare": "npm run build",
|
|
46
|
+
"test": "npm run build && node --test test/test.js test/cli-help.test.js test/helpers/e2e-helpers.test.js test/environments.test.js test/refresh-environments.test.js test/watched-dependencies.test.js test/chunk-sharing-report.test.js test/product-manifest.test.js",
|
|
47
|
+
"test:e2e": "npm run build && node --test test/e2e.test.js",
|
|
48
|
+
"test:e2e:smoke": "bash scripts/e2e-pass.sh smoke",
|
|
49
|
+
"test:e2e:pr": "bash scripts/e2e-pass.sh pr",
|
|
50
|
+
"test:e2e:nightly": "bash scripts/e2e-pass.sh nightly",
|
|
51
|
+
"benchmark": "npm run build && node benchmark.js"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@ipld/car": "^5.4.3",
|
|
55
|
+
"@ipld/dag-pb": "^4.1.3",
|
|
56
|
+
"@noble/hashes": "^1.7.2",
|
|
57
|
+
"@polkadot-api/metadata-builders": "^0.14.2",
|
|
58
|
+
"@polkadot-api/substrate-bindings": "^0.20.2",
|
|
59
|
+
"@polkadot-labs/hdkd": "^0.0.28",
|
|
60
|
+
"@polkadot-labs/hdkd-helpers": "^0.0.30",
|
|
61
|
+
"@polkadot/keyring": "^14.0.3",
|
|
62
|
+
"@polkadot/util-crypto": "^14.0.3",
|
|
63
|
+
"@sentry/node": "^9.14.0",
|
|
64
|
+
"ipfs-unixfs": "^11.2.0",
|
|
65
|
+
"ipfs-unixfs-importer": "^16.1.4",
|
|
66
|
+
"jiti": "^2.4.2",
|
|
67
|
+
"multiformats": "^13.4.1",
|
|
68
|
+
"polkadot-api": "^2.1.3",
|
|
69
|
+
"verifiablejs": "^1.2.0",
|
|
70
|
+
"viem": "^2.30.5"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@types/node": "^22.0.0",
|
|
74
|
+
"tsup": "^8.5.0",
|
|
75
|
+
"typescript": "^5.9.3",
|
|
76
|
+
"ws": "^8.20.1"
|
|
77
|
+
},
|
|
78
|
+
"minimumVersion": "0.5.6",
|
|
79
|
+
"engines": {
|
|
80
|
+
"node": ">=22"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Selective retry wrapper for release E2E.
|
|
3
|
+
//
|
|
4
|
+
// Spawns a child process (the deploy CLI / test runner invocation), captures
|
|
5
|
+
// stdout AND stderr, classifies the failure mode, and exits with 75 on
|
|
6
|
+
// flake-class matches (retry-eligible) or the child's own exit code otherwise.
|
|
7
|
+
//
|
|
8
|
+
// Both streams are passed through to the parent's stdout/stderr so the GH
|
|
9
|
+
// Actions job log still shows everything live.
|
|
10
|
+
//
|
|
11
|
+
// node --test captures each test-file subprocess's output and re-emits it as
|
|
12
|
+
// TAP YAML on its own stdout — so deploy CLI errors (e.g. "ChainHead
|
|
13
|
+
// disjointed") appear on stdout, not stderr. Capturing both is required.
|
|
14
|
+
//
|
|
15
|
+
// Configure nick-fields/retry@v3 with retry_on_exit_code: 75 so retries only
|
|
16
|
+
// fire for the named transient classes. See
|
|
17
|
+
// docs-internal/superpowers/specs/2026-05-22-ci-restructure-design.md.
|
|
18
|
+
|
|
19
|
+
import { spawn } from "node:child_process";
|
|
20
|
+
|
|
21
|
+
// Exact substrings that map to retry-eligible flake classes.
|
|
22
|
+
// Patterns derived from Sentry telemetry (top transient errors over 30d on
|
|
23
|
+
// the e2e-ci-pr and e2e-ci-release tags).
|
|
24
|
+
const FLAKE_PATTERNS = [
|
|
25
|
+
"Invalid: Stale", // tx Invalid/Stale (nonce race) — papi 1.x format
|
|
26
|
+
'"type": "Stale"', // tx Invalid/Stale — papi 2.x JSON format
|
|
27
|
+
"ChainHead disjointed", // RPC reorg / WS flake
|
|
28
|
+
"Connection lost", // WS hard drop
|
|
29
|
+
"Account mapping did not take effect", // Revive mapping race
|
|
30
|
+
"requires Node.js >=22", // parity-default runner downgrade (Node v18) — infra flake
|
|
31
|
+
"received a shutdown signal", // runner process killed mid-job — CI infra flake
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
// output: combined stdout+stderr text from the child. Any flake pattern
|
|
35
|
+
// appearing anywhere in the child's output makes the run retry-eligible.
|
|
36
|
+
export function classifyForRetry(output, childExitCode = 1) {
|
|
37
|
+
if (childExitCode === 0) return 0;
|
|
38
|
+
for (const pat of FLAKE_PATTERNS) {
|
|
39
|
+
if (output.includes(pat)) return 75;
|
|
40
|
+
}
|
|
41
|
+
return childExitCode || 1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// CLI entry: when run directly, spawn argv tail as a child and classify.
|
|
45
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
46
|
+
const [cmd, ...args] = process.argv.slice(2);
|
|
47
|
+
if (!cmd) {
|
|
48
|
+
console.error("usage: release-retry-wrapper.mjs <command> [args...]");
|
|
49
|
+
process.exit(2);
|
|
50
|
+
}
|
|
51
|
+
const child = spawn(cmd, args, { stdio: ["inherit", "pipe", "pipe"] });
|
|
52
|
+
let outputBuf = "";
|
|
53
|
+
child.stdout.on("data", (chunk) => {
|
|
54
|
+
process.stdout.write(chunk); // pass through stdout to job log
|
|
55
|
+
outputBuf += chunk.toString();
|
|
56
|
+
});
|
|
57
|
+
child.stderr.on("data", (chunk) => {
|
|
58
|
+
process.stderr.write(chunk); // pass through stderr to job log
|
|
59
|
+
outputBuf += chunk.toString();
|
|
60
|
+
});
|
|
61
|
+
child.on("error", (err) => {
|
|
62
|
+
process.stderr.write(`[release-retry-wrapper] failed to spawn: ${err.message}\n`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
});
|
|
65
|
+
// Use `close` (not `exit`) so both pipes are fully drained before we
|
|
66
|
+
// classify — `exit` can fire before the last `data` chunk lands.
|
|
67
|
+
child.on("close", (code) => {
|
|
68
|
+
const cls = classifyForRetry(outputBuf, code ?? 1);
|
|
69
|
+
if (cls === 75) {
|
|
70
|
+
console.error("[release-retry-wrapper] flake-class match — exiting 75 to signal retry");
|
|
71
|
+
}
|
|
72
|
+
process.exit(cls);
|
|
73
|
+
});
|
|
74
|
+
}
|