1
0
mirror of https://github.com/tektoncd/catalog.git synced 2024-11-21 05:55:35 +00:00

Add support for comment update to github comment task

Enhance the GitHub add comment task with the ability to update
a comment if applicable. This achieved by tagging comments with
and invisible (HTML comment) unique text, and looking for that
text to identify a comment.

This does not use the nodeid because that is generated by GitHub
and it would require task users to store known node IDs somewhere
across task executions.

Signed-off-by: Andrea Frittoli <andrea.frittoli@gmail.com>
This commit is contained in:
Andrea Frittoli 2021-03-26 15:44:18 +00:00 committed by tekton-robot
parent 52b1848b00
commit 66df9ddf53
5 changed files with 374 additions and 0 deletions

View File

@ -0,0 +1,148 @@
# Add a comment to an issue or a pull request
The `github-add-comment` task let you add a comment to a pull request or an
issue.
## Changelog
- Added support for replacing a comment. It works by adding an invisible tag into the comment, which allows for
later identification and update of the comment. It introduces two new parameters: `COMMENT_TAG` and `REPLACE`.
## Install the Task
```
kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/github-add-comment/0.4/github-add-comment.yaml
```
## Secrets
This Task requires access to a GitHub token set via a Kubernetes Secret. By default, the name of this Secret should be `github` and the secret key should be `token`, but you can configure this via the `GITHUB_TOKEN_SECRET_NAME` and `GITHUB_TOKEN_SECRET_KEY` [parameters](#parameters) described below.
To create such a Secret via `kubectl`:
```
kubectl create secret generic github --from-literal token="MY_TOKEN"
```
Check [this](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) to get personal access token for `Github`.
See GitHub's documentation on [Understanding scopes for OAuth Apps](https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/) to figure out what scopes you need to give to this token to add comment to an issue or a pull request.
## Parameters
- **GITHUB_HOST_URL:**: The GitHub host domain (_default:_ `api.github.com`)
- **API_PATH_PREFIX:**: The GitHub Enterprise has a prefix for the API path. _e.g:_ `/api/v3`
- **REQUEST_URL:**: The GitHub pull request or issue url, _e.g:_
`https://github.com/tektoncd/catalog/issues/46`
- **COMMENT_OR_FILE:**: The actual comment to add or the filename inside the
optional workspace `comment-file` containing comment to post. _e.g:_ `don't forget to eat your vegetables before commiting.` _or_ `input.txt`
- **COMMENT_TAG:**: An invisible tag to be added into the comment. The tag is
made invisible by embedding in an an HTML comment. The tag allows
for later retrieval of the comment, and it allows replacing an existing comment. _e.g._ `myservice.[commit-sha]`. (_default:_ `""`).
- **REPLACE:**: When a tag is specified, and `REPLACE` is `true`, look for a
comment with a matching tag and replace it with the new comment. (_default:_ `false`).
- **GITHUB_TOKEN_SECRET_NAME**: The name of the Kubernetes Secret that
contains the GitHub token. (_default:_ `github`).
- **GITHUB_TOKEN_SECRET_KEY**: The key within the Kubernetes Secret that contains the GitHub token. (_default:_ `token`).
## Results
- **OLD_COMMENT:**: The old text of the comment, if any.
- **NEW_COMMENT:**: The new text of the comment, if any.
## Workspaces
- **comment-file**: The optional workspace containing comment file to be posted.
## Usage
This TaskRun add a comment to an issue.
```yaml
---
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
labels:
tekton.dev/task: github-add-comment
name: github-add-comment-to-pr-22
spec:
taskRef:
kind: Task
name: github-add-comment
params:
- name: REQUEST_URL
value: https://github.com/chmouel/scratchpad/pull/46
- name: COMMENT_OR_FILE
value: |
The cat went here and there
And the moon spun round like a top,
And the nearest kin of the moon,
The creeping cat, looked up.
Black Minnaloushe stared at the moon,
For, wander and wail as he would,
The pure cold light in the sky
Troubled his animal blood.
```
### When passing a comment via file
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: comment-cm
data:
input.txt: |
This is the sample input comment via file.
---
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
labels:
tekton.dev/task: github-add-comment
name: github-add-comment-to-pr-22
spec:
taskRef:
kind: Task
name: github-add-comment
workspace:
- name: comment-file
configMap:
name: comment-cm
params:
- name: REQUEST_URL
value: https://github.com/chmouel/scratchpad/pull/46
- name: COMMENT_OR_FILE
value: "input.txt"
```
### This TaskRun replaces a comment in an issue
```yaml
---
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: github-add-comment-to-pr-22
spec:
taskRef:
kind: Task
name: github-add-comment
params:
- name: REQUEST_URL
value: https://github.com/chmouel/scratchpad/pull/46
- name: COMMENT_TAG
value: catalog-sha123abc
- name: REPLACE
value: "true"
- name: COMMENT_OR_FILE
value: |
The cat went here and there
And the moon spun round like a top,
And the nearest kin of the moon,
The creeping cat, looked up.
Black Minnaloushe stared at the moon,
For, wander and wail as he would,
The pure cold light in the sky
Troubled his animal blood.

View File

@ -0,0 +1,184 @@
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: github-add-comment
labels:
app.kubernetes.io/version: "0.4"
annotations:
tekton.dev/pipelines.minVersion: "0.17.0"
tekton.dev/tags: github
tekton.dev/displayName: "add github comment"
spec:
description: >-
This Task will add a comment to a pull request or an issue.
It can take either a filename or a comment as input and can
post the comment back to GitHub accordingly.
workspaces:
- name: comment-file
optional: true
description: The optional workspace containing comment file to be posted.
results:
- name: OLD_COMMENT
description: The old text of the comment, if any.
- name: NEW_COMMENT
description: The new text of the comment, if any.
params:
- name: GITHUB_HOST_URL
description: |
The GitHub host, adjust this if you run a GitHub enteprise.
default: "api.github.com"
type: string
- name: API_PATH_PREFIX
description: |
The API path prefix, GitHub Enterprise has a prefix e.g. /api/v3
default: ""
type: string
- name: REQUEST_URL
description: |
The GitHub issue or pull request URL where we want to add a new
comment.
type: string
- name: COMMENT_OR_FILE
description: |
The actual comment to add or the filename containing comment to post.
type: string
- name: GITHUB_TOKEN_SECRET_NAME
description: |
The name of the Kubernetes Secret that contains the GitHub token.
type: string
default: github
- name: GITHUB_TOKEN_SECRET_KEY
description: |
The key within the Kubernetes Secret that contains the GitHub token.
type: string
default: token
- name: COMMENT_TAG
description: |
An invisible tag to be added into the comment. The tag is made
invisible by embedding in an an HTML comment. The tag allows for later
retrieval of the comment, and it allows replacing an existing comment.
type: string
default: ""
- name: REPLACE
description: |
When a tag is specified, and `REPLACE` is `true`, look for a comment
with a matching tag and replace it with the new comment.
type: string
default: "false" # Alternative value: "true"
steps:
- name: post-comment
workingDir: $(workspaces.comment-file.path)
env:
- name: GITHUBTOKEN
valueFrom:
secretKeyRef:
name: $(params.GITHUB_TOKEN_SECRET_NAME)
key: $(params.GITHUB_TOKEN_SECRET_KEY)
image: registry.access.redhat.com/ubi8/ubi-minimal:8.2
script: |
#!/usr/libexec/platform-python
import json
import os
import http.client
import sys
import urllib.parse
split_url = urllib.parse.urlparse(
"$(params.REQUEST_URL)").path.split("/")
# This will convert https://github.com/foo/bar/pull/202 to
# api url path /repos/foo/issues/
api_url = "{base}/repos/{package}/issues/{id}".format(
base="", package="/".join(split_url[1:3]), id=split_url[-1])
commentParamValue = "$(params.COMMENT_OR_FILE)"
# check if workspace is bound and parameter passed is a filename or not
if "$(workspaces.comment-file.bound)" == "true" and os.path.exists(commentParamValue):
commentParamValue = open(commentParamValue, "r").read()
# If a tag was specified, append it to the comment
if "$(params.COMMENT_TAG)":
commentParamValue += "<!-- {tag} -->".format(tag="$(params.COMMENT_TAG)")
data = {
"body": commentParamValue,
}
# This is for our fake github server
if "$(params.GITHUB_HOST_URL)".startswith("http://"):
conn = http.client.HTTPConnection("$(params.GITHUB_HOST_URL)".replace("http://", ""))
else:
conn = http.client.HTTPSConnection("$(params.GITHUB_HOST_URL)")
# If REPLACE is true, we need to search for comments first
matching_comment = ""
if "$(params.REPLACE)" == "true":
if not "$(params.COMMENT_TAG)":
print("REPLACE requested but no COMMENT_TAG specified")
sys.exit(1)
r = conn.request(
"GET",
api_url + "/comments",
headers={
"User-Agent": "TektonCD, the peaceful cat",
"Authorization": "Bearer " + os.environ["GITHUBTOKEN"],
})
resp = conn.getresponse()
if not str(resp.status).startswith("2"):
print("Error: %d" % (resp.status))
print(resp.read())
sys.exit(1)
print(resp.status)
comments = json.loads(resp.read())
print(comments)
# If more than one comment is found take the last one
matching_comment = [x for x in comments if '$(params.COMMENT_TAG)' in x['body']][-1:]
if matching_comment:
with open("$(results.OLD_COMMENT.path)", "w") as result_old:
result_old.write(str(matching_comment[0]))
matching_comment = matching_comment[0]['url']
if matching_comment:
method = "PATCH"
target_url = urllib.parse.urlparse(matching_comment).path
else:
method = "POST"
target_url = api_url + "/comments"
print("Sending this data to GitHub with {}: ".format(method))
print(data)
r = conn.request(
method,
target_url,
body=json.dumps(data),
headers={
"User-Agent": "TektonCD, the peaceful cat",
"Authorization": "Bearer " + os.environ["GITHUBTOKEN"],
})
resp = conn.getresponse()
if not str(resp.status).startswith("2"):
print("Error: %d" % (resp.status))
print(resp.read())
else:
with open("$(results.NEW_COMMENT.path)", "wb") as result_new:
result_new.write(resp.read())
print("a GitHub comment has been {} to $(params.REQUEST_URL)".format(
"updated" if matching_comment else "added"))

View File

@ -0,0 +1,8 @@
---
headers:
method: POST
path: /repos/{repo:[^/]+/[^/]+}/issues/{issue:[0-9]+}/comments
response:
status: 200
output: '{"status": 200}'
content-type: text/json

View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
kubectl -n ${tns} create secret generic github --from-literal token="secret"

View File

@ -0,0 +1,31 @@
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: github-add-comment-test
spec:
workspaces:
- name: comment-file
optional: true
tasks:
- name: add-comment
taskRef:
name: github-add-comment
workspaces:
- name: comment-file
workspace: comment-file
params:
- name: GITHUB_HOST_URL
value: http://127.0.0.1:8080
- name: COMMENT_OR_FILE
value: "Hello from TektonCD test"
- name: REQUEST_URL
value: https://github.com/tektoncd/catalog/issues/1
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: github-add-comment-test-run
spec:
pipelineRef:
name: github-add-comment-test