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
73 changes: 59 additions & 14 deletions .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ fileignoreconfig:
- filename: src/core/failure.test.ts
checksum: 242d43885d1e3ef46edf1e347899a90549ebf95ec6827426746852f7a6dfc418
- filename: test/integration/retired-commands.test.ts
checksum: f43448a6d3855c3823d65dd66150bbd26410ae0be8a921476ca8a948d65caa16
checksum: 4f1a3d7b6b6684986f720a44dcd4d4c014a64dd15c41d41d0266afb0ebe828c0
- filename: test/integration/manage-base-path.test.ts
checksum: 79eb9ad420ea47d5bee8045d812c45b010bbeeafcaf5f85d11653140b0cd0db1
- filename: src/transport/rest-client.ts
Expand Down Expand Up @@ -87,7 +87,7 @@ fileignoreconfig:
- "'SECRET=hunter2'"
- "formFieldKey"
- filename: test/integration/projects-create.test.ts
checksum: 0161c3bba176134df0bc1a3a29cda4e1c0b143afbee202c110cdfed19b08d8e0
checksum: e37d9a0fdce75f942836f621a2e281cb9b448cd583673ebcacb075de3faaf187
- filename: test/fixtures/README.md
checksum: d801c84c8b7d7f38f967573e9a3a70da4405b7cbcbf10d2a6e5be3d65fb3daa1
allowed_patterns:
Expand Down Expand Up @@ -167,11 +167,11 @@ fileignoreconfig:
ignore_detectors:
- filename
- filename: src/environments/environment.inputs.test.ts
checksum: 499a4601152dded32b766abd8e43aa2ddd88e4e62fc5389b00a268d730178565
checksum: 3590697ca0f0f0c0c7b6e64eddfecbdef8838ff260315c70178786490664682c
ignore_detectors:
- filename
- filename: src/core/inputs.ts
checksum: 638c1093562cc19038395b498202d06aef53b8d2537ee80b715611f19f83c78b
checksum: a4094f68a2fb6b012cfc259f686e362d5a00b34dce85f9d46f1ead270263f15e
allowed_patterns:
- "FlagKey"
- "InputKeys"
Expand Down Expand Up @@ -224,11 +224,12 @@ fileignoreconfig:
allowed_patterns:
- "FlagKey"
- filename: src/resources.test.ts
checksum: 742d9faaa855390c853963388bb2479355fe69f0ee05b5a8965de091621d711d
allowed_patterns:
- "a project name passed on argv to the project resolver"
- "expect\\(Object.keys\\(DEPENDENCIES\\)\\).toEqual\\(\\['project', 'env'\\]\\)"
- filename: AGENTS.md
checksum: 562fc91581867ca4682ce2181379aeedd6c50ff666fa706c558eabfb688e1a46
checksum: 89b7e72236e7218326eb3c9c3176c5ab36d58e79a9bf845f422fe28d98c144a1
allowed_patterns:
- "Do not add an exemption to a guard to make a new file pass"
- "passes its own error wording to `client.request\\(req, MESSAGES\\)`"
Expand All @@ -246,25 +247,25 @@ fileignoreconfig:
- filename: src/core/project-config.test.ts
checksum: 65c0a613ec77d4dc6727224d4d097de4a02b300339286db692dbaea9379565ae
- filename: src/core/resolve.ts
checksum: 5d150db11cb1c976911ecba61336118ddad051942da95f809695c0cf0346de42
checksum: a5608d22286efdd4915639faff6e05a588e60e205c74e0398e389822eb8c7292
- filename: src/core/resolve.test.ts
checksum: b62b53aedd32ab01212508d79bf4c306dfbd9b0c9788e5fc449886eb770e0377
checksum: 8740a27f759a106e0ddcf38874f83394d2226dd8a908d9499898d774fea3a7a0
- filename: src/git/local-repository.ts
checksum: b9091ed135dfebdf590a5412bbfba2b2f96d4a177cf944a20909b93405268e9f
- filename: test/guards/layering.test.ts
checksum: 2f1b3934e685c2366e45c75f379d63c0ca7bee11108df1e0010ead13159c6b9b
checksum: fea55eeb036ea4acb1cc4d177ae9cbfc1a06bbc5a1ea65b2f5c82717cd0251a9
- filename: src/commands/launch/projects/create.test.ts
checksum: 9c40b4b6ed4f7d678ecb921a71f5af7284cd685c1337f47144456ae43a38b1ad
- filename: src/commands/launch/projects/delete.test.ts
checksum: d67d8a804d14f9b809153d10b0cf9d5e52b70f9e0b65678ebb1663a7d2da22c1
- filename: test/integration/projects-delete.test.ts
checksum: bb59cbe1f4f7b3ac6aa7944067c1ab1214a7c5d20229e9d6577cdaabec56622e
- filename: src/core/launch-command.ts
checksum: b14abd1d4cee3e93c4458ab3567b1f252564bda7e12773cfa1e0d678967664a4
checksum: 01904855aca54cbbcb846069cee5a0732da1db082110e7e454a5c1c532ab02fb
- filename: src/core/launch-command.test.ts
checksum: c4d3785f25377db560bb9daa5d0d080a0131056e6c31e3b45cb4f1f2347305ed
- filename: src/projects/project.inputs.test.ts
checksum: eaecaba9eddec128186871550fc5802166fa56a2e89741d72ac955fcfe2f952f
checksum: 8242f4d40388f1a7f1d08c11d2571cb45a9294069a8248a5272bc5606807bb60
- filename: test/integration/projects-command-flows.test.ts
checksum: 30858bb3dff8a22406efa4ac82d882d1501797cdda24e09555aecc0bcd8dca0b
- filename: src/core/redact.test.ts
Expand Down Expand Up @@ -292,7 +293,7 @@ fileignoreconfig:
- filename: src/functions/function.errors.test.ts
checksum: ac0a55e5bee974fefa9fb95541adba63e9a2c2c6e6c47b87c8ca1022542e75f0
- filename: src/transport/errors.test.ts
checksum: b7e28a9062e29a87c8c8b882c6543d50e90e12509c5629ee362ffcac430d01f1
checksum: f38547e2a4639ae150b53f955963ce00c1922a4223c89e489ba5b7ca75a691d0
- filename: src/transport/auth-strategy.ts
checksum: 6fe87def1b508cb67203d4445d9bd889570e512ed4194dfc4fdd3182bc8b87b2
- filename: src/functions/function.logger.test.ts
Expand All @@ -304,7 +305,7 @@ fileignoreconfig:
- filename: test/credential-guard.setup.ts
checksum: 519ccbeb0552fdb1d5f27308c56477c0258ee6cc0adec8f618e8e5bc047cbf6d
- filename: src/environments/types.ts
checksum: 8f57348764a69aeb7c2351faf3a5c80fda483a1a1f009e126ff71a9679d92457
checksum: 6c054295075e51e9ce0f4514ebdc86a48bb74db9932a2baaa9f9158e9c14c6e8
- filename: src/commands/launch/env/get.test.ts
checksum: 6e739ef12bc0d887e652e23ee54d9fac30dd6a3505cf464cdaefc0e696cf3e51
- filename: test/integration/environments-delete.test.ts
Expand All @@ -324,13 +325,13 @@ fileignoreconfig:
- filename: src/commands/launch/env/update.test.ts
checksum: 2da219594e7bdd589adc0eff9ff035252a75aaa51dfa20514b18fd3266d7b752
- filename: README.md
checksum: 6d13077c028465448536779a02a635c55069d5aeaeea6f6e4882226da8b9f75e
checksum: 9c87e9e46dbc9606b4946bb6d84ce36352d8f6d733280f5f48e0a65bd6cf6ded
allowed_patterns:
- "password-protection"
- "-p, --password"
- "-u, --username"
- filename: test/integration/environments-create.test.ts
checksum: 1b87f454b1534bf0b73ebb52cdaf9af231beb57d5746e521a4504edad819c89a
checksum: 0c64a4408d3c150a33c442403688d1e1d058f415cfdba704e372455927daa7e4
- filename: src/commands/launch/variables/list.test.ts
checksum: 87ccb762f4931326fc50bca1c01aeb4a16d552e4dfa141d00370fdfafa4363be
- filename: src/commands/launch/variables/set.test.ts
Expand Down Expand Up @@ -411,8 +412,52 @@ fileignoreconfig:
checksum: 5ea6a0fcd331496ca19773e90dab81e09eb5290b8f22a1880bffc7916f3778b2
- filename: test/integration/variables-set-unset.test.ts
checksum: 7af9dde4711849d0908d0de54347055a7c2a8d8920f9fcc0b24382b02bceaed9
- filename: test/fixtures/deployments-list.json
checksum: 2f10f24dc0ceb8e85f5201b7c1530c0c540c044ef50b732cc29e07289112316e
- filename: test/integration/deployments-get.test.ts
checksum: beb431ee58fbb3cf72da369514bbeede2c7358f95960979157362053f5b89789
- filename: test/integration/deployments-list.test.ts
checksum: c661f0bd3682ea5b0bfeed782a7c5d03ed75bd86aa1c283bb4b2bda1325bab00
- filename: src/deployments/deployment.inputs.test.ts
checksum: 4c6244f99f62f9731ee925526d17f3ee611d3562cc51cace09ad740ba20c4c84
- filename: test/fixtures/deployment-get.json
checksum: acae8ee5ba96a2aafcf43e0b35b3bd22df78bb9ddbe3bad5e7f86c537316721a
- filename: src/commands/launch/deployments/get.test.ts
checksum: ae3346f213f9ba5a0a32ef2f2f88146e705838f1eca035de659fc4f8d9c0223b
- filename: src/commands/launch/deployments/list.test.ts
checksum: e493cd51e7c65bbf5b4f71704478b7a669bca4342efc865a1363bc508fe6f9f0
- filename: src/deployments/deployment.presenter.test.ts
checksum: e393d6bb6ce3fd92920f5003603b161186085ea8939fae704e6f71bd9e1778bc
- filename: test/integration/deployments-create.test.ts
checksum: fd367019e10b47121898440e4b3a54fb2041d6302bee2dea28a97ad58eb88ee9
- filename: src/deployments/deployment.watcher.test.ts
checksum: c2cdab908cba7d4e162d06f59a471f918c959eb9c220ebc3666f0c6299f141b2
- filename: src/deployments/deployment.create.ts
checksum: ca64f3b29a68c4a2755a88a141e2cd9dbd6fa851a2776876d78c40f3168492e3
- filename: src/commands/launch/deployments/create.test.ts
checksum: 50c3f35c7246b49f6ebf5e48a9a9646ccbcb563c0c0e042fd38917e2f98cbba3
- filename: src/deployments/deployment.create.test.ts
checksum: 6545afa21a23b7e5de18ad8ff417f88a184577e7042713cfda90758ccbcd9869
- filename: test/integration/deployments-rollback.test.ts
checksum: 08400c5435c84cd162fefc585f6c32cddfcaa8909d2369341748b421e7f12073
- filename: test/integration/deployments-cancel.test.ts
checksum: 02c012da974f1f9b8b851d7e00878fef50c1ba7e32b6acf72a309582c66aa5c2
- filename: src/commands/launch/deployments/cancel.test.ts
checksum: da8d09de7f03cfe67df75ebc1636b36feb6688cf85984c357fd5304852d126e5
- filename: src/commands/launch/deployments/rollback.test.ts
checksum: 5331e774d07387b1691c47168afa8d454bdee60d26ac9c6ed3f4640fc85ff8b8
- filename: src/deployments/deployments.api.test.ts
checksum: b27d91317c17f1754d5853c68f4968e63dc2b3579eab26b4c772cf3cd3efbdd0
- filename: src/deployments/deployment.prompt.test.ts
checksum: 3367e53ce2f0284c14524da893e7f82ef613fcdac1e9689ac408709e7f7c153d
- filename: test/integration/deployments-request-bodies.test.ts
checksum: 37d518b1d7671dc1bb9edd147f381c63ddb22e8a413dd43c1c280fb583e83ad2
- filename: src/cache/cache.inputs.test.ts
checksum: 4c602f53a296caec6bab752c905a8abb3da2462ed83b0a5337e8838e87cd9dbd
- filename: src/commands/launch/cache/purge.test.ts
checksum: f1a319cc3af775f28919e56fa17bd7b7e6b89cb4541db506ca8e5fac5edb6026
- filename: src/deployments/commit.prompt.test.ts
checksum: d811a8b35d640708a9d0e7b03d006fcae4718192adee94c47f625ce7662ea715
- filename: src/deployments/commit.prompt.ts
checksum: 6991eb373ee016ce44fc4f47044d559cfeefa1c411526d6fd88d77c568379041
version: "1.0"
41 changes: 29 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ file and line that broke its rule, and each was proven red by reintroducing its
| `test/guards/prompt-types.test.ts` | Every prompt call in `src` names a literal `type`, and every such type is registered with the real inquirer `cliux.inquire` uses once `LaunchCommand.init` has run. inquirer silently turns an unregistered type into a plain text box. | D1: `search-list` used, never registered |
| `test/integration/transport-content-type.test.ts` | For every method in `HTTP_METHODS`, a bodyless request carries no content type and a request with a body carries `application/json`, asserted on the wire. `withoutDefaultContentType` suppresses the utility client's default, so a bodyless POST, PUT or PATCH (for example `deployments:cancel`) no longer goes out as `application/x-www-form-urlencoded`. Only `utility-http-client.ts` builds an `HttpClient` and only `rest-client.ts` sets the JSON type. | D5: every DELETE sent `Content-Type: application/json` |
| `test/guards/tty-streams.test.ts` | `stdin.isTTY`, and the `isTTY` it becomes on the service context, are read only to decide whether the CLI may prompt (a read next to a prompt or a refusal to prompt) or on the plumbing lines that carry it there. Anything deciding what to draw reads `outputIsTTY` / `process.stdout.isTTY`. | D6: heartbeat drawn into a redirected file |
| `test/integration/deployments-request-bodies.test.ts` | A deployments mutation puts on the wire only the fields the management service DTO declares - `{commitHash?, uploadUid?}` for a create, `{deployment, reason?}` for a rollback - and never `environment`, which is the URL path. The service validates with `whitelist` and `forbidNonWhitelisted`, so any other key is a bare 400. | Live harness: `deployments:create` and `:rollback` sent `{environment, ...}` and failed with `Bad request` |
| `test/integration/retired-commands.test.ts` (named commands) | Every `launch:…` command named anywhere in `src` - a retirement message, a failure hint, an example - is either a registered command or on `PLANNED_COMMANDS` with the ticket that builds it, and a command drops off that list once it ships. | Review: retirement messages and hints pointed at commands the beta does not have |
| `test/guards/prompt-funnel.test.ts` | Every prompt goes through `LaunchCommand`'s `ux`, built once as `cancelOnInterrupt(cliux)`, so Ctrl-C at any prompt exits 3. The wrapper stays attached to `SIGINT` until the signal has reached every listener (it detaches in a microtask): inquirer's `cli-cursor` loads `signal-exit`, which re-raises `SIGINT` - exit 130 - when it finds itself the only listener, so a `once` listener made every list and checkbox prompt exit 130 (`src/core/interruptible-ux.test.ts` pins it). No source calls `cliux.inquire` / `prompt` / `confirm` under any name, hands `cliux` on as a value, or imports a prompt library; `search-list.ts` may register a type but never prompt. | D2: Ctrl-C exited 130 |

