mirror of
https://github.com/gradle/gradle-build-action
synced 2024-11-27 12:02:15 +00:00
Adapt dependency-graph support for new artifact API
- Don't upload artifacts when using 'generate-and-submit' - New option 'generate-and-upload' to be used with 'download-and-submit' - Use Artifact API for downloading in the same and different workflow
This commit is contained in:
parent
51b7a82e8e
commit
a4dabb3a70
5 changed files with 75 additions and 82 deletions
|
@ -31,7 +31,7 @@ jobs:
|
||||||
- name: Setup Gradle for dependency-graph generate
|
- name: Setup Gradle for dependency-graph generate
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
dependency-graph: generate
|
dependency-graph: generate-and-upload
|
||||||
- name: Run gradle build
|
- name: Run gradle build
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
working-directory: .github/workflow-samples/groovy-dsl
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
|
@ -55,7 +55,7 @@ jobs:
|
||||||
working-directory: .github/workflow-samples/kotlin-dsl
|
working-directory: .github/workflow-samples/kotlin-dsl
|
||||||
|
|
||||||
submit:
|
submit:
|
||||||
needs: [groovy-generate, kotlin-generate]
|
needs: [groovy-generate]
|
||||||
runs-on: "ubuntu-latest"
|
runs-on: "ubuntu-latest"
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
|
@ -80,7 +80,7 @@ jobs:
|
||||||
- name: Setup Gradle for dependency-graph generate
|
- name: Setup Gradle for dependency-graph generate
|
||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
dependency-graph: generate
|
dependency-graph: generate-and-submit
|
||||||
- id: gradle-assemble
|
- id: gradle-assemble
|
||||||
run: ./gradlew assemble
|
run: ./gradlew assemble
|
||||||
working-directory: .github/workflow-samples/groovy-dsl
|
working-directory: .github/workflow-samples/groovy-dsl
|
||||||
|
|
|
@ -64,7 +64,7 @@ inputs:
|
||||||
default: true
|
default: true
|
||||||
|
|
||||||
dependency-graph:
|
dependency-graph:
|
||||||
description: Specifies if a GitHub dependency snapshot should be generated for each Gradle build, and if so, how. Valid values are 'disabled' (default), 'generate', 'generate-and-submit' and 'download-and-submit'.
|
description: Specifies if a GitHub dependency snapshot should be generated for each Gradle build, and if so, how. Valid values are 'disabled' (default), 'generate', 'generate-and-submit', 'generate-and-upload' and 'download-and-submit'.
|
||||||
required: false
|
required: false
|
||||||
default: 'disabled'
|
default: 'disabled'
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as artifact from '@actions/artifact'
|
|
||||||
import * as github from '@actions/github'
|
import * as github from '@actions/github'
|
||||||
import * as glob from '@actions/glob'
|
import * as glob from '@actions/glob'
|
||||||
import * as toolCache from '@actions/tool-cache'
|
import {DefaultArtifactClient} from '@actions/artifact'
|
||||||
import {GitHub} from '@actions/github/lib/utils'
|
import {GitHub} from '@actions/github/lib/utils'
|
||||||
import {RequestError} from '@octokit/request-error'
|
import {RequestError} from '@octokit/request-error'
|
||||||
import type {PullRequestEvent} from '@octokit/webhooks-types'
|
import type {PullRequestEvent} from '@octokit/webhooks-types'
|
||||||
|
@ -13,7 +12,7 @@ import fs from 'fs'
|
||||||
import * as layout from './repository-layout'
|
import * as layout from './repository-layout'
|
||||||
import {DependencyGraphOption, getJobMatrix, getArtifactRetentionDays} from './input-params'
|
import {DependencyGraphOption, getJobMatrix, getArtifactRetentionDays} from './input-params'
|
||||||
|
|
||||||
const DEPENDENCY_GRAPH_ARTIFACT = 'dependency-graph'
|
const DEPENDENCY_GRAPH_PREFIX = 'dependency-graph_'
|
||||||
|
|
||||||
export async function setup(option: DependencyGraphOption): Promise<void> {
|
export async function setup(option: DependencyGraphOption): Promise<void> {
|
||||||
if (option === DependencyGraphOption.Disabled) {
|
if (option === DependencyGraphOption.Disabled) {
|
||||||
|
@ -39,37 +38,48 @@ export async function setup(option: DependencyGraphOption): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function complete(option: DependencyGraphOption): Promise<void> {
|
export async function complete(option: DependencyGraphOption): Promise<void> {
|
||||||
|
try {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case DependencyGraphOption.Disabled:
|
case DependencyGraphOption.Disabled:
|
||||||
|
case DependencyGraphOption.Generate: // Performed via init-script: nothing to do here
|
||||||
case DependencyGraphOption.DownloadAndSubmit: // Performed in setup
|
case DependencyGraphOption.DownloadAndSubmit: // Performed in setup
|
||||||
return
|
return
|
||||||
case DependencyGraphOption.Generate:
|
|
||||||
await uploadDependencyGraphs()
|
|
||||||
return
|
|
||||||
case DependencyGraphOption.GenerateAndSubmit:
|
case DependencyGraphOption.GenerateAndSubmit:
|
||||||
await submitDependencyGraphs(await uploadDependencyGraphs())
|
await submitDependencyGraphs(await findGeneratedDependencyGraphFiles())
|
||||||
return
|
return
|
||||||
|
case DependencyGraphOption.GenerateAndUpload:
|
||||||
|
await uploadDependencyGraphs(await findGeneratedDependencyGraphFiles())
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
core.warning(`Failed to ${option} dependency graph. Will continue. ${String(e)}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadDependencyGraphs(): Promise<string[]> {
|
async function findGeneratedDependencyGraphFiles(): Promise<string[]> {
|
||||||
const workspaceDirectory = layout.workspaceDirectory()
|
const workspaceDirectory = layout.workspaceDirectory()
|
||||||
const graphFiles = await findDependencyGraphFiles(workspaceDirectory)
|
return await findDependencyGraphFiles(workspaceDirectory)
|
||||||
|
}
|
||||||
|
|
||||||
const relativeGraphFiles = graphFiles.map(x => getRelativePathFromWorkspace(x))
|
async function uploadDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> {
|
||||||
core.info(`Uploading dependency graph files: ${relativeGraphFiles}`)
|
const workspaceDirectory = layout.workspaceDirectory()
|
||||||
|
|
||||||
const artifactClient = artifact.create()
|
const artifactClient = new DefaultArtifactClient()
|
||||||
artifactClient.uploadArtifact(DEPENDENCY_GRAPH_ARTIFACT, graphFiles, workspaceDirectory, {
|
for (const dependencyGraphFile of dependencyGraphFiles) {
|
||||||
|
const relativePath = getRelativePathFromWorkspace(dependencyGraphFile)
|
||||||
|
core.info(`Uploading dependency graph file: ${relativePath}`)
|
||||||
|
const artifactName = `${DEPENDENCY_GRAPH_PREFIX}${path.basename(dependencyGraphFile)}`
|
||||||
|
await artifactClient.uploadArtifact(artifactName, [dependencyGraphFile], workspaceDirectory, {
|
||||||
retentionDays: getArtifactRetentionDays()
|
retentionDays: getArtifactRetentionDays()
|
||||||
})
|
})
|
||||||
|
}
|
||||||
return graphFiles
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadAndSubmitDependencyGraphs(): Promise<void> {
|
async function downloadAndSubmitDependencyGraphs(): Promise<void> {
|
||||||
const workspaceDirectory = layout.workspaceDirectory()
|
try {
|
||||||
submitDependencyGraphs(await retrieveDependencyGraphs(workspaceDirectory))
|
await submitDependencyGraphs(await downloadDependencyGraphs())
|
||||||
|
} catch (e) {
|
||||||
|
core.warning(`Download and submit dependency graph failed. Will continue. ${String(e)}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> {
|
async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> {
|
||||||
|
@ -111,56 +121,37 @@ async function submitDependencyGraphFile(jsonFile: string): Promise<void> {
|
||||||
core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`)
|
core.notice(`Submitted ${relativeJsonFile}: ${response.data.message}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function retrieveDependencyGraphs(workspaceDirectory: string): Promise<string[]> {
|
async function downloadDependencyGraphs(): Promise<string[]> {
|
||||||
if (github.context.payload.workflow_run) {
|
const workspaceDirectory = layout.workspaceDirectory()
|
||||||
return await retrieveDependencyGraphsForWorkflowRun(github.context.payload.workflow_run.id, workspaceDirectory)
|
|
||||||
|
const findBy = github.context.payload.workflow_run
|
||||||
|
? {
|
||||||
|
token: getGithubToken(),
|
||||||
|
workflowRunId: github.context.payload.workflow_run.id,
|
||||||
|
repositoryName: github.context.repo.repo,
|
||||||
|
repositoryOwner: github.context.repo.owner
|
||||||
}
|
}
|
||||||
return retrieveDependencyGraphsForCurrentWorkflow(workspaceDirectory)
|
: undefined
|
||||||
}
|
|
||||||
|
|
||||||
async function retrieveDependencyGraphsForWorkflowRun(runId: number, workspaceDirectory: string): Promise<string[]> {
|
const artifactClient = new DefaultArtifactClient()
|
||||||
const octokit = getOctokit()
|
|
||||||
|
|
||||||
// Find the workflow run artifacts named "dependency-graph"
|
|
||||||
const artifacts = await octokit.rest.actions.listWorkflowRunArtifacts({
|
|
||||||
owner: github.context.repo.owner,
|
|
||||||
repo: github.context.repo.repo,
|
|
||||||
run_id: runId
|
|
||||||
})
|
|
||||||
|
|
||||||
const matchArtifact = artifacts.data.artifacts.find(candidate => {
|
|
||||||
return candidate.name === DEPENDENCY_GRAPH_ARTIFACT
|
|
||||||
})
|
|
||||||
|
|
||||||
if (matchArtifact === undefined) {
|
|
||||||
throw new Error(`Dependency graph artifact not found. Has it been generated by workflow run '${runId}'?`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download the dependency-graph artifact
|
|
||||||
const download = await octokit.rest.actions.downloadArtifact({
|
|
||||||
owner: github.context.repo.owner,
|
|
||||||
repo: github.context.repo.repo,
|
|
||||||
artifact_id: matchArtifact.id,
|
|
||||||
archive_format: 'zip'
|
|
||||||
})
|
|
||||||
|
|
||||||
const downloadBuffer = download.data as ArrayBuffer
|
|
||||||
const downloadZip = path.resolve(workspaceDirectory, 'dependency-graph.zip')
|
|
||||||
fs.writeFileSync(downloadZip, Buffer.from(downloadBuffer))
|
|
||||||
|
|
||||||
// Expance the dependency-graph zip and locate each dependency-graph JSON file
|
|
||||||
const extractDir = path.resolve(workspaceDirectory, 'dependency-graph')
|
|
||||||
const extracted = await toolCache.extractZip(downloadZip, extractDir)
|
|
||||||
core.info(`Extracted dependency graph artifacts to ${extracted}: ${fs.readdirSync(extracted)}`)
|
|
||||||
|
|
||||||
return findDependencyGraphFiles(extracted)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function retrieveDependencyGraphsForCurrentWorkflow(workspaceDirectory: string): Promise<string[]> {
|
|
||||||
const artifactClient = artifact.create()
|
|
||||||
const downloadPath = path.resolve(workspaceDirectory, 'dependency-graph')
|
const downloadPath = path.resolve(workspaceDirectory, 'dependency-graph')
|
||||||
await artifactClient.downloadArtifact(DEPENDENCY_GRAPH_ARTIFACT, downloadPath)
|
|
||||||
return await findDependencyGraphFiles(downloadPath)
|
const dependencyGraphArtifacts = (
|
||||||
|
await artifactClient.listArtifacts({
|
||||||
|
latest: true,
|
||||||
|
findBy
|
||||||
|
})
|
||||||
|
).artifacts.filter(candidate => candidate.name.startsWith(DEPENDENCY_GRAPH_PREFIX))
|
||||||
|
|
||||||
|
for (const artifact of dependencyGraphArtifacts) {
|
||||||
|
const downloadedArtifact = await artifactClient.downloadArtifact(artifact.id, {
|
||||||
|
path: downloadPath,
|
||||||
|
findBy
|
||||||
|
})
|
||||||
|
core.info(`Downloading dependency-graph artifact ${artifact.name} to ${downloadedArtifact.downloadPath}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return findDependencyGraphFiles(downloadPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findDependencyGraphFiles(dir: string): Promise<string[]> {
|
async function findDependencyGraphFiles(dir: string): Promise<string[]> {
|
||||||
|
|
|
@ -84,11 +84,13 @@ export function getDependencyGraphOption(): DependencyGraphOption {
|
||||||
return DependencyGraphOption.Generate
|
return DependencyGraphOption.Generate
|
||||||
case 'generate-and-submit':
|
case 'generate-and-submit':
|
||||||
return DependencyGraphOption.GenerateAndSubmit
|
return DependencyGraphOption.GenerateAndSubmit
|
||||||
|
case 'generate-and-upload':
|
||||||
|
return DependencyGraphOption.GenerateAndUpload
|
||||||
case 'download-and-submit':
|
case 'download-and-submit':
|
||||||
return DependencyGraphOption.DownloadAndSubmit
|
return DependencyGraphOption.DownloadAndSubmit
|
||||||
}
|
}
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
`The value '${val} is not valid for 'dependency-graph. Valid values are: [disabled, generate-and-upload, generate-and-submit, download-and-submit]. The default value is 'disabled'.`
|
`The value '${val} is not valid for 'dependency-graph. Valid values are: [disabled, generate, generate-and-submit, generate-and-upload, download-and-submit]. The default value is 'disabled'.`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,8 +125,9 @@ function getBooleanInput(paramName: string, paramDefault = false): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DependencyGraphOption {
|
export enum DependencyGraphOption {
|
||||||
Disabled,
|
Disabled = 'disabled',
|
||||||
Generate,
|
Generate = 'generate',
|
||||||
GenerateAndSubmit,
|
GenerateAndSubmit = 'generate-and-submit',
|
||||||
DownloadAndSubmit
|
GenerateAndUpload = 'generate-and-upload',
|
||||||
|
DownloadAndSubmit = 'download-and-submit'
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ if (isTopLevelBuild) {
|
||||||
new File(githubOutput) << "dependency-graph-file=${reportFile.absolutePath}\n"
|
new File(githubOutput) << "dependency-graph-file=${reportFile.absolutePath}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
println "Generating dependency graph into '${reportFile}'"
|
println "Generating dependency graph into '${reportFile}'"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue