Allow a task name to be specified for dependency-submission

Fixes: #125
This commit is contained in:
daz 2024-04-09 08:46:20 -06:00
parent e235596c88
commit 92975d7f32
No known key found for this signature in database
8 changed files with 88 additions and 38 deletions

View file

@ -112,7 +112,7 @@ jobs:
uses: ./dependency-submission
with:
build-root-directory: .github/workflow-samples/groovy-dsl
additional-arguments: --no-build-cache
dependency-resolution-task: assemble
- name: Check generated dependency graphs
shell: bash
run: |

View file

@ -2,6 +2,7 @@ name: Gradle Dependency Submission
description: Generates a dependency graph for a Gradle project and submits it via the Dependency Submission API
inputs:
# Gradle execution configuration
gradle-version:
description: |
Gradle version to use. If specified, this Gradle version will be downloaded, added to the PATH and used for invoking Gradle.
@ -12,6 +13,12 @@ inputs:
description: Path to the root directory of the build. Default is the root of the GitHub workspace.
required: false
dependency-resolution-task:
description: |
Task(s) that should be executed in order to resolve all project dependencies.
By default, the built-in `:ForceDependencyResolutionPlugin_resolveAllDependencies` task is executed.
required: false
additional-arguments:
description: |
Additional arguments to pass to Gradle when generating the dependency graph.

View file