Expand Down Expand Up @@ -151,8 +152,9 @@ src/
each name the other in the layering allow-list
deployments/ the deployment repository, the status classification, the
wait/stream loop and LogTail that projects:create, deployments:create
and logs:get all drive, and the DeploymentFollower that watches one
deployment and announces its live URL
and logs:get all drive, the DeploymentFollower that watches one
deployment and announces its live URL, and the DeploymentCreator behind
deployments:create. It reaches uploads, for a FileUpload create
uploads/ zipping a folder, the signed upload URL, and the transfer behind every
FileUpload source (FolderUploader). The UploadScope picks the endpoint:
{ org } for a new project, { org, project } for a new environment,
Expand Down Expand Up @@ -640,6 +642,23 @@ there is **no server-side maximum at all**.
each repository builds on `scanPages`, because the page size is that repository's decision and not a
CLI-wide one; the scan-limit error each raises carries its own wording.

**The deployment commands (CL-7170).** `deployments:list`, `:get`, `:create`, `:rollback` and `:cancel`.

- `--deployment` is a 24-hex uid, validated while parsing (`FlagValueError`, exit 2, nothing sent; `LaunchCommand.init`
rethrows it as a plain `UsageError` so oclif's `Parsing --deployment` prefix never reaches the user), so `get`,
`rollback` and `cancel` share it. It depends on `--org`, `--project` and `--env`. `get` leaves it optional and
defaults to the latest deployment; `rollback` and `cancel` declare `picker` on the input (`all`, or `in-flight`
for `cancel`), which is the only case where the spec's `promptWhen` lets the picker run (`promptForDeployment`,
`src/deployments/deployment.prompt.ts`), so a terminal gets a list of the environment's newest deployments and
anything else gets the exit-2 missing-value error. A supplied flag never prompts.
- The service answers HTTP 200 `{ "deployment": null }` for a deployment that is not in the environment, so
`DeploymentsApi.get` words that as the same 404 `launch.DEPLOYMENT.NOT_FOUND` a missing one gets, and the commands
report the generic `No deployment with UID "<uid>" found in this environment.`
- Request bodies carry no `environment`; see the guard table. A validation rejection the service sends keyed by
field with only the generic `Bad request` is worded by `LaunchApiError` from the field and its code.
- Every table cell is stripped of control characters and line breaks by `renderTable`, and the presenter shows
only the first line of a commit message, truncated to 72 characters.

