Skip to content

Commit 4d9466f

Browse files
committed
working on cdn remote reports assets
1 parent e59f0de commit 4d9466f

File tree

15 files changed

+192
-55
lines changed

15 files changed

+192
-55
lines changed

.pnp.cjs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/core/src/api.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export interface PluginInstance {
1212
enabled: boolean;
1313
plugin: Plugin;
1414
options: Record<string, any>;
15+
packageName?: string;
16+
packageVersion?: string;
1517
}
1618

1719
export interface FullConfig {
@@ -46,6 +48,5 @@ export interface FullConfig {
4648
url?: string;
4749
project?: string;
4850
accessToken?: string;
49-
publish?: boolean;
5051
};
5152
}

packages/core/src/config.ts

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import type { Config, PluginDescriptor } from "@allurereport/plugin-api";
22
import * as console from "node:console";
3-
import { stat } from "node:fs/promises";
4-
import { resolve } from "node:path";
3+
import { readFile, stat } from "node:fs/promises";
4+
import { join, resolve, sep } from "node:path";
55
import * as process from "node:process";
66
import type { FullConfig, PluginInstance } from "./api.js";
77
import { readKnownIssues } from "./known.js";
88
import { FileSystemReportFiles } from "./plugin.js";
9-
import { importWrapper } from "./utils/module.js";
9+
import { importWrapper, resolveWrapper } from "./utils/module.js";
1010
import { normalizeImportPath } from "./utils/path.js";
1111

