feat: adding support for a proxy

This commit is contained in:
Michael Shick 2020-07-06 21:47:29 -04:00
parent fdfdba3fa2
commit b62030a7fc
No known key found for this signature in database
GPG key ID: ADF5BC9704BB4A61
3 changed files with 96 additions and 17 deletions

View file

@ -4,9 +4,7 @@
## Limitations ## Limitations
Due to how GitHub handles permissions in PRs coming from forks, this action is limited to PRs based on branches. See this issue: https://github.community/t/github-actions-are-severely-limited-on-prs/18179/4 for more detail. Due to how GitHub handles permissions in PRs coming from forks you will need to deploy an app if you want to post comments in those situations. [See below](#proxy-for-fork-based-prs).
I'm currently investigating a workaround via a simple bot you can easily deploy. More soon...
## Usage ## Usage
@ -60,6 +58,31 @@ jobs:
| allow-repeats | with | A boolean flag to allow identical messages to be posted each time this action is run | no | false | | allow-repeats | with | A boolean flag to allow identical messages to be posted each time this action is run | no | false |
| GITHUB_TOKEN | env | A valid GitHub token, can alternatively be defined in the env | maybe | | | GITHUB_TOKEN | env | A valid GitHub token, can alternatively be defined in the env | maybe | |
## Proxy for Fork-based PRs
GitHub limits `GITHUB_TOKEN` and other API access token permissions when creating a PR from a fork. This makes it impossible to add comments when your PRs are coming from forks, which is the norm for open source projects. To work around this situation I've created a simple companion app you can deploy to Cloud Run or another environment to proxy the create comment requests and escalate the token privileges.
See this issue: https://github.community/t/github-actions-are-severely-limited-on-prs/18179/4 for more detail.
**Example**
```yaml
on:
pull_request:
jobs:
pr:
runs-on: ubuntu-latest
steps:
- uses: mshick/add-pr-comment@v1
with:
message: |
**Howdie!**
proxy-url: https://add-pr-comment-proxy-94idvmwyie-uc.a.run.app/
proxy-secret: foobar
repo-token: ${{ secrets.GITHUB_TOKEN }}
```
## Features ## Features
- Fast, runs in the GitHub Actions node.js runtime; no Docker pull needed. - Fast, runs in the GitHub Actions node.js runtime; no Docker pull needed.

View file

@ -14,6 +14,12 @@ inputs:
description: "Allow messages to be repeated." description: "Allow messages to be repeated."
required: false required: false
default: "false" default: "false"
proxy-url:
description: "Proxy URL for comment creation"
required: false
proxy-secret:
description: "A secret to use for authenticating against the proxy"
required: false
branding: branding:
icon: message-circle icon: message-circle
color: purple color: purple

View file

@ -4,13 +4,7 @@ import {HttpClient} from '@actions/http-client'
import {Endpoints, RequestHeaders, IssuesListCommentsResponseData} from '@octokit/types' import {Endpoints, RequestHeaders, IssuesListCommentsResponseData} from '@octokit/types'
type ListCommitPullsResponse = Endpoints['GET /repos/:owner/:repo/commits/:commit_sha/pulls']['response']['data'] type ListCommitPullsResponse = Endpoints['GET /repos/:owner/:repo/commits/:commit_sha/pulls']['response']['data']
type CreateIssueCommentResponseData = Endpoints['POST /repos/:owner/:repo/issues/:issue_number/comments']['response']['data']
interface AddPrCommentInputs {
allowRepeats: boolean
message: string
repoToken?: string
repoTokenUserLogin?: string
}
interface ListCommitPullsParams { interface ListCommitPullsParams {
repoToken: string repoToken: string
@ -40,6 +34,35 @@ const listCommitPulls = async (params: ListCommitPullsParams): Promise<ListCommi
const getIssueNumberFromCommitPullsList = (commitPullsList: ListCommitPullsResponse): number | null => const getIssueNumberFromCommitPullsList = (commitPullsList: ListCommitPullsResponse): number | null =>
commitPullsList.length ? commitPullsList[0].number : null commitPullsList.length ? commitPullsList[0].number : null
interface CreateCommentProxyParams {
repoToken: string
body: string
owner: string
repo: string
issueNumber: number
proxyUrl: string
proxySecret: string
}
const createCommentProxy = async (params: CreateCommentProxyParams): Promise<CreateIssueCommentResponseData | null> => {
const {repoToken, owner, repo, issueNumber, body, proxyUrl, proxySecret} = params
const http = new HttpClient('http-client-add-pr-comment')
const additionalHeaders: RequestHeaders = {
authorization: `basic ${Buffer.from(proxySecret + ':').toString('base64')}`,
['temporary-github-token']: repoToken,
}
const response = await http.postJson<CreateIssueCommentResponseData>(
`${proxyUrl}/repos/${owner}/${repo}/issues/${issueNumber}/comments`,
{body},
additionalHeaders,
)
return response.result
}
const isMessagePresent = ( const isMessagePresent = (
message: AddPrCommentInputs['message'], message: AddPrCommentInputs['message'],
comments: IssuesListCommentsResponseData, comments: IssuesListCommentsResponseData,
@ -58,10 +81,21 @@ const isMessagePresent = (
}) })
} }
interface AddPrCommentInputs {
allowRepeats: boolean
message: string
proxySecret?: string
proxyUrl?: string
repoToken?: string
repoTokenUserLogin?: string
}
const getInputs = (): AddPrCommentInputs => { const getInputs = (): AddPrCommentInputs => {
return { return {
allowRepeats: Boolean(core.getInput('allow-repeats') === 'true'), allowRepeats: Boolean(core.getInput('allow-repeats') === 'true'),
message: core.getInput('message'), message: core.getInput('message'),
proxySecret: core.getInput('proxy-secret'),
proxyUrl: core.getInput('proxy-url'),
repoToken: core.getInput('repo-token') || process.env['GITHUB_TOKEN'], repoToken: core.getInput('repo-token') || process.env['GITHUB_TOKEN'],
repoTokenUserLogin: core.getInput('repo-token-user-login'), repoTokenUserLogin: core.getInput('repo-token-user-login'),
} }
@ -69,7 +103,7 @@ const getInputs = (): AddPrCommentInputs => {
const run = async (): Promise<void> => { const run = async (): Promise<void> => {
try { try {
const {allowRepeats, message, repoToken, repoTokenUserLogin} = getInputs() const {allowRepeats, message, repoToken, repoTokenUserLogin, proxyUrl, proxySecret} = getInputs()
if (!repoToken) { if (!repoToken) {
throw new Error('no github token provided, set one with the repo-token input or GITHUB_TOKEN env variable') throw new Error('no github token provided, set one with the repo-token input or GITHUB_TOKEN env variable')
@ -125,12 +159,28 @@ const run = async (): Promise<void> => {
} }
if (shouldCreateComment) { if (shouldCreateComment) {
await octokit.issues.createComment({ if (proxyUrl) {
owner, if (!proxySecret) {
repo, throw new Error('proxy-url defined, but proxy-secret is missing')
issue_number: issueNumber, }
body: message,
}) await createCommentProxy({
owner,
repo,
issueNumber,
body: message,
repoToken,
proxyUrl,
proxySecret,
})
} else {
await octokit.issues.createComment({
owner,
repo,
issue_number: issueNumber,
body: message,
})
}
core.setOutput('comment-created', 'true') core.setOutput('comment-created', 'true')
} else { } else {