(
opts: CreateFromPlanOptions,
deps: TestDeps = {},
)
| 1840 | * when M3.3 lands. |
| 1841 | */ |
| 1842 | export async function runCreateFromPlan( |
| 1843 | opts: CreateFromPlanOptions, |
| 1844 | deps: TestDeps = {}, |
| 1845 | ): Promise<CliCreateFromPlanResponse> { |
| 1846 | assertIdempotencyKey(opts.idempotencyKey); |
| 1847 | // codex #128 P2: validate the derived `<key>:run` chain key before the |
| 1848 | // create POST (see runCreate) so a near-limit base key fails fast instead |
| 1849 | // of orphaning a created test with no run. |
| 1850 | assertChainedRunKeyFits(opts.run, opts.idempotencyKey); |
| 1851 | requireNonEmpty('plan-from', opts.planFrom); |
| 1852 | |
| 1853 | if (opts.targetUrl !== undefined) { |
| 1854 | assertNotLocal(opts.targetUrl); |
| 1855 | } |
| 1856 | |
| 1857 | const plan = readPlanFromGuarded(opts.planFrom); |
| 1858 | |
| 1859 | // The plan validated (projectId/type/name/planSteps present). Only NOW |
| 1860 | // warn that overlapping `test create` flags were ignored — emitting this |
| 1861 | // before validation made a missing-projectId failure look like the |
| 1862 | // ignored --project flag was the cause (dogfood L1778). |
| 1863 | if (opts.ignoredFlags && opts.ignoredFlags.length > 0) { |
| 1864 | const stderr = deps.stderr ?? ((line: string) => process.stderr.write(`${line}\n`)); |
| 1865 | stderr( |
| 1866 | `warning: --plan-from supplies the test definition; ignoring ${opts.ignoredFlags.join(', ')}. ` + |
| 1867 | `Edit the plan JSON to change these fields.`, |
| 1868 | ); |
| 1869 | } |
| 1870 | |
| 1871 | // FE-only after the 2026-05-13 scope cut. The server also rejects |
| 1872 | // BE plans, but bailing here saves a round trip and matches piece-2's |
| 1873 | // "fast-fail at the input gate" pattern. |
| 1874 | if (plan.type === 'backend') { |
| 1875 | throw ApiError.fromEnvelope({ |
| 1876 | error: { |
| 1877 | code: 'VALIDATION_ERROR', |
| 1878 | message: 'Backend tests via the CLI require --code-file.', |
| 1879 | nextAction: |
| 1880 | "Backend tests via the CLI require '--code-file <path>'. Use 'testsprite test create --type backend --code-file foo.py'.", |
| 1881 | requestId: 'local', |
| 1882 | details: { field: 'type', reason: 'backend not supported in --plan-from path' }, |
| 1883 | }, |
| 1884 | }); |
| 1885 | } |
| 1886 | |
| 1887 | const idempotencyKey = opts.idempotencyKey ?? `cli-create-plan-${randomUUID()}`; |
| 1888 | if (opts.idempotencyKey === undefined && (opts.output === 'json' || opts.verbose || opts.debug)) { |
| 1889 | const stderr = deps.stderr ?? ((line: string) => process.stderr.write(`${line}\n`)); |
| 1890 | stderr(`idempotency-key: ${idempotencyKey}`); |
| 1891 | } |
| 1892 | |
| 1893 | const body = { |
| 1894 | projectId: plan.projectId, |
| 1895 | type: plan.type, |
| 1896 | name: plan.name, |
| 1897 | description: plan.description, |
| 1898 | priority: plan.priority, |
| 1899 | planSteps: plan.planSteps, |
no test coverage detected