Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comment On Forks Instead Writes To Artifact #322

Merged
merged 22 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all 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: 5 additions & 0 deletions .changes/comment-error-to-artifact.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"action": patch
---

On comment post error, upload the content instead as an artifact. This prevents the workflow from failing on a fork, and allows another workflow with permissions to handle the work from there.
2 changes: 1 addition & 1 deletion .github/workflows/comment-on-forks.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Covector Comment
name: covector comment on forks

on:
workflow_run:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run-on-pr.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: covector
name: covector status
on: pull_request

jobs:
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ Below is a list of all of the packages within this repository. The usage and doc
| [@covector/command](./packages/command) | [![npm](https://img.shields.io/npm/v/@covector/command?style=for-the-badge)](https://www.npmjs.com/package/@covector/command) | [./packages/command/CHANGELOG.md](https://github.com/jbolda/covector/blob/main/packages/command/CHANGELOG.md) |
| [@covector/files](./packages/files) | [![npm](https://img.shields.io/npm/v/@covector/files?style=for-the-badge)](https://www.npmjs.com/package/@covector/files) | [./packages/files/CHANGELOG.md](https://github.com/jbolda/covector/blob/main/packages/files/CHANGELOG.md) |


## Prior Art

We drew on inspiration from [changesets](https://github.com/atlassian/changesets) which specifically focuses on the npm ecosystem with the expectation to publish to [npmjs.com](https://www.npmjs.com/). We had a need for much greater flexibility, primarily around additional languages, which changesets wasn't looking to handle. You may notice some similarities around the markdown based change files, and it begins to diverge from there. Since we started the codebase from scratch, it also opened the door for incredibly flexible and unique publishing schemes, deep changelogs, and the ability to publish to any "target" with any "asset" (such as publishing a website, a github action or a vscode extension even!).
Expand Down
13 changes: 7 additions & 6 deletions package-lock.json

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

36 changes: 36 additions & 0 deletions packages/action/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,39 @@ Besides these static outputs, we also supply dynamic outputs for each of your pa
Outputs will generally be specified in the [action.yml](./action.yml), but since these are dynamic, it is not possible. See the [docs noting this is an optional required](https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#outputs).

> If you don't declare an output in your action metadata file, you can still set outputs and use them in a workflow.

## Comments On Forks

The action runs in a reduced-permission environment on forks which will cause an API call to add a comment to fail. To work around this, with `comment: true` specified, it will upload the comment content as an artifact to the workflow if it fails. With the following additional workflow, it will pick up that workflow completion and post the comment as `workflow_run` has normal repository permissions.

```yml
name: Covector Comment

on:
workflow_run:
workflows: [covector status] # the `name` of the workflow run on `pull_request` running `status` with `comment: true`
types:
- completed

# note all other permissions are set to none if not specified
permissions:
# to read the action artifacts
actions: read
# to write the comment
pull-requests: write
# note that these set the permissions for `secrets.GITHUB_TOKEN`
# if you plan to use your own token, use `permissions: {}` instead
# to completely remove all default permissions for added security

jobs:
download:
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion == 'success' &&
(github.event.workflow_run.head_repository.full_name != github.repository || github.actor == 'dependabot[bot]')
steps:
- name: covector status
uses: jbolda/covector/packages/action@covector-v0
with:
token: ${{ secrets.GITHUB_TOKEN }}
command: "status"
```
1 change: 1 addition & 0 deletions packages/action/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"clean": "echo noop"
},
"dependencies": {
"@actions/artifact": "^2.1.7",
"@actions/core": "^1.10.1",
"@actions/github": "^5.1.1",
"effection": "^2.0.6",
Expand Down
69 changes: 52 additions & 17 deletions packages/action/src/comment/postGithubComment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { GitHub } from "@actions/github/lib/utils";
import { DefaultArtifactClient } from "@actions/artifact";
import fs from "node:fs/promises";
import path from "node:path";
import type { GitHub } from "@actions/github/lib/utils";
import { Operation } from "effection";
import { Logger } from "@covector/types";

Expand All @@ -9,13 +12,15 @@ export function* postGithubComment({
repo,
owner,
prNumber: issue_number,
artifactOnFailure = true,
}: {
logger: Logger;
comment: string;
octokit: InstanceType<typeof GitHub>;
repo: string;
owner: string;
prNumber: number;
artifactOnFailure?: boolean;
}): Operation<void> {
const tag = "<!-- Covector Action -->\n";
const body = tag + comment;
Expand All @@ -30,21 +35,51 @@ export function* postGithubComment({
comment.body.includes(tag)
);

if (previousComment) {
logger.info("Updating comment in pull request.");
yield octokit.rest.issues.updateComment({
owner,
repo,
comment_id: previousComment.id,
body,
});
} else {
logger.info("Posting comment in pull request.");
yield octokit.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
// this can fail if the token doesn't have permissions
try {
if (previousComment) {
logger.info("Updating comment in pull request.");
yield octokit.rest.issues.updateComment({
owner,
repo,
comment_id: previousComment.id,
body,
});
} else {
logger.info("Posting comment in pull request.");
yield octokit.rest.issues.createComment({
owner,
repo,
issue_number,
body,
});
}
} catch (error) {
if (artifactOnFailure) {
logger.error("Posting comment failed, creating artifact instead.");
const artifactRoot = process.env.RUNNER_TEMP ?? "..";

const artifactFilename = "./covector-comment.md";
const artifactAbsolutePath = path.join(artifactRoot, artifactFilename);
logger.debug(`Writing comment body to ${artifactAbsolutePath}`);
yield fs.writeFile(artifactAbsolutePath, body);

const artifactPRNumber = "./covector-prNumber.md";
const prNumberAbsolutePath = path.join(artifactRoot, artifactPRNumber);
yield fs.writeFile(prNumberAbsolutePath, issue_number.toString());

const artifact = new DefaultArtifactClient();
logger.debug(`Uploading comment from ${artifactAbsolutePath}`);
yield artifact.uploadArtifact(
"covector-comment",
[artifactAbsolutePath, prNumberAbsolutePath],
artifactRoot,
{
retentionDays: 1,
}
);
} else {
logger.fatal(`Posting comment failed.`);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,6 @@ export function* postGithubCommentFromArtifact({
repo,
owner,
prNumber,
artifactOnFailure: false,
});
}
Loading