Skip to content

Commit 5db9416

Browse files
committed
Hook up the front end
1 parent 54c1b17 commit 5db9416

File tree

7 files changed

+8687
-175
lines changed

7 files changed

+8687
-175
lines changed

componentDetection.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import {downloadLatestRelease, runComponentDetection} from './componentDetection';
1+
import {downloadLatestRelease, getManifestsFromResults, runComponentDetection} from './componentDetection';
22

33
test('Downloads CLI', async () => {
44
downloadLatestRelease();
55
});
66

77
test('Runs CLI', async () => {
88
runComponentDetection('./test');
9+
});
10+
11+
test('Parses CLI output', async () => {
12+
getManifestsFromResults();
913
});

componentDetection.ts

Lines changed: 132 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -16,55 +16,142 @@ import dotenv from 'dotenv'
1616
import { Context } from '@actions/github/lib/context'
1717
import { unmockedModulePathPatterns } from './jest.config'
1818
dotenv.config();
19+
export default class ComponentDetection {
20+
private componentDetectionPath = './component-detection';
21+
private outputPath = './output.json';
22+
23+
// This is the default entry point for this class.
24+
static async scanAndGetManifests(path: string): Promise<Manifest[] | undefined> {
25+
await this.downloadLatestRelease();
26+
await this.runComponentDetection(path);
27+
return await this.getManifestsFromResults();
28+
}
29+
// Get the latest release from the component-detection repo, download the tarball, and extract it
30+
private static async downloadLatestRelease() {
31+
try {
32+
const downloadURL = await getLatestReleaseURL();
33+
const blob = await (await fetch(new URL(downloadURL))).blob();
34+
const arrayBuffer = await blob.arrayBuffer();
35+
const buffer = Buffer.from(arrayBuffer);
36+
37+
// Write the blob to a file
38+
await fs.writeFile(componentDetectionPath, buffer, {mode: 0o777, flag: 'w'},
39+
(err: any) => {
40+
if (err) {
41+
core.error(err);
42+
}
43+
});
44+
} catch (error: any) {
45+
core.error(error);
46+
}
47+
}
1948

20-
export const componentDetectionPath = './component-detection';
21-
const outputPath = './output.json';
22-
dependencyGraphs: {
23-
manifest: {
24-
graph: {
25-
dependencies: [],
26-
},
27-
explicitlyReferencedComponentIds: [],
28-
developmentDependencies: [],
29-
dependencies: []
30-
}
31-
},
32-
componentsFound: [
33-
{
34-
locationsFoundAt: [
35-
filePath: string
36-
],
37-
component: {
38-
name: string,
39-
version: string,
40-
hash: string,
41-
author: string,
42-
type: string,
43-
id: string,
44-
packageUrl: {
45-
Scheme: string,
46-
Type: string,
47-
Namespace: string,
48-
Name: string,
49-
Version: string,
50-
Qualifiers: string,
51-
Subpath: string
52-
},
53-
},
54-
detectorId: string,
55-
isDevelopmentDependency: boolean,
56-
dependencyScope: string,
57-
topLevelReferrers: [],
58-
containerDetailIds: [],
59-
containerLayerIds: []
49+
// Run the component-detection CLI on the path specified
50+
private static async runComponentDetection(path: string) {
51+
try {
52+
await exec.exec(`${componentDetectionPath} scan --SourceDirectory ${path} --ManifestFile ${outputPath}`);
53+
} catch (error: any) {
54+
core.error(error);
55+
}
56+
}
57+
58+
private static async getManifestsFromResults(): Promise<Manifest[]| undefined> {
59+
60+
try {
61+
// Parse the result file and add the packages to the package cache
62+
const packageCache = new PackageCache();
63+
const packages: Array<ComponentDetectionPackage>= [];
64+
65+
const results = await fs.readFileSync(outputPath, 'utf8');
66+
67+
var json: any = JSON.parse(results);
68+
json.componentsFound.forEach(async (component: any) => {
69+
const packageUrl = makePackageUrl(component.component.packageUrl);
70+
71+
if (!packageCache.hasPackage(packageUrl)) {
72+
const pkg = new ComponentDetectionPackage(packageUrl, component.component.id,
73+
component.isDevelopmentDependency,component.topLevelReferrers,component.locationsFoundAt, component.containerDetailIds, component.containerLayerIds);
74+
packageCache.addPackage(pkg);
75+
packages.push(pkg);
76+
}
77+
});
78+
79+
// Set the transitive dependencies
80+
packages.forEach(async (pkg: ComponentDetectionPackage) => {
81+
pkg.toplevelReferrers.forEach(async (referrer: any) => {
82+
const referrerPackage = packageCache.lookupPackage(makePackageUrl(referrer.packageUrl));
83+
if (referrerPackage) {
84+
referrerPackage.dependsOn(pkg);
85+
}
86+
});
87+
});
88+
89+
// Create manifests
90+
const manifests: Array<Manifest> = [];
91+
92+
// Check the locationsFoundAt for every package and add each as a manifest
93+
packages.forEach(async (pkg: ComponentDetectionPackage) => {
94+
pkg.locationsFoundAt.forEach(async (location: any) => {
95+
if (!manifests[location.filePath]) {
96+
const manifest = new Manifest(location.filePath, location.filePath);
97+
manifests.push(manifest);
98+
}
99+
if (pkg.toplevelReferrers.length == 0) {
100+
manifests.find((manifest: Manifest) => manifest.file == location.filePath)?.addDirectDependency(pkg, getDependencyScope(pkg));
101+
} else {
102+
manifests.find((manifest: Manifest) => manifest.file == location.filePath)?.addIndirectDependency(pkg, getDependencyScope(pkg)); }
103+
});
104+
});
105+
core.debug(JSON.stringify(manifests));
106+
return manifests;
107+
} catch (error: any) {
108+
core.error(error);
109+
return undefined;
110+
}
111+
}
112+
113+
private static getDependencyScope(pkg: ComponentDetectionPackage) {
114+
return pkg.isDevelopmentDependency ? 'development' : 'runtime'
115+
}
116+
117+
private static makePackageUrl(packageUrlJson: any): string {
118+
var packageUrl = `${packageUrlJson.Scheme}:${packageUrlJson.Type}/`;
119+
if (packageUrlJson.Namespace) {
120+
packageUrl += `${packageUrlJson.Namespace.replace("@", "%40")}/`;
121+
}
122+
packageUrl += `${packageUrlJson.Name.replace("@", "%40")}`;
123+
if (packageUrlJson.Version) {
124+
packageUrl += `@${packageUrlJson.Version}`;
125+
}
126+
if (packageUrlJson.Qualifiers) {
127+
packageUrl += `?${packageUrlJson.Qualifiers}`;
128+
}
129+
return packageUrl;
130+
}
131+
132+
private static getLatestReleaseURL(): Promise<string> {
133+
const githubToken = core.getInput('token') || process.env.GITHUB_TOKEN2 || "";
134+
const octokit = github.getOctokit(githubToken);
135+
const owner = "microsoft";
136+
const repo = "component-detection";
137+
138+
const latestRelease = await octokit.rest.repos.getLatestRelease({
139+
owner, repo
140+
});
141+
142+
var downloadURL: string = "";
143+
latestRelease.data.assets.forEach((asset: any) => {
144+
if (asset.name === "component-detection-linux-x64") {
145+
downloadURL = asset.browser_download_url;
60146
}
61-
],
62-
detectorsInScan: [],
63-
sourceDirectory: string,
64-
};
65-
*/
147+
});
148+
149+
return downloadURL;
150+
}
151+
}
66152

