You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by po...@apache.org on 2020/12/27 13:57:24 UTC
[airflow-label-when-approved] 08/09: Add triggering by workflow_run
(#4)
This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airflow-label-when-approved.git
commit 7872312da76508d29f98d4fa68843ea91754cc59
Author: Tobiasz Kędzierski <to...@gmail.com>
AuthorDate: Wed Oct 28 20:48:12 2020 +0100
Add triggering by workflow_run (#4)
---
README.md | 54 +++++++++++++++++++---
action.yml | 3 ++
dist/index.js | 116 ++++++++++------------------------------------
src/main.ts | 145 +++++++++++++---------------------------------------------
4 files changed, 106 insertions(+), 212 deletions(-)
diff --git a/README.md b/README.md
index a6d05d4..ef14fd3 100644
--- a/README.md
+++ b/README.md
@@ -15,8 +15,9 @@
- [Outputs](#outputs)
- [Examples](#examples)
- [Workflow Run event](#workflow-run-event)
- - [Development environment](#development-environment)
- - [License](#license)
+ - [Pull Request Review event](#pull-request-review-event)
+- [Development environment](#development-environment)
+- [License](#license)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -31,6 +32,13 @@ The required input `require_committers_approval` says is approval can be done by
or by anyone. It may be useful in repositories which requires committers approvals like [Apache Software Foundation](https://github.com/apache/)
projects.
+It can be used in workflows triggered by "pull_request_review" or "workflow_run".
+When used on "pull_request_review" any workflows triggered from pull request created from fork will fail
+due to insufficient permissions. Because of this support for "workflow_run" was added.
+It should be triggered by workflows "pull_request_review" and requires additional input `pullRequestNumber`.
+Pull request number can be obtained by using [potiuk/get-workflow-origin)](https://github.com/potiuk/get-workflow-origin) action (see example [workflow-run-event](#workflow-run-event)).
+
+
# Inputs and outputs
## Inputs
@@ -41,6 +49,7 @@ projects.
| `label` | no | `Approved by committers` | Label to be added/removed to the Pull Request if approved/not approved |
| `require_committers_approval` | no | `true` | Is approval from user with write permission required |
| `comment` | no | `PR approved by at least one committer and no changes requested.` | Add optional comment to the PR when approved (requires label input to be set) |
+| `pullRequestNumber` | no | `${{ steps.source-run-info.outputs.pullRequestNumber }}` | Pull request number if triggered by "worfklow_run" |
## Outputs
@@ -55,6 +64,38 @@ projects.
### Workflow Run event
```yaml
+name: "Label when approved"
+on:
+ workflow_run:
+ workflows: ["Workflow triggered on pull_request_review"]
+ types: ['requested']
+
+jobs:
+
+ label-when-approved:
+ name: "Label when approved"
+ runs-on: ubuntu-latest
+ steps:
+ - name: "Get information about the original trigger of the run"
+ uses: potiuk/get-workflow-origin@v1_2
+ id: source-run-info
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ sourceRunId: ${{ github.event.workflow_run.id }}
+ - name: Label when approved by anyone
+ uses: TobKed/label-when-approved-action@v1.2
+ id: label-when-approved-by-anyone
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ require_committers_approval: 'true'
+ label: 'Approved by committer'
+ comment: 'PR approved by at least one committer and no changes requested.'
+ pullRequestNumber: ${{ steps.source-run-info.outputs.pullRequestNumber }}
+```
+
+### Pull Request Review event
+
+```yaml
name: Label when approved
on: pull_request_review
@@ -68,7 +109,7 @@ jobs:
isApprovedByAnyone: ${{ steps.label-when-approved-by-anyone.outputs.isApproved }}
steps:
- name: Label when approved by commiters
- uses: TobKed/label-when-approved-action@v1.1
+ uses: TobKed/label-when-approved-action@v1.2
id: label-when-approved-by-commiters
with:
token: ${{ secrets.GITHUB_TOKEN }}
@@ -76,19 +117,18 @@ jobs:
require_committers_approval: 'true'
comment: 'PR approved by at least one committer and no changes requested.'
- name: Label when approved by anyone
- uses: TobKed/label-when-approved-action@v1.1
+ uses: TobKed/label-when-approved-action@v1.2
id: label-when-approved-by-anyone
with:
token: ${{ secrets.GITHUB_TOKEN }}
```
-
-## Development environment
+# Development environment
It is highly recommended tu use [pre commit](https://pre-commit.com). The pre-commits
installed via pre-commit tool handle automatically linting (including automated fixes) as well
as building and packaging Javascript index.js from the main.ts Typescript code, so you do not have
to run it yourself.
-## License
+# License
[MIT License](LICENSE) covers the scripts and documentation in this project.
diff --git a/action.yml b/action.yml
index ae16b48..9027254 100644
--- a/action.yml
+++ b/action.yml
@@ -14,6 +14,9 @@ inputs:
comment:
description: 'Comment to be added to Pull Request if approved'
required: false
+ pullRequestNumber:
+ description: 'Pull request number if triggered by "worfklow_run"'
+ required: false
outputs:
isApproved:
description: 'Is Pull Reqeuest approved'
diff --git a/dist/index.js b/dist/index.js
index b9ac4e2..8e040f7 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -1470,15 +1470,9 @@ function verboseOutput(name, value) {
core.info(`Setting output: ${name}: ${value}`);
core.setOutput(name, value);
}
-function getPullRequest(octokit, context, owner, repo) {
+function getPullRequest(octokit, owner, repo, pullRequestNumber) {
return __awaiter(this, void 0, void 0, function* () {
- const pullRequestNumber = context.payload.pull_request
- ? context.payload.pull_request.number
- : null;
- if (pullRequestNumber === null) {
- throw Error(`Could not find PR number in context payload.`);
- }
- core.info(`pullRequestNumber: ${pullRequestNumber}`);
+ core.info(`Fetching pull request with number: ${pullRequestNumber}`);
const pullRequest = yield octokit.pulls.get({
owner,
repo,
@@ -1597,92 +1591,49 @@ function addComment(octokit, owner, repo, pullRequestNumber, comment) {
});
});
}
-function getWorkflowId(octokit, runId, owner, repo) {
- return __awaiter(this, void 0, void 0, function* () {
- const reply = yield octokit.actions.getWorkflowRun({
- owner,
- repo,
- // eslint-disable-next-line @typescript-eslint/camelcase
- run_id: runId
- });
- core.info(`The source run ${runId} is in ${reply.data.workflow_url} workflow`);
- const workflowIdString = reply.data.workflow_url.split('/').pop() || '';
- if (!(workflowIdString.length > 0)) {
- throw new Error('Could not resolve workflow');
- }
- return parseInt(workflowIdString);
- });
-}
-function getPrWorkflowRunsIds(octokit, owner, repo, branch, sha, skipRunId) {
- return __awaiter(this, void 0, void 0, function* () {
- const workflowRuns = yield octokit.actions.listRepoWorkflowRuns({
- owner,
- repo,
- branch,
- event: 'pull_request',
- status: 'completed',
- // eslint-disable-next-line @typescript-eslint/camelcase
- per_page: 100
- });
- // may be no need to rerun pending/queued runs
- const filteredRunsIds = [];
- const filteredWorklowRunsIds = [];
- for (const workflowRun of workflowRuns.data.workflow_runs) {
- const workflowId = parseInt(workflowRun.workflow_url.split('/').pop() || '0');
- if (workflowRun.head_sha === sha &&
- !filteredRunsIds.includes(workflowId) &&
- workflowId !== skipRunId) {
- filteredRunsIds.push(workflowId);
- filteredWorklowRunsIds.push(workflowRun.id);
- }
- }
- return filteredWorklowRunsIds;
- });
-}
-function rerunWorkflows(octokit, owner, repo, runIds) {
- return __awaiter(this, void 0, void 0, function* () {
- core.info(`Rerun worklowws: ${runIds}`);
- for (const runId of runIds) {
- yield octokit.actions.reRunWorkflow({
- owner,
- repo,
- // eslint-disable-next-line @typescript-eslint/camelcase
- run_id: runId
- });
- }
- });
-}
-function printDebug(item, description) {
+function printDebug(item, description = '') {
return __awaiter(this, void 0, void 0, function* () {
const itemJson = JSON.stringify(item);
- core.info(`\n ######### ${description} ######### \n: ${itemJson}\n\n`);
+ core.debug(`\n ######### ${description} ######### \n: ${itemJson}\n\n`);
});
}
function run() {
- var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
const token = core.getInput('token', { required: true });
const userLabel = core.getInput('label') || 'not set';
const requireCommittersApproval = core.getInput('require_committers_approval') === 'true';
const comment = core.getInput('comment') || '';
+ const pullRequestNumberInput = core.getInput('pullRequestNumber') || 'not set';
const octokit = new github.GitHub(token);
const context = github.context;
const repository = getRequiredEnv('GITHUB_REPOSITORY');
const eventName = getRequiredEnv('GITHUB_EVENT_NAME');
- const selfRunId = parseInt(getRequiredEnv('GITHUB_RUN_ID'));
const [owner, repo] = repository.split('/');
- const selfWorkflowId = yield getWorkflowId(octokit, selfRunId, owner, repo);
- const branch = (_a = context.payload.pull_request) === null || _a === void 0 ? void 0 : _a.head.ref;
- const sha = (_b = context.payload.pull_request) === null || _b === void 0 ? void 0 : _b.head.sha;
+ let pullRequestNumber;
core.info(`\n############### Set Label When Approved start ##################\n` +
`label: "${userLabel}"\n` +
`requireCommittersApproval: ${requireCommittersApproval}\n` +
- `comment: ${comment}`);
- if (eventName !== 'pull_request_review') {
- throw Error(`This action is only useful in "pull_request_review" triggered runs and you used it in "${eventName}"`);
+ `comment: ${comment}\n` +
+ `pullRequestNumber: ${pullRequestNumberInput}`);
+ if (eventName === 'pull_request_review') {
+ pullRequestNumber = context.payload.pull_request
+ ? context.payload.pull_request.number
+ : undefined;
+ if (pullRequestNumber === undefined) {
+ throw Error(`Could not find PR number in context payload.`);
+ }
+ }
+ else if (eventName === 'workflow_run') {
+ if (pullRequestNumberInput === 'not set') {
+ throw Error(`If action is triggered by "workflow_run" then input "pullRequestNumber" is required.`);
+ }
+ pullRequestNumber = parseInt(pullRequestNumberInput);
+ }
+ else {
+ throw Error(`This action is only useful in "pull_request_review" or "workflow_run" triggered runs and you used it in "${eventName}"`);
}
// PULL REQUEST
- const pullRequest = yield getPullRequest(octokit, context, owner, repo);
+ const pullRequest = yield getPullRequest(octokit, owner, repo, pullRequestNumber);
// LABELS
const labelNames = getPullRequestLabels(pullRequest);
// REVIEWS
@@ -1704,23 +1655,6 @@ function run() {
yield removeLabel(octokit, owner, repo, pullRequest.number, userLabel);
}
}
- //// Future option to rerun workflows if PR approved
- //// Rerun workflow can have dynamic matrixes which check presence of labels
- //// it is not possible to rerun successful runs
- //// https://github.community/t/cannot-re-run-a-successful-workflow-run-using-the-rest-api/123661
- //
- // if (isLabelShouldBeSet) {
- // const prWorkflowRunsIds = await getPrWorkflowRunsIds(
- // octokit,
- // owner,
- // repo,
- // branch,
- // sha,
- // selfWorkflowId
- // )
- //
- // await rerunWorkflows(octokit, owner, repo, prWorkflowRunsIds)
- // }
// OUTPUT
verboseOutput('isApproved', String(isApproved));
verboseOutput('labelSet', String(isLabelShouldBeSet));
diff --git a/src/main.ts b/src/main.ts
index 12e0fea..f7b61d6 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,7 +1,6 @@
import * as github from '@actions/github'
import * as core from '@actions/core'
import * as rest from '@octokit/rest'
-import {Context} from '@actions/github/lib/context'
function getRequiredEnv(key: string): string {
const value = process.env[key]
@@ -19,17 +18,11 @@ function verboseOutput(name: string, value: string): void {
async function getPullRequest(
octokit: github.GitHub,
- context: Context,
owner: string,
- repo: string
+ repo: string,
+ pullRequestNumber: number
): Promise<rest.PullsGetResponse> {
- const pullRequestNumber = context.payload.pull_request
- ? context.payload.pull_request.number
- : null
- if (pullRequestNumber === null) {
- throw Error(`Could not find PR number in context payload.`)
- }
- core.info(`pullRequestNumber: ${pullRequestNumber}`)
+ core.info(`Fetching pull request with number: ${pullRequestNumber}`)
const pullRequest = await octokit.pulls.get({
owner,
repo,
@@ -179,88 +172,12 @@ async function addComment(
})
}
-async function getWorkflowId(
- octokit: github.GitHub,
- runId: number,
- owner: string,
- repo: string
-): Promise<number> {
- const reply = await octokit.actions.getWorkflowRun({
- owner,
- repo,
- // eslint-disable-next-line @typescript-eslint/camelcase
- run_id: runId
- })
- core.info(`The source run ${runId} is in ${reply.data.workflow_url} workflow`)
- const workflowIdString = reply.data.workflow_url.split('/').pop() || ''
- if (!(workflowIdString.length > 0)) {
- throw new Error('Could not resolve workflow')
- }
- return parseInt(workflowIdString)
-}
-
-async function getPrWorkflowRunsIds(
- octokit: github.GitHub,
- owner: string,
- repo: string,
- branch: string,
- sha: string,
- skipRunId: number
-): Promise<number[]> {
- const workflowRuns = await octokit.actions.listRepoWorkflowRuns({
- owner,
- repo,
- branch,
- event: 'pull_request',
- status: 'completed',
- // eslint-disable-next-line @typescript-eslint/camelcase
- per_page: 100
- })
- // may be no need to rerun pending/queued runs
- const filteredRunsIds: number[] = []
- const filteredWorklowRunsIds: number[] = []
-
- for (const workflowRun of workflowRuns.data.workflow_runs) {
- const workflowId = parseInt(
- workflowRun.workflow_url.split('/').pop() || '0'
- )
-
- if (
- workflowRun.head_sha === sha &&
- !filteredRunsIds.includes(workflowId) &&
- workflowId !== skipRunId
- ) {
- filteredRunsIds.push(workflowId)
- filteredWorklowRunsIds.push(workflowRun.id)
- }
- }
-
- return filteredWorklowRunsIds
-}
-
-async function rerunWorkflows(
- octokit: github.GitHub,
- owner: string,
- repo: string,
- runIds: number[]
-): Promise<void> {
- core.info(`Rerun worklowws: ${runIds}`)
- for (const runId of runIds) {
- await octokit.actions.reRunWorkflow({
- owner,
- repo,
- // eslint-disable-next-line @typescript-eslint/camelcase
- run_id: runId
- })
- }
-}
-
async function printDebug(
item: object | string | boolean | number,
- description: string
+ description: string = ''
): Promise<void> {
const itemJson = JSON.stringify(item)
- core.info(`\n ######### ${description} ######### \n: ${itemJson}\n\n`)
+ core.debug(`\n ######### ${description} ######### \n: ${itemJson}\n\n`)
}
async function run(): Promise<void> {
@@ -269,31 +186,49 @@ async function run(): Promise<void> {
const requireCommittersApproval =
core.getInput('require_committers_approval') === 'true'
const comment = core.getInput('comment') || ''
+ const pullRequestNumberInput = core.getInput('pullRequestNumber') || 'not set'
const octokit = new github.GitHub(token)
const context = github.context
const repository = getRequiredEnv('GITHUB_REPOSITORY')
const eventName = getRequiredEnv('GITHUB_EVENT_NAME')
- const selfRunId = parseInt(getRequiredEnv('GITHUB_RUN_ID'))
const [owner, repo] = repository.split('/')
- const selfWorkflowId = await getWorkflowId(octokit, selfRunId, owner, repo)
- const branch = context.payload.pull_request?.head.ref
- const sha = context.payload.pull_request?.head.sha
+ let pullRequestNumber: number | undefined
core.info(
`\n############### Set Label When Approved start ##################\n` +
`label: "${userLabel}"\n` +
`requireCommittersApproval: ${requireCommittersApproval}\n` +
- `comment: ${comment}`
+ `comment: ${comment}\n` +
+ `pullRequestNumber: ${pullRequestNumberInput}`
)
- if (eventName !== 'pull_request_review') {
+ if (eventName === 'pull_request_review') {
+ pullRequestNumber = context.payload.pull_request
+ ? context.payload.pull_request.number
+ : undefined
+ if (pullRequestNumber === undefined) {
+ throw Error(`Could not find PR number in context payload.`)
+ }
+ } else if (eventName === 'workflow_run') {
+ if (pullRequestNumberInput === 'not set') {
+ throw Error(
+ `If action is triggered by "workflow_run" then input "pullRequestNumber" is required.`
+ )
+ }
+ pullRequestNumber = parseInt(pullRequestNumberInput)
+ } else {
throw Error(
- `This action is only useful in "pull_request_review" triggered runs and you used it in "${eventName}"`
+ `This action is only useful in "pull_request_review" or "workflow_run" triggered runs and you used it in "${eventName}"`
)
}
// PULL REQUEST
- const pullRequest = await getPullRequest(octokit, context, owner, repo)
+ const pullRequest = await getPullRequest(
+ octokit,
+ owner,
+ repo,
+ pullRequestNumber
+ )
// LABELS
const labelNames = getPullRequestLabels(pullRequest)
@@ -331,24 +266,6 @@ async function run(): Promise<void> {
}
}
- //// Future option to rerun workflows if PR approved
- //// Rerun workflow can have dynamic matrixes which check presence of labels
- //// it is not possible to rerun successful runs
- //// https://github.community/t/cannot-re-run-a-successful-workflow-run-using-the-rest-api/123661
- //
- // if (isLabelShouldBeSet) {
- // const prWorkflowRunsIds = await getPrWorkflowRunsIds(
- // octokit,
- // owner,
- // repo,
- // branch,
- // sha,
- // selfWorkflowId
- // )
- //
- // await rerunWorkflows(octokit, owner, repo, prWorkflowRunsIds)
- // }
-
// OUTPUT
verboseOutput('isApproved', String(isApproved))
verboseOutput('labelSet', String(isLabelShouldBeSet))