Skip to content

Commit

Permalink
Introduce 'reason' output (#180)
Browse files Browse the repository at this point in the history
* Udpdate all dependencies

See #159

* Switch to Node.js v16

Node.js v16 is current LTS and now supported as action runtime

* Only format files in 'src' folder

* Introduce 'reason' output

See #159

Co-authored-by: Felix K <17876666+fkirc@users.noreply.github.com>
  • Loading branch information
paescuj and fkirc committed Jan 16, 2022
1 parent b18a05d commit bda236d
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 43 deletions.
6 changes: 5 additions & 1 deletion README.md
Expand Up @@ -105,9 +105,13 @@ One of `never`, `same_content`, `same_content_newer`, `outdated_runs`, `always`.

Returns true if the current run should be skipped according to your configured rules. This should be evaluated for either individual steps or entire jobs.

### `reason`

The reason why the current run is considered skippable or unskippable. Corresponds approximately to the input options, for example `skip_after_successful_duplicate`.

### `skipped_by`

Information about the workflow run which caused the current run to be skipped.
Information about the workflow run which caused the current run to be skipped. Returns information only when current run is considered skippable.

## Usage examples

Expand Down
2 changes: 2 additions & 0 deletions action.yml
Expand Up @@ -36,6 +36,8 @@ inputs:
outputs:
should_skip:
description: 'Returns true if the current run should be skipped according to your configured rules. This should be evaluated for either individual steps or entire jobs.'
reason:
description: 'The reason why the current run is considered skippable or unskippable. Corresponds approximately to the input options, for example `skip_after_successful_duplicate`.'
skipped_by:
description: 'Information about the workflow run which caused the current run to be skipped.'
runs:
Expand Down
60 changes: 41 additions & 19 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 49 additions & 23 deletions src/main.ts
Expand Up @@ -168,8 +168,11 @@ async function main(): Promise<void> {
if (e instanceof Error || typeof e === 'string') {
core.warning(e)
}
core.warning(`Failed to fetch the required workflow information`)
exitSuccess({shouldSkip: false})
core.warning('Failed to fetch the required workflow information')
exitSuccess({
shouldSkip: false,
reason: 'no_workflow_information'
})
}

const cancelOthers = getBooleanInput('cancel_others', false)
Expand All @@ -180,25 +183,48 @@ async function main(): Promise<void> {
core.info(
`Do not skip execution because the workflow was triggered with '${context.currentRun.event}'`
)
exitSuccess({shouldSkip: false})
exitSuccess({
shouldSkip: false,
reason: 'do_not_skip'
})
}
const skipAfterSuccessfulDuplicates = getBooleanInput(
'skip_after_successful_duplicate',
true
)
if (skipAfterSuccessfulDuplicates) {
detectSuccessfulDuplicateRuns(context)
const successfulDuplicateRun = detectSuccessfulDuplicateRuns(context)
if (successfulDuplicateRun) {
core.info(
`Skip execution because the exact same files have been successfully checked in ${successfulDuplicateRun.html_url}`
)
exitSuccess({
shouldSkip: true,
reason: 'skip_after_successful_duplicate',
skippedBy: successfulDuplicateRun
})
}
}
if (context.concurrentSkipping !== 'never') {
detectConcurrentRuns(context)
const concurrentRun = detectConcurrentRuns(context)
if (concurrentRun) {
exitSuccess({
shouldSkip: true,
reason: 'concurrent_skipping',
skippedBy: concurrentRun
})
}
}
if (context.paths.length >= 1 || context.pathsIgnore.length >= 1) {
await backtracePathSkipping(context)
}
core.info(
'Do not skip execution because we did not find a transferable run'
)
exitSuccess({shouldSkip: false})
exitSuccess({
shouldSkip: false,
reason: 'no_transferable_run'
})
} catch (e) {
if (e instanceof Error) {
core.error(e)
Expand All @@ -220,7 +246,7 @@ async function cancelOutdatedRuns(context: WRunContext): Promise<void> {
)
})
if (!cancelVictims.length) {
return core.info(`Did not find other workflow-runs to be cancelled`)
return core.info('Did not find other workflow-runs to be cancelled')
}
for (const victim of cancelVictims) {
await cancelWorkflowRun(victim, context)
Expand All @@ -246,22 +272,19 @@ async function cancelWorkflowRun(
}
}