**The deployment wait/stream loop.** `src/deployments/deployment.watcher.ts` polls a deployment to a
terminal state and is the single place any command waits on one. `POST /projects` creates the
project, its first environment **and** its first deployment, so `projects:create` is its first
Expand Down Expand Up @@ -686,7 +705,7 @@ shade, and in green when stdout is a terminal (`styled` in `src/core/style.ts`,
redirected output stays free of escape codes). Once `POST /projects` succeeds, before the config file is
written or anything is watched, create prints V1's green `info: New project created successfully`
(`projectCreatedLine`); a failed create never prints it. On success create then prints V1's
`Deployment URL <url>` line - label bold, url blue on a terminal - before the project summary,
`Deployment URL: <url>` line - label bold, url blue on a terminal - before the project summary,
waits `SITE_OPEN_DELAY_MS` (six seconds, V1's wait, because a site opened the moment it reports
live can still answer "site not reachable") and opens that url in the browser, terminal or not, as V1
did. The wait goes through the injected `sleep`, so it is awaited and the browser opens before the
Expand All @@ -696,9 +715,8 @@ parseable timestamp printed: with a `timestamp` the service returns what came st
ascending order, and without one it returns the newest page in **descending** order, so never let the
cursor drop the query. The poll that sees the terminal status still reads the logs once more before
returning, so the last lines of a build are never lost. The logs are auxiliary: a
failed read prints one ` ! Could not read the deployment logs (...)` notice for the whole wait, is
retried from the same cursor on the next poll, and never changes the outcome - the status poll alone
decides that.
failed read prints nothing, is retried from the same cursor on the next poll, and never changes the
outcome - the status poll alone decides that.

