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 uses: ./dependency-submission
with: with:
build-root-directory: .github/workflow-samples/groovy-dsl build-root-directory: .github/workflow-samples/groovy-dsl
additional-arguments: --no-build-cache dependency-resolution-task: assemble
- name: Check generated dependency graphs - name: Check generated dependency graphs
shell: bash shell: bash
run: | 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 description: Generates a dependency graph for a Gradle project and submits it via the Dependency Submission API
inputs: inputs:
# Gradle execution configuration
gradle-version: gradle-version:
description: | description: |
Gradle version to use. If specified, this Gradle version will be downloaded, added to the PATH and used for invoking Gradle. 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. description: Path to the root directory of the build. Default is the root of the GitHub workspace.
required: false 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: additional-arguments:
description: | description: |
Additional arguments to pass to Gradle when generating the dependency graph. Additional arguments to pass to Gradle when generating the dependency graph.

View File

@ -43,6 +43,21 @@ jobs:
- name: Generate and submit dependency graph - name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@v3 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 ### 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`. 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. 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 ```yaml
- name: Generate and save dependency graph - name: Generate and save dependency graph
uses: gradle/actions/dependency-submission@v3 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. # The gradle project is not in the root of the repository.
build-root-directory: my-gradle-project 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. # Enable configuration-cache reuse for this build.
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} 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 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 # Resolving a dependency vulnerability
## Finding the source of 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 * as dependencyGraph from '../dependency-graph'
import {parseArgsStringToArgv} from 'string-argv' 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. * 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 // 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 = ` const executionArgs = `
-Dorg.gradle.configureondemand=false -Dorg.gradle.configureondemand=false
-Dorg.gradle.dependency.verification=off -Dorg.gradle.dependency.verification=off
-Dorg.gradle.unsafe.isolated-projects=false -Dorg.gradle.unsafe.isolated-projects=false
:ForceDependencyResolutionPlugin_resolveAllDependencies ${taskList}
${additionalArgs} ${additionalArgs}
` `
const args: string[] = parseArgsStringToArgv(executionArgs) const args: string[] = parseArgsStringToArgv(executionArgs)
await gradle.provisionAndMaybeExecute(args) await gradle.provisionAndMaybeExecute(
executionConfig.getGradleVersion(),
executionConfig.getBuildRootDirectory(),
args
)
await dependencyGraph.complete(config) await dependencyGraph.complete(config)
} catch (error) { } catch (error) {

View File

@ -1,19 +1,20 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as exec from '@actions/exec' import * as exec from '@actions/exec'
import * as path from 'path'
import * as params from '../input-params'
import * as provisioner from './provision' import * as provisioner from './provision'
import * as gradlew from './gradlew' 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 // Download and install Gradle if required
const executable = await provisioner.provisionGradle() const executable = await provisioner.provisionGradle(gradleVersion)
// Only execute if arguments have been provided // Only execute if arguments have been provided
if (args.length > 0) { 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`) 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 toolCache from '@actions/tool-cache'
import * as gradlew from './gradlew' import * as gradlew from './gradlew'
import * as params from '../input-params'
import {handleCacheFailure} from '../caching/cache-utils' import {handleCacheFailure} from '../caching/cache-utils'
import {CacheConfig} from '../input-params' 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. * Install any configured version of Gradle, adding the executable to the PATH.
* @return Installed Gradle executable or undefined if no version configured. * @return Installed Gradle executable or undefined if no version configured.
*/ */
export async function provisionGradle(): Promise<string | undefined> { export async function provisionGradle(gradleVersion: string): Promise<string | undefined> {
const gradleVersion = params.getGradleVersion()
if (gradleVersion !== '' && gradleVersion !== 'wrapper') { if (gradleVersion !== '' && gradleVersion !== 'wrapper') {
return addToPath(await installGradle(gradleVersion)) 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 {SUMMARY_ENV_VAR} from '@actions/core/lib/summary'
import {parseArgsStringToArgv} from 'string-argv' import {parseArgsStringToArgv} from 'string-argv'
import path from 'path'
export class DependencyGraphConfig { export class DependencyGraphConfig {
getDependencyGraphOption(): DependencyGraphOption { getDependencyGraphOption(): DependencyGraphOption {
@ -218,19 +219,35 @@ export class BuildScanConfig {
} }
} }
export function getGradleVersion(): string { export class GradleExecutionConfig {
getGradleVersion(): string {
return core.getInput('gradle-version') return core.getInput('gradle-version')
} }
export function getBuildRootDirectory(): string { getBuildRootDirectory(): string {
return core.getInput('build-root-directory') 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[] { getArguments(): string[] {
const input = core.getInput('arguments') const input = core.getInput('arguments')
return parseArgsStringToArgv(input) return parseArgsStringToArgv(input)
} }
getDependencyResolutionTask(): string {
return core.getInput('dependency-resolution-task') || ':ForceDependencyResolutionPlugin_resolveAllDependencies'
}
getAdditionalArguments(): string {
return core.getInput('additional-arguments')
}
}
// Internal parameters // Internal parameters
export function getJobMatrix(): string { export function getJobMatrix(): string {
return core.getInput('workflow-job-context') return core.getInput('workflow-job-context')

View File

@ -3,7 +3,7 @@ import * as core from '@actions/core'
import * as setupGradle from '../setup-gradle' import * as setupGradle from '../setup-gradle'
import * as gradle from '../execution/gradle' import * as gradle from '../execution/gradle'
import * as dependencyGraph from '../dependency-graph' 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. * 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 // Configure the dependency graph submission
await dependencyGraph.setup(new DependencyGraphConfig()) await dependencyGraph.setup(new DependencyGraphConfig())
const args: string[] = getArguments() const config = new GradleExecutionConfig()
await gradle.provisionAndMaybeExecute(args) await gradle.provisionAndMaybeExecute(
config.getGradleVersion(),
config.getBuildRootDirectory(),
config.getArguments()
)
} catch (error) { } catch (error) {
core.setFailed(String(error)) core.setFailed(String(error))
if (error instanceof Error && error.stack) { if (error instanceof Error && error.stack) {