Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/pull-request-automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ on:
pull_request_target:
types: [opened]
push:
workflow_run:
workflows: [Build Gutenberg Plugin Zip]
types: [completed, in_progress]
name: Pull request automation

jobs:
pull-request-automation:
runs-on: ubuntu-latest
if: ${{ github.repository == 'WordPress/gutenberg' }}
if: ${{ true || github.repository == 'WordPress/gutenberg' }}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I made this always true to test on personal repo, should be removed on trunk

strategy:
matrix:
node: ['16']
Expand Down
5 changes: 5 additions & 0 deletions packages/project-management-automation/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const assignFixedIssues = require( './tasks/assign-fixed-issues' );
const firstTimeContributorAccountLink = require( './tasks/first-time-contributor-account-link' );
const firstTimeContributorLabel = require( './tasks/first-time-contributor-label' );
const addMilestone = require( './tasks/add-milestone' );
const prPreviewLink = require( './tasks/pr-preview-link' );
const debug = require( './debug' );

/**
Expand Down Expand Up @@ -52,6 +53,10 @@ const automations = [
event: 'push',
task: addMilestone,
},
{
event: 'workflow_run',
task: prPreviewLink,
},
];

( async function main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// @ts-nocheck

/**
* Internal dependencies
*/
const debug = require( '../../debug' );

/** @typedef {ReturnType<import('@actions/github').getOctokit>} GitHub */
/** @typedef {any} WorkflowRunEvent */

/**
* Identifier used to find existing comment.
*
* @type {string}
*/
const COMMENT_PLACEHOLDER = 'gutenberg-run-placeholder:cmt@v1';

const createBuildSummary = async (
{ buildStatus, latestCommit, pullRequestNumber, artifact },
octokit
) => {
let status, previewMsg, artifactMsg;
status = previewMsg = artifactMsg = '🚧 Building in progress...';
if ( buildStatus === 'success' ) {
status = '✅ Build successful!';
previewMsg = `🔗 [gutenberg.run/${ pullRequestNumber }](gutenberg.run/${ pullRequestNumber } )`;
artifactMsg = `📦 [gutenberg-plugin](${ artifact.url }) - ${ artifact.size } MB`;
} else if ( buildStatus === 'failure' ) {
status = previewMsg = artifactMsg = '🚫 Build failed!';
}

const response = await octokit.rest.markdown.render( {
mode: 'gfm',
text: `
# Gutenberg Plugin build status
| Name | Result |
| ----------------------- | - |
| **Last commit:** | ${ latestCommit } |
| **Status**: | ${ status } |
| **Preview URL**: | ${ previewMsg } |
| **Gutenberg plugin zip**: | ${ artifactMsg } |
`,
} );
return `<!--${ COMMENT_PLACEHOLDER }-->${ response.data }`;
};

const writeComment = async (
{ owner, repo, pullRequestNumber, commentBody },
octokit
) => {
debug( 'pr-preview-link: Find and replace build status comment' );
// First check if there is already a comment from this action
const comments = await octokit.rest.issues.listComments( {
issue_number: pullRequestNumber,
owner,
repo,
} );

const existingComment = comments.data.filter( ( comment ) =>
comment.body.includes( COMMENT_PLACEHOLDER )
);

if ( existingComment.length ) {
await octokit.rest.issues.updateComment( {
owner,
repo,
comment_id: existingComment[ 0 ].id,
body: commentBody,
} );
} else {
await octokit.rest.issues.createComment( {
owner,
repo,
issue_number: pullRequestNumber,
body: commentBody,
} );
}
};

/**
* Adds a comment to new PRs with a link to the corresponding gutenberg.run preview site.
*
* @param {WorkflowRunEvent} payload Workflow Run event payload.
* @param {GitHub} octokit Initialized Octokit REST client.
*/
async function prPreviewLink( payload, octokit ) {
const action = payload.action;
const repo = payload.repository.name;
const owner = payload.repository.owner.login;
const repoHtmlUrl = payload.repository.html_url;
const workflowRun = payload.workflow_run;
const workflowRunId = workflowRun.id;
const pullRequestNumber = workflowRun.pull_requests[ 0 ].number;
const checkSuiteId = workflowRun.check_suite_id;
const latestCommit = `${ repoHtmlUrl }/pull/${ pullRequestNumber }/commits/${ workflowRun.head_sha }`;

if ( action === 'in_progress' ) {
const commentBody = await createBuildSummary(
{
buildStatus: action,
latestCommit,
pullRequestNumber,
artifact: null,
},
octokit
);

await writeComment(
{ owner, repo, pullRequestNumber, commentBody },
octokit
);
}

if ( action === 'completed' ) {
debug( 'pr-preview-link: Build complete, request artifact from API' );
const artifactsResponse =
await octokit.rest.actions.listWorkflowRunArtifacts( {
owner,
repo,
run_id: workflowRunId,
name: 'gutenberg-plugin',
per_page: 1,
} );
const artifacts = artifactsResponse.data.artifacts;

let commentBody;
if ( ! artifacts.length ) {
debug( 'pr-preview-link: No artifact found, mark as failure' );

commentBody = await createBuildSummary(
{
buildStatus: 'failure',
latestCommit,
pullRequestNumber,
artifactsUrl: null,
},
octokit
);
} else {
debug( 'pr-preview-link: Found artifact, mark as success' );

const artifact = artifacts[ 0 ];
// The artifact URL on Checks screen
const artifactUrl = `${ repoHtmlUrl }/suites/${ checkSuiteId }/artifacts/${ artifact.id }`;
const sizeInMB = artifact.size_in_bytes / ( 1024 * 1024 );
commentBody = await createBuildSummary(
{
buildStatus: 'success',
latestCommit,
pullRequestNumber,
artifact: {
url: artifactUrl,
size: sizeInMB.toFixed( 2 ),
},
},
octokit
);
}

await writeComment(
{ owner, repo, pullRequestNumber, commentBody },
octokit
);
}
}

module.exports = prPreviewLink;