Skip to content

Commit f7b0174

Browse files
authored
feat: add yarn support (#191)
* feat: add yarn support Signed-off-by: Ruben Romero Montes <[email protected]> * chore: adjust error messages Signed-off-by: Ruben Romero Montes <[email protected]> * chore: refactor as suggested Signed-off-by: Ruben Romero Montes <[email protected]> --------- Signed-off-by: Ruben Romero Montes <[email protected]>
1 parent ed6c326 commit f7b0174

File tree

65 files changed

+39718
-3126
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+39718
-3126
lines changed

.github/workflows/pr.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ jobs:
2929
node-version: ${{ matrix.node }}
3030
cache: npm
3131

32+
- name: Enable Corepack
33+
run: corepack enable
34+
35+
- name: Prepare Yarn
36+
run: corepack prepare [email protected] --activate
37+
38+
- name: Prepare PNPM
39+
run: corepack prepare pnpm@latest --activate
40+
3241
- name: Setup Java 17
3342
uses: actions/setup-java@v4
3443
with:
@@ -51,9 +60,6 @@ jobs:
5160
with:
5261
go-version: '1.20.1'
5362

54-
- name: Install pnpm
55-
run: npm install -g pnpm
56-
5763
- name: Setup Gradle
5864
uses: gradle/actions/setup-gradle@v4
5965

.github/workflows/stage.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ jobs:
4646
cache: npm
4747
registry-url: 'https://npm.pkg.github.com'
4848

49+
- name: Enable Corepack
50+
run: corepack enable
51+
52+
- name: Prepare Yarn
53+
run: corepack prepare [email protected] --activate
54+
55+
- name: Prepare PNPM
56+
run: corepack prepare pnpm@latest --activate
57+
58+
4959
- name: Setup Java 17
5060
uses: actions/setup-java@v4
5161
with:

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ $ exhort-javascript-api component /path/to/pom.xml
153153
<li><a href="https://www.java.com/">Java</a> - <a href="https://maven.apache.org/">Maven</a></li>
154154
<li><a href="https://www.javascript.com/">JavaScript</a> - <a href="https://www.npmjs.com/">Npm</a></li>
155155
<li><a href="https://www.javascript.com/">JavaScript</a> - <a href="https://pnpm.io/">pnpm</a></li>
156+
<li><a href="https://www.javascript.com/">JavaScript</a> - <a href="https://classic.yarnpkg.com/">Yarn Classic</a> / <a href="https://yarnpkg.com/">Yarn Berry</a></li>
156157
<li><a href="https://go.dev/">Golang</a> - <a href="https://go.dev/blog/using-go-modules/">Go Modules</a></li>
157158
<li><a href="https://www.python.org/">Python</a> - <a href="https://pypi.org/project/pip/">pip Installer</a></li>
158159
<li><a href="https://gradle.org/">Gradle (Groovy and Kotlin DSL)</a> - <a href="https://gradle.org/install/">Gradle Installation</a></li>
@@ -179,7 +180,7 @@ Excluding a package from any analysis can be achieved by marking the package for
179180
</ul>
180181
<ul>
181182
<li>
182-
<em>Javascript NPM </em> users can add a root (key, value) pair with value of list of names (strings) to be ignored (without versions), and key called <b>exhortignore</b> in <em>package.json</em>, example:
183+
<em>Javascript</em> users can add a root (key, value) pair with value of list of names (strings) to be ignored (without versions), and key called <b>exhortignore</b> in <em>package.json</em>, example:
183184

184185
```json
185186
{
@@ -350,6 +351,11 @@ following keys for setting custom paths for the said executables.
350351
<td>EXHORT_PNPM_PATH</td>
351352
</tr>
352353
<tr>
354+
<td><a href="https://classic.yarnpkg.com/">Yarn Classic</a> / <a href="https://yarnpkg.com/">Yarn Berry</a></td>
355+
<td><em>yarn</em></td>
356+
<td>EXHORT_YARN_PATH</td>
357+
</tr>
358+
<tr>
353359
<td><a href="https://go.dev/blog/using-go-modules/">Go Modules</a></td>
354360
<td><em>go</em></td>
355361
<td>EXHORT_GO_PATH</td>

src/cyclone_dx_sbom.js

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {PackageURL} from "packageurl-js";
88
* @return {{"bom-ref": string, name, purl: string, type, version}}
99
* @private
1010
*/
11-
function getComponent(component,type) {
11+
function getComponent(component, type) {
1212
let componentObject;
1313
if(component instanceof PackageURL)
1414
{
@@ -88,34 +88,41 @@ export default class CycloneDxSbom {
8888
}
8989

9090
/**
91-
* @param {component} sourceRef current target Component ( Starting from root component by clients)
92-
* @param {PackageURL} targetRef current dependency to add to Dependencies list of component sourceRef
93-
* @return Sbom
91+
* Adds a dependency relationship between two components in the SBOM
92+
* @param {PackageURL} sourceRef - The source component (parent)
93+
* @param {PackageURL} targetRef - The target component (dependency)
94+
* @return {CycloneDxSbom} The updated SBOM
9495
*/
9596
addDependency(sourceRef, targetRef) {
96-
let componentIndex = this.getComponentIndex(sourceRef);
97-
if (componentIndex < 0) {
98-
this.components.push(getComponent(sourceRef, "library"))
99-
}
100-
let dependencyIndex = this.getDependencyIndex(sourceRef.purl)
101-
if (dependencyIndex < 0) {
102-
this.dependencies.push(createDependency(sourceRef.purl))
103-
dependencyIndex = this.getDependencyIndex(sourceRef.purl)
104-
}
97+
const sourcePurl = sourceRef.toString();
98+
const targetPurl = targetRef.toString();
99+
100+
// Ensure both components exist in the components list
101+
[sourceRef, targetRef].forEach((ref, index) => {
102+
const purl = index === 0 ? sourcePurl : targetPurl;
103+
if (this.getComponentIndex(purl) < 0) {
104+
this.components.push(getComponent(ref, "library"));
105+
}
106+
});
105107

106-
//Only if the dependency doesn't exists on the dependency list of dependency, then add it to this list.
107-
if (this.dependencies[dependencyIndex].dependsOn.findIndex(dep => dep === targetRef.toString()) === -1) {
108-
this.dependencies[dependencyIndex].dependsOn.push(targetRef.toString())
108+
// Ensure source dependency exists
109+
let sourceDepIndex = this.getDependencyIndex(sourcePurl);
110+
if (sourceDepIndex < 0) {
111+
this.dependencies.push(createDependency(sourcePurl));
112+
sourceDepIndex = this.dependencies.length - 1;
109113
}
110-
if (this.getDependencyIndex(targetRef.toString()) < 0) {
111-
this.dependencies.push(createDependency(targetRef.toString()))
114+
115+
// Add target to source's dependencies if not already present
116+
if (!this.dependencies[sourceDepIndex].dependsOn.includes(targetPurl)) {
117+
this.dependencies[sourceDepIndex].dependsOn.push(targetPurl);
112118
}
113-
let newComponent = getComponent(targetRef, "library");
114-
// Only if component doesn't exists in component list, add it to the list.
115-
if (this.getComponentIndex(newComponent) < 0) {
116-
this.components.push(newComponent)
119+
120+
// Ensure target dependency exists
121+
if (this.getDependencyIndex(targetPurl) < 0) {
122+
this.dependencies.push(createDependency(targetPurl));
117123
}
118-
return this
124+
125+
return this;
119126
}
120127

121128
/** @param {{}} opts - various options, settings and configuration of application.
@@ -170,8 +177,7 @@ export default class CycloneDxSbom {
170177
* @private
171178
*/
172179
getComponentIndex(theComponent) {
173-
174-
return this.components.findIndex(component => component.purl === theComponent.purl)
180+
return this.components.findIndex(component => component.purl === theComponent)
175181
}
176182

177183
/** This method gets a PackageUrl, and returns a Component of CycloneDx Sbom
@@ -190,16 +196,18 @@ export default class CycloneDxSbom {
190196
filterIgnoredDeps(deps) {
191197
deps.forEach(dep => {
192198
let index = this.components.findIndex(component => component.name === dep);
193-
if (index >= 0) {
194-
this.components.splice(index, 1)
199+
if (index === -1) {
200+
return;
195201
}
202+
const depPurl = this.components[index].purl;
203+
this.components.splice(index, 1)
196204
index = this.dependencies.findIndex(dependency => dependency.ref.includes(dep));
197-
if (index >= 0) {
198-
this.dependencies.splice(index, 1)
205+
if (index === -1) {
206+
return;
199207
}
200-
208+
this.dependencies.splice(index, 1)
201209
this.dependencies.forEach(dependency => {
202-
let indexDependsOn = dependency.dependsOn.findIndex(theDep => theDep.includes(dep));
210+
let indexDependsOn = dependency.dependsOn.findIndex(theDep => theDep.includes(depPurl));
203211
if (indexDependsOn > -1) {
204212
dependency.dependsOn.splice(indexDependsOn, 1)
205213
}

src/index.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,13 @@ import fs from 'node:fs'
77
import { getCustom } from "./tools.js";
88
import.meta.dirname
99
import * as url from 'url';
10-
// const packageJson = await import ('../package.json',{ with: { type: 'json' } })
1110

1211
export default { AnalysisReport, componentAnalysis, stackAnalysis, validateToken }
1312

1413
export const exhortDevDefaultUrl = 'https://exhort.stage.devshift.net';
1514

16-
1715
export const exhortDefaultUrl = "https://rhda.rhcloud.com";
1816

19-
2017
function logOptionsAndEnvironmentsVariables(alongsideText,valueToBePrinted) {
2118
if (process.env["EXHORT_DEBUG"] === "true") {
2219
console.log(`${alongsideText}: ${valueToBePrinted} ${EOL}`)

src/provider.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Java_maven from "./providers/java_maven.js";
77
import pythonPipProvider from './providers/python_pip.js'
88
import Javascript_npm from './providers/javascript_npm.js';
99
import Javascript_pnpm from './providers/javascript_pnpm.js';
10+
import Javascript_yarn from './providers/javascript_yarn.js';
1011

1112
/** @typedef {{ecosystem: string, contentType: string, content: string}} Provided */
1213
/** @typedef {{isSupported: function(string): boolean, validateLockFile: function(string): void, provideComponent: function(string, {}): Provided, provideStack: function(string, {}): Provided}} Provider */
@@ -15,7 +16,15 @@ import Javascript_pnpm from './providers/javascript_pnpm.js';
1516
* MUST include all providers here.
1617
* @type {[Provider]}
1718
*/
18-
export const availableProviders = [new Java_maven(), new Java_gradle_groovy(), new Java_gradle_kotlin(), new Javascript_npm(), new Javascript_pnpm(), golangGomodulesProvider, pythonPipProvider]
19+
export const availableProviders = [
20+
new Java_maven(),
21+
new Java_gradle_groovy(),
22+
new Java_gradle_kotlin(),
23+
new Javascript_npm(),
24+
new Javascript_pnpm(),
25+
new Javascript_yarn(),
26+
golangGomodulesProvider,
27+
pythonPipProvider]
1928

2029
/**
2130
* Match a provider from a list or providers based on file type.

src/providers/base_java.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default class Base_Java {
4646
let matchedScopeSrc = src.match(/:compile|:provided|:runtime|:test|:system|:import/g)
4747
// only add dependency to sbom if it's not with test scope or if it's root
4848
if ((matchedScope && matchedScope[0] !== ":test" && (matchedScopeSrc && matchedScopeSrc[0] !== ":test")) || (srcDepth === 0 && matchedScope && matchedScope[0] !== ":test")) {
49-
sbom.addDependency(sbom.purlToComponent(from), to)
49+
sbom.addDependency(from, to)
5050
}
5151
} else {
5252
this.parseDependencyTree(lines[index - 1], this.#getDepth(lines[index - 1]), lines.slice(index), sbom)

0 commit comments

Comments
 (0)