1212
export const getPluginId = (key: string) => {
@@ -177,22 +177,52 @@ export const enforcePlugin = (config: FullConfig, pluginInstance: PluginInstance
177177
return newConfig;
178178
};
179179

180-
export const resolvePlugin = async (path: string) => {
180+
export const getPluginRootPath = (packageName: string, packagePath: string) => {
181+
const parts = packagePath.split(sep);
182+
const pkgIdx = parts.indexOf(packageName);
183+
184+
return parts.slice(0, pkgIdx - 1).join(sep);
185+
};
186+
187+
export const getPluginVersion = async (packagePath: string) => {
188+
const packageJsonPath = join(packagePath, "package.json");
189+
const packageJson = await readFile(packageJsonPath, "utf-8");
190+
const { version } = JSON.parse(packageJson);
191+
192+
return version;
193+
};
194+
195+
export const resolvePlugin = async (pkg: string) => {
181196
// try to append @allurereport/plugin- scope
182-
if (!path.startsWith("@allurereport/plugin-")) {
197+
if (!pkg.startsWith("@allurereport/plugin-")) {
183198
try {
184-
const module = await importWrapper(`@allurereport/plugin-${path}`);
185-
186-
return module.default;
187-
} catch (err) {}
199+
const packageName = `@allurereport/plugin-${pkg}`;
200+
const packageFsPath = resolveWrapper(packageName);
201+
const packageRootPath = getPluginRootPath(packageName, packageFsPath);
202+
const packageVersion = await getPluginVersion(packageRootPath);
203+
const module = await importWrapper(packageName);
204+
205+
return {
206+
packageName,
207+
packageVersion,
208+
module: module.default,
209+
};
210+
} catch (ignored) {}
188211
}
189212

190213
try {
191-
const module = await importWrapper(path);
192-
193-
return module.default;
194-
} catch (err) {
195-
throw new Error(`Cannot resolve plugin: ${path}`);
214+
const packageFsPath = resolveWrapper(pkg);
215+
const packageRootPath = getPluginRootPath(pkg, packageFsPath);
216+
const packageVersion = await getPluginVersion(packageRootPath);
217+
const module = await importWrapper(pkg);
218+
219+
return {
220+
packageName: pkg,
221+
packageVersion,
222+
module: module.default,
223+
};
224+
} catch (ignored) {
225+
throw new Error(`Cannot resolve plugin: ${pkg}`);
196226
}
197227
};
198228

@@ -201,13 +231,15 @@ const resolvePlugins = async (plugins: Record<string, PluginDescriptor>) => {
201231

202232
for (const id in plugins) {
203233
const pluginConfig = plugins[id];
204-
const Plugin = await resolvePlugin(pluginConfig.import ?? id);
234+
const { module: Plugin, packageName, packageVersion } = await resolvePlugin(pluginConfig.import ?? id);
205235

206236
pluginInstances.push({
207237
id: getPluginId(id),
208238
enabled: pluginConfig.enabled ?? true,
209239
options: pluginConfig.options ?? {},
210240
plugin: new Plugin(pluginConfig.options),
241+
packageName,
242+
packageVersion,
211243
});
212244
}
213245

packages/core/src/report.ts

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@ import type {
77
ReportFiles,
88
ResultFile,
99
} from "@allurereport/plugin-api";
10-
import AwesomePlugin from "@allurereport/plugin-awesome";
1110
import { allure1, allure2, attachments, cucumberjson, junitXml, readXcResultBundle } from "@allurereport/reader";
1211
import { PathResultFile, type ResultsReader } from "@allurereport/reader-api";
13-
import { AllureRemoteHistory, AllureServiceClient, KnownError, UnknownError } from "@allurereport/service";
12+
import {
13+
AllureRemoteHistory,
14+
AllureServiceClient,
15+
KnownError,
16+
type RemotePluginsMap,
17+
UnknownError,
18+
} from "@allurereport/service";
1419
import { generateSummary } from "@allurereport/summary";
1520
import console from "node:console";
1621
import { randomUUID } from "node:crypto";
@@ -43,7 +48,7 @@ export class AllureReport {
4348
readonly #output: string;
4449
readonly #history: AllureHistory | undefined;
4550
readonly #allureServiceClient: AllureServiceClient | undefined;
46-
readonly #publish: boolean;
51+
4752
#reportUrl?: string;
4853
#state?: Record<string, PluginState>;
4954
#stage: "init" | "running" | "done" = "init";
@@ -66,7 +71,6 @@ export class AllureReport {
6671
} = opts;
6772

6873
this.#allureServiceClient = allureServiceConfig?.url ? new AllureServiceClient(allureServiceConfig) : undefined;
69-
this.#publish = allureServiceConfig?.publish ?? false;
7074
this.#reportUuid = randomUUID();
7175
this.#reportName = name;
7276
this.#eventEmitter = new EventEmitter<AllureStoreEvents>();
@@ -111,6 +115,37 @@ export class AllureReport {
111115
return this.#qualityGate.result;
112116
}
113117

118+
get #remotePluginsMap() {
119+
return this.#plugins
120+
.filter(({ enabled, options }) => enabled && options.publish)
121+
.reduce(
122+
(acc, { id, packageName, packageVersion, options }) => ({
123+
...acc,
124+
[id]: {
125+
packageName,
126+
packageVersion,
127+
singleFile: options.singleFile ?? false,
128+
},
129+
}),
130+
{} as RemotePluginsMap,
131+
);
132+
}
133+
134+
#filterRemoteFiles(files: Record<string, string>) {
135+
return Object.entries(files).reduce(
136+
(acc, [key, filename]) => {
137+
if (!/^(data|widgets|index\.html$)/.test(key)) {
138+
return acc;
139+
}
140+
141+
acc[key] = filename;
142+
143+
return acc;
144+
},
145+
{} as Record<string, string>,
146+
);
147+
}
148+
114149
readDirectory = async (resultsDir: string) => {
115150
if (this.#stage !== "running") {
116151
throw new Error(initRequired);
@@ -174,10 +209,11 @@ export class AllureReport {
174209
this.#stage = "running";
175210

176211
// create remote report to publish files into
177-
if (this.#allureServiceClient && this.#publish) {
212+
if (this.#allureServiceClient && Object.keys(this.#remotePluginsMap).length > 0) {
178213
const { url } = await this.#allureServiceClient.createReport({
179214
reportUuid: this.#reportUuid,
180215
reportName: this.#reportName,
216+
plugins: this.#remotePluginsMap,
181217
});
182218

183219
this.#reportUrl = url;
@@ -216,27 +252,24 @@ export class AllureReport {
216252
// closing it early, to prevent future reads
217253
this.#stage = "done";
218254

219-
await this.#eachPlugin(false, async (plugin, context, id) => {
255+
await this.#eachPlugin(false, async (plugin, context, { id }) => {
220256
const pluginFiles = (await context.state.get("files")) ?? {};
257+
const remotePlugin = this.#remotePluginsMap[id];
221258

222259
await plugin.done?.(context, this.#store);
223260

224-
// publish only Allure Awesome reports
225-
if (
226-
plugin instanceof AwesomePlugin &&
227-
this.#history &&
228-
this.#allureServiceClient &&
229-
this.#publish &&
230-
Object.keys(pluginFiles).length
231-
) {
261+
if (this.#allureServiceClient && remotePlugin) {
262+
const filteredPluginFiles = this.#filterRemoteFiles(pluginFiles as Record<string, string>);
263+
232264
await Promise.all(
233-
Object.entries(pluginFiles).map(([key, filepath]) =>
265+
Object.entries(filteredPluginFiles).map(([key, filepath]) => {
234266
this.#allureServiceClient?.addReportFile({
235267
reportUuid: this.#reportUuid,
268+
pluginId: id,
236269
key,
237270
filepath,
238-
}),
239-
),
271+
});
272+
}),
240273
);
241274
}
242275

@@ -313,20 +346,18 @@ export class AllureReport {
313346

314347
#eachPlugin = async (
315348
initState: boolean,
316-
consumer: (plugin: Plugin, context: PluginContext, id: string) => Promise<void>,
349+
consumer: (plugin: Plugin, context: PluginContext, options: { id: string }) => Promise<void>,
317350
) => {
318351
if (initState) {
319352
// reset state on start;
320353
this.#state = {};
321354
}
322355

323-
for (const descriptor of this.#plugins) {
324-
if (!descriptor.enabled) {
356+
for (const { enabled, id, plugin } of this.#plugins) {
357+
if (!enabled) {
325358
continue;
326359
}
327360

328-
const id = descriptor.id;
329-
const plugin = descriptor.plugin;
330361
const pluginState = this.#getPluginState(initState, id);
331362

332363
if (!pluginState) {
@@ -357,7 +388,7 @@ export class AllureReport {
357388
};
358389

359390
try {
360-
await consumer.call(this, plugin, pluginContext, id);
391+
await consumer.call(this, plugin, pluginContext, { id });
361392

362393
if (initState) {
363394
this.#state![id] = pluginState;

packages/core/src/utils/module.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,18 @@ import { normalizeImportPath } from "./path.js";
33

44
const require = createRequire(import.meta.url);
55

6+
/**
7+
* Dead simple wrapper around require.resolve to make it possible to mock it in the tests
8+
* @param path
9+
*/
10+
export const resolveWrapper = (path: string) => {
11+
return require.resolve(path);
12+
};
13+
614
/**
715
* Dead simple wrapper around import function to make it possible to mock it in the tests
816
* @param path
917
*/
1018
export const importWrapper = async (path: string) => {
11-
return import(normalizeImportPath(require.resolve(path)));
19+
return import(normalizeImportPath(resolveWrapper(path)));
1220
};

packages/core/test/config.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class PluginFixture {}
1919

2020
vi.mock("../src/utils/module.js", () => ({
2121
importWrapper: vi.fn(),
22+
resolveWrapper: vi.fn(),
2223
}));
2324

2425
beforeEach(() => {
@@ -136,7 +137,10 @@ describe("resolvePlugin", () => {
136137
expect(importWrapper).toHaveBeenCalledTimes(2);
137138
expect(importWrapper).toHaveBeenCalledWith("@allurereport/plugin-classic");
138139
expect(importWrapper).toHaveBeenCalledWith("classic");
139-
expect(plugin).toEqual(fixture);
140+
expect(plugin).toEqual({
141+
module: fixture,
142+
package: "classic",
143+
});
140144
});
141145

142146
it("throws an error when plugin can't be resolved", async () => {
@@ -229,12 +233,14 @@ describe("resolveConfig", () => {
229233
id: "awesome",
230234
enabled: true,
231235
options: {},
236+
package: "@allurereport/plugin-awesome",
232237
plugin: expect.any(PluginFixture),
233238
});
234239
expect((await resolveConfig({ plugins: {} })).plugins).toContainEqual({
235240
id: "awesome",
236241
enabled: true,
237242
options: {},
243+
package: "@allurereport/plugin-awesome",
238244
plugin: expect.any(PluginFixture),
239245
});
240246
});
@@ -305,6 +311,8 @@ describe("enforcePlugin", () => {
305311
options: {
306312
groupBy: ["test"],
307313
},
314+
packageName: "awesome",
315+
packageVersion: "1.0.0",
308316
plugin: new PluginFixture(),
309317
} as PluginInstance;
310318
const config = {
@@ -324,6 +332,8 @@ describe("enforcePlugin", () => {
324332
options: {
325333
groupBy: ["test"],
326334
},
335+
packageName: "awesome",
336+
packageVersion: "1.0.0",
327337
plugin: new PluginFixture(),
328338
} as PluginInstance;
329339
const config = {

packages/plugin-api/src/config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ export interface Config {
4343
url?: string;
4444
project?: string;
4545
accessToken?: string;
46-
publish?: boolean;
4746
};
4847
}
4948

packages/plugin-awesome/src/generators.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,21 +330,23 @@ export const generateStaticFiles = async (
330330

331331
if (!payload.singleFile) {
332332
for (const key in manifest) {
333-
const fileName = manifest[key];
333+
// file path including query parameter for cache busting
334+
const fileHref = manifest[key];
335+
const fileName = fileHref.replace(/\?\S+$/, "");
334336
const filePath = require.resolve(
335337
join("@allurereport/web-awesome/dist", singleFile ? "single" : "multi", fileName),
336338
);
337339

338340
if (key.includes(".woff")) {
339-
headTags.push(createFontLinkTag(fileName));
341+
headTags.push(createFontLinkTag(fileHref));
340342
}
341343

342344
if (key === "main.css") {
343-
headTags.push(createStylesLinkTag(fileName));
345+
headTags.push(createStylesLinkTag(fileHref));
344346
}
345347

346348
if (key === "main.js") {
347-
bodyTags.push(createScriptTag(fileName));
349+
bodyTags.push(createScriptTag(fileHref));
348350
}
349351

350352
// we don't need to handle another files in single file mode

packages/plugin-awesome/src/model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export type AwesomeOptions = {
1919
charts?: ChartOptions[];
2020
sections?: string[];
2121
defaultSection?: string;
22+
publish?: boolean;
2223
};
2324

2425
export type TemplateManifest = Record<string, string>;

0 commit comments

Comments
 (0)