Generated graph is submitted immediately by dependency-submission action

While `setup-gradle` must wait until the end of job to submit all of the generated
graphs, the `dependency-submission` action will not save/upload the generated graph
immediately, in the same step where it is generated.
This commit is contained in:
daz 2024-04-07 12:27:51 -06:00
parent 38a821729e
commit 90bf65c87c
No known key found for this signature in database
7 changed files with 105 additions and 69 deletions

View file

@ -16,5 +16,9 @@ jobs:
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4
- name: 'Dependency Submission'
uses: ./dependency-submission
with:
build-root-directory: .github/workflow-samples/groovy-dsl
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4

View file

@ -89,51 +89,72 @@ jobs:
with:
build-root-directory: .github/workflow-samples/kotlin-dsl
# TODO - Test this scenario (and make it work)
# multiple-builds:
# strategy:
# matrix:
# os: ${{fromJSON(inputs.runner-os)}}
# runs-on: ${{ matrix.os }}
# steps:
# - name: Checkout sources
# uses: actions/checkout@v4
# - name: Initialize integ-test
# uses: ./.github/actions/init-integ-test
multiple-builds:
strategy:
matrix:
os: ${{fromJSON(inputs.runner-os)}}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Initialize integ-test
uses: ./.github/actions/init-integ-test
- id: kotlin-dsl
uses: ./dependency-submission
with:
build-root-directory: .github/workflow-samples/kotlin-dsl
- id: groovy-dsl
uses: ./dependency-submission
with:
build-root-directory: .github/workflow-samples/groovy-dsl
- id: groovy-dsl-again
uses: ./dependency-submission
with:
build-root-directory: .github/workflow-samples/groovy-dsl
additional-arguments: --no-build-cache
- name: Check generated dependency graphs
shell: bash
run: |
echo "kotlin-dsl report file: ${{ steps.kotlin-dsl.outputs.dependency-graph-file }}"
echo "groovy-dsl report file: ${{ steps.groovy-dsl.outputs.dependency-graph-file }}"
echo "groovy-dsl-again report file: ${{ steps.groovy-dsl-again.outputs.dependency-graph-file }}"
ls -l dependency-graph-reports
if [ ! -e "${{ steps.kotlin-dsl.outputs.dependency-graph-file }}" ]; then
echo "Did not find kotlin-dsl dependency graph file"
exit 1
fi
if [ ! -e "${{ steps.groovy-dsl.outputs.dependency-graph-file }}" ]; then
echo "Did not find groovy-dsl dependency graph file"
exit 1
fi
if [ ! -e "${{ steps.groovy-dsl-again.outputs.dependency-graph-file }}" ]; then
echo "Did not find groovy-dsl-again dependency graph file"
exit 1
fi
multiple-builds-upload:
strategy:
matrix:
os: ${{fromJSON(inputs.runner-os)}}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Initialize integ-test
uses: ./.github/actions/init-integ-test
- id: kotlin-dsl
uses: ./dependency-submission
with:
dependency-graph: generate-and-upload
build-root-directory: .github/workflow-samples/kotlin-dsl
- id: groovy-dsl
uses: ./dependency-submission
with:
dependency-graph: generate-and-upload
build-root-directory: .github/workflow-samples/groovy-dsl
# - name: Setup Gradle for dependency-graph generate
# uses: ./setup-gradle
# with:
# dependency-graph: generate-and-submit
# - id: gradle-assemble
# run: ./gradlew assemble
# working-directory: .github/workflow-samples/groovy-dsl
# - id: gradle-build
# run: ./gradlew build
# working-directory: .github/workflow-samples/groovy-dsl
# - id: gradle-build-again
# run: ./gradlew build
# working-directory: .github/workflow-samples/groovy-dsl
# - name: Check generated dependency graphs
# shell: bash
# run: |
# echo "gradle-assemble report file: ${{ steps.gradle-assemble.outputs.dependency-graph-file }}"
# echo "gradle-build report file: ${{ steps.gradle-build.outputs.dependency-graph-file }}"
# echo "gradle-build-again report file: ${{ steps.gradle-build-again.outputs.dependency-graph-file }}"
# ls -l dependency-graph-reports
# if [ ! -e "${{ steps.gradle-assemble.outputs.dependency-graph-file }}" ]; then
# echo "Did not find gradle-assemble dependency graph file"
# exit 1
# fi
# if [ ! -e "${{ steps.gradle-build.outputs.dependency-graph-file }}" ]; then
# echo "Did not find gradle-build dependency graph files"
# exit 1
# fi
# if [ ! -e "${{ steps.gradle-build-again.outputs.dependency-graph-file }}" ]; then
# echo "Did not find gradle-build-again dependency graph files"
# exit 1
# fi
config-cache:
runs-on: ubuntu-latest
steps:
@ -154,7 +175,7 @@ jobs:
echo "Did not find config-cache-store dependency graph files"
exit 1
fi
rm ${{ steps.config-cache-store.outputs.dependency-graph-file }}
rm ${{ steps.config-cache-store.outputs.dependency-graph-file }}*
- id: config-cache-reuse
uses: ./dependency-submission
with:

View file

@ -288,18 +288,11 @@ jobs:
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@v3
dependency-review:
needs: dependency-submission
runs-on: ubuntu-latest
steps:
- name: Perform dependency review
uses: actions/dependency-review-action@v3
```
Note that the `dependency-submission` action submits the dependency graph at the completion of the workflow Job.
For this reason, the `dependency-review-action` must be executed in a dependent job, and not as a subsequent step in the job that generates the dependency graph.
## Usage with pull requests from public forked repositories
This `contents: write` permission is [not available for any workflow that is triggered by a pull request submitted from a public forked repository](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token).

View file

@ -14,6 +14,7 @@
"no-unused-vars": "off",
"no-shadow": "off",
"sort-imports": "off",
"github/array-foreach": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
"@typescript-eslint/no-require-imports": "error",

View file

@ -54,11 +54,6 @@ function maybeExportVariable(variableName: string, value: unknown): void {
}
export async function complete(config: DependencyGraphConfig): Promise<void> {
if (isRunningInActEnvironment()) {
core.info('Dependency graph upload and submit not supported in the ACT environment.')
return
}
const option = config.getDependencyGraphOption()
try {
switch (option) {
@ -84,6 +79,12 @@ async function findGeneratedDependencyGraphFiles(): Promise<string[]> {
}
async function uploadDependencyGraphs(dependencyGraphFiles: string[], config: DependencyGraphConfig): Promise<void> {
if (isRunningInActEnvironment()) {
core.info('Dependency graph upload not supported in the ACT environment.')
core.info(`Would upload: ${dependencyGraphFiles.join(', ')}`)
return
}
const workspaceDirectory = layout.workspaceDirectory()
const artifactClient = new DefaultArtifactClient()
@ -111,12 +112,18 @@ async function downloadAndSubmitDependencyGraphs(config: DependencyGraphConfig):
}
async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> {
for (const jsonFile of dependencyGraphFiles) {
if (isRunningInActEnvironment()) {
core.info('Dependency graph submit not supported in the ACT environment.')
core.info(`Would submit: ${dependencyGraphFiles.join(', ')}`)
return
}
for (const dependencyGraphFile of dependencyGraphFiles) {
try {
await submitDependencyGraphFile(jsonFile)
await submitDependencyGraphFile(dependencyGraphFile)
} catch (error) {
if (error instanceof RequestError) {
throw new Error(translateErrorMessage(jsonFile, error))
throw new Error(translateErrorMessage(dependencyGraphFile, error))
} else {
throw error
}
@ -184,8 +191,20 @@ async function downloadDependencyGraphs(): Promise<string[]> {
async function findDependencyGraphFiles(dir: string): Promise<string[]> {
const globber = await glob.create(`${dir}/dependency-graph-reports/*.json`)
const graphFiles = globber.glob()
return graphFiles
const allFiles = await globber.glob()
const unprocessedFiles = allFiles.filter(file => !isProcessed(file))
unprocessedFiles.forEach(markProcessed)
return unprocessedFiles
}
function isProcessed(dependencyGraphFile: string): boolean {
const markerFile = `${dependencyGraphFile}.processed`
return fs.existsSync(markerFile)
}
function markProcessed(dependencyGraphFile: string): void {
const markerFile = `${dependencyGraphFile}.processed`
fs.writeFileSync(markerFile, '')
}
function warnOrFail(config: DependencyGraphConfig, option: String, error: unknown): void {

View file

@ -42,6 +42,8 @@ export async function run(): Promise<void> {
const args: string[] = parseArgsStringToArgv(executionArgs)
const buildRootDirectory = layout.buildRootDirectory()
await execution.executeGradleBuild(executable, buildRootDirectory, args)
await dependencyGraph.complete(config)
} catch (error) {
core.setFailed(String(error))
if (error instanceof Error && error.stack) {

View file

@ -1,8 +1,7 @@
import * as core from '@actions/core'
import * as setupGradle from '../setup-gradle'
import * as dependencyGraph from '../dependency-graph'
import {CacheConfig, DependencyGraphConfig, SummaryConfig} from '../input-params'
import {CacheConfig, SummaryConfig} from '../input-params'
import {PostActionJobFailure} from '../errors'
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
@ -15,10 +14,7 @@ process.on('uncaughtException', e => handleFailure(e))
*/
export async function run(): Promise<void> {
try {
if (await setupGradle.complete(new CacheConfig(), new SummaryConfig())) {
// Only submit the dependency graphs once per job
await dependencyGraph.complete(new DependencyGraphConfig())
}
await setupGradle.complete(new CacheConfig(), new SummaryConfig())
} catch (error) {
if (error instanceof PostActionJobFailure) {
core.setFailed(String(error))