Adding more configuration options for Maven execution #7 and support for mvnw #6

This commit is contained in:
Peter Murray
2022-10-26 15:22:37 +00:00
committed by GitHub
parent 438332251b
commit 37a172d2c1
18 changed files with 1220 additions and 155 deletions
+14
View File
@@ -11,6 +11,20 @@ inputs:
type: string
default: ${{ github.workspace }}
settings-file:
description: Optional path to a Maven settings.xml file for the dependencies to be resolved
type: string
ignore-maven-wrapper:
description: Flag for optionally ignoring any maven wrapper files (mvnw) and instead rely on the PATH provided mvn
type: boolean
default: false
maven-args:
description: Additional maven arguments to add to the command line invocation of maven when it generates the dependency snapshot
type: string
default: ''
token:
description: The GitHub token to use to submit the depedency snapshot to the repository
type: string
+285 -82
View File
@@ -2,38 +2,15 @@ require('./sourcemap-register.js');/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 8047:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.artifactToPackageURL = exports.parseDependencyJson = exports.MavenDependencyGraph = void 0;
const fs = __importStar(__nccwpck_require__(7147));
const packageurl_js_1 = __nccwpck_require__(8915);
const dependency_submission_toolkit_1 = __nccwpck_require__(9810);
const file_utils_1 = __nccwpck_require__(799);
class MavenDependencyGraph {
constructor(graph) {
this.depGraph = graph;
@@ -83,9 +60,10 @@ class MavenDependencyGraph {
parseDependencies() {
const graph = this.depGraph;
const cache = this.cache;
const dependencies = graph.dependencies || [];
const rootArtifactIds = [];
const dependencyIdMap = dependencyMap(graph.dependencies);
const dependencyArtifactIdsWithParents = extractDependencyArtifactIdsWithParents(graph.dependencies);
const dependencyIdMap = dependencyMap(dependencies);
const dependencyArtifactIdsWithParents = extractDependencyArtifactIdsWithParents(dependencies);
const idToPackageCachePackage = new Map();
// Create the packages for all known artifacts
graph.artifacts.forEach((artifact) => {
@@ -118,7 +96,7 @@ class MavenDependencyGraph {
});
const uniqueRootArtifactDependencies = [];
rootArtifactIds.forEach(rootArtifactId => {
const dependencyIds = getDirectDependencies(rootArtifactId, graph.dependencies);
const dependencyIds = getDirectDependencies(rootArtifactId, dependencies);
if (dependencyIds) {
dependencyIds.forEach(dependencyId => {
if (uniqueRootArtifactDependencies.indexOf(dependencyId) === -1) {
@@ -132,19 +110,22 @@ class MavenDependencyGraph {
}
exports.MavenDependencyGraph = MavenDependencyGraph;
function parseDependencyJson(file, isMultiModule = false) {
const data = (0, file_utils_1.loadFileContents)(file);
if (!data) {
return {
graphName: 'empty',
artifacts: [],
dependencies: [],
isMultiModule: isMultiModule
};
}
try {
const data = fs.readFileSync(file);
try {
const depGraph = JSON.parse(data.toString('utf-8'));
depGraph.isMultiModule = isMultiModule;
return depGraph;
}
catch (err) {
throw new Error(`Failed to parse JSON payload: ${err.message}`);
}
const depGraph = JSON.parse(data);
depGraph.isMultiModule = isMultiModule;
return depGraph;
}
catch (err) {
throw new Error(`Failed to load file ${file}: ${err}`);
throw new Error(`Failed to parse JSON dependency data: ${err.message}`);
}
}
exports.parseDependencyJson = parseDependencyJson;
@@ -164,19 +145,24 @@ function getDependencyScopeForMavenScope(mavenScopes) {
return 'runtime';
}
function extractDependencyArtifactIdsWithParents(dependencies) {
return dependencies.map(dependency => { return dependency.to; });
if (dependencies) {
return dependencies.map(dependency => { return dependency.to; });
}
return [];
}
function dependencyMap(dependencies) {
const map = new Map();
dependencies.forEach(dependency => {
const fromUrl = dependency.from;
let deps = map[fromUrl];
if (!deps) {
deps = [];
map[fromUrl] = deps;
}
deps.push(dependency.to);
});
if (dependencies) {
dependencies.forEach(dependency => {
const fromUrl = dependency.from;
let deps = map[fromUrl];
if (!deps) {
deps = [];
map[fromUrl] = deps;
}
deps.push(dependency.to);
});
}
return map;
}
function getDirectDependencies(artifactId, dependencies) {
@@ -233,7 +219,12 @@ function run() {
let snapshot;
try {
const directory = core.getInput('directory', { required: true });
snapshot = yield (0, snapshot_generator_1.generateSnapshot)(directory);
const mavenConfig = {
ignoreMavenWrapper: core.getBooleanInput('ignore-maven-wrapper'),
settingsFile: core.getInput('settings-file'),
mavenArgs: core.getInput('maven-args') || '',
};
snapshot = yield (0, snapshot_generator_1.generateSnapshot)(directory, mavenConfig);
}
catch (err) {
core.error(err);
@@ -254,6 +245,160 @@ run();
/***/ }),
/***/ 7433:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.MavenRunner = void 0;
const exec = __importStar(__nccwpck_require__(1514));
const core = __importStar(__nccwpck_require__(2186));
const path = __importStar(__nccwpck_require__(1017));
const file_utils_1 = __nccwpck_require__(799);
class MavenRunner {
constructor(directory, settingsFile, ingoreWrapper = false, mavenArguments = '') {
this.mavenExecutable = resolveMavenExecutable(directory, ingoreWrapper);
if (settingsFile) {
if ((0, file_utils_1.fileExists)(settingsFile)) {
this.settings = settingsFile;
}
else {
throw new Error(`The specified settings file '${settingsFile}' does not exist`);
}
}
this.additionalArguments = [];
if (mavenArguments.trim().length > 0) {
this.additionalArguments = mavenArguments.trim().split(' ');
}
}
get configuration() {
return {
executable: this.mavenExecutable,
settingsFile: this.settings
};
}
exec(cwd, parameters) {
return __awaiter(this, void 0, void 0, function* () {
const commandArgs = [];
// implictly run in batch mode, might need to make this configurable in the future
commandArgs.push('-B');
if (this.settings) {
commandArgs.push('--settings');
commandArgs.push(this.settings);
}
// Only append the additional arguments they are not empty values
if (this.additionalArguments && this.additionalArguments.length > 0) {
this.additionalArguments.forEach(arg => {
if (arg.trim().length > 0) {
commandArgs.push(arg);
}
});
}
Array.prototype.push.apply(commandArgs, parameters);
let executionOutput = '';
let executionErrors = '';
const options = {
cwd: cwd,
listeners: {
stdout: (data) => {
executionOutput += data.toString();
},
stderr: (data) => {
executionErrors += data.toString();
}
}
};
try {
const exitCode = yield exec.exec(this.mavenExecutable, commandArgs, options);
return {
stdout: executionOutput,
stderr: executionErrors,
exitCode: exitCode
};
}
catch (err) {
//TODO possibly throw a wrapped error here
core.warning(`Error encountered executing maven: ${err.message}`);
return {
stdout: executionOutput,
stderr: executionErrors,
exitCode: -1
};
}
});
}
}
exports.MavenRunner = MavenRunner;
function resolveMavenExecutable(directory, ignoreWrapper = false) {
if (ignoreWrapper) {
return getMavenExecutable();
}
const wrapper = getMavenWrapper(directory);
// Return the matche maven wrapper script or otherwise fall back to mvn on the path
return wrapper || getMavenExecutable();
}
function getMavenWrapper(directory) {
if (!directory) {
return undefined;
}
const mavenWrapperFilename = path.join(directory, getMavenWrapperExecutable());
if ((0, file_utils_1.fileExists)(mavenWrapperFilename)) {
return mavenWrapperFilename;
}
return undefined;
}
function getMavenWrapperExecutable() {
if (isWindows()) {
return 'mvnw.cmd';
}
return 'mvnw';
}
function getMavenExecutable() {
if (isWindows()) {
return 'mvn.cmd';
}
return 'mvn';
}
function isWindows() {
return process.platform === 'win32';
}
//# sourceMappingURL=maven-runner.js.map
/***/ }),
/***/ 2963:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
@@ -293,17 +438,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.generateDependencyGraph = exports.generateSnapshot = void 0;
const exec = __importStar(__nccwpck_require__(1514));
const core = __importStar(__nccwpck_require__(2186));
const path = __importStar(__nccwpck_require__(1017));
const fs = __importStar(__nccwpck_require__(7147));
const dependency_submission_toolkit_1 = __nccwpck_require__(9810);
const depgraph_1 = __nccwpck_require__(8047);
const maven_runner_1 = __nccwpck_require__(7433);
const file_utils_1 = __nccwpck_require__(799);
const version = (__nccwpck_require__(2876)/* .version */ .i8);
const DEPGRAPH_MAVEN_PLUGIN_VERSION = '4.0.2';
function generateSnapshot(directory, context, job) {
function generateSnapshot(directory, mvnConfig, context, job) {
return __awaiter(this, void 0, void 0, function* () {
const depgraph = yield generateDependencyGraph(directory);
const depgraph = yield generateDependencyGraph(directory, mvnConfig);
try {
const mavenDependencies = new depgraph_1.MavenDependencyGraph(depgraph);
// The filepath to the POM needs to be relative to the root of the GitHub repository for the links to work once uploaded
@@ -327,42 +472,36 @@ function getDetector() {
version: version
};
}
function generateDependencyGraph(directory) {
function generateDependencyGraph(directory, config) {
return __awaiter(this, void 0, void 0, function* () {
try {
let executionOutput = '';
let errors = '';
const options = {
cwd: directory,
listeners: {
stdout: (data) => {
executionOutput += data.toString();
},
stderr: (data) => {
errors += data.toString();
}
}
};
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);
core.startGroup('depgraph-maven-plugin:reactor');
const mavenReactorArguments = [
`com.github.ferstl:depgraph-maven-plugin:${DEPGRAPH_MAVEN_PLUGIN_VERSION}:reactor`,
'-DgraphFormat=json',
'-DoutputFileName=reactor.json'
];
yield exec.exec('mvn', mavenReactorArguments, options);
core.info(executionOutput);
core.info(errors);
const reactorResults = yield mvn.exec(directory, mavenReactorArguments);
core.info(reactorResults.stdout);
core.info(reactorResults.stderr);
core.endGroup();
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',
'-DoutputFileName=aggregate-depgraph.json'
];
yield exec.exec('mvn', mavenAggregateArguments, options);
core.info(executionOutput);
core.info(errors);
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);
@@ -371,22 +510,22 @@ function generateDependencyGraph(directory) {
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 file = path.join(targetPath, 'aggregate-depgraph.json');
const aggregateGraphFile = path.join(targetPath, 'aggregate-depgraph.json');
try {
return (0, depgraph_1.parseDependencyJson)(file, isMultiModule);
return (0, depgraph_1.parseDependencyJson)(aggregateGraphFile, isMultiModule);
}
catch (err) {
core.error(err);
throw new Error(`Could not parse maven dependency file, '${file}': ${err.message}`);
throw new Error(`Could not parse maven dependency file, '${aggregateGraphFile}': ${err.message}`);
}
});
}
exports.generateDependencyGraph = generateDependencyGraph;
function checkForMultiModule(reactorJsonFile) {
try {
const data = fs.readFileSync(reactorJsonFile);
const data = (0, file_utils_1.loadFileContents)(reactorJsonFile);
if (data) {
try {
const reactor = JSON.parse(data.toString('utf-8'));
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;
}
@@ -394,9 +533,8 @@ function checkForMultiModule(reactorJsonFile) {
throw new Error(`Failed to parse reactor JSON payload: ${err.message}`);
}
}
catch (err) {
throw new Error(`Failed to load file ${reactorJsonFile}: ${err}`);
}
// 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) {
@@ -414,6 +552,71 @@ function getRepositoryRelativePath(file) {
/***/ }),
/***/ 799:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.fileExists = exports.loadFileContents = void 0;
const fs = __importStar(__nccwpck_require__(7147));
function loadFileContents(file) {
if (!fileExists(file)) {
return undefined;
}
try {
const data = fs.readFileSync(file);
return data.toString('utf8');
}
catch (err) {
throw new Error(`Failed to load file contents ${file}: ${err}`);
}
}
exports.loadFileContents = loadFileContents;
function fileExists(file) {
if (!file) {
return false;
}
try {
const wrapperFileStats = fs.statSync(file);
// TODO might need to deal with a linked file, but ingoring that for now
return wrapperFileStats && wrapperFileStats.isFile();
}
catch (err) {
if (err.code == 'ENOENT') {
return false;
}
throw err;
}
}
exports.fileExists = fileExists;
//# sourceMappingURL=file-utils.js.map
/***/ }),
/***/ 7351:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+1 -1
View File
File diff suppressed because one or more lines are too long
+39 -27
View File
@@ -1,17 +1,16 @@
import * as fs from 'fs';
import { PackageURL } from 'packageurl-js'
import { PackageCache, Package, Manifest } from '@github/dependency-submission-toolkit';
import { DependencyScope } from '@github/dependency-submission-toolkit/dist/manifest';
import { loadFileContents } from './utils/file-utils';
type Depgraph = {
export type Depgraph = {
graphName: string,
artifacts: DepgraphArtifact[],
dependencies: DepgraphDependency[],
isMultiModule: boolean,
}
type DepgraphArtifact = {
export type DepgraphArtifact = {
id: string,
numericId: number,
groupId: string,
@@ -22,7 +21,7 @@ type DepgraphArtifact = {
types?: string[],
}
type DepgraphDependency = {
export type DepgraphDependency = {
from: string,
to: string,
numericFrom: number,
@@ -102,9 +101,11 @@ export class MavenDependencyGraph {
const graph = this.depGraph;
const cache = this.cache;
const dependencies = graph.dependencies || [];
const rootArtifactIds: string[] = [];
const dependencyIdMap = dependencyMap(graph.dependencies);
const dependencyArtifactIdsWithParents = extractDependencyArtifactIdsWithParents(graph.dependencies);
const dependencyIdMap = dependencyMap(dependencies);
const dependencyArtifactIdsWithParents = extractDependencyArtifactIdsWithParents(dependencies);
const idToPackageCachePackage: Map<string, Package> = new Map<string, Package>();
// Create the packages for all known artifacts
@@ -145,7 +146,7 @@ export class MavenDependencyGraph {
const uniqueRootArtifactDependencies: string[] = [];
rootArtifactIds.forEach(rootArtifactId => {
const dependencyIds = getDirectDependencies(rootArtifactId, graph.dependencies);
const dependencyIds = getDirectDependencies(rootArtifactId, dependencies);
if (dependencyIds) {
dependencyIds.forEach(dependencyId => {
if (uniqueRootArtifactDependencies.indexOf(dependencyId) === -1) {
@@ -160,17 +161,23 @@ export class MavenDependencyGraph {
}
export function parseDependencyJson(file: string, isMultiModule: boolean = false): Depgraph {
const data = loadFileContents(file);
if (!data) {
return {
graphName: 'empty',
artifacts: [],
dependencies: [],
isMultiModule: isMultiModule
};
}
try {
const data: Buffer = fs.readFileSync(file);
try {
const depGraph: Depgraph = JSON.parse(data.toString('utf-8'));
depGraph.isMultiModule = isMultiModule;
return depGraph;
} catch (err: any) {
throw new Error(`Failed to parse JSON payload: ${err.message}`);
}
const depGraph: Depgraph = JSON.parse(data);
depGraph.isMultiModule = isMultiModule;
return depGraph;
} catch (err: any) {
throw new Error(`Failed to load file ${file}: ${err}`);
throw new Error(`Failed to parse JSON dependency data: ${err.message}`);
}
}
@@ -199,23 +206,28 @@ function getDependencyScopeForMavenScope(mavenScopes: string[] | undefined | nul
}
function extractDependencyArtifactIdsWithParents(dependencies: DepgraphDependency[]): string[] {
return dependencies.map(dependency => { return dependency.to; })
if (dependencies) {
return dependencies.map(dependency => { return dependency.to; })
}
return [];
}
function dependencyMap(dependencies: DepgraphDependency[]): Map<string, string[] | undefined> {
const map = new Map<string, string[]>();
dependencies.forEach(dependency => {
const fromUrl = dependency.from;
if (dependencies) {
dependencies.forEach(dependency => {
const fromUrl = dependency.from;
let deps = map[fromUrl];
if (!deps) {
deps = [];
map[fromUrl] = deps;
}
let deps = map[fromUrl];
if (!deps) {
deps = [];
map[fromUrl] = deps;
}
deps.push(dependency.to);
});
deps.push(dependency.to);
});
}
return map;
}
+3 -1
View File
@@ -38,7 +38,9 @@ async function execute() {
id: `${opts.runId || Date.now()}`
};
snapshot = await generateSnapshot(opts.directory, context, job);
const mvnConfig = {};
snapshot = await generateSnapshot(opts.directory, mvnConfig, context, job);
} catch (err: any) {
console.error(`Failed to generate a dependency snapshot, check logs for more details, ${err}`);
+6 -2
View File
@@ -2,14 +2,18 @@ import * as core from '@actions/core';
import {Snapshot, submitSnapshot} from '@github/dependency-submission-toolkit';
import { generateSnapshot } from './snapshot-generator';
async function run() {
let snapshot: Snapshot | undefined;
try {
const directory = core.getInput('directory', { required: true });
snapshot = await generateSnapshot(directory);
const mavenConfig = {
ignoreMavenWrapper: core.getBooleanInput('ignore-maven-wrapper'),
settingsFile: core.getInput('settings-file'),
mavenArgs: core.getInput('maven-args') || '',
}
snapshot = await generateSnapshot(directory, mavenConfig);
} catch (err: any) {
core.error(err);
core.setFailed(`Failed to generate a dependency snapshot, check logs for more details, ${err}`);
+117
View File
@@ -0,0 +1,117 @@
import * as path from 'path';
import { getMavenProjectDirectory, getMavenSettingsFile } from './utils/test-util';
import { MavenRunner } from './maven-runner';
describe('maven-runner', () => {
jest.setTimeout(20000);
describe('create', () => {
it('should create a runner without a wrapper', async () => {
const projectDir = getMavenProjectDirectory('simple');
const runner = new MavenRunner(projectDir);
expect(runner.configuration.executable).toBeDefined();
expect(runner.configuration.executable).toBe('mvn');
expect(runner.configuration.settingsFile).toBeUndefined();
});
it('should create a runner with wrapper', async () => {
const projectDir = getMavenProjectDirectory('maven-wrapper');
const runner = new MavenRunner(projectDir);
expect(runner.configuration.executable).toBeDefined();
expect(runner.configuration.executable).toBe(path.join(projectDir, 'mvnw'));
expect(runner.configuration.settingsFile).toBeUndefined();
});
describe('with settings', () => {
it('should create a runner without a wrapper', async () => {
const projectDir = getMavenProjectDirectory('simple');
const settings = getMavenSettingsFile();
const runner = new MavenRunner(projectDir, settings);
expect(runner.configuration.executable).toBeDefined();
expect(runner.configuration.executable).toBe('mvn');
expect(runner.configuration.settingsFile).toBe(settings);
});
})
});
describe('#exec()', () => {
it('should run path provided maven', async () => {
const projectDir = getMavenProjectDirectory('simple');
const runner = new MavenRunner(projectDir);
const results = await runner.exec(projectDir, ['--version']);
expect(results.exitCode).toBe(0);
expect(results.stdout).toContain('Apache Maven');
});
it('should run wrapper provided maven', async () => {
const projectDir = getMavenProjectDirectory('maven-wrapper');
const runner = new MavenRunner(projectDir);
const results = await runner.exec(projectDir, ['--version']);
expect(results.exitCode).toBe(0);
expect(results.stdout).toContain('Apache Maven');
expect(results.stdout).toContain('3.8.6');
});
it('should run wrapper provided maven with validate phase', async () => {
const projectDir = getMavenProjectDirectory('maven-wrapper');
const runner = new MavenRunner(projectDir);
const results = await runner.exec(projectDir, ['validate']);
expect(results.exitCode).toBe(0);
});
describe('with additional arguments', () => {
it('should run path provided maven with additional arguments', async () => {
const projectDir = getMavenProjectDirectory('simple');
const additionalMavenArgs = ' -DskipTests -q';
const runner = new MavenRunner(projectDir, undefined, false, additionalMavenArgs);
const results = await runner.exec(projectDir, ['validate']);
expect(results.exitCode).toBe(0);
// by running with quiet mode there should be no output
expect(results.stdout.length).toBe(0);
});
});
describe('with settings', () => {
it('should run path provided maven with settings file', async () => {
const projectDir = getMavenProjectDirectory('simple');
const settingsFile = getMavenSettingsFile();
const runner = new MavenRunner(projectDir, settingsFile);
const results = await runner.exec(projectDir, ['-X', 'validate']);
expect(results.exitCode).toBe(0);
// When running in debug mode the settings files that are loaded are displayed in the stdout
expect(results.stdout).toContain(`Reading user settings from ${path.resolve(settingsFile)}`);
});
it('should run wrapper provided maven with settings file', async () => {
const projectDir = getMavenProjectDirectory('maven-wrapper');
const settingsFile = getMavenSettingsFile();
const runner = new MavenRunner(projectDir, settingsFile);
const results = await runner.exec(projectDir, ['-X', 'validate']);
expect(results.exitCode).toBe(0);
// When running in debug mode the settings files that are loaded are displayed in the stdout
expect(results.stdout).toContain(`Reading user settings from ${path.resolve(settingsFile)}`);
});
});
});
});
+148
View File
@@ -0,0 +1,148 @@
import * as exec from '@actions/exec';
import * as core from '@actions/core';
import * as path from 'path';
import * as fs from 'fs';
import { fileExists } from './utils/file-utils';
export type ExecResults = {
stdout: string,
stderr: string,
exitCode: number
}
export type MavenRunnerConfiguration = {
executable: string
settingsFile?: string
mavenArgs?: string
}
export class MavenRunner {
private mavenExecutable: string
private settings: string | undefined;
private additionalArguments: string[];
constructor(directory?: string, settingsFile?: string, ingoreWrapper: boolean = false, mavenArguments: string = '') {
this.mavenExecutable = resolveMavenExecutable(directory, ingoreWrapper);
if (settingsFile) {
if (fileExists(settingsFile)) {
this.settings = settingsFile;
} else {
throw new Error(`The specified settings file '${settingsFile}' does not exist`);
}
}
this.additionalArguments = [];
if (mavenArguments.trim().length > 0) {
this.additionalArguments = mavenArguments.trim().split(' ');
}
}
get configuration() {
return {
executable: this.mavenExecutable,
settingsFile: this.settings
};
}
async exec(cwd: string, parameters: string[]): Promise<ExecResults> {
const commandArgs: string[] = [];
// implictly run in batch mode, might need to make this configurable in the future
commandArgs.push('-B');
if (this.settings) {
commandArgs.push('--settings')
commandArgs.push(this.settings);
}
// Only append the additional arguments they are not empty values
if (this.additionalArguments && this.additionalArguments.length > 0) {
this.additionalArguments.forEach(arg => {
if (arg.trim().length > 0) {
commandArgs.push(arg);
}
});
}
Array.prototype.push.apply(commandArgs, parameters);
let executionOutput = '';
let executionErrors = '';
const options = {
cwd: cwd,
listeners: {
stdout: (data: Buffer) => {
executionOutput += data.toString();
},
stderr: (data: Buffer) => {
executionErrors += data.toString();
}
}
};
try {
const exitCode = await exec.exec(this.mavenExecutable, commandArgs, options);
return {
stdout: executionOutput,
stderr: executionErrors,
exitCode: exitCode
}
} catch (err: any) {
//TODO possibly throw a wrapped error here
core.warning(`Error encountered executing maven: ${err.message}`);
return {
stdout: executionOutput,
stderr: executionErrors,
exitCode: -1
}
}
}
}
function resolveMavenExecutable(directory?: string, ignoreWrapper: boolean = false): string {
if (ignoreWrapper) {
return getMavenExecutable();
}
const wrapper = getMavenWrapper(directory);
// Return the matche maven wrapper script or otherwise fall back to mvn on the path
return wrapper || getMavenExecutable();
}
function getMavenWrapper(directory?: string): string | undefined {
if (!directory) {
return undefined;
}
const mavenWrapperFilename = path.join(directory, getMavenWrapperExecutable());
if (fileExists(mavenWrapperFilename)) {
return mavenWrapperFilename;
}
return undefined;
}
function getMavenWrapperExecutable(): string {
if (isWindows()) {
return 'mvnw.cmd';
}
return 'mvnw';
}
function getMavenExecutable(): string {
if (isWindows()) {
return 'mvn.cmd';
}
return 'mvn';
}
function isWindows() {
return process.platform === 'win32';
}
+11 -6
View File
@@ -1,4 +1,4 @@
import * as path from 'path';
import { getMavenProjectDirectory } from './utils/test-util';
import { generateDependencyGraph, generateSnapshot } from './snapshot-generator';
describe('snapshot-generator', () => {
@@ -42,9 +42,14 @@ describe('snapshot-generator', () => {
expect(snapshot.detector.version).toBe(version);
expect(snapshot.manifests['bs-parent'].countDependencies()).toBe(20);
});
});
});
function getMavenProjectDirectory(name: string): string {
return path.join(__dirname, '..', 'test-data', 'maven', name);
}
it('should generate a snapshot for a maven-wrapper project', async () => {
const projectDir = getMavenProjectDirectory('maven-wrapper');
const snapshot = await generateSnapshot(projectDir);
expect(snapshot.manifests['maven-wrapper-test']).toBeDefined();
expect(snapshot.detector.version).toBe(version);
expect(snapshot.manifests['maven-wrapper-test'].countDependencies()).toBe(0);
});
});
});
+38 -36
View File
@@ -1,18 +1,23 @@
import * as exec from '@actions/exec';
import * as core from '@actions/core';
import * as path from 'path';
import * as fs from 'fs';
import { Snapshot } from '@github/dependency-submission-toolkit';
import { MavenDependencyGraph, parseDependencyJson } from './depgraph';
import { Depgraph, MavenDependencyGraph, parseDependencyJson } from './depgraph';
import { MavenRunner } from './maven-runner';
import { loadFileContents } from './utils/file-utils';
const version = require('../package.json')['version'];
const DEPGRAPH_MAVEN_PLUGIN_VERSION = '4.0.2';
export async function generateSnapshot(directory: string, context?: any, job?: any) {
const depgraph = await generateDependencyGraph(directory);
export type MavenConfiguration = {
ignoreMavenWrapper?: boolean;
settingsFile?: string;
mavenArgs?: string;
}
export async function generateSnapshot(directory: string, mvnConfig?: MavenConfiguration, context?: any, job?: any) {
const depgraph = await generateDependencyGraph(directory, mvnConfig);
try {
const mavenDependencies = new MavenDependencyGraph(depgraph);
@@ -37,22 +42,9 @@ function getDetector() {
};
}
export async function generateDependencyGraph(directory: string) {
export async function generateDependencyGraph(directory: string, config?: MavenConfiguration): Promise<Depgraph> {
try {
let executionOutput = '';
let errors = '';
const options = {
cwd: directory,
listeners: {
stdout: (data: Buffer) => {
executionOutput += data.toString();
},
stderr: (data: Buffer) => {
errors += data.toString();
}
}
};
const mvn = new MavenRunner(directory, config?.settingsFile, config?.ignoreMavenWrapper);
core.startGroup('depgraph-maven-plugin:reactor');
const mavenReactorArguments = [
@@ -60,23 +52,31 @@ export async function generateDependencyGraph(directory: string) {
'-DgraphFormat=json',
'-DoutputFileName=reactor.json'
];
await exec.exec('mvn', mavenReactorArguments, options);
const reactorResults = await mvn.exec(directory, mavenReactorArguments);
core.info(executionOutput);
core.info(errors);
core.info(reactorResults.stdout);
core.info(reactorResults.stderr);
core.endGroup();
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',
'-DoutputFileName=aggregate-depgraph.json'
];
await exec.exec('mvn', mavenAggregateArguments, options);
const aggregateResults = await mvn.exec(directory, mavenAggregateArguments);
core.info(executionOutput);
core.info(errors);
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}`);
@@ -86,28 +86,30 @@ export async function generateDependencyGraph(directory: string) {
const isMultiModule = checkForMultiModule(path.join(targetPath, 'reactor.json'));
// Now we have the aggregate dependency graph file to process
const file = path.join(targetPath, 'aggregate-depgraph.json');
const aggregateGraphFile = path.join(targetPath, 'aggregate-depgraph.json');
try {
return parseDependencyJson(file, isMultiModule);
return parseDependencyJson(aggregateGraphFile, isMultiModule);
} catch (err: any) {
core.error(err);
throw new Error(`Could not parse maven dependency file, '${file}': ${err.message}`);
throw new Error(`Could not parse maven dependency file, '${aggregateGraphFile}': ${err.message}`);
}
}
function checkForMultiModule(reactorJsonFile) {
try {
const data: Buffer = fs.readFileSync(reactorJsonFile);
function checkForMultiModule(reactorJsonFile): boolean {
const data = loadFileContents(reactorJsonFile);
if (data) {
try {
const reactor = JSON.parse(data.toString('utf-8'));
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) {
throw new Error(`Failed to parse reactor JSON payload: ${err.message}`);
}
} catch (err: any) {
throw new Error(`Failed to load file ${reactorJsonFile}: ${err}`);
}
// 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...
+31
View File
@@ -0,0 +1,31 @@
import * as fs from 'fs';
export function loadFileContents(file: string): string | undefined {
if (!fileExists(file)) {
return undefined;
}
try {
const data: Buffer = fs.readFileSync(file);
return data.toString('utf8');
} catch (err: any) {
throw new Error(`Failed to load file contents ${file}: ${err}`);
}
}
export function fileExists(file?: string): boolean {
if (!file) {
return false;
}
try {
const wrapperFileStats = fs.statSync(file);
// TODO might need to deal with a linked file, but ingoring that for now
return wrapperFileStats && wrapperFileStats.isFile();
} catch (err: any) {
if (err.code == 'ENOENT') {
return false;
}
throw err;
}
}
+13
View File
@@ -0,0 +1,13 @@
import * as path from 'path';
function getTestDataDirectory() {
return path.join(__dirname, '..', '..', 'test-data');
}
export function getMavenProjectDirectory(name: string): string {
return path.join(getTestDataDirectory(), 'maven', name);
}
export function getMavenSettingsFile(): string {
return path.join(getTestDataDirectory(), 'maven', 'settings.xml');
}
Binary file not shown.
@@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
+287
View File
@@ -0,0 +1,287 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.1.1
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
JAVA_HOME="`/usr/libexec/java_home`"; export JAVA_HOME
else
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`\\unset -f command; \\command -v java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
printf '%s' "$(cd "$basedir"; pwd)"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=$(find_maven_basedir "$(dirname $0)")
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
else
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) wrapperUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $wrapperUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
QUIET="--quiet"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
QUIET=""
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath"
else
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath"
fi
[ $? -eq 0 ] || rm -f "$wrapperJarPath"
elif command -v curl > /dev/null; then
QUIET="--silent"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
QUIET=""
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L
else
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L
fi
[ $? -eq 0 ] || rm -f "$wrapperJarPath"
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaSource="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaSource=`cygpath --path --windows "$javaSource"`
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaSource" ]; then
if [ ! -e "$javaClass" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaSource")
fi
if [ -e "$javaClass" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
+187
View File
@@ -0,0 +1,187 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Apache Maven Wrapper startup batch script, version 3.1.1
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %WRAPPER_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%
+10
View File
@@ -0,0 +1,10 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.octodemo</groupId>
<artifactId>maven-wrapper-test</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- puposely has no dependencies -->
</project>
+12
View File
@@ -0,0 +1,12 @@
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<offline/>
<pluginGroups/>
<servers/>
<mirrors/>
<proxies/>
<profiles/>
<activeProfiles/>
</settings>