Compare commits
1 Commits
main
..
hm/sync-fork
| Author | SHA1 | Date | |
|---|---|---|---|
| bc7ed6e727 |
@@ -1,3 +0,0 @@
|
||||
# Managed and Maintained by:
|
||||
|
||||
* @actions/advanced-security-dependency-graph
|
||||
@@ -0,0 +1,123 @@
|
||||
name: Release
|
||||
|
||||
run-name: Release ${{ inputs.version }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
type: string
|
||||
required: true
|
||||
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
name: Build and test
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
|
||||
- name: Build and Test
|
||||
run: |
|
||||
npm ci
|
||||
npm run test --if-present
|
||||
npm run build --if-present
|
||||
npm run build-exe --if-present
|
||||
|
||||
|
||||
validate_version:
|
||||
name: Validate version number
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Process version number as SemVer
|
||||
id: semver
|
||||
uses: peter-murray/semver-data-action@v1
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
|
||||
release:
|
||||
name: Release
|
||||
|
||||
needs:
|
||||
- validate_version
|
||||
- build_and_test
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Process version number as SemVer
|
||||
id: semver
|
||||
uses: peter-murray/semver-data-action@v1
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set git user
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
|
||||
- name: Version application
|
||||
run: |
|
||||
npm version ${{ steps.semver.outputs.semver }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
npm ci
|
||||
npm run build --if-present
|
||||
npm run build-exe --if-present
|
||||
|
||||
- name: Check that build is clean
|
||||
id: clean_build
|
||||
continue-on-error: true
|
||||
run: |
|
||||
git diff --exit-code
|
||||
|
||||
- name: Update release
|
||||
if: steps.clean_build.outcome == 'failure'
|
||||
run: |
|
||||
git add .
|
||||
git commit -m "chore: Updating release files"
|
||||
|
||||
- name: Update tags
|
||||
if: steps.semver.outputs.isPreRelease == 'false'
|
||||
run: |
|
||||
git tag "v${{ steps.semver.outputs.semver }}" --force
|
||||
git tag "v${{ steps.semver.outputs.major }}" --force
|
||||
git tag "v${{ steps.semver.outputs.major }}.${{ steps.semver.outputs.minor }}" --force
|
||||
git tag "v${{ steps.semver.outputs.major }}.${{ steps.semver.outputs.minor }}.${{ steps.semver.outputs.patch }}" --force
|
||||
|
||||
git push origin ${{ github.ref_name }}
|
||||
git push origin --tags --force
|
||||
|
||||
- name: Attach CLI artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cli
|
||||
path: cli
|
||||
|
||||
- name: Create release
|
||||
uses: ncipollo/release-action@v1.13.0
|
||||
with:
|
||||
artifacts: cli/*
|
||||
prerelease: ${{ steps.semver.outputs.isPreRelease }}
|
||||
tag: v${{ steps.semver.outputs.semver }}
|
||||
@@ -1,8 +1,5 @@
|
||||
name: Publish Executables
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
name: Release
|
||||
|
||||
run-name: Release ${{ inputs.version }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
type: string
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
name: Build and test
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
|
||||
- name: Build and Test
|
||||
run: |
|
||||
npm ci
|
||||
npm run test --if-present
|
||||
npm run build --if-present
|
||||
npm run build-exe --if-present
|
||||
|
||||
# - name: Check that build is clean
|
||||
# run: |
|
||||
# git diff --exit-code
|
||||
|
||||
|
||||
validate_version:
|
||||
name: Validate version number
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Process version number as SemVer
|
||||
id: semver
|
||||
uses: peter-murray/semver-data-action@v1
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
|
||||
release:
|
||||
name: Release
|
||||
|
||||
needs:
|
||||
- validate_version
|
||||
- build_and_test
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Process version number as SemVer
|
||||
id: semver
|
||||
uses: peter-murray/semver-data-action@v1
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set git user
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
|
||||
- name: Version application
|
||||
run: |
|
||||
npm version ${{ steps.semver.outputs.semver }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
npm ci
|
||||
npm run build --if-present
|
||||
npm run build-exe --if-present
|
||||
|
||||
- name: Check that build is clean
|
||||
id: clean_build
|
||||
continue-on-error: true
|
||||
run: |
|
||||
git diff --exit-code
|
||||
|
||||
- name: Update release
|
||||
if: steps.clean_build.outcome == 'failure'
|
||||
run: |
|
||||
git add .
|
||||
git commit -m "chore: Updating release files"
|
||||
|
||||
- name: Update tags
|
||||
if: steps.semver.outputs.isPreRelease == 'false'
|
||||
run: |
|
||||
git tag "v${{ steps.semver.outputs.semver }}" --force
|
||||
git tag "v${{ steps.semver.outputs.major }}" --force
|
||||
git tag "v${{ steps.semver.outputs.major }}.${{ steps.semver.outputs.minor }}" --force
|
||||
git tag "v${{ steps.semver.outputs.major }}.${{ steps.semver.outputs.minor }}.${{ steps.semver.outputs.patch }}" --force
|
||||
|
||||
git push origin ${{ github.ref_name }}
|
||||
git push origin --tags --force
|
||||
|
||||
- name: Attach CLI artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cli
|
||||
path: cli
|
||||
|
||||
- name: Create release
|
||||
uses: ncipollo/release-action@v1.13.0
|
||||
with:
|
||||
artifacts: cli/*
|
||||
prerelease: ${{ steps.semver.outputs.isPreRelease }}
|
||||
tag: v${{ steps.semver.outputs.semver }}
|
||||
@@ -1,45 +1,15 @@
|
||||
name: Sync Fork with Upstream
|
||||
name: Sync fork
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 1' # Runs at midnight UTC every Monday
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
# Daily at 4:24am
|
||||
- cron: "24 4 * * *"
|
||||
workflow_dispatch: {}
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Fetch Upstream Remote
|
||||
run: |
|
||||
git remote add upstream https://github.com/advanced-security/maven-dependency-submission-action.git
|
||||
git fetch upstream
|
||||
|
||||
- name: Set Git Config
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Create and Push Branch
|
||||
run: |
|
||||
git checkout -b weekly-sync-branch-${{ github.run_id }}
|
||||
git merge upstream/main --no-commit
|
||||
git reset -- ./.github
|
||||
git commit -m "Merge upstream:main"
|
||||
git commit --allow-empty -m "Empty commit to open PR"
|
||||
git push --set-upstream origin weekly-sync-branch-${{ github.run_id }}
|
||||
|
||||
- name: Open Pull Request
|
||||
run: |
|
||||
gh repo set-default actions/maven-dependency-submission-action
|
||||
gh pr create -B main -H weekly-sync-branch-${{ github.run_id }} --title 'Sync Fork with Upstream' --body 'Weekly Cron. Created by GitHub Actions.'
|
||||
- run: gh repo sync actions/maven-dependency-submission-action -b main
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
name: Test Local Action
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
|
||||
@@ -24,47 +24,6 @@ Here are a few things you can do that will increase the likelihood of your pull
|
||||
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
|
||||
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||
|
||||
## Cutting a new release
|
||||
|
||||
<details>
|
||||
|
||||
_Note: these instructions are for maintainers_
|
||||
|
||||
1. Update the version number in [package.json](https://github.com/advanced-security/maven-dependency-submission-action/blob/main/package.json) and run `npm i` to update the lockfile. This is also a good time to make sure that the `dist/index.js` file is up to date by running `npm run build`.
|
||||
2. Go to [Draft a new
|
||||
release](https://github.com/advanced-security/maven-dependency-submission-action/releases/new)
|
||||
in the Releases page.
|
||||
3. Make sure that the `Publish this Action to the GitHub Marketplace`
|
||||
checkbox is enabled
|
||||
|
||||
<img width="481" alt="Screenshot 2022-06-15 at 12 08 19" src="https://user-images.githubusercontent.com/2161/173822484-4b60d8b4-c674-4bff-b5ff-b0c4a3650ab7.png">
|
||||
|
||||
4. Click "Choose a tag" and then "Create new tag", where the tag name
|
||||
will be your version prefixed by a `v` (e.g. `v4.1.2`).
|
||||
5. Use a version number for the release title (e.g. "4.1.2").
|
||||
|
||||
<img width="700" alt="Screenshot 2022-06-15 at 12 08 36" src="https://user-images.githubusercontent.com/2161/173822548-33ab3432-d679-4dc1-adf8-b50fdaf47de3.png">
|
||||
|
||||
6. Add your release notes. If this is a major version make sure to
|
||||
include a small description of the biggest changes in the new version.
|
||||
7. Build the release executables by manually triggering [this action](https://github.com/advanced-security/maven-dependency-submission-action/actions/workflows/publish_executables.yml). The output of this action will be a zip file that you should download, extract, and drag into the binaries section. There should be three files there: ending in `-linux`, `-macos`, and `-win.exe`.
|
||||
8. Click "Publish Release".
|
||||
|
||||
You now have a tag and release using the semver version you used
|
||||
above. The last remaining thing to do is to move the dynamic version
|
||||
identifier to match the current SHA. This allows users to adopt a
|
||||
major version number (e.g. `v1`) in their workflows while
|
||||
automatically getting all the
|
||||
minor/patch updates.
|
||||
|
||||
To do this just checkout `main`, force-create a new annotated tag, and push it:
|
||||
|
||||
```
|
||||
git tag -fa v5 -m "Updating v5 to 5.0.0"
|
||||
git push origin v5 --force
|
||||
```
|
||||
</details>
|
||||
|
||||
## Resources
|
||||
|
||||
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
This is a GitHub Action that will generate a complete dependency graph for a Maven project and submit the graph to the GitHub repository so that the graph is complete and includes all the transitive dependencies.
|
||||
|
||||
The action will invoke maven using the `com.github.ferstl:depgraph-maven-plugin:4.0.3` plugin to generate JSON output of the complete dependency graph, which is then processed and submitted using the [Dependency Submission Toolkit](https://github.com/github/dependency-submission-toolkit) to the GitHub repository.
|
||||
The action will invoke maven using the `com.github.ferstl:depgraph-maven-plugin:4.0.2` plugin to generate JSON output of the complete dependency graph, which is then processed and submitted using the [Dependency Submission Toolkit](https://github.com/github/dependency-submission-toolkit) to the GitHub repository.
|
||||
|
||||
> **Warning** The dependency submission APIs and toolkit are still currently in beta and as such subject to changes in future releases.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
As of version `3.0.0` this action now supports Maven multi-module projects as well as additional Maven configuration parameters. As of version `5.0.0`, multi-module projects report dependencies as coming from their respective `pom.xml` files.
|
||||
As of version `3.0.0` this action now support Maven multi-module projects as well as additional Maven configuration parameters.
|
||||
|
||||
|
||||
### Pre-requisites
|
||||
@@ -15,7 +17,7 @@ For this action to work properly, you must have the Maven available on PATH (`mv
|
||||
|
||||
Custom maven `settings.xml` can now be specified as an input parameter to the action.
|
||||
|
||||
This action writes information in the repository dependency graph, so if you are using the default token, you need to set the `contents: write` permission to the workflow or job. If you are using a personal access token, this token must have the `repo` scope. ([API used by this action](https://docs.github.com/en/rest/dependency-graph/dependency-submission#create-a-snapshot-of-dependencies-for-a-repository))
|
||||
This action writes informations in the repository dependency graph, so if you are using the default token, you need to set the `contents: write` permission to the workflow or job. If you are using a personal access token, this token must have the `repo` scope. ([API used by this action](https://docs.github.com/en/rest/dependency-graph/dependency-submission#create-a-snapshot-of-dependencies-for-a-repository))
|
||||
|
||||
### Inputs
|
||||
|
||||
@@ -29,7 +31,10 @@ This action writes information in the repository dependency graph, so if you are
|
||||
|
||||
* `maven-args` - An optional string value (space separated) options to pass to the maven command line when generating the dependency snapshot. This is empty by default.
|
||||
|
||||
* `correlator`: An optional identifier to distinguish between multiple dependency snapshots of the same type. Defaults to the [job_id](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_id) of the current job.
|
||||
* `snapshot-include-file-name`: Optional flag to control whether or no the path and file name of the pom.xml is provided with the snapshot submission. Defaults to `true` so as to create a link to the repository file from the dependency tree view, but at the cost of losing the POM `artifactId` when it renders.
|
||||
|
||||
* `snapshot-dependency-file-name`: An optional user control file path to the POM file, requires `snapshot-include-file-name` to be `true` for the value to be submitted.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -37,43 +42,13 @@ Generating and submitting a dependency snapshot using the defaults:
|
||||
|
||||
```
|
||||
- name: Submit Dependency Snapshot
|
||||
uses: advanced-security/maven-dependency-submission-action@v5
|
||||
uses: advanced-security/maven-dependency-submission-action@v3
|
||||
```
|
||||
|
||||
Upon success it will generate a snapshot captured from Maven POM like;
|
||||

|
||||
|
||||
### Configuring for Matrix-Based Workflows
|
||||
|
||||
To ensure that the job parameter of the submission remains unique when the action is being called from a workflow that has a matrix, you can pass a `correlator` to the action. This identifier will be appended to the default correlator propterty of a job, ensuring uniqueness across matrix-based workflows. When dealing with Maven-based Java projects that utilize different `pom.xml` files across matrix jobs, you can specify the `directory` relevant to each matrix job. This ensures that the dependency snapshot accurately reflects the dependencies for each specific configuration.
|
||||
|
||||
Example of specifying `pom.xml` files for different matrix jobs:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- java-version: 8
|
||||
directory: project1
|
||||
- java-version: 11
|
||||
directory: project2
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK ${{ matrix.java-version }}
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: ${{ matrix.java-version }}
|
||||
- name: Submit Dependency Snapshot
|
||||
uses: advanced-security/maven-dependency-submission-action@v3
|
||||
with:
|
||||
directory: ${{ matrix.directory }}
|
||||
correlator: ${{ github.job }}-${{ matrix.directory }}
|
||||
```
|
||||
|
||||
In this example, the action is configured to use different working directories based on the Java version specified in the matrix. This ensures that the dependency snapshot is accurate for each Java version being tested.
|
||||
|
||||
## Command Line Usage
|
||||
|
||||
|
||||
+10
-17
@@ -25,6 +25,16 @@ inputs:
|
||||
type: string
|
||||
default: ''
|
||||
|
||||
snapshot-include-file-name:
|
||||
description: Optionally include the file name in the dependency snapshot report to GitHub. This is required to be true if you want the results in the dependency tree to have a working link.
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
snapshot-dependency-file-name:
|
||||
description: An optional override to specify the path to the file in the repository that the snapshot should be associated with.
|
||||
type: string
|
||||
required: false
|
||||
|
||||
token:
|
||||
description: The GitHub token to use to submit the depedency snapshot to the repository
|
||||
type: string
|
||||
@@ -42,23 +52,6 @@ inputs:
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
detector-name:
|
||||
description: The name of the detector that generated the dependency snapshot
|
||||
type: string
|
||||
|
||||
detector-version:
|
||||
description: The version of the detector that generated the dependency snapshot
|
||||
type: string
|
||||
|
||||
detector-url:
|
||||
description: The URL to the detector that generated the dependency snapshot
|
||||
type: string
|
||||
|
||||
correlator:
|
||||
description: An optional identifier to distinguish between multiple dependency snapshots of the same type
|
||||
type: string
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
runs:
|
||||
using: node20
|
||||
|
||||
Vendored
+92
-101
@@ -7,11 +7,10 @@ require('./sourcemap-register.js');/******/ (() => { // webpackBootstrap
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.artifactToPackageURL = exports.parseDependencyJson = exports.MavenDependencyGraph = exports.depgraphfilename = void 0;
|
||||
exports.artifactToPackageURL = exports.parseDependencyJson = exports.MavenDependencyGraph = void 0;
|
||||
const packageurl_js_1 = __nccwpck_require__(8915);
|
||||
const dependency_submission_toolkit_1 = __nccwpck_require__(3415);
|
||||
const file_utils_1 = __nccwpck_require__(799);
|
||||
exports.depgraphfilename = 'maven-dependency-submission-action-depgraph.json';
|
||||
class MavenDependencyGraph {
|
||||
constructor(graph) {
|
||||
this.depGraph = graph;
|
||||
@@ -48,19 +47,13 @@ class MavenDependencyGraph {
|
||||
const artifact = this.packageUrlToArtifact[depPackage.packageURL.toString()];
|
||||
let scope = getDependencyScopeForMavenScope(artifact.scopes);
|
||||
manifest.addDirectDependency(depPackage, scope);
|
||||
function addTransitiveDeps(dependencies, seen = new Set()) {
|
||||
function addTransitiveDeps(dependencies) {
|
||||
if (dependencies) {
|
||||
dependencies.forEach(transitiveDep => {
|
||||
let purl = transitiveDep.packageURL.toString();
|
||||
if (seen.has(purl)) {
|
||||
// we're in a cycle! skip this one.
|
||||
return;
|
||||
}
|
||||
const transitiveDepArtifact = packageUrlToArtifact[purl];
|
||||
const transitiveDepArtifact = packageUrlToArtifact[transitiveDep.packageURL.toString()];
|
||||
const transitiveDepScope = getDependencyScopeForMavenScope(transitiveDepArtifact.scopes);
|
||||
manifest.addIndirectDependency(transitiveDep, transitiveDepScope);
|
||||
seen.add(purl);
|
||||
addTransitiveDeps(transitiveDep.dependencies, seen);
|
||||
addTransitiveDeps(transitiveDep.dependencies);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -120,20 +113,20 @@ class MavenDependencyGraph {
|
||||
}
|
||||
}
|
||||
exports.MavenDependencyGraph = MavenDependencyGraph;
|
||||
function parseDependencyJson(file) {
|
||||
function parseDependencyJson(file, isMultiModule = false) {
|
||||
const data = (0, file_utils_1.loadFileContents)(file);
|
||||
const pomXmlFilepath = file.replace(`target/${exports.depgraphfilename}`, 'pom.xml');
|
||||
if (!data) {
|
||||
return {
|
||||
filePath: pomXmlFilepath,
|
||||
graphName: 'empty',
|
||||
artifacts: [],
|
||||
dependencies: [],
|
||||
isMultiModule: isMultiModule
|
||||
};
|
||||
}
|
||||
try {
|
||||
const depGraph = JSON.parse(data);
|
||||
return Object.assign(Object.assign({}, depGraph), { filePath: pomXmlFilepath });
|
||||
depGraph.isMultiModule = isMultiModule;
|
||||
return depGraph;
|
||||
}
|
||||
catch (err) {
|
||||
throw new Error(`Failed to parse JSON dependency data: ${err.message}`);
|
||||
@@ -253,21 +246,11 @@ function run() {
|
||||
mavenArgs: core.getInput('maven-args') || '',
|
||||
};
|
||||
const snapshotConfig = {
|
||||
includeManifestFile: core.getBooleanInput('snapshot-include-file-name'),
|
||||
manifestFile: core.getInput('snapshot-dependency-file-name'),
|
||||
sha: core.getInput('snapshot-sha'),
|
||||
ref: core.getInput('snapshot-ref'),
|
||||
};
|
||||
const correlator = core.getInput('correlator');
|
||||
if (correlator) {
|
||||
snapshotConfig.correlator = correlator;
|
||||
}
|
||||
const detectorName = core.getInput('detector-name');
|
||||
if (detectorName !== '') {
|
||||
snapshotConfig.detector = {
|
||||
name: detectorName,
|
||||
url: core.getInput('detector-url', { required: true }),
|
||||
version: core.getInput('detector-version', { required: true }),
|
||||
};
|
||||
}
|
||||
snapshot = yield (0, snapshot_generator_1.generateSnapshot)(directory, mavenConfig, snapshotConfig);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -481,45 +464,51 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.generateDependencyGraphs = exports.generateSnapshot = void 0;
|
||||
exports.generateDependencyGraph = exports.generateSnapshot = void 0;
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const path = __importStar(__nccwpck_require__(1017));
|
||||
const dependency_submission_toolkit_1 = __nccwpck_require__(3415);
|
||||
const depgraph_1 = __nccwpck_require__(8047);
|
||||
const maven_runner_1 = __nccwpck_require__(7433);
|
||||
const fs_1 = __nccwpck_require__(7147);
|
||||
const file_utils_1 = __nccwpck_require__(799);
|
||||
const packageData = __nccwpck_require__(2876);
|
||||
const DEPGRAPH_MAVEN_PLUGIN_VERSION = '4.0.3';
|
||||
const DEPGRAPH_MAVEN_PLUGIN_VERSION = '4.0.2';
|
||||
function generateSnapshot(directory, mvnConfig, snapshotConfig) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
var _a, _b;
|
||||
const depgraphs = yield generateDependencyGraphs(directory, mvnConfig);
|
||||
const detector = (_a = snapshotConfig === null || snapshotConfig === void 0 ? void 0 : snapshotConfig.detector) !== null && _a !== void 0 ? _a : getDetector();
|
||||
let snapshot = new dependency_submission_toolkit_1.Snapshot(detector, snapshotConfig === null || snapshotConfig === void 0 ? void 0 : snapshotConfig.context, snapshotConfig === null || snapshotConfig === void 0 ? void 0 : snapshotConfig.job);
|
||||
snapshot.job.correlator = (snapshotConfig === null || snapshotConfig === void 0 ? void 0 : snapshotConfig.correlator)
|
||||
? snapshotConfig.correlator
|
||||
: (_b = snapshot.job) === null || _b === void 0 ? void 0 : _b.correlator;
|
||||
const specifiedRef = getNonEmptyValue(snapshotConfig === null || snapshotConfig === void 0 ? void 0 : snapshotConfig.ref);
|
||||
if (specifiedRef) {
|
||||
snapshot.ref = specifiedRef;
|
||||
}
|
||||
const specifiedSha = getNonEmptyValue(snapshot === null || snapshot === void 0 ? void 0 : snapshot.sha);
|
||||
if (specifiedSha) {
|
||||
snapshot.sha = specifiedSha;
|
||||
}
|
||||
const depgraph = yield generateDependencyGraph(directory, mvnConfig);
|
||||
try {
|
||||
for (const depgraph of depgraphs) {
|
||||
const mavenDependencies = new depgraph_1.MavenDependencyGraph(depgraph);
|
||||
const pomFile = getRepositoryRelativePath(depgraph.filePath);
|
||||
const manifest = mavenDependencies.createManifest(pomFile);
|
||||
snapshot.addManifest(manifest);
|
||||
const mavenDependencies = new depgraph_1.MavenDependencyGraph(depgraph);
|
||||
let manifest;
|
||||
if (snapshotConfig === null || snapshotConfig === void 0 ? void 0 : snapshotConfig.includeManifestFile) {
|
||||
let pomFile;
|
||||
if (snapshotConfig === null || snapshotConfig === void 0 ? void 0 : snapshotConfig.manifestFile) {
|
||||
pomFile = snapshotConfig.manifestFile;
|
||||
}
|
||||
else {
|
||||
// The filepath to the POM needs to be relative to the root of the GitHub repository for the links to work once uploaded
|
||||
pomFile = getRepositoryRelativePath(path.join(directory, 'pom.xml'));
|
||||
}
|
||||
manifest = mavenDependencies.createManifest(pomFile);
|
||||
}
|
||||
else {
|
||||
manifest = mavenDependencies.createManifest();
|
||||
}
|
||||
const snapshot = new dependency_submission_toolkit_1.Snapshot(getDetector(), snapshotConfig === null || snapshotConfig === void 0 ? void 0 : snapshotConfig.context, snapshotConfig === null || snapshotConfig === void 0 ? void 0 : snapshotConfig.job);
|
||||
snapshot.addManifest(manifest);
|
||||
const specifiedRef = getNonEmtptyValue(snapshotConfig === null || snapshotConfig === void 0 ? void 0 : snapshotConfig.ref);
|
||||
if (specifiedRef) {
|
||||
snapshot.ref = specifiedRef;
|
||||
}
|
||||
const specifiedSha = getNonEmtptyValue(snapshot === null || snapshot === void 0 ? void 0 : snapshot.sha);
|
||||
if (specifiedSha) {
|
||||
snapshot.sha = specifiedSha;
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
catch (err) {
|
||||
core.error(err);
|
||||
throw new Error(`Could not generate a snapshot of the dependencies; ${err.message}`);
|
||||
}
|
||||
return snapshot;
|
||||
});
|
||||
}
|
||||
exports.generateSnapshot = generateSnapshot;
|
||||
@@ -530,44 +519,71 @@ function getDetector() {
|
||||
version: packageData.version
|
||||
};
|
||||
}
|
||||
function generateDependencyGraphs(directory, config) {
|
||||
function generateDependencyGraph(directory, config) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
const mvn = new maven_runner_1.MavenRunner(directory, config === null || config === void 0 ? void 0 : config.settingsFile, config === null || config === void 0 ? void 0 : config.ignoreMavenWrapper, config === null || config === void 0 ? void 0 : config.mavenArgs);
|
||||
core.startGroup('depgraph-maven-plugin:aggregate');
|
||||
const mavenGraphArguments = [
|
||||
`com.github.ferstl:depgraph-maven-plugin:${DEPGRAPH_MAVEN_PLUGIN_VERSION}:graph`,
|
||||
core.startGroup('depgraph-maven-plugin:reactor');
|
||||
const mavenReactorArguments = [
|
||||
`com.github.ferstl:depgraph-maven-plugin:${DEPGRAPH_MAVEN_PLUGIN_VERSION}:reactor`,
|
||||
'-DgraphFormat=json',
|
||||
`-DoutputFileName=${depgraph_1.depgraphfilename}`,
|
||||
'-DoutputFileName=reactor.json'
|
||||
];
|
||||
const graphResults = yield mvn.exec(directory, mavenGraphArguments);
|
||||
core.info(graphResults.stdout);
|
||||
core.info(graphResults.stderr);
|
||||
const reactorResults = yield mvn.exec(directory, mavenReactorArguments);
|
||||
core.info(reactorResults.stdout);
|
||||
core.info(reactorResults.stderr);
|
||||
core.endGroup();
|
||||
if (graphResults.exitCode !== 0) {
|
||||
throw new Error(`Failed to successfully dependency results with Maven, exit code: ${graphResults.exitCode}`);
|
||||
if (reactorResults.exitCode !== 0) {
|
||||
throw new Error(`Failed to successfully generate reactor results with Maven, exit code: ${reactorResults.exitCode}`);
|
||||
}
|
||||
core.startGroup('depgraph-maven-plugin:aggregate');
|
||||
const mavenAggregateArguments = [
|
||||
`com.github.ferstl:depgraph-maven-plugin:${DEPGRAPH_MAVEN_PLUGIN_VERSION}:aggregate`,
|
||||
'-DgraphFormat=json',
|
||||
'-DoutputDirectory=target',
|
||||
'-DoutputFileName=aggregate-depgraph.json'
|
||||
];
|
||||
const aggregateResults = yield mvn.exec(directory, mavenAggregateArguments);
|
||||
core.info(aggregateResults.stdout);
|
||||
core.info(aggregateResults.stderr);
|
||||
core.endGroup();
|
||||
if (aggregateResults.exitCode !== 0) {
|
||||
throw new Error(`Failed to successfully dependency results with Maven, exit code: ${aggregateResults.exitCode}`);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
core.error(err);
|
||||
throw new Error(`A problem was encountered generating dependency files, please check execution logs for details; ${err.message}`);
|
||||
}
|
||||
const graphFiles = getDepgraphFiles(directory, depgraph_1.depgraphfilename);
|
||||
let results = [];
|
||||
for (const graphFile of graphFiles) {
|
||||
core.debug(`Found depgraph file: ${graphFile}`);
|
||||
try {
|
||||
const depgraph = (0, depgraph_1.parseDependencyJson)(graphFile);
|
||||
results.push(depgraph);
|
||||
}
|
||||
catch (err) {
|
||||
core.error(`Could not parse depgraph file, '${graphFile}': ${err.message}`);
|
||||
}
|
||||
const targetPath = path.join(directory, 'target');
|
||||
const isMultiModule = checkForMultiModule(path.join(targetPath, 'reactor.json'));
|
||||
// Now we have the aggregate dependency graph file to process
|
||||
const aggregateGraphFile = path.join(targetPath, 'aggregate-depgraph.json');
|
||||
try {
|
||||
return (0, depgraph_1.parseDependencyJson)(aggregateGraphFile, isMultiModule);
|
||||
}
|
||||
catch (err) {
|
||||
core.error(err);
|
||||
throw new Error(`Could not parse maven dependency file, '${aggregateGraphFile}': ${err.message}`);
|
||||
}
|
||||
return results;
|
||||
});
|
||||
}
|
||||
exports.generateDependencyGraphs = generateDependencyGraphs;
|
||||
exports.generateDependencyGraph = generateDependencyGraph;
|
||||
function checkForMultiModule(reactorJsonFile) {
|
||||
const data = (0, file_utils_1.loadFileContents)(reactorJsonFile);
|
||||
if (data) {
|
||||
try {
|
||||
const reactor = JSON.parse(data);
|
||||
// The reactor file will have an array of artifacts making up the parent and child modules if it is a multi module project
|
||||
return reactor.artifacts && reactor.artifacts.length > 0;
|
||||
}
|
||||
catch (err) {
|
||||
throw new Error(`Failed to parse reactor JSON payload: ${err.message}`);
|
||||
}
|
||||
}
|
||||
// If no data report that it is not a multi module project
|
||||
return false;
|
||||
}
|
||||
// TODO this is assuming the checkout was made into the base path of the workspace...
|
||||
function getRepositoryRelativePath(file) {
|
||||
const workspaceDirectory = path.resolve(process.env.GITHUB_WORKSPACE || '.');
|
||||
@@ -583,7 +599,7 @@ function getRepositoryRelativePath(file) {
|
||||
core.debug(`Snapshot relative file = ${result}`);
|
||||
return result;
|
||||
}
|
||||
function getNonEmptyValue(str) {
|
||||
function getNonEmtptyValue(str) {
|
||||
if (str) {
|
||||
const trimmed = str.trim();
|
||||
if (trimmed.length > 0) {
|
||||
@@ -592,31 +608,6 @@ function getNonEmptyValue(str) {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
// getDepgraphFiles recursively finds all files that match the filename within the directory
|
||||
function getDepgraphFiles(directory, filename) {
|
||||
let files = [];
|
||||
// debug only
|
||||
files = (0, fs_1.readdirSync)(directory);
|
||||
try {
|
||||
files = (0, fs_1.readdirSync)(directory)
|
||||
.filter((f) => f === filename)
|
||||
.map((f) => path.join(directory, f));
|
||||
}
|
||||
catch (err) {
|
||||
core.error(`Could not read depgraphs directory: ${err.message}`);
|
||||
return [];
|
||||
}
|
||||
// recursively find all files that match the filename within the directory
|
||||
const subdirs = (0, fs_1.readdirSync)(directory, { withFileTypes: true })
|
||||
.filter(dirent => dirent.isDirectory())
|
||||
.map(dirent => dirent.name);
|
||||
for (const subdir of subdirs) {
|
||||
const subdirPath = path.join(directory, subdir);
|
||||
const subdirFiles = getDepgraphFiles(subdirPath, filename);
|
||||
files = files.concat(subdirFiles);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
//# sourceMappingURL=snapshot-generator.js.map
|
||||
|
||||
/***/ }),
|
||||
@@ -33287,7 +33278,7 @@ exports.submitSnapshot = L;
|
||||
/***/ ((module) => {
|
||||
|
||||
"use strict";
|
||||
module.exports = JSON.parse('{"name":"maven-dependency-submission-action","version":"5.0.0","description":"Submit Maven dependencies to GitHub dependency submission API","main":"index.js","scripts":{"base-build":"npm ci && tsc","build":"npm run base-build && npm exec -- @vercel/ncc build --source-map lib/src/index.js","build-exe":"npm run build && pkg package.json --compress Gzip","test":"vitest --run"},"repository":{"type":"git","url":"git+https://github.com/advanced-security/maven-dependency-submission-action.git"},"keywords":[],"author":"GitHub, Inc","license":"MIT","bugs":{"url":"https://github.com/advanced-security/maven-dependency-submission-action/issues"},"homepage":"https://github.com/advanced-security/maven-dependency-submission-action","dependencies":{"@actions/core":"^1.10.1","@actions/exec":"^1.1.1","@github/dependency-submission-toolkit":"^2.0.0","commander":"^12.0.0","packageurl-js":"^1.2.0"},"devDependencies":{"@types/chai":"^4.3.1","@vercel/ncc":"^0.38.1","chai":"^4.3.6","@yao-pkg/pkg":"^5.11.5","ts-node":"^10.9.2","typescript":"^5.3.3","vitest":"^1.6.1"},"bin":{"cli":"lib/src/executable/cli.js"},"pkg":{"targets":["node20-linux-x64","node20-win-x64","node20-macos-x64"],"assets":["package.json"],"publicPackages":"*","outputPath":"cli"}}');
|
||||
module.exports = JSON.parse('{"name":"maven-dependency-submission-action","version":"4.0.3","description":"Submit Maven dependencies to GitHub dependency submission API","main":"index.js","scripts":{"base-build":"npm ci && tsc","build":"npm run base-build && npm exec -- @vercel/ncc build --source-map lib/src/index.js","build-exe":"npm run build && pkg package.json --compress Gzip","test":"vitest --run"},"repository":{"type":"git","url":"git+https://github.com/advanced-security/maven-dependency-submission-action.git"},"keywords":[],"author":"GitHub, Inc","license":"MIT","bugs":{"url":"https://github.com/advanced-security/maven-dependency-submission-action/issues"},"homepage":"https://github.com/advanced-security/maven-dependency-submission-action","dependencies":{"@actions/core":"^1.10.1","@actions/exec":"^1.1.1","@github/dependency-submission-toolkit":"^2.0.0","commander":"^12.0.0","packageurl-js":"^1.2.0"},"devDependencies":{"@types/chai":"^4.3.1","@vercel/ncc":"^0.38.1","chai":"^4.3.6","@yao-pkg/pkg":"^5.11.5","ts-node":"^10.9.2","typescript":"^5.3.3","vitest":"^1.2.1"},"bin":{"cli":"lib/src/executable/cli.js"},"pkg":{"targets":["node20-linux-x64","node20-win-x64","node20-macos-x64"],"assets":["package.json"],"publicPackages":"*","outputPath":"cli"}}');
|
||||
|
||||
/***/ })
|
||||
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Generated
+710
-826
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "maven-dependency-submission-action",
|
||||
"version": "5.0.0",
|
||||
"version": "4.0.3",
|
||||
"description": "Submit Maven dependencies to GitHub dependency submission API",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -34,7 +34,7 @@
|
||||
"@yao-pkg/pkg": "^5.11.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3",
|
||||
"vitest": "^3.1.3"
|
||||
"vitest": "^1.2.1"
|
||||
},
|
||||
"bin": {
|
||||
"cli": "lib/src/executable/cli.js"
|
||||
|
||||
@@ -116,25 +116,6 @@ describe('depgraph', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('cycle-tree', () => {
|
||||
let depGraph;
|
||||
beforeAll(() => {
|
||||
depGraph = parseDependencyJson(getTestDataFile("cycle-tree"));
|
||||
});
|
||||
|
||||
it('should parse out the top level dependencies', () => {
|
||||
const mavenDependencies = new MavenDependencyGraph(depGraph);
|
||||
expect(mavenDependencies.getPackageCount()).to.equal(3);
|
||||
});
|
||||
|
||||
it('should be able to generate a manifest despite having a cycle', () => {
|
||||
const mavenDependencies = new MavenDependencyGraph(depGraph);
|
||||
const manifest = mavenDependencies.createManifest();
|
||||
|
||||
expect(manifest.name).to.equal('hadoop-main');
|
||||
expect(manifest.countDependencies()).to.equal(2);
|
||||
})
|
||||
});
|
||||
|
||||
describe('bs-parent-dep-tree', () => {
|
||||
|
||||
|
||||
+8
-19
@@ -4,10 +4,10 @@ import { DependencyScope } from '@github/dependency-submission-toolkit';
|
||||
import { loadFileContents } from './utils/file-utils';
|
||||
|
||||
export type Depgraph = {
|
||||
filePath: string,
|
||||
graphName: string,
|
||||
artifacts: DepgraphArtifact[],
|
||||
dependencies: DepgraphDependency[],
|
||||
isMultiModule: boolean,
|
||||
}
|
||||
|
||||
export type DepgraphArtifact = {
|
||||
@@ -30,8 +30,6 @@ export type DepgraphDependency = {
|
||||
resolution: string,
|
||||
}
|
||||
|
||||
export const depgraphfilename = 'maven-dependency-submission-action-depgraph.json';
|
||||
|
||||
export class MavenDependencyGraph {
|
||||
|
||||
private depGraph: Depgraph;
|
||||
@@ -87,19 +85,13 @@ export class MavenDependencyGraph {
|
||||
let scope = getDependencyScopeForMavenScope(artifact.scopes);
|
||||
manifest.addDirectDependency(depPackage, scope);
|
||||
|
||||
function addTransitiveDeps(dependencies, seen: Set<string> = new Set()) {
|
||||
function addTransitiveDeps(dependencies) {
|
||||
if (dependencies) {
|
||||
dependencies.forEach(transitiveDep => {
|
||||
let purl = transitiveDep.packageURL.toString();
|
||||
if (seen.has(purl)) {
|
||||
// we're in a cycle! skip this one.
|
||||
return;
|
||||
}
|
||||
const transitiveDepArtifact = packageUrlToArtifact[purl];
|
||||
const transitiveDepArtifact = packageUrlToArtifact[transitiveDep.packageURL.toString()];
|
||||
const transitiveDepScope = getDependencyScopeForMavenScope(transitiveDepArtifact.scopes);
|
||||
manifest.addIndirectDependency(transitiveDep, transitiveDepScope);
|
||||
seen.add(purl);
|
||||
addTransitiveDeps(transitiveDep.dependencies, seen);
|
||||
addTransitiveDeps(transitiveDep.dependencies);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -173,25 +165,22 @@ export class MavenDependencyGraph {
|
||||
}
|
||||
}
|
||||
|
||||
export function parseDependencyJson(file: string): Depgraph {
|
||||
export function parseDependencyJson(file: string, isMultiModule: boolean = false): Depgraph {
|
||||
const data = loadFileContents(file);
|
||||
const pomXmlFilepath = file.replace(`target/${depgraphfilename}`, 'pom.xml');
|
||||
|
||||
if (!data) {
|
||||
return {
|
||||
filePath: pomXmlFilepath,
|
||||
graphName: 'empty',
|
||||
artifacts: [],
|
||||
dependencies: [],
|
||||
isMultiModule: isMultiModule
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const depGraph: Depgraph = JSON.parse(data);
|
||||
return {
|
||||
...depGraph,
|
||||
filePath: pomXmlFilepath,
|
||||
};
|
||||
depGraph.isMultiModule = isMultiModule;
|
||||
return depGraph;
|
||||
} catch (err: any) {
|
||||
throw new Error(`Failed to parse JSON dependency data: ${err.message}`);
|
||||
}
|
||||
|
||||
+3
-27
@@ -18,10 +18,7 @@ program.option('-j --job-name <jobName>', 'Optional name for the activity creati
|
||||
program.option('-i --run-id <jobName>', 'Optional Run ID number for the activity that is providing the graph');
|
||||
|
||||
program.option('--snapshot-exclude-file-name', 'exclude the file name in the dependency snapshot report. If false the name of the artifactor from the POM will be used, but any links in GitHub will not work.');
|
||||
|
||||
program.option('--detector-name <detectorName>', 'optional name of the detector that generated the snapshot');
|
||||
program.option('--detector-url <detectorUrl>', 'optional URL of the detector that generated the snapshot, but not optional if you specify an detector-name');
|
||||
program.option('--detector-version <detectorVersion>', 'optional version of the detector that generated the snapshot, but not optional if you specify an detector-name');
|
||||
program.option('--snapshot-dependency-file-name <fileName>', 'optional override to specificy the path to the file that the snapshot will be associated with in the repository');
|
||||
|
||||
program.parse(process.argv);
|
||||
|
||||
@@ -47,25 +44,6 @@ async function execute() {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// If the detector-name is provided, then the other detector options become mandatory, check these early
|
||||
let detector;
|
||||
if (opts.detectorName) {
|
||||
if (!opts.detectorUrl) {
|
||||
console.error(`Error: detector-url is required when detector-name is provided\n`);
|
||||
program.help({ error: true });
|
||||
}
|
||||
|
||||
if (!opts.detectorVersion) {
|
||||
console.error(`Error: detector-version is required when detector-name is provided\n`);
|
||||
program.help({ error: true });
|
||||
}
|
||||
detector = {
|
||||
name: opts.detectorName,
|
||||
url: opts.detectorUrl,
|
||||
version: opts.detectorVersion,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Build a fake GitHub Actions context so that values for the submission APIs can be retrieved
|
||||
const context = {
|
||||
@@ -91,12 +69,10 @@ async function execute() {
|
||||
sha: opts.sha,
|
||||
ref: opts.branchRef,
|
||||
|
||||
detector: detector
|
||||
manifestFile: opts.snapshotDependencyFileName,
|
||||
includeManifestFile: !opts.snapshotExcludeFileName,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
snapshot = await generateSnapshot(opts.directory, mvnConfig, snapshotConfig);
|
||||
|
||||
} catch (err: any) {
|
||||
|
||||
+3
-13
@@ -13,21 +13,11 @@ async function run() {
|
||||
mavenArgs: core.getInput('maven-args') || '',
|
||||
}
|
||||
const snapshotConfig: SnapshotConfig = {
|
||||
includeManifestFile: core.getBooleanInput('snapshot-include-file-name'),
|
||||
manifestFile: core.getInput('snapshot-dependency-file-name'),
|
||||
sha: core.getInput('snapshot-sha'),
|
||||
ref: core.getInput('snapshot-ref'),
|
||||
}
|
||||
const correlator = core.getInput('correlator');
|
||||
if (correlator) {
|
||||
snapshotConfig.correlator = correlator;
|
||||
}
|
||||
const detectorName = core.getInput('detector-name');
|
||||
if (detectorName !== '') {
|
||||
snapshotConfig.detector = {
|
||||
name: detectorName,
|
||||
url: core.getInput('detector-url', { required: true }),
|
||||
version: core.getInput('detector-version', { required: true }),
|
||||
};
|
||||
}
|
||||
|
||||
snapshot = await generateSnapshot(directory, mavenConfig, snapshotConfig);
|
||||
} catch (err: any) {
|
||||
@@ -46,4 +36,4 @@ async function run() {
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
run();
|
||||
@@ -1,7 +1,6 @@
|
||||
import { getMavenProjectDirectory } from './utils/test-util';
|
||||
import { generateDependencyGraphs, generateSnapshot } from './snapshot-generator';
|
||||
import { generateDependencyGraph, generateSnapshot } from './snapshot-generator';
|
||||
import {describe, it, expect} from 'vitest';
|
||||
import { Manifest } from '@github/dependency-submission-toolkit';
|
||||
|
||||
describe('snapshot-generator', () => {
|
||||
|
||||
@@ -9,11 +8,7 @@ describe('snapshot-generator', () => {
|
||||
|
||||
it('should generate a snapshot for a simple project', async () => {
|
||||
const projectDir = getMavenProjectDirectory('simple');
|
||||
const depGraphs = await generateDependencyGraphs(projectDir);
|
||||
expect(depGraphs).toBeDefined();
|
||||
expect(depGraphs.length).toBe(1);
|
||||
const depGraph = depGraphs[0];
|
||||
|
||||
const depGraph = await generateDependencyGraph(projectDir);
|
||||
expect(depGraph.dependencies.length).toBe(20);
|
||||
}, 20000);
|
||||
});
|
||||
@@ -42,50 +37,9 @@ describe('snapshot-generator', () => {
|
||||
const projectDir = getMavenProjectDirectory('multi-module-multi-branch');
|
||||
const snapshot = await generateSnapshot(projectDir);
|
||||
|
||||
expect(snapshot.manifests['bs-parent']).toBeDefined();
|
||||
expect(snapshot.detector.version).toBe(version);
|
||||
|
||||
const bsParentManifest = snapshot.manifests['bs-parent'];
|
||||
expect(bsParentManifest).toBeDefined();
|
||||
expect(getDirectDependencyPurls(bsParentManifest)).toEqual([
|
||||
'pkg:maven/junit/junit@4.13?type=jar']);
|
||||
|
||||
const bsApplicationManifest = snapshot.manifests['bs-application'];
|
||||
expect(bsApplicationManifest).toBeDefined();
|
||||
expect(getDirectDependencyPurls(bsApplicationManifest)).toEqual([
|
||||
'pkg:maven/com.github.octodemo/bs-library-web@1.0.0-SNAPSHOT?type=jar',
|
||||
'pkg:maven/junit/junit@4.13?type=jar',
|
||||
'pkg:maven/org.eclipse.jetty/jetty-server@10.0.10?type=jar',
|
||||
]);
|
||||
|
||||
const bsLibrariesManifest = snapshot.manifests['bs-libraries'];
|
||||
expect(bsLibrariesManifest).toBeDefined();
|
||||
expect(getDirectDependencyPurls(bsLibrariesManifest)).toEqual([
|
||||
'pkg:maven/junit/junit@4.13?type=jar',
|
||||
'pkg:maven/org.apache.logging.log4j/log4j-api@2.19.0?type=jar',
|
||||
]);
|
||||
|
||||
const bsOtherManifest = snapshot.manifests['bs-other'];
|
||||
expect(bsOtherManifest).toBeDefined();
|
||||
expect(getDirectDependencyPurls(bsOtherManifest)).toEqual([
|
||||
'pkg:maven/junit/junit@4.13?type=jar',
|
||||
]);
|
||||
|
||||
const bsLibraryDatabaseManifest = snapshot.manifests['bs-library-database'];
|
||||
expect(bsLibraryDatabaseManifest).toBeDefined();
|
||||
expect(getDirectDependencyPurls(bsLibraryDatabaseManifest)).toEqual([
|
||||
'pkg:maven/junit/junit@4.13?type=jar',
|
||||
'pkg:maven/org.apache.logging.log4j/log4j-api@2.19.0?type=jar',
|
||||
'pkg:maven/org.postgresql/postgresql@42.5.0?type=jar',
|
||||
'pkg:maven/org.xerial/sqlite-jdbc@3.36.0.3?type=jar',
|
||||
]);
|
||||
|
||||
const bsLibraryWebManifest = snapshot.manifests['bs-library-web'];
|
||||
expect(bsLibraryWebManifest).toBeDefined();
|
||||
expect(getDirectDependencyPurls(bsLibraryWebManifest)).toEqual([
|
||||
'pkg:maven/junit/junit@4.13?type=jar',
|
||||
'pkg:maven/org.apache.logging.log4j/log4j-api@2.19.0?type=jar',
|
||||
'pkg:maven/org.eclipse.jetty.http2/http2-http-client-transport@10.0.10?type=jar',
|
||||
]);
|
||||
expect(snapshot.manifests['bs-parent'].countDependencies()).toBe(20);
|
||||
}, 20000);
|
||||
|
||||
it('should generate a snapshot for a maven-wrapper project', async () => {
|
||||
@@ -114,34 +68,5 @@ describe('snapshot-generator', () => {
|
||||
expect(snapshot.detector.version).toBe(version);
|
||||
expect(snapshot.manifests['problem-dependency-graph-2602'].countDependencies()).toBe(230);
|
||||
}, 40000);
|
||||
|
||||
it('should use correlator from snapshotConfig if it exists', async() => {
|
||||
const projectDir = getMavenProjectDirectory('simple');
|
||||
const snapshotConfig = {
|
||||
correlator: 'configCorrelator',
|
||||
job: {
|
||||
correlator: 'jobCorrelator'
|
||||
}
|
||||
};
|
||||
const snapshot = await generateSnapshot(projectDir, undefined, snapshotConfig);
|
||||
|
||||
expect(snapshot.job.correlator).toBe('configCorrelator');
|
||||
}, 20000);
|
||||
|
||||
it('should use a default job correlator when not specified', async() => {
|
||||
const projectDir = getMavenProjectDirectory('simple');
|
||||
const snapshotConfig = {
|
||||
job: {
|
||||
correlator: 'jobCorrelator'
|
||||
}
|
||||
};
|
||||
const snapshot = await generateSnapshot(projectDir, undefined, snapshotConfig);
|
||||
|
||||
expect(snapshot.job.correlator).toBe('jobCorrelator');
|
||||
}, 20000);
|
||||
});
|
||||
});
|
||||
|
||||
function getDirectDependencyPurls(manifest: Manifest): string[] {
|
||||
return Object.values(manifest.resolved).filter(dep => dep.relationship === 'direct').map(dep => dep.depPackage.packageURL.toString()).sort();
|
||||
}
|
||||
});
|
||||
+86
-78
@@ -2,13 +2,12 @@ import * as core from '@actions/core';
|
||||
import * as path from 'path';
|
||||
|
||||
import { Manifest, Snapshot } from '@github/dependency-submission-toolkit';
|
||||
import { Depgraph, MavenDependencyGraph, parseDependencyJson, depgraphfilename } from './depgraph';
|
||||
import { Depgraph, MavenDependencyGraph, parseDependencyJson } from './depgraph';
|
||||
import { MavenRunner } from './maven-runner';
|
||||
import { loadFileContents } from './utils/file-utils';
|
||||
import { readdirSync } from 'fs';
|
||||
|
||||
const packageData = require('../package.json');
|
||||
const DEPGRAPH_MAVEN_PLUGIN_VERSION = '4.0.3';
|
||||
const DEPGRAPH_MAVEN_PLUGIN_VERSION = '4.0.2';
|
||||
|
||||
export type MavenConfiguration = {
|
||||
ignoreMavenWrapper?: boolean;
|
||||
@@ -17,50 +16,52 @@ export type MavenConfiguration = {
|
||||
}
|
||||
|
||||
export type SnapshotConfig = {
|
||||
includeManifestFile?: boolean;
|
||||
manifestFile?: string;
|
||||
context?: any;
|
||||
job?: any;
|
||||
sha?: any;
|
||||
ref?: any;
|
||||
detector?: {
|
||||
name: string;
|
||||
url: string;
|
||||
version: string;
|
||||
};
|
||||
correlator?: string;
|
||||
};
|
||||
|
||||
export async function generateSnapshot(directory: string, mvnConfig?: MavenConfiguration, snapshotConfig?: SnapshotConfig) {
|
||||
const depgraphs = await generateDependencyGraphs(directory, mvnConfig);
|
||||
const detector = snapshotConfig?.detector ?? getDetector();
|
||||
let snapshot = new Snapshot(detector, snapshotConfig?.context, snapshotConfig?.job);
|
||||
|
||||
snapshot.job.correlator = snapshotConfig?.correlator
|
||||
? snapshotConfig.correlator
|
||||
: snapshot.job?.correlator;
|
||||
|
||||
const specifiedRef = getNonEmptyValue(snapshotConfig?.ref);
|
||||
if (specifiedRef) {
|
||||
snapshot.ref = specifiedRef;
|
||||
}
|
||||
|
||||
const specifiedSha = getNonEmptyValue(snapshot?.sha);
|
||||
if (specifiedSha) {
|
||||
snapshot.sha = specifiedSha;
|
||||
}
|
||||
const depgraph = await generateDependencyGraph(directory, mvnConfig);
|
||||
|
||||
try {
|
||||
for (const depgraph of depgraphs) {
|
||||
const mavenDependencies = new MavenDependencyGraph(depgraph);
|
||||
const pomFile = getRepositoryRelativePath(depgraph.filePath);
|
||||
const manifest = mavenDependencies.createManifest(pomFile);
|
||||
const mavenDependencies = new MavenDependencyGraph(depgraph);
|
||||
|
||||
snapshot.addManifest(manifest);
|
||||
let manifest: Manifest;
|
||||
if (snapshotConfig?.includeManifestFile) {
|
||||
let pomFile;
|
||||
if (snapshotConfig?.manifestFile) {
|
||||
pomFile = snapshotConfig.manifestFile;
|
||||
} else {
|
||||
// The filepath to the POM needs to be relative to the root of the GitHub repository for the links to work once uploaded
|
||||
pomFile = getRepositoryRelativePath(path.join(directory, 'pom.xml'));
|
||||
}
|
||||
manifest = mavenDependencies.createManifest(pomFile);
|
||||
} else {
|
||||
manifest = mavenDependencies.createManifest();
|
||||
}
|
||||
|
||||
const snapshot = new Snapshot(getDetector(), snapshotConfig?.context, snapshotConfig?.job);
|
||||
snapshot.addManifest(manifest);
|
||||
|
||||
const specifiedRef = getNonEmtptyValue(snapshotConfig?.ref);
|
||||
if (specifiedRef) {
|
||||
snapshot.ref = specifiedRef;
|
||||
}
|
||||
|
||||
const specifiedSha = getNonEmtptyValue(snapshot?.sha);
|
||||
if (specifiedSha) {
|
||||
snapshot.sha = specifiedSha;
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
} catch (err: any) {
|
||||
core.error(err);
|
||||
throw new Error(`Could not generate a snapshot of the dependencies; ${err.message}`);
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
function getDetector() {
|
||||
@@ -71,42 +72,75 @@ function getDetector() {
|
||||
};
|
||||
}
|
||||
|
||||
export async function generateDependencyGraphs(directory: string, config?: MavenConfiguration): Promise<Depgraph[]> {
|
||||
export async function generateDependencyGraph(directory: string, config?: MavenConfiguration): Promise<Depgraph> {
|
||||
try {
|
||||
const mvn = new MavenRunner(directory, config?.settingsFile, config?.ignoreMavenWrapper, config?.mavenArgs);
|
||||
|
||||
core.startGroup('depgraph-maven-plugin:aggregate');
|
||||
const mavenGraphArguments = [
|
||||
`com.github.ferstl:depgraph-maven-plugin:${DEPGRAPH_MAVEN_PLUGIN_VERSION}:graph`,
|
||||
core.startGroup('depgraph-maven-plugin:reactor');
|
||||
const mavenReactorArguments = [
|
||||
`com.github.ferstl:depgraph-maven-plugin:${DEPGRAPH_MAVEN_PLUGIN_VERSION}:reactor`,
|
||||
'-DgraphFormat=json',
|
||||
`-DoutputFileName=${depgraphfilename}`,
|
||||
'-DoutputFileName=reactor.json'
|
||||
];
|
||||
const graphResults = await mvn.exec(directory, mavenGraphArguments);
|
||||
const reactorResults = await mvn.exec(directory, mavenReactorArguments);
|
||||
|
||||
core.info(graphResults.stdout);
|
||||
core.info(graphResults.stderr);
|
||||
core.info(reactorResults.stdout);
|
||||
core.info(reactorResults.stderr);
|
||||
core.endGroup();
|
||||
|
||||
if (graphResults.exitCode !== 0) {
|
||||
throw new Error(`Failed to successfully generate dependency results with Maven, exit code: ${graphResults.exitCode}`);
|
||||
if (reactorResults.exitCode !== 0) {
|
||||
throw new Error(`Failed to successfully generate reactor results with Maven, exit code: ${reactorResults.exitCode}`);
|
||||
}
|
||||
|
||||
core.startGroup('depgraph-maven-plugin:aggregate');
|
||||
const mavenAggregateArguments = [
|
||||
`com.github.ferstl:depgraph-maven-plugin:${DEPGRAPH_MAVEN_PLUGIN_VERSION}:aggregate`,
|
||||
'-DgraphFormat=json',
|
||||
'-DoutputDirectory=target',
|
||||
'-DoutputFileName=aggregate-depgraph.json'
|
||||
];
|
||||
const aggregateResults = await mvn.exec(directory, mavenAggregateArguments);
|
||||
|
||||
core.info(aggregateResults.stdout);
|
||||
core.info(aggregateResults.stderr);
|
||||
core.endGroup();
|
||||
|
||||
if (aggregateResults.exitCode !== 0) {
|
||||
throw new Error(`Failed to successfully dependency results with Maven, exit code: ${aggregateResults.exitCode}`);
|
||||
}
|
||||
} catch (err: any) {
|
||||
core.error(err);
|
||||
throw new Error(`A problem was encountered generating dependency files, please check execution logs for details; ${err.message}`);
|
||||
}
|
||||
|
||||
const graphFiles = getDepgraphFiles(directory, depgraphfilename);
|
||||
let results: Depgraph[] = [];
|
||||
for (const graphFile of graphFiles) {
|
||||
core.debug(`Found depgraph file: ${graphFile}`);
|
||||
const targetPath = path.join(directory, 'target');
|
||||
const isMultiModule = checkForMultiModule(path.join(targetPath, 'reactor.json'));
|
||||
|
||||
// Now we have the aggregate dependency graph file to process
|
||||
const aggregateGraphFile = path.join(targetPath, 'aggregate-depgraph.json');
|
||||
try {
|
||||
return parseDependencyJson(aggregateGraphFile, isMultiModule);
|
||||
} catch (err: any) {
|
||||
core.error(err);
|
||||
throw new Error(`Could not parse maven dependency file, '${aggregateGraphFile}': ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
function checkForMultiModule(reactorJsonFile): boolean {
|
||||
const data = loadFileContents(reactorJsonFile);
|
||||
|
||||
if (data) {
|
||||
try {
|
||||
const depgraph = parseDependencyJson(graphFile);
|
||||
results.push(depgraph);
|
||||
const reactor = JSON.parse(data);
|
||||
// The reactor file will have an array of artifacts making up the parent and child modules if it is a multi module project
|
||||
return reactor.artifacts && reactor.artifacts.length > 0;
|
||||
} catch (err: any) {
|
||||
core.error(`Could not parse depgraph file, '${graphFile}': ${err.message}`);
|
||||
throw new Error(`Failed to parse reactor JSON payload: ${err.message}`);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
|
||||
// If no data report that it is not a multi module project
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO this is assuming the checkout was made into the base path of the workspace...
|
||||
@@ -128,7 +162,7 @@ function getRepositoryRelativePath(file) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getNonEmptyValue(str?: string) {
|
||||
function getNonEmtptyValue(str?: string) {
|
||||
if (str) {
|
||||
const trimmed = str.trim();
|
||||
if (trimmed.length > 0) {
|
||||
@@ -136,30 +170,4 @@ function getNonEmptyValue(str?: string) {
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// getDepgraphFiles recursively finds all files that match the filename within the directory
|
||||
function getDepgraphFiles(directory: string, filename: string): string[] {
|
||||
let files: string[] = [];
|
||||
try {
|
||||
files = readdirSync(directory)
|
||||
.filter((f: string) => f === filename)
|
||||
.map((f: string) => path.join(directory, f));
|
||||
} catch (err: any) {
|
||||
core.error(`Could not read depgraphs directory: ${err.message}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
// recursively find all files that match the filename within the directory
|
||||
const subdirs = readdirSync(directory, { withFileTypes: true })
|
||||
.filter(dirent => dirent.isDirectory())
|
||||
.map(dirent => dirent.name);
|
||||
|
||||
for (const subdir of subdirs) {
|
||||
const subdirPath = path.join(directory, subdir);
|
||||
const subdirFiles = getDepgraphFiles(subdirPath, filename);
|
||||
files = files.concat(subdirFiles);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
{
|
||||
"graphName" : "hadoop-main",
|
||||
"artifacts" : [ {
|
||||
"id" : "org.apache.hadoop:hadoop-annotations:jar:compile",
|
||||
"numericId" : 1,
|
||||
"groupId" : "org.apache.hadoop",
|
||||
"artifactId" : "hadoop-annotations",
|
||||
"version" : "3.5.0-SNAPSHOT",
|
||||
"optional" : false,
|
||||
"scopes" : [ "compile" ],
|
||||
"types" : [ "jar" ]
|
||||
}, {
|
||||
"id" : "jdiff:jdiff:jar:provided",
|
||||
"numericId" : 2,
|
||||
"groupId" : "jdiff",
|
||||
"artifactId" : "jdiff",
|
||||
"version" : "1.0.9",
|
||||
"optional" : false,
|
||||
"scopes" : [ "provided" ],
|
||||
"types" : [ "jar" ]
|
||||
}, {
|
||||
"id" : "org.apache.hadoop:hadoop-project-dist:pom:compile",
|
||||
"numericId" : 3,
|
||||
"groupId" : "org.apache.hadoop",
|
||||
"artifactId" : "hadoop-project-dist",
|
||||
"version" : "3.5.0-SNAPSHOT",
|
||||
"optional" : false,
|
||||
"scopes" : [ "compile" ],
|
||||
"types" : [ "pom" ]
|
||||
} ],
|
||||
"dependencies" : [ {
|
||||
"from" : "org.apache.hadoop:hadoop-annotations:jar:compile",
|
||||
"to" : "jdiff:jdiff:jar:provided",
|
||||
"numericFrom" : 1,
|
||||
"numericTo" : 2,
|
||||
"resolution" : "INCLUDED"
|
||||
}, {
|
||||
"from" : "org.apache.hadoop:hadoop-annotations:jar:compile",
|
||||
"to" : "jdiff:jdiff:jar:provided",
|
||||
"numericFrom" : 1,
|
||||
"numericTo" : 3,
|
||||
"resolution" : "INCLUDED"
|
||||
}, {
|
||||
"from" : "jdiff:jdiff:jar:provided",
|
||||
"to" : "org.apache.hadoop:hadoop-project-dist:pom:compile",
|
||||
"numericFrom" : 2,
|
||||
"numericTo" : 3,
|
||||
"resolution" : "INCLUDED"
|
||||
}, {
|
||||
"from" : "org.apache.hadoop:hadoop-project-dist:pom:compile",
|
||||
"to" : "jdiff:jdiff:jar:provided",
|
||||
"numericFrom" : 3,
|
||||
"numericTo" : 2,
|
||||
"resolution" : "INCLUDED"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user