**Writing a test for it: the fake clock must advance.** `now()` and `sleep()` are injected and both
are required, not optional with defaults. A fake `now: () => 0` with a `sleep` that does nothing
Expand Down Expand Up @@ -812,12 +830,11 @@ project and `--config`.
**Deployment failure is a partial success, and the wording says so.** The project and environment are
real and are **not** rolled back. Everything after `POST /projects` - finding the first environment,
finding its first deployment, and the wait itself - goes through the same wording when it fails, so a
502 from a lookup still tells the user what exists. `deploymentFailureMessage` names the status, the project and
environment that survived, and both follow-up commands with their scope already filled in -
`deployments:create` to retry and `logs:get` to inspect. It exits **1**, not 2: nothing about the
invocation was wrong. A wait that runs out is worded differently: the deployment may still finish, so
the message says not to start another one and names `deployments:get` and `logs:get` instead of
`deployments:create`.
502 from a lookup still tells the user what exists. `firstDeploymentFailureMessage` is the one builder:
it names the deployment and its status, says what was created (when something was) and ends with one
command - `logs:get` for a failed deployment, `deployments:get` for a wait that ran out or could not be
followed, `deployments:list` when no deployment was found - with its scope already filled in. It exits
**1**, not 2: nothing about the invocation was wrong.

**The FileUpload archive.** `src/uploads/upload.archive.ts` owns the exclusion list
(`node_modules`, `.git`, `.env`, `.env.local`, `.next`, `logs`, `.vscode`, `.cs-launch.json`) and
Expand Down
Loading
Loading