Skip to content

Commit b92e061

Browse files
committed
Refactor component detection tests and update jest configuration for ESM compatibility (required to refactor to dynamically load dependency)
1 parent 7f8a022 commit b92e061

File tree

3 files changed

+102
-44
lines changed

3 files changed

+102
-44
lines changed

componentDetection.test.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,48 @@ test("Runs CLI", async () => {
1313
}, 10000);
1414

1515
test("Parses CLI output", async () => {
16-
await ComponentDetection.downloadLatestRelease();
17-
await ComponentDetection.runComponentDetection("./test");
16+
// Mock the CLI output file
17+
const mockOutput = JSON.stringify({
18+
componentsFound: [
19+
{
20+
component: {
21+
packageUrl: {
22+
Scheme: "pkg",
23+
Type: "npm",
24+
Namespace: "github",
25+
Name: "component-detection-action",
26+
Version: "0.0.2",
27+
Qualifiers: { arch: "amd64", os: "linux" }
28+
},
29+
id: "1"
30+
},
31+
isDevelopmentDependency: false,
32+
topLevelReferrers: [],
33+
locationsFoundAt: ["/test/package.json"],
34+
containerDetailIds: [],
35+
containerLayerIds: []
36+
},
37+
{
38+
component: {
39+
packageUrl: {
40+
Scheme: "pkg",
41+
Type: "npm",
42+
Namespace: "github",
43+
Name: "component-detection-action",
44+
Version: "0.0.3",
45+
Qualifiers: { arch: "amd64", os: "linux" }
46+
},
47+
id: "2"
48+
},
49+
isDevelopmentDependency: true,
50+
topLevelReferrers: [],
51+
locationsFoundAt: ["/test/package-lock.json"],
52+
containerDetailIds: [],
53+
containerLayerIds: []
54+
}
55+
]
56+
});
57+
fs.writeFileSync(ComponentDetection.outputPath, mockOutput, { encoding: 'utf8' });
1858
var manifests = await ComponentDetection.getManifestsFromResults();
1959
expect(manifests?.length == 2);
2060
});