function detectSuccessfulDuplicateRuns(context: WRunContext): void {
function detectSuccessfulDuplicateRuns(
context: WRunContext
): WorkflowRun | undefined {
const duplicateRuns = context.olderRuns.filter(
run => run.treeHash === context.currentRun.treeHash
)
const successfulDuplicate = duplicateRuns.find(run => {
return run.status === 'completed' && run.conclusion === 'success'
})
if (successfulDuplicate) {
core.info(
`Skip execution because the exact same files have been successfully checked in ${successfulDuplicate.html_url}`
)
exitSuccess({shouldSkip: true, skippedBy: successfulDuplicate})
}
return successfulDuplicate
}

function detectConcurrentRuns(context: WRunContext): void {
function detectConcurrentRuns(context: WRunContext): WorkflowRun | undefined {
const concurrentRuns: WorkflowRun[] = context.allRuns.filter(run => {
if (run.status === 'completed') {
return false
Expand All @@ -271,6 +294,7 @@ function detectConcurrentRuns(context: WRunContext): void {
}
return true
})

if (!concurrentRuns.length) {
core.info(`Did not find any concurrent workflow-runs`)
return
Expand All @@ -279,7 +303,7 @@ function detectConcurrentRuns(context: WRunContext): void {
core.info(
`Skip execution because another instance of the same workflow is already running in ${concurrentRuns[0].html_url}`
)
exitSuccess({shouldSkip: true, skippedBy: concurrentRuns[0]})
return concurrentRuns[0]
} else if (context.concurrentSkipping === 'outdated_runs') {
const newerRun = concurrentRuns.find(
run =>
Expand All @@ -290,7 +314,7 @@ function detectConcurrentRuns(context: WRunContext): void {
core.info(
`Skip execution because a newer instance of the same workflow is running in ${newerRun.html_url}`
)
exitSuccess({shouldSkip: true, skippedBy: newerRun})
return newerRun
}
} else if (context.concurrentSkipping === 'same_content') {
const concurrentDuplicate = concurrentRuns.find(
Expand All @@ -300,7 +324,7 @@ function detectConcurrentRuns(context: WRunContext): void {
core.info(
`Skip execution because the exact same files are concurrently checked in ${concurrentDuplicate.html_url}`
)
exitSuccess({shouldSkip: true, skippedBy: concurrentDuplicate})
return concurrentDuplicate
}
} else if (context.concurrentSkipping === 'same_content_newer') {
const concurrentIsOlder = concurrentRuns.find(
Expand All @@ -312,10 +336,10 @@ function detectConcurrentRuns(context: WRunContext): void {
core.info(
`Skip execution because the exact same files are concurrently checked in older ${concurrentIsOlder.html_url}`
)
exitSuccess({shouldSkip: true, skippedBy: concurrentIsOlder})
return concurrentIsOlder
}
}
core.info(`Did not find any skippable concurrent workflow-runs`)
core.info(`Did not find any concurrent workflow-runs that justify skipping`)
}

async function backtracePathSkipping(context: WRunContext): Promise<void> {
Expand Down Expand Up @@ -358,7 +382,7 @@ function exitIfSuccessfulRunExists(
core.info(
`Skip execution because all changes since ${successfulRun.html_url} are in ignored or skipped paths`
)
exitSuccess({shouldSkip: true, skippedBy: successfulRun})
exitSuccess({shouldSkip: true, reason: 'paths', skippedBy: successfulRun})
}
}

Expand Down Expand Up @@ -386,7 +410,7 @@ function isCommitSkippable(
}

const globOptions = {
dot: true // Match dotfiles. Otherwise dotfiles are ignored unless a . is explicitly defined in the pattern.
dot: true // Match dotfiles. Otherwise dotfiles are ignored unless a "." is explicitly defined in the pattern.
}

function isCommitPathIgnored(
Expand Down Expand Up @@ -458,10 +482,12 @@ async function fetchCommitDetails(

function exitSuccess(args: {
shouldSkip: boolean
reason: string
skippedBy?: WorkflowRun
}): never {
core.setOutput('should_skip', args.shouldSkip)
core.setOutput('skipped_by', args.skippedBy)
core.setOutput('reason', args.reason)
core.setOutput('skipped_by', args.skippedBy || {})
return process.exit(0)
}

Expand Down

0 comments on commit bda236d

Please sign in to comment.