67153
class ComponentDetectionPackage extends Package {
154+
68155
constructor(packageUrl: string, id: string, isDevelopmentDependency:boolean, topLevelReferrers: [],
69156
locationsFoundAt: [], containerDetailIds: [], containerLayerIds: []) {
70157
super(packageUrl);
@@ -84,129 +171,11 @@ class ComponentDetectionPackage extends Package {
84171
}
85172

86173

87-
// Get the latest release from the component-detection repo, download the tarball, and extract it
88-
export async function downloadLatestRelease() {
89-
try {
90-
const downloadURL = await getLatestReleaseURL();
91-
const blob = await (await fetch(new URL(downloadURL))).blob();
92-
const arrayBuffer = await blob.arrayBuffer();
93-
const buffer = Buffer.from(arrayBuffer);
94-
95-
// Write the blob to a file
96-
await fs.writeFile(componentDetectionPath, buffer, {mode: 0o777, flag: 'w'},
97-
(err: any) => {
98-
if (err) {
99-
core.error(err);
100-
}
101-
});
102-
} catch (error: any) {
103-
core.error(error);
104-
}
105-
}
106-
107-
// Run the component-detection CLI on the path specified
108-
export async function runComponentDetection(path: string) {
109-
try {
110-
await exec.exec(`${componentDetectionPath} scan --SourceDirectory ${path} --ManifestFile ${outputPath}`);
111-
} catch (error: any) {
112-
core.error(error);
113-
}
114-
}
115-
116-
117-
118-
export async function getManifestsFromResults(): Promise<Manifest[]| undefined> {
119-
120-
try {
121-
// Parse the result file and add the packages to the package cache
122-
const packageCache = new PackageCache();
123-
const packages: Array<ComponentDetectionPackage>= [];
124-
125-
const results = await fs.readFileSync(outputPath, 'utf8');
126-
127-
var json: any = JSON.parse(results);
128-
json.componentsFound.forEach(async (component: any) => {
129-
const packageUrl = makePackageUrl(component.component.packageUrl);
130-
131-
if (!packageCache.hasPackage(packageUrl)) {
132-
const pkg = new ComponentDetectionPackage(packageUrl, component.component.id,
133-
component.isDevelopmentDependency,component.topLevelReferrers,component.locationsFoundAt, component.containerDetailIds, component.containerLayerIds);
134-
packageCache.addPackage(pkg);
135-
packages.push(pkg);
136-
}
137-
});
138-
139-
// Set the transitive dependencies
140-
packages.forEach(async (pkg: ComponentDetectionPackage) => {
141-
pkg.toplevelReferrers.forEach(async (referrer: any) => {
142-
const referrerPackage = packageCache.lookupPackage(makePackageUrl(referrer.packageUrl));
143-
if (referrerPackage) {
144-
referrerPackage.dependsOn(pkg);
145-
}
146-
});
147-
});
148-
149-
// Create manifests
150-
const manifests: Array<Manifest> = [];
151-
152-
// Check the locationsFoundAt for every package and add each as a manifest
153-
packages.forEach(async (pkg: ComponentDetectionPackage) => {
154-
pkg.locationsFoundAt.forEach(async (location: any) => {
155-
if (!manifests[location.filePath]) {
156-
const manifest = new Manifest(location.filePath, location.filePath);
157-
manifests.push(manifest);
158-
}
159-
if (pkg.toplevelReferrers.length == 0) {
160-
manifests.find((manifest: Manifest) => manifest.file == location.filePath)?.addDirectDependency(pkg, getDependencyScope(pkg));
161-
} else {
162-
manifests.find((manifest: Manifest) => manifest.file == location.filePath)?.addIndirectDependency(pkg, getDependencyScope(pkg)); }
163-
});
164-
});
165-
core.debug(JSON.stringify(manifests));
166-
return manifests;
167-
} catch (error: any) {
168-
core.error(error);
169-
return undefined;
170-
}
171-
}
172174

173175

174176

175-
function getDependencyScope(pkg: ComponentDetectionPackage) {
176-
return pkg.isDevelopmentDependency ? 'development' : 'runtime'
177-
}
178177

179-
function makePackageUrl(packageUrlJson: any): string {
180-
var packageUrl = `${packageUrlJson.Scheme}:${packageUrlJson.Type}/`;
181-
if (packageUrlJson.Namespace) {
182-
packageUrl += `${packageUrlJson.Namespace.replace("@", "%40")}/`;
183-
}
184-
packageUrl += `${packageUrlJson.Name.replace("@", "%40")}`;
185-
if (packageUrlJson.Version) {
186-
packageUrl += `@${packageUrlJson.Version}`;
187-
}
188-
if (packageUrlJson.Qualifiers) {
189-
packageUrl += `?${packageUrlJson.Qualifiers}`;
190-
}
191-
return packageUrl;
192-
}
193178

194-
async function getLatestReleaseURL(): Promise<string> {
195-
const githubToken = core.getInput('token') || process.env.GITHUB_TOKEN2 || "";
196-
const octokit = github.getOctokit(githubToken);
197-
const owner = "microsoft";
198-
const repo = "component-detection";
199179

200-
const latestRelease = await octokit.rest.repos.getLatestRelease({
201-
owner, repo
202-
});
203180

204-
var downloadURL: string = "";
205-
latestRelease.data.assets.forEach((asset: any) => {
206-
if (asset.name === "component-detection-linux-x64") {
207-
downloadURL = asset.browser_download_url;
208-
}
209-
});
210181

211-
return downloadURL;
212-
}

index.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,15 @@ import {
1010
submitSnapshot
1111
} from '@github/dependency-submission-toolkit';
1212

13-
import CondaParser from './condaParser';
13+
import ComponentDetection from './componentDetection';
1414

1515
async function run() {
16-
let manifests = CondaParser.getManifestsFromEnvironmentFiles(
17-
CondaParser.searchFiles(core.getInput('filePath'), core.getInput('filePattern')));
16+
let manifests = await ComponentDetection.scanAndGetManifests(core.getInput('path'));
1817

1918
let snapshot = new Snapshot({
20-
name: "conda-dependency-submission-action",
19+
name: "Component Detection",
2120
version: "0.0.1",
22-
url: "https://github.com/jhutchings1/conda-dependency-submission-action",
21+
url: "https://github.com/jhutchings1/component-detection-action",
2322
},
2423
github.context,
2524
{

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"name": "Conda-dependency-submission-action",
2+
"name": "component-detection-action",
33
"version": "1.0.0",
4-
"description": "Conda dependency submission action",
4+
"description": "Component detection action",
55
"main": "index.ts",
66
"scripts": {
77
"lint": "eslint .",
@@ -11,7 +11,7 @@
1111
},
1212
"repository": {
1313
"type": "git",
14-
"url": "git+https://github.com/jhutchings1/spdx-to-dependency-graph-action.git"
14+
"url": "git+https://github.com/jhutchings1/component-detection-action.git"
1515
},
1616
"keywords": [
1717
"GitHub",
@@ -21,9 +21,9 @@
2121
"author": "",
2222
"license": "MIT",
2323
"bugs": {
24-
"url": "https://github.com/jhutchings1/spdx-to-dependency-graph-action/issues"
24+
"url": "https://github.com/jhutchings1/component-detection-action/issues"
2525
},
26-
"homepage": "https://github.com/jhutchings1/spdx-to-dependency-graph-action#readme",
26+
"homepage": "https://github.com/jhutchings1/component-detection-action#readme",
2727
"dependencies": {
2828
"@actions/core": "^1.10.0",
2929
"@actions/github": "^5.1.1",

0 commit comments

Comments
 (0)