Skip to content

feat(deploy): add --manifest for machine-readable deploy output#47

Open
shawntabrizi wants to merge 1 commit intomainfrom
feat/deploy-manifest-output
Open

feat(deploy): add --manifest for machine-readable deploy output#47
shawntabrizi wants to merge 1 commit intomainfrom
feat/deploy-manifest-output

Conversation

@shawntabrizi
Copy link
Copy Markdown
Member

Summary

  • Adds dot deploy --manifest <path> — writes a versioned JSON manifest on success with domain, app URL, CIDs, and deployed contract addresses
  • Fixes a display gap: deployed contracts were silently dropped from the final summary in both the TUI and the headless output even though the orchestrator already collected them
  • New module src/utils/deploy/manifest.ts (React/Ink-free per the SDK invariant) + 6 tests

Why

dot deploy --contracts deploys contracts to Asset Hub and the orchestrator already knows their addresses — DeployOutcome.contracts: Array<{ name; address }> is populated by maybeRunContracts in run.ts. But nothing crossed the process boundary:

  • The TUI FinalResult component only rendered URL / domain / appCid / ipfsCid / metadataCid.
  • The headless printFinalResult printed the same set; no contracts line.
  • There was no JSON / manifest output of any kind.

Downstream tooling (template generators, CIs that wire contract addresses into a frontend build) had two bad options:

  1. Parse the Ink TUI — fragile, shouldn't be a contract.
  2. Re-query the chain for Revive.Instantiated events from the deployer's address and disambiguate by code hash — requires re-deriving what the CLI already had.

Every comparable Solidity deploy tool writes a deployment manifest as a standard part of its flow: hardhat-deploy writes deployments/<network>/<name>.json, Hardhat Ignition writes ignition/deployments/<id>/deployed_addresses.json, Foundry writes broadcast/<Script>.s.sol/<chainId>/run-latest.json. Ignition is the closest precedent — also a CLI, also has to expose state across a process boundary — and its manifest shape is what this PR models on.

Manifest shape

{
    "version": 1,
    "fullDomain": "my-app.dot",
    "appUrl": "https://my-app.dot.li",
    "appCid": "bafy…",
    "ipfsCid": "bafy…",
    "metadataCid": "bafy…",
    "contracts": [{ "name": "ProofOfExistence", "address": "0x…" }]
}

ipfsCid and metadataCid are omitted (not null) when absent, so schema consumers can rely on in checks. Versioned so future shape changes are non-breaking additions or get a version: 2 bump.

Error behaviour

If the manifest write fails (e.g. unwritable path), we log a warning to stderr but do not fail the deploy — the on-chain work is done by the time we write, so blowing up the exit code would mislead CI into retrying a deploy that actually succeeded.

Changes

File What
src/utils/deploy/manifest.ts New — DeployManifest type, buildManifest, writeManifest. Stays React/Ink-free per the deploy-SDK invariant.
src/utils/deploy/manifest.test.ts New — 6 tests covering field carry-through, absent-field omission, order preservation, round-trip, nested directory creation.
src/commands/deploy/index.ts Adds --manifest option; both dispatch branches (runHeadless + runInteractive) now return DeployOutcome so the write happens in one place, identically, regardless of how the user invoked dot deploy. printFinalResult also now prints the deployed contracts.
src/commands/deploy/DeployScreen.tsx FinalResult now lists { name: address } rows for each deployed contract.
README.md Documents --manifest with the format.
.changeset/deploy-manifest-output.md minor changeset.

Test plan

  • pnpm format:check clean
  • npx tsc --noEmit clean
  • pnpm test — 353 passed (up from 347; +6 for manifest)
  • pnpm buildbun build --compile produces ./dist/dot
  • Manual smoke: dot deploy --signer dev --domain test-xx --buildDir dist --manifest /tmp/deploy.json in a hardhat project, verify /tmp/deploy.json contains the two deployed contracts

`dot deploy --contracts` already knows the deployed contract addresses at
the end of the run — `DeployOutcome.contracts` is populated by the
contracts phase — but the info never crossed the process boundary. The
TUI's final screen silently dropped the addresses, and there was no
machine-readable output at all, so downstream tooling had to re-query
the chain for Revive.Instantiated events just to rebuild what the CLI
already had.

Add `--manifest <path>` that writes a versioned JSON file on success:

    {
      "version": 1,
      "fullDomain": "my-app.dot",
      "appUrl": "https://my-app.dot.li",
      "appCid": "bafy...",
      "ipfsCid": "bafy...",
      "metadataCid": "bafy...",
      "contracts": [{ "name": "ProofOfExistence", "address": "0x..." }]
    }

Also surface the deployed contracts in the human-readable output path of
both the TUI and the headless summary — previously hidden in both.

Manifest serialisation lives in src/utils/deploy/manifest.ts so the SDK
consumers (WebContainer / RevX) can format their own manifests without
going through the CLI process boundary. React/Ink-free per the
deploy-SDK invariant.
@github-actions
Copy link
Copy Markdown
Contributor

Dev build ready — try this branch:

curl -fsSL https://raw.githubusercontent.com/paritytech/playground-cli/main/install.sh | VERSION=dev/feat/deploy-manifest-output bash

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant