From 3248f57d9336856ef95f4e2310ba807b6c2c4bec Mon Sep 17 00:00:00 2001 From: finalerock44 Date: Thu, 5 Nov 2026 14:42:17 +0000 Subject: [PATCH] feat(report): deprecate allure and html-detailed, removed on 7 December 2026 The allure and html-detailed report formats are deprecated and will be removed on 7 December 2026. Both values stay valid after that date. A run that asks for html-detailed gets the standard HTML report, and a run that asks for allure gets no report, but neither run fails. - `dcd cloud` adds `report` to the notice context, so the server-side deprecation notices can be shown to runs that ask for either format. Older CLIs leave it out and evaluate the gate as false. - `dcd artifacts --report allure|html-detailed` prints a deprecation line on stderr, because that command fetches no notices. - The help for --report and --allure-path, and the MCP download tool's description, give the date. The old advice to use allure for a complete HTML report is gone. --- src/commands/artifacts.ts | 13 +++++++-- src/commands/cloud.ts | 3 +++ src/config/flags/output.flags.ts | 4 +-- src/mcp/tools/download-artifacts.ts | 4 ++- src/services/report-download.service.ts | 24 +++++++++++++++++ .../integration/artifacts.integration.test.ts | 26 ++++++++++++++++++ test/unit/notices.test.ts | 24 +++++++++++++++++ test/unit/report-download.service.test.ts | 27 ++++++++++++++++++- 8 files changed, 119 insertions(+), 6 deletions(-) diff --git a/src/commands/artifacts.ts b/src/commands/artifacts.ts index 4abbac5..c87448b 100644 --- a/src/commands/artifacts.ts +++ b/src/commands/artifacts.ts @@ -5,10 +5,12 @@ import { jsonFlag } from '../config/flags/output.flags.js'; import { type DownloadResult, ReportDownloadService, + reportFormatDeprecation, } from '../services/report-download.service.js'; import { resolveAuth } from '../utils/auth.js'; import { CliError, logger, validateEnum } from '../utils/cli.js'; import { resolveApiUrl } from '../utils/config-store.js'; +import { ui } from '../utils/ui.js'; const DOWNLOAD_OPTIONS = ['ALL', 'FAILED'] as const; const REPORT_OPTIONS = ['allure', 'html', 'html-detailed', 'junit'] as const; @@ -43,12 +45,12 @@ export const artifactsCommand = defineCommand({ report: { type: 'string', description: - 'Download a test report in the specified format (options: allure, html, html-detailed, junit)', + 'Download a test report in the specified format (options: junit, html, html-detailed, allure). allure and html-detailed are deprecated and will be removed on 7 December 2026.', }, 'allure-path': { type: 'string', description: - 'Custom file path for downloaded Allure report (default: ./report.html)', + 'Custom file path for downloaded Allure report (default: ./report.html). Deprecated: Allure reports will be removed on 7 December 2026.', }, 'html-path': { type: 'string', @@ -85,6 +87,13 @@ export const artifactsCommand = defineCommand({ // Success lines are dropped under --json; warnings stay on stderr. const log = json ? undefined : (m: string) => logger.log(m); + // This command fetches no notices and submits nothing, so neither the + // deprecation notice nor the API's submit warning reaches it. + const deprecation = reportFormatDeprecation(report); + if (deprecation) { + process.stderr.write(`${ui.deprecation(deprecation)}\n`); + } + const auth = await resolveAuth({ apiKeyFlag }); if (downloadArtifacts && report) { diff --git a/src/commands/cloud.ts b/src/commands/cloud.ts index f9a8261..13870b4 100644 --- a/src/commands/cloud.ts +++ b/src/commands/cloud.ts @@ -509,6 +509,9 @@ export const cloudCommand = defineCommand({ // As requested ('default' when not passed), not as the API resolves // it: the gpu1 retirement notice is aimed at runs that ask for gpu1. runner_type: runnerType, + // As passed (undefined without --report): the allure and + // html-detailed retirement notices are gated on it. + report, cli_version: cliVersion, ci_provider: ciContext.provider, ci_wrapper_version: ciContext.wrapperVersion, diff --git a/src/config/flags/output.flags.ts b/src/config/flags/output.flags.ts index c4fdff0..eeeac3c 100644 --- a/src/config/flags/output.flags.ts +++ b/src/config/flags/output.flags.ts @@ -26,7 +26,7 @@ export const outputFlags = { 'allure-path': { type: 'string', description: - 'Custom file path for downloaded Allure report (requires --report allure, default: ./report.html)', + 'Custom file path for downloaded Allure report (requires --report allure, default: ./report.html). Deprecated: Allure reports will be removed on 7 December 2026.', }, 'html-path': { type: 'string', @@ -79,6 +79,6 @@ export const outputFlags = { type: 'string', alias: ['format'], description: - 'Generate and download test reports in the specified format (options: allure, junit, html, html-detailed). Use "allure" for a complete HTML report.', + 'Generate and download test reports in the specified format (options: junit, html, html-detailed, allure). allure and html-detailed are deprecated and will be removed on 7 December 2026: from that date html-detailed gives the standard HTML report and allure gives none, and runs still run.', }, } as const satisfies ArgsDef; diff --git a/src/mcp/tools/download-artifacts.ts b/src/mcp/tools/download-artifacts.ts index 5af9b97..c5705d0 100644 --- a/src/mcp/tools/download-artifacts.ts +++ b/src/mcp/tools/download-artifacts.ts @@ -37,7 +37,9 @@ export function registerDownloadArtifacts(server: McpServer): void { report: z .enum(['junit', 'allure', 'html']) .optional() - .describe('Also download a formatted report of this type'), + .describe( + 'Also download a formatted report of this type. allure is deprecated and will be removed on 7 December 2026; prefer junit or html.', + ), reportPath: z .string() .optional() diff --git a/src/services/report-download.service.ts b/src/services/report-download.service.ts index c938809..6587e22 100644 --- a/src/services/report-download.service.ts +++ b/src/services/report-download.service.ts @@ -25,6 +25,30 @@ export interface ReportDownloadOptions extends DownloadOptions { reportType: 'allure' | 'html' | 'html-detailed' | 'junit'; } +/** + * The report formats retired on 7 December 2026, and what each one + * does from that date. `dcd cloud` users are told by the API's submit message + * and a notice; `dcd artifacts` fetches neither, so it prints this itself. + * The values stay valid after the date: a run that asks for one must not fail. + */ +export function reportFormatDeprecation( + report: string | undefined, +): string | undefined { + switch (report) { + case 'allure': { + return '--report allure is deprecated and will be removed on 7 December 2026. From that date runs get no Allure report. Use --report html or --report junit instead.'; + } + + case 'html-detailed': { + return '--report html-detailed is deprecated and will be removed on 7 December 2026. From that date it gives the standard HTML report. Use --report html instead.'; + } + + default: { + return undefined; + } + } +} + /** What one download attempt did; failures are warned about, not thrown. */ export interface DownloadResult { error?: string; diff --git a/test/integration/artifacts.integration.test.ts b/test/integration/artifacts.integration.test.ts index 9a79b04..5069bc9 100644 --- a/test/integration/artifacts.integration.test.ts +++ b/test/integration/artifacts.integration.test.ts @@ -146,6 +146,32 @@ describe('Artifacts Command Integration Tests', () => { }); }); + // This command fetches no notices, so it prints the deprecation + // itself. On stderr, before any download is tried. + describe('report format deprecation', () => { + it('warns that --report allure goes on 7 December 2026', async () => { + const { stderr } = await run( + `--upload-id ${mockUploadId} --report allure --api-key ${mockApiKey} --api-url ${DEAD_API_URL}`, + ); + expect(stderr).to.include('--report allure is deprecated'); + expect(stderr).to.include('7 December 2026'); + }); + + it('warns about --report html-detailed', async () => { + const { stderr } = await run( + `--upload-id ${mockUploadId} --report html-detailed --api-key ${mockApiKey} --api-url ${DEAD_API_URL}`, + ); + expect(stderr).to.include('--report html-detailed is deprecated'); + }); + + it('says nothing for --report junit', async () => { + const { stderr } = await run( + `--upload-id ${mockUploadId} --report junit --api-key ${mockApiKey} --api-url ${DEAD_API_URL}`, + ); + expect(stderr).to.not.include('deprecated'); + }); + }); + describe('help', () => { it('should display help with all expected flags', async () => { const { stdout } = await exec(`${CLI} artifacts --help`, { diff --git a/test/unit/notices.test.ts b/test/unit/notices.test.ts index 38d5413..f3cbaaf 100644 --- a/test/unit/notices.test.ts +++ b/test/unit/notices.test.ts @@ -24,3 +24,27 @@ describe('notice gating on runner_type', () => { expect(matchesRules(gpu1Gate, { platform: 'android' })).to.equal(false); }); }); + +// The allure and html-detailed retirement notices (dcd +// `deprecate-report-{allure,html-detailed}-2026-12-07`) are gated on `report` +// with no min_client_version, for the same reason as gpu1: a CLI from before +// 5.12.0 has no report in its context and must evaluate the gate as false. +describe('notice gating on report', () => { + const allureGate = { + rules: [{ field: 'report', op: 'equals' as const, value: 'allure' }], + }; + + it('shows the notice to a run that asks for allure', () => { + expect(matchesRules(allureGate, { report: 'allure' })).to.equal(true); + }); + + it('hides it from runs with another format, or none', () => { + expect(matchesRules(allureGate, { report: 'junit' })).to.equal(false); + expect(matchesRules(allureGate, { report: 'html-detailed' })).to.equal(false); + expect(matchesRules(allureGate, { report: undefined })).to.equal(false); + }); + + it('hides it from a context with no report, as an older CLI sends', () => { + expect(matchesRules(allureGate, { platform: 'android' })).to.equal(false); + }); +}); diff --git a/test/unit/report-download.service.test.ts b/test/unit/report-download.service.test.ts index fa0a072..5077afb 100644 --- a/test/unit/report-download.service.test.ts +++ b/test/unit/report-download.service.test.ts @@ -4,7 +4,10 @@ import * as os from 'node:os'; import * as path from 'node:path'; import { ApiGateway } from '../../src/gateways/api-gateway.js'; -import { ReportDownloadService } from '../../src/services/report-download.service.js'; +import { + ReportDownloadService, + reportFormatDeprecation, +} from '../../src/services/report-download.service.js'; import type { AuthContext } from '../../src/types/domain/auth.types.js'; const TEST_AUTH: AuthContext = { @@ -550,3 +553,25 @@ describe('ReportDownloadService default report paths', () => { ]); }); }); + +// allure and html-detailed go on 7 December 2026. The values stay +// valid (a run that asks for one must not fail), so the only signal is this. +describe('reportFormatDeprecation', () => { + it('names the date and the replacement for allure', () => { + const message = reportFormatDeprecation('allure'); + expect(message).to.include('7 December 2026'); + expect(message).to.include('--report html or --report junit'); + }); + + it('names the date and the replacement for html-detailed', () => { + const message = reportFormatDeprecation('html-detailed'); + expect(message).to.include('7 December 2026'); + expect(message).to.include('--report html instead'); + }); + + it('says nothing for the formats that stay, or for no format', () => { + for (const report of ['junit', 'html', undefined]) { + expect(reportFormatDeprecation(report)).to.equal(undefined); + } + }); +});