@ -43,6 +43,21 @@ jobs:
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@v3
```
### Gradle execution
To generate a dependency graph, the `dependency-submission` action must perform a Gradle execution that resolves
the dependencies of the project. All dependencies that are resolved in this execution will be included in the
generated dependency graph. By default action executes a built-in task that is designed to resolve all build dependencies
(`:ForceDependencyResolutionPlugin_resolveAllDependencies`).
The action looks for a Gradle project in the root of the workspace, and executes this project with
the Gradle wrapper, if configured for the project. If the wrapper is not configured, whatever `gradle` available
on the command-line will be used.
The action provides the ability to override the Gradle version and task to execute, as well as provide
additional arguments that will be passed to Gradle on the command-line. See [Configuration Parameters](#configuration-parameters) below.
### Publishing a Develocity Build Scan® from your dependency submission workflow
You can automatically publish a free Develocity Build Scan on every run of `gradle/actions/dependency-submission`.
@ -64,8 +79,6 @@ A Build Scan makes it easy to determine the source of any dependency vulnerabili
In some cases, the default action configuration will not be sufficient, and additional action parameters will need to be specified.
See the example below for a summary, and the [Action Metadata file](action.yml) for a more detailed description of each input parameter.
```yaml
- name: Generate and save dependency graph
uses: gradle/actions/dependency-submission@v3
@ -76,6 +89,12 @@ See the example below for a summary, and the [Action Metadata file](action.yml)
# The gradle project is not in the root of the repository.
build-root-directory: my-gradle-project
# Choose a task that will trigger dependency resolution
dependency-resolution-task: myDependencyResolutionTask
# Additional arguments that should be passed to execute Gradle
additonal-arguments: --no-configuration-cache
# Enable configuration-cache reuse for this build.
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
@ -83,6 +102,8 @@ See the example below for a summary, and the [Action Metadata file](action.yml)
dependency-graph: generate-and-upload
```
See the [Action Metadata file](../dependency-submission/action.yml) for a more detailed description of each input parameter.
# Resolving a dependency vulnerability
## Finding the source of a dependency vulnerability

View file

@ -5,7 +5,13 @@ import * as gradle from '../execution/gradle'
import * as dependencyGraph from '../dependency-graph'
import {parseArgsStringToArgv} from 'string-argv'
import {BuildScanConfig, CacheConfig, DependencyGraphConfig, DependencyGraphOption} from '../input-params'
import {
BuildScanConfig,
CacheConfig,
DependencyGraphConfig,
DependencyGraphOption,
GradleExecutionConfig
} from '../input-params'
/**
* The main entry point for the action, called by Github Actions for the step.
@ -25,16 +31,22 @@ export async function run(): Promise<void> {
}
// Only execute if arguments have been provided
const additionalArgs = core.getInput('additional-arguments')
const executionConfig = new GradleExecutionConfig()
const taskList = executionConfig.getDependencyResolutionTask()
const additionalArgs = executionConfig.getAdditionalArguments()
const executionArgs = `
-Dorg.gradle.configureondemand=false
-Dorg.gradle.dependency.verification=off
-Dorg.gradle.unsafe.isolated-projects=false
:ForceDependencyResolutionPlugin_resolveAllDependencies
${taskList}
${additionalArgs}
`
const args: string[] = parseArgsStringToArgv(executionArgs)
await gradle.provisionAndMaybeExecute(args)
await gradle.provisionAndMaybeExecute(
executionConfig.getGradleVersion(),
executionConfig.getBuildRootDirectory(),
args
)
await dependencyGraph.complete(config)
} catch (error) {

View file

@ -1,19 +1,20 @@
import * as core from '@actions/core'
import * as exec from '@actions/exec'
import * as path from 'path'
import * as params from '../input-params'
import * as provisioner from './provision'
import * as gradlew from './gradlew'
import {getWorkspaceDirectory} from '../input-params'
export async function provisionAndMaybeExecute(args: string[]): Promise<void> {
export async function provisionAndMaybeExecute(
gradleVersion: string,
buildRootDirectory: string,
args: string[]
): Promise<void> {
// Download and install Gradle if required
const executable = await provisioner.provisionGradle()
const executable = await provisioner.provisionGradle(gradleVersion)
// Only execute if arguments have been provided
if (args.length > 0) {
await executeGradleBuild(executable, buildRootDirectory(), args)
await executeGradleBuild(executable, buildRootDirectory, args)
}
}
@ -30,13 +31,3 @@ async function executeGradleBuild(executable: string | undefined, root: string,
core.setFailed(`Gradle build failed: see console output for details`)
}
}
function buildRootDirectory(): string {
const baseDirectory = getWorkspaceDirectory()
const buildRootDirectoryInput = params.getBuildRootDirectory()
const resolvedBuildRootDirectory =
buildRootDirectoryInput === ''
? path.resolve(baseDirectory)
: path.resolve(baseDirectory, buildRootDirectoryInput)
return resolvedBuildRootDirectory
}

View file

@ -7,7 +7,6 @@ import * as cache from '@actions/cache'
import * as toolCache from '@actions/tool-cache'
import * as gradlew from './gradlew'
import * as params from '../input-params'
import {handleCacheFailure} from '../caching/cache-utils'
import {CacheConfig} from '../input-params'
@ -17,8 +16,7 @@ const gradleVersionsBaseUrl = 'https://services.gradle.org/versions'
* Install any configured version of Gradle, adding the executable to the PATH.
* @return Installed Gradle executable or undefined if no version configured.
*/
export async function provisionGradle(): Promise<string | undefined> {
const gradleVersion = params.getGradleVersion()
export async function provisionGradle(gradleVersion: string): Promise<string | undefined> {
if (gradleVersion !== '' && gradleVersion !== 'wrapper') {
return addToPath(await installGradle(gradleVersion))
}

View file

@ -4,6 +4,7 @@ import * as cache from '@actions/cache'
import {SUMMARY_ENV_VAR} from '@actions/core/lib/summary'
import {parseArgsStringToArgv} from 'string-argv'
import path from 'path'
export class DependencyGraphConfig {
getDependencyGraphOption(): DependencyGraphOption {
@ -218,17 +219,33 @@ export class BuildScanConfig {
}
}
export function getGradleVersion(): string {
return core.getInput('gradle-version')
}
export class GradleExecutionConfig {
getGradleVersion(): string {
return core.getInput('gradle-version')
}
export function getBuildRootDirectory(): string {
return core.getInput('build-root-directory')
}
getBuildRootDirectory(): string {
const baseDirectory = getWorkspaceDirectory()
const buildRootDirectoryInput = core.getInput('build-root-directory')
const resolvedBuildRootDirectory =
buildRootDirectoryInput === ''
? path.resolve(baseDirectory)
: path.resolve(baseDirectory, buildRootDirectoryInput)
return resolvedBuildRootDirectory
}
export function getArguments(): string[] {
const input = core.getInput('arguments')
return parseArgsStringToArgv(input)
getArguments(): string[] {
const input = core.getInput('arguments')
return parseArgsStringToArgv(input)
}
getDependencyResolutionTask(): string {
return core.getInput('dependency-resolution-task') || ':ForceDependencyResolutionPlugin_resolveAllDependencies'
}
getAdditionalArguments(): string {
return core.getInput('additional-arguments')
}
}
// Internal parameters

View file

@ -3,7 +3,7 @@ import * as core from '@actions/core'
import * as setupGradle from '../setup-gradle'
import * as gradle from '../execution/gradle'
import * as dependencyGraph from '../dependency-graph'
import {BuildScanConfig, CacheConfig, DependencyGraphConfig, getArguments} from '../input-params'
import {BuildScanConfig, CacheConfig, DependencyGraphConfig, GradleExecutionConfig} from '../input-params'
/**
* The main entry point for the action, called by Github Actions for the step.
@ -16,8 +16,12 @@ export async function run(): Promise<void> {
// Configure the dependency graph submission
await dependencyGraph.setup(new DependencyGraphConfig())
const args: string[] = getArguments()
await gradle.provisionAndMaybeExecute(args)
const config = new GradleExecutionConfig()
await gradle.provisionAndMaybeExecute(
config.getGradleVersion(),
config.getBuildRootDirectory(),
config.getArguments()
)
} catch (error) {
core.setFailed(String(error))
if (error instanceof Error && error.stack) {