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: steps:
- name: 'Checkout Repository' - name: 'Checkout Repository'
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: 'Dependency Submission'
uses: ./dependency-submission
with:
build-root-directory: .github/workflow-samples/groovy-dsl
- name: 'Dependency Review' - name: 'Dependency Review'
uses: actions/dependency-review-action@v4 uses: actions/dependency-review-action@v4

View file

@ -89,51 +89,72 @@ jobs:
with: with:
build-root-directory: .github/workflow-samples/kotlin-dsl build-root-directory: .github/workflow-samples/kotlin-dsl
# TODO - Test this scenario (and make it work) multiple-builds:
# multiple-builds: strategy:
# strategy: matrix:
# matrix: os: ${{fromJSON(inputs.runner-os)}}
# os: ${{fromJSON(inputs.runner-os)}} runs-on: ${{ matrix.os }}
# runs-on: ${{ matrix.os }} steps:
# steps: - name: Checkout sources
# - name: Checkout sources uses: actions/checkout@v4
# uses: actions/checkout@v4 - name: Initialize integ-test
# - name: Initialize integ-test uses: ./.github/actions/init-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: config-cache:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -154,7 +175,7 @@ jobs:
echo "Did not find config-cache-store dependency graph files" echo "Did not find config-cache-store dependency graph files"
exit 1 exit 1
fi fi
rm ${{ steps.config-cache-store.outputs.dependency-graph-file }} rm ${{ steps.config-cache-store.outputs.dependency-graph-file }}*
- id: config-cache-reuse - id: config-cache-reuse
uses: ./dependency-submission uses: ./dependency-submission
with: with:

View file

@ -288,18 +288,11 @@ 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
dependency-review:
needs: dependency-submission
runs-on: ubuntu-latest
steps:
- name: Perform dependency review - name: Perform dependency review
uses: actions/dependency-review-action@v3 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 ## 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). 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-unused-vars": "off",
"no-shadow": "off", "no-shadow": "off",
"sort-imports": "off", "sort-imports": "off",
"github/array-foreach": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}], "@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
"@typescript-eslint/no-require-imports": "error", "@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> { 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() const option = config.getDependencyGraphOption()
try { try {
switch (option) { switch (option) {
@ -84,6 +79,12 @@ async function findGeneratedDependencyGraphFiles(): Promise<string[]> {
} }
async function uploadDependencyGraphs(dependencyGraphFiles: string[], config: DependencyGraphConfig): Promise<void> { 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 workspaceDirectory = layout.workspaceDirectory()
const artifactClient = new DefaultArtifactClient() const artifactClient = new DefaultArtifactClient()
@ -111,12 +112,18 @@ async function downloadAndSubmitDependencyGraphs(config: DependencyGraphConfig):
} }
async function submitDependencyGraphs(dependencyGraphFiles: string[]): Promise<void> { 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 { try {
await submitDependencyGraphFile(jsonFile) await submitDependencyGraphFile(dependencyGraphFile)
} catch (error) { } catch (error) {
if (error instanceof RequestError) { if (error instanceof RequestError) {
throw new Error(translateErrorMessage(jsonFile, error)) throw new Error(translateErrorMessage(dependencyGraphFile, error))
} else { } else {
throw error throw error
} }
@ -184,8 +191,20 @@ async function downloadDependencyGraphs(): Promise<string[]> {
async function findDependencyGraphFiles(dir: string): Promise<string[]> { async function findDependencyGraphFiles(dir: string): Promise<string[]> {
const globber = await glob.create(`${dir}/dependency-graph-reports/*.json`) const globber = await glob.create(`${dir}/dependency-graph-reports/*.json`)
const graphFiles = globber.glob() const allFiles = await globber.glob()
return graphFiles 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 { 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 args: string[] = parseArgsStringToArgv(executionArgs)
const buildRootDirectory = layout.buildRootDirectory() const buildRootDirectory = layout.buildRootDirectory()
await execution.executeGradleBuild(executable, buildRootDirectory, args) await execution.executeGradleBuild(executable, buildRootDirectory, args)
await dependencyGraph.complete(config)
} catch (error) { } catch (error) {
core.setFailed(String(error)) core.setFailed(String(error))
if (error instanceof Error && error.stack) { if (error instanceof Error && error.stack) {

View file

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