componentDetection.ts

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
11
import * as github from '@actions/github'
22
import * as core from '@actions/core'
3-
import { Octokit, App } from "octokit"
4-
import {
5-
PackageCache,
6-
BuildTarget,
7-
Package,
8-
Snapshot,
9-
Manifest,
10-
submitSnapshot
11-
} from '@github/dependency-submission-toolkit'
123
import fetch from 'cross-fetch'
134
import tar from 'tar'
145
import fs from 'fs'
@@ -23,7 +14,7 @@ export default class ComponentDetection {
2314
public static outputPath = './output.json';
2415

2516
// This is the default entry point for this class.
26-
static async scanAndGetManifests(path: string): Promise<Manifest[] | undefined> {
17+
static async scanAndGetManifests(path: string): Promise<any[] | undefined> {
2718
await this.downloadLatestRelease();
2819
await this.runComponentDetection(path);
2920
return await this.getManifestsFromResults();
@@ -33,26 +24,34 @@ export default class ComponentDetection {
3324
try {
3425
core.debug(`Downloading latest release for ${process.platform}`);
3526
const downloadURL = await this.getLatestReleaseURL();
27+
core.info(`Download URL: ${downloadURL}`);
3628
const blob = await (await fetch(new URL(downloadURL))).blob();
3729
const arrayBuffer = await blob.arrayBuffer();
3830
const buffer = Buffer.from(arrayBuffer);
3931

4032
// Write the blob to a file
4133
core.debug(`Writing binary to file ${this.componentDetectionPath}`);
4234
await fs.writeFileSync(this.componentDetectionPath, buffer, { mode: 0o777, flag: 'w' });
35+
core.info(`Binary written to ${this.componentDetectionPath}`);
36+
core.info(`File exists: ${fs.existsSync(this.componentDetectionPath)}`);
37+
core.info(`File permissions: ${fs.statSync(this.componentDetectionPath).mode.toString(8)}`);
4338
} catch (error: any) {
4439
core.error(error);
40+
core.info(`Download or write failed: ${error.message}`);
4541
}
4642
}
4743

4844
// Run the component-detection CLI on the path specified
4945
public static async runComponentDetection(path: string) {
5046
core.info("Running component-detection");
51-
47+
core.info(`CLI path: ${this.componentDetectionPath}`);
48+
core.info(`Output path: ${this.outputPath}`);
5249
try {
5350
await exec.exec(`${this.componentDetectionPath} scan --SourceDirectory ${path} --ManifestFile ${this.outputPath} ${this.getComponentDetectionParameters()}`);
51+
core.info(`CLI run complete. Output exists: ${fs.existsSync(this.outputPath)}`);
5452
} catch (error: any) {
5553
core.error(error);
54+
core.info(`CLI run failed: ${error.message}`);
5655
}
5756
}
5857

@@ -65,11 +64,34 @@ export default class ComponentDetection {
6564
return parameters;
6665
}
6766

68-
public static async getManifestsFromResults(): Promise<Manifest[] | undefined> {
67+
public static async getManifestsFromResults(): Promise<any[] | undefined> {
6968
core.info("Getting manifests from results");
69+
// Dynamically import toolkit
70+
const toolkit = await import('@github/dependency-submission-toolkit');
71+
const PackageCache = toolkit.PackageCache;
72+
const Manifest = toolkit.Manifest;
73+
const Package = toolkit.Package;
74+
// Define a dynamic class extending Package
75+
class ComponentDetectionPackage extends Package {
76+
id: any;
77+
isDevelopmentDependency: any;
78+
topLevelReferrers: any;
79+
locationsFoundAt: any;
80+
containerDetailIds: any;
81+
containerLayerIds: any;
82+
constructor(packageUrl: string, id: any, isDevelopmentDependency: any, topLevelReferrers: any, locationsFoundAt: any, containerDetailIds: any, containerLayerIds: any) {
83+
super(packageUrl);
84+
this.id = id;
85+
this.isDevelopmentDependency = isDevelopmentDependency;
86+
this.topLevelReferrers = topLevelReferrers;
87+
this.locationsFoundAt = locationsFoundAt;
88+
this.containerDetailIds = containerDetailIds;
89+
this.containerLayerIds = containerLayerIds;
90+
}
91+
}
7092
// Parse the result file and add the packages to the package cache
7193
const packageCache = new PackageCache();
72-
const packages: Array<ComponentDetectionPackage> = [];
94+
const packages: Array<any> = [];
7395

7496
const results = await fs.readFileSync(this.outputPath, 'utf8');
7597

@@ -78,16 +100,23 @@ export default class ComponentDetection {
78100
const packageUrl = ComponentDetection.makePackageUrl(component.component.packageUrl);
79101

80102
if (!packageCache.hasPackage(packageUrl)) {
81-
const pkg = new ComponentDetectionPackage(packageUrl, component.component.id,
82-
component.isDevelopmentDependency, component.topLevelReferrers, component.locationsFoundAt, component.containerDetailIds, component.containerLayerIds);
103+
const pkg = new ComponentDetectionPackage(
104+
packageUrl,
105+
component.component.id,
106+
component.isDevelopmentDependency,
107+
component.topLevelReferrers,
108+
component.locationsFoundAt,
109+
component.containerDetailIds,
110+
component.containerLayerIds
111+
);
83112
packageCache.addPackage(pkg);
84113
packages.push(pkg);
85114
}
86115
});
87116

88117
// Set the transitive dependencies
89118
core.debug("Sorting out transitive dependencies");
90-
packages.forEach(async (pkg: ComponentDetectionPackage) => {
119+
packages.forEach(async (pkg: any) => {
91120
pkg.topLevelReferrers.forEach(async (referrer: any) => {
92121
const referrerPackage = packageCache.lookupPackage(ComponentDetection.makePackageUrl(referrer.packageUrl));
93122
if (referrerPackage) {
@@ -97,26 +126,26 @@ export default class ComponentDetection {
97126
});
98127

99128
// Create manifests
100-
const manifests: Array<Manifest> = [];
129+
const manifests: Array<any> = [];
101130

102131
// Check the locationsFoundAt for every package and add each as a manifest
103-
packages.forEach(async (pkg: ComponentDetectionPackage) => {
132+
packages.forEach(async (pkg: any) => {
104133
pkg.locationsFoundAt.forEach(async (location: any) => {
105-
if (!manifests.find((manifest: Manifest) => manifest.name == location)) {
134+
if (!manifests.find((manifest: any) => manifest.name == location)) {
106135
const manifest = new Manifest(location, location);
107136
manifests.push(manifest);
108137
}
109138
if (pkg.topLevelReferrers.length == 0) {
110-
manifests.find((manifest: Manifest) => manifest.name == location)?.addDirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
139+
manifests.find((manifest: any) => manifest.name == location)?.addDirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
111140
} else {
112-
manifests.find((manifest: Manifest) => manifest.name == location)?.addIndirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
141+
manifests.find((manifest: any) => manifest.name == location)?.addIndirectDependency(pkg, ComponentDetection.getDependencyScope(pkg));
113142
}
114143
});
115144
});
116145
return manifests;
117146
}
118147

119-
private static getDependencyScope(pkg: ComponentDetectionPackage) {
148+
private static getDependencyScope(pkg: any) {
120149
return pkg.isDevelopmentDependency ? 'development' : 'runtime'
121150
}
122151

@@ -150,6 +179,8 @@ export default class ComponentDetection {
150179
if (ghesMode) {
151180
githubToken = "";
152181
}
182+
// Dynamically import octokit
183+
const { Octokit } = await import("octokit");
153184
const octokit = new Octokit({ auth: githubToken, baseUrl: githubAPIURL, request: { fetch: fetch}, log: {
154185
debug: core.debug,
155186
info: core.info,
@@ -182,14 +213,6 @@ export default class ComponentDetection {
182213
}
183214
}
184215

185-
class ComponentDetectionPackage extends Package {
186-
187-
constructor(packageUrl: string, public id: string, public isDevelopmentDependency: boolean, public topLevelReferrers: [],
188-
public locationsFoundAt: [], public containerDetailIds: [], public containerLayerIds: []) {
189-
super(packageUrl);
190-
}
191-
}
192-
193216

194217

195218

jest.config.js

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,15 @@
22
module.exports = {
33
transform: {
44
"^.+\\.tsx?$": "ts-jest",
5-
"^.+\\.[t|j]sx?$": "babel-jest", // Use Babel for transforming JS and TS files
6-
"^.+\\.mjs$": "jest-transform-stub", // Use the stub to handle ES modules
5+
"^.+\\.[t|j]sx?$": "babel-jest"
76
},
87
preset: 'ts-jest',
98
testEnvironment: 'node',
109
moduleNameMapper: {
11-
"^octokit$": "<rootDir>/node_modules/octokit/dist-bundle/index.js",
12-
"^@github/dependency-submission-toolkit$": "<rootDir>/node_modules/@github/dependency-submission-toolkit/dist/index.js",
10+
"^octokit$": "<rootDir>/node_modules/octokit/dist-bundle/index.js"
11+
// Removed toolkit mapping for ESM compatibility
1312
},
14-
extensionsToTreatAsEsm: [".ts"],
15-
transformIgnorePatterns: ["/node_modules/(?!(octokit|\\@github\\/dependency-submission-toolkit)/)"], // Ensure octokit and @github/dependency-submission-toolkit are transformed
16-
globals: {
17-
"ts-jest": {
18-
useESM: true,
19-
},
20-
},
21-
};
13+
transformIgnorePatterns: [
14+
"/node_modules/(?!(octokit)/)" // Only octokit is transformed, toolkit is left as ESM
15+
],
16+
};

0 commit comments

Comments
 (0)