Skip to content

Commit

Permalink
Support the workflow_run event (#147)
Browse files Browse the repository at this point in the history
Co-authored-by: Darragh Bailey <dbailey@hpe.com>
Co-authored-by: Darragh Bailey <daragh.bailey@gmail.com>
  • Loading branch information
3 people authored Apr 17, 2021
1 parent e05b62f commit bd5708a
Show file tree
Hide file tree
Showing 9 changed files with 586 additions and 88 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ This will trigger on all pushes and automatically update any pull requests, if c
For more information on customising event triggers, see [Github's documentation](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows#push-event-push).
The following events are supported:
* push
* pull_request
* workflow_run
## Configuration
The following configuration options are supported. To change any of these, simply specify it as an `env` value in your workflow file.
Expand Down Expand Up @@ -101,10 +105,10 @@ Here's a screenshot:
* There is [an open issue in the Github community forum](https://github.saobby.my.eu.orgmunity/t5/GitHub-Actions/Triggering-a-new-workflow-from-another-workflow/td-p/31676) tracking this

## Coming soon
* Conflict handling
* Rebase support
* Label negation support
* Token support in custom merge messages
* `schedule` event support

## Also see
* [automerge](https://github.com/pascalgn/automerge-action/) for automatic merging of PRs
Expand Down
19 changes: 17 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
"@actions/core": "^1.2.6",
"@actions/github": "^4.0.0",
"@octokit/types": "^6.13.0",
"@octokit/webhooks": "^9.0.0",
"@types/node": "^14.14.37",
"@vercel/ncc": "^0.27.0",
"ttypescript": "^1.5.12",
"typescript": "^4.2.4"
},
"devDependencies": {
Expand All @@ -33,16 +35,29 @@
"eslint-plugin-jest": "^24.3.5",
"eslint-plugin-prettier": "^3.3.1",
"jest": "^26.6.3",
"jest-ts-auto-mock": "^2.0.0",
"nock": "^13.0.11",
"prettier": "^2.2.1",
"ts-auto-mock": "^3.1.2",
"ts-jest": "^26.5.4"
},
"jest": {
"preset": "ts-jest",
"clearMocks": true,
"collectCoverage": true,
"coverageDirectory": "coverage",
"coverageProvider": "v8",
"testEnvironment": "node"
"globals": {
"ts-jest": {
"compiler": "ttypescript"
}
},
"preset": "ts-jest",
"setupFiles": [
"<rootDir>/test/config.ts"
],
"testEnvironment": "node",
"transform": {
".(ts|tsx)": "ts-jest"
}
}
}
96 changes: 67 additions & 29 deletions src/autoupdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,87 @@ import * as github from '@actions/github';
import { GitHub } from '@actions/github/lib/utils';
import * as ghCore from '@actions/core';
import * as octokit from '@octokit/types';
import {
PullRequestEvent,
PushEvent,
Repository,
WebhookEvent,
WorkflowRunEvent,
} from '@octokit/webhooks-definitions/schema';
import { ConfigLoader } from './config-loader';
import { Endpoints } from '@octokit/types';

type PullRequest =
| PullRequestResponse['data']
| PullRequestEvent['pull_request'];
type PullRequestResponse = Endpoints['GET /repos/{owner}/{repo}/pulls/{pull_number}']['response'];
type MergeParameters = Endpoints['POST /repos/{owner}/{repo}/merges']['parameters'];

export class AutoUpdater {
eventData: any;
// See https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads
eventData: WebhookEvent;
config: ConfigLoader;
octokit: InstanceType<typeof GitHub>;

constructor(
config: ConfigLoader,
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
eventData: any,
) {
constructor(config: ConfigLoader, eventData: WebhookEvent) {
this.eventData = eventData;
this.config = config;
this.octokit = github.getOctokit(this.config.githubToken());
}

async handlePush(): Promise<number> {
const { ref, repository } = this.eventData;
const { ref, repository } = this.eventData as PushEvent;

ghCore.info(`Handling push event on ref '${ref}'`);

return await this.pulls(ref, repository);
}

async handlePullRequest(): Promise<boolean> {
const { action, pull_request } = this.eventData as PullRequestEvent;

ghCore.info(`Handling pull_request event triggered by action '${action}'`);

const isUpdated = await this.update(pull_request);
if (isUpdated) {
ghCore.info(
'Auto update complete, pull request branch was updated with changes from the base branch.',
);
} else {
ghCore.info('Auto update complete, no changes were made.');
}

return isUpdated;
}

async handleWorkflowRun(): Promise<number> {
const { workflow_run: workflowRun, repository } = this
.eventData as WorkflowRunEvent;
const { head_branch: branch, event } = workflowRun;

if (!['push', 'pull_request'].includes(event)) {
ghCore.error(
`workflow_run events triggered via ${event} workflows are not supported.`,
);
return 0;
}

// This may not be possible given the check above, but here for safety.
if (!branch) {
ghCore.warning('Event was not on a branch, skipping.');
return 0;
}

ghCore.info(
`Handling workflow_run event triggered by '${event}' on '${branch}'`,
);

// The `pull_request` event is handled the same way as `push` as we may
// get multiple PRs.
return await this.pulls(`refs/heads/${branch}`, repository);
}

async pulls(ref: string, repository: Repository): Promise<number> {
if (!ref.startsWith('refs/heads/')) {
ghCore.warning('Push event was not on a branch, skipping.');
return 0;
Expand All @@ -37,7 +92,7 @@ export class AutoUpdater {

let updated = 0;
const paginatorOpts = this.octokit.pulls.list.endpoint.merge({
owner: repository.owner.name,
owner: repository.owner.name || repository.owner.login,
repo: repository.name,
base: baseBranch,
state: 'open',
Expand Down Expand Up @@ -66,24 +121,7 @@ export class AutoUpdater {
return updated;
}

async handlePullRequest(): Promise<boolean> {
const { action } = this.eventData;

ghCore.info(`Handling pull_request event triggered by action '${action}'`);

const isUpdated = await this.update(this.eventData.pull_request);
if (isUpdated) {
ghCore.info(
'Auto update complete, pull request branch was updated with changes from the base branch.',
);
} else {
ghCore.info('Auto update complete, no changes were made.');
}

return isUpdated;
}

async update(pull: PullRequestResponse['data']): Promise<boolean> {
async update(pull: PullRequest): Promise<boolean> {
const { ref } = pull.head;
ghCore.info(`Evaluating pull request #${pull.number}...`);

Expand Down Expand Up @@ -131,7 +169,7 @@ export class AutoUpdater {
return true;
}

async prNeedsUpdate(pull: PullRequestResponse['data']): Promise<boolean> {
async prNeedsUpdate(pull: PullRequest): Promise<boolean> {
if (pull.merged === true) {
ghCore.warning('Skipping pull request, already merged.');
return false;
Expand Down Expand Up @@ -170,7 +208,7 @@ export class AutoUpdater {
if (excludedLabels.length > 0) {
for (const label of pull.labels) {
if (label.name === undefined) {
ghCore.warning(`Label name is undefined, continuing.`);
ghCore.debug(`Label name is undefined, continuing.`);
continue;
}
if (excludedLabels.includes(label.name)) {
Expand Down Expand Up @@ -209,7 +247,7 @@ export class AutoUpdater {

for (const label of pull.labels) {
if (label.name === undefined) {
ghCore.warning(`Label name is undefined, continuing.`);
ghCore.debug(`Label name is undefined, continuing.`);
continue;
}

Expand Down
12 changes: 5 additions & 7 deletions src/router.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { WebhookEvent } from '@octokit/webhooks-definitions/schema';
import { AutoUpdater } from '../src/autoupdater';
import { ConfigLoader } from '../src/config-loader';

export class Router {
eventData: any;
updater: AutoUpdater;

constructor(
config: ConfigLoader,
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
eventData: any,
) {
constructor(config: ConfigLoader, eventData: WebhookEvent) {
this.updater = new AutoUpdater(config, eventData);
}

Expand All @@ -24,9 +20,11 @@ export class Router {
await this.updater.handlePullRequest();
} else if (eventName === 'push') {
await this.updater.handlePush();
} else if (eventName === 'workflow_run') {
await this.updater.handleWorkflowRun();
} else {
throw new Error(
`Unknown event type '${eventName}', only 'push' and 'pull_request' are supported.`,
`Unknown event type '${eventName}', only 'push', 'pull_request' and 'workflow_run' are supported.`,
);
}
}
Expand Down
Loading

0 comments on commit bd5708a

Please sign in to comment.