Skip to content

Commit

Permalink
Add Task equivlalent of PullRequest PipelineResource ⚗️
Browse files Browse the repository at this point in the history
With the addition of workspaces and results, we are exploring a world
without PipelineResources! (see
tektoncd/pipeline#1673)

To that end, this commit adds a Task that does the same things as the
PullRequest PipelineResource. It still uses the same underlying image,
pullrequest-init, which is currently built and published as part of the
Tekton Pipelines release, but which one day may be in another repo and
published separately.

This also includes a "sample" which uses the Task to post a comment on
an existing known PR - the only requirement to run it is a secret that
contains a github token.

Part of tektoncd#95
  • Loading branch information
bobcatfish committed Mar 5, 2020
1 parent 7082865 commit f9e2515
Show file tree
Hide file tree
Showing 34 changed files with 927 additions and 0 deletions.
4 changes: 4 additions & 0 deletions pullrequest/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
approvers:
- bobcatfish
- wlynch
- chmouel
195 changes: 195 additions & 0 deletions pullrequest/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# Generic PullRequest interaction

This Task allows a user to interact with an SCM (source control management) system through an abstracted interface
(implemented uisng [jenkins-x/go-scm](https://github.com/jenkins-x/go-scm)).

* [Install the Task](#install-the-tasks)
* [Configure the Task](#configure-the-tasks)
* [Usage](#usage)
* [PullRequest Image](#pullrequest-image)

_This `Task` works with both public SCM instances and self-hosted/enterprise GitHub/GitLab instances. For a GitHub specific `Task` see [github](../github)._

## Mode: Upload or Download

In `download` mode, this `Task` will look at the state of an existing pull request and populate
[the `pr` workspace](#workspaces) with the state of the pull request, including
the `.MANIFEST` file.

If you want to update or delete existing attributes of a PR, running `download`
first will allow you to use `upload` to make those changes.

In `upload` mode, this `Task` will look at the contents of [the `pr` workspace](#workspaces)
and compare it to the `.MANIFEST` file (if it exists). Any differences will result
in requests being made to bring the Pull Request into the state described in the
workspace.

## Install the Tasks

To install the Task:

```bash
kubectl apply -f pullrequest/pr.yaml
```

## Configuring the Tasks

### Parameters

* `mode` (_Required_)- The [mode ("upload" or "download")](#mode-upload-or-download)
* `url` (_Required_) - The complete URL of the Pull Request, e.g. `https://github.com/bobcatfish/catservice/pull/16`
* `provider` (_Required_) - The type of SCM system, currently `github` or `gitlab`
* `secret-key-ref` (_Required_) - The name of a secret key containing
[the token required for SCM requests](#permissions)
* `insecure-skip-tls-verify` (_Default: `"false"`_) - If `"true"`, certificate validation will be disabled

### Workspaces

The `pr` workspace holds all the data about any labels, statuses, comments you want to update.

The files in the `pr` workspace represent the state of [the configured PR](#parameters),
i.e. the current state when using [download mode](#mode-uploapr-sample-add-comment-q26vrd-or-download) and/or
the desired state when using [upload mode](#mode-upload-or-download).

The structure of the workspace is:

* `/labels/<label>` - These are empty files, the name of the file is the name of the label
(URL encode non-URL safe characters).
* `/status/<status>` - These are [json files that represent statuses](#statuses)
* `/comments/<comment>` - These are [json files that represent comments](#comments)
* `base.json` - Information about the base commit of the PR
* `head.json` - Information about the head commit of the PR
* `pr.json` - Information about the PR

When populated via [download](#mode-upload-or-download), the file `.MANIFEST` is
populated and used to represent the current state of the Pull Request; before
[upload](#mode-upload-or-download) mutates the the Pull Request it will compare
the contents of the `pr` workspace to this file to determine what has changed.

_See [pr-example](.pr-example) for an example of a `pr` workspace poulated with comments, labels,
and statuses (.MANIFEST file not included)._

##### statuses

Each status file is a json file containing a dictionary with the following keys:

* `Label`: The name of the status
* `Desc`: (_optional_) A string to associate with the current state of the status
* `Target`: (_optional_) A link to where more information can be found (e.g. link to logs)
* `State`: The state of the status, [valid options](https://github.com/jenkins-x/go-scm/blob/68aae24e07bc56f684a2f2b9da451b2386ca8545/scm/const.go#L29-L50) are:
* `unknown`
* `pending`
* `running`
* `success`
* `failure`
* `cancelled`
* `expected`
* `error`

```json
{
"State": "pending",
"Label": "pull-tekton-pipeline-build-tests",
"Desc": "Job triggered.",
"Target": "https://tekton-releases.appspot.com/build/tekton-prow/pr-logs/pull/tektoncd_pipeline/995/pull-tekton-pipeline-build-tests/1146102490727452672/"
}
```

_See [pr-example/status](.pr-example/status) for examples._

##### comments

The format of the files in `comments` depends on whether
[upload or download mode is being used](#modes-upload-or-download).

_[pipeline#2168](https://github.com/tektoncd/pipeline/issues/2168)_

###### upload mode comments

When uploading comments, the content of the file is used as the body of the comment.

###### download mode comments

Each comment file is a json file containing a dictionary that represents a comment
in a vendor agnostic way [with these keys](https://github.com/jenkins-x/go-scm/blob/68aae24e07bc56f684a2f2b9da451b2386ca8545/scm/issue.go#L54-L61):

* `ID` - Identifier of the comment
* `Body` - Body of the comment
* `Link` - URL that links to the comment
* `Created` - [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) conforming string
* `Updated` - [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) conforming string
* `Author` - Another dictionary representing the user who made the comment
[with the _optional_ keys](https://github.com/jenkins-x/go-scm/blob/68aae24e07bc56f684a2f2b9da451b2386ca8545/scm/user.go#L14-L22)
* `Login` - User's handle
* `Name` - User's name
* `Email` - User's email
* `Avatar` - Link to user's avatar image
* `Link` - Link to user's profile
* `Created` - [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) conforming string
* `Updated` - [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) conforming string

_See [pr-example/comments](.pr-example/comments) for examples of GitHub comments._

## Usage

### Permissions

The Task will need access to an opaque secret containing a token to use when making
requests to the SCM provider (configured via [the `secret-key-ref` param](#parameters)).
The secret is expected to contain a key called `token` which contains the auth token as a
base64 encoded string, for example:

```yaml
apiVersion: v1
kind: Secret
metadata:
name: github-auth-token
type: Opaque
data:
token: dG9rZW4=
```
### Running the Task
Example `TaskRun` that would run this `Task` in [download mode](#modes-upload-or-download):

```yaml
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
generateName: some-task-run-
spec:
taskRef:
- name: pull-request
workspaces:
- name: pr
persistentVolumeClaim:
claimName: shared-task-storage
params:
- name: mode
value: download
- name: url
value: https://github.com/bobcatfish/catservice/pull/16
- name: provider
value: github
- name: secret-key-ref
value: some-secret
```

[sample/add-comment.yaml](sample/add-comment.yaml) contains an example of a `PipelineRun`
which creates a `Pipeline` to exercise this Task's upload and download functionality.

To try out the sample (note that it expects the existence of a [secret](#permissions) called
'webhook-secret`):
```bash
kubectl apply -f pullrequest/sample/static.yaml
kubectl create -f pullrequest/sample/add-comment.yaml
```
## PullRequest Image
This Task was created to have feature parity with
[the Tekton Pipelines PullRequest PipelineResource](https://github.com/tektoncd/pipeline/blob/master/docs/resources.md#pull-request-resource)
and uses [the pullrequest-init image](https://github.com/tektoncd/pipeline/tree/master/cmd/pullrequest-init)
which is built and published as part of [Tekton Pipeline releases](https://github.com/tektoncd/pipeline/releases).
8 changes: 8 additions & 0 deletions pullrequest/pr-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# pullrequest-init examples

This directory serves as an example of the pull request payloads you can expect
from the pull request pipeline resource.

See
https://github.com/tektoncd/pipeline/blob/master/docs/resources.md#pull-request-resource
for more documentation.
22 changes: 22 additions & 0 deletions pullrequest/pr-example/base.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"Ref": "master",
"Sha": "723b9a9d560bdf4dc8fc6f697d53f662d3454ac8",
"Repo": {
"ID": "146641150",
"Namespace": "tektoncd",
"Name": "pipeline",
"FullName": "tektoncd/pipeline",
"Perm": {
"Pull": false,
"Push": false,
"Admin": false
},
"Branch": "master",
"Private": false,
"Clone": "https://github.com/tektoncd/pipeline.git",
"CloneSSH": "[email protected]:tektoncd/pipeline.git",
"Link": "https://github.com/tektoncd/pipeline",
"Created": "2018-08-29T18:21:55Z",
"Updated": "2019-12-04T17:26:42Z"
}
}
16 changes: 16 additions & 0 deletions pullrequest/pr-example/comments/505233618.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ID": 505233618,
"Body": "/retest",
"Author": {
"Login": "wlynch",
"Name": "",
"Email": "",
"Avatar": "https://avatars3.githubusercontent.com/u/1844673?v=4",
"Link": "",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
},
"Link": "https://github.com/tektoncd/pipeline/pull/995#issuecomment-505233618",
"Created": "2019-06-25T00:48:38Z",
"Updated": "2019-06-25T00:48:38Z"
}
16 changes: 16 additions & 0 deletions pullrequest/pr-example/comments/505476017.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ID": 505476017,
"Body": "> Looks good to me, question though : right now it's up to the user to write github status or not right (with this PR) ? Do we envision some \"automation\" around that ?\r\n\r\nYup! Great question, I'd love to source more ideas around this. The straight-forward answer would be to provide a runner binary that would wrap test execution and transform status codes and stdout/stderr to the pull request object.\r\n\r\nIs there any work being done around passing state between TaskRuns (e.g. for conditional execution or something similar)?",
"Author": {
"Login": "wlynch",
"Name": "",
"Email": "",
"Avatar": "https://avatars3.githubusercontent.com/u/1844673?v=4",
"Link": "",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
},
"Link": "https://github.com/tektoncd/pipeline/pull/995#issuecomment-505476017",
"Created": "2019-06-25T14:40:57Z",
"Updated": "2019-06-25T14:40:57Z"
}
16 changes: 16 additions & 0 deletions pullrequest/pr-example/comments/505482755.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ID": 505482755,
"Body": "@wlynch yeah we need to think about that, as I think I remember talking about notification as a first-class citizen in Tekton maybe ? (and most likely write on a design docs).\r\n\r\n> Is there any work being done around passing state between TaskRuns (e.g. for conditional execution or something similar)?\r\n\r\n@dibyom ^^ :angel: ",
"Author": {
"Login": "vdemeester",
"Name": "",
"Email": "",
"Avatar": "https://avatars0.githubusercontent.com/u/6508?v=4",
"Link": "",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
},
"Link": "https://github.com/tektoncd/pipeline/pull/995#issuecomment-505482755",
"Created": "2019-06-25T14:56:09Z",
"Updated": "2019-06-25T14:56:09Z"
}
16 changes: 16 additions & 0 deletions pullrequest/pr-example/comments/505529049.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ID": 505529049,
"Body": "@wlynch yes, the condition container will have access to some read only metadata. Right now, this is just the pipeline run including the status fields. We could expose this to task runs as well? Or do you need to write additional metadata that needs to be exposed?",
"Author": {
"Login": "dibyom",
"Name": "",
"Email": "",
"Avatar": "https://avatars2.githubusercontent.com/u/3316877?v=4",
"Link": "",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
},
"Link": "https://github.com/tektoncd/pipeline/pull/995#issuecomment-505529049",
"Created": "2019-06-25T16:50:26Z",
"Updated": "2019-06-25T16:50:26Z"
}
16 changes: 16 additions & 0 deletions pullrequest/pr-example/comments/505616303.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ID": 505616303,
"Body": "@dibyom Don't need to write more data, but it would be useful to expose it to TaskRuns to have a binary look for this information and automatically prep PR output as a response. Can you link me to that data and how TaskRuns can access it?",
"Author": {
"Login": "wlynch",
"Name": "",
"Email": "",
"Avatar": "https://avatars3.githubusercontent.com/u/1844673?v=4",
"Link": "",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
},
"Link": "https://github.com/tektoncd/pipeline/pull/995#issuecomment-505616303",
"Created": "2019-06-25T20:47:32Z",
"Updated": "2019-06-25T20:47:32Z"
}
16 changes: 16 additions & 0 deletions pullrequest/pr-example/comments/505676294.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ID": 505676294,
"Body": "> @wlynch yeah we need to think about that, as I think I remember talking about notification as a first-class citizen in Tekton maybe ? (and most likely write on a design docs).\r\n> \r\n> >\r\n\r\nYeah, I think the automated use-cases for this would fit into something around either \"notification\" or \"conditional execution\".\r\n\r\nWith the conditional execution approach, a pipeline would have a Task that runs on either success or failure and writes the status to Github/Gitlab.",
"Author": {
"Login": "dlorenc",
"Name": "",
"Email": "",
"Avatar": "https://avatars1.githubusercontent.com/u/1714486?v=4",
"Link": "",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
},
"Link": "https://github.com/tektoncd/pipeline/pull/995#issuecomment-505676294",
"Created": "2019-06-26T01:02:26Z",
"Updated": "2019-06-26T01:02:26Z"
}
16 changes: 16 additions & 0 deletions pullrequest/pr-example/comments/505798994.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ID": 505798994,
"Body": "> Yeah, I think the automated use-cases for this would fit into something around either \"notification\" or \"conditional execution\".\r\n\r\nThis could be implemented with the CloudEventPipelineResource as well. \r\nThe setup would be:\r\n- each task that needs to publish test results to the PR has an output resource of type cloudevent, which is sent to a dedicated tekton listener. The TaskRun, including status, is sent as body of the cloudevent.\r\n- an event binding is defined that accepts TaskRun completion events, and triggers a GitHub PR update Task(Run)\r\n- The GitHub PR update taskrun uses the PullRequest resource as input and output, and the metadata in the TaskRun (passed as parameter to the Task) to update GitHub\r\n\r\nThe advantages of using a separate Task/TaskRun are:\r\n- The status of the original Task is not affected by the outcome of the PR update\r\n- It doesn't require conditional execution\r\n- The Task that updates GitHub PRs can be as isolated as we want from the Task that runs the tests, which should make it easier to avoid leaking the GitHub token in logs.",
"Author": {
"Login": "afrittoli",
"Name": "",
"Email": "",
"Avatar": "https://avatars0.githubusercontent.com/u/2205608?v=4",
"Link": "",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
},
"Link": "https://github.com/tektoncd/pipeline/pull/995#issuecomment-505798994",
"Created": "2019-06-26T09:33:55Z",
"Updated": "2019-06-26T09:33:55Z"
}
16 changes: 16 additions & 0 deletions pullrequest/pr-example/comments/505890656.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ID": 505890656,
"Body": "/retest",
"Author": {
"Login": "afrittoli",
"Name": "",
"Email": "",
"Avatar": "https://avatars0.githubusercontent.com/u/2205608?v=4",
"Link": "",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
},
"Link": "https://github.com/tektoncd/pipeline/pull/995#issuecomment-505890656",
"Created": "2019-06-26T14:06:11Z",
"Updated": "2019-06-26T14:06:11Z"
}
16 changes: 16 additions & 0 deletions pullrequest/pr-example/comments/505923534.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"ID": 505923534,
"Body": "> @dibyom Don't need to write more data, but it would be useful to expose it to TaskRuns to have a binary look for this information and automatically prep PR output as a response. Can you link me to that data and how TaskRuns can access it?\r\n\r\nWIP but its a file (`pr-metadata.json`) in `/workspace` for condition containers ([sample](https://gist.github.com/dibyom/95031ac458455ca2b0c25206b7420f24))\r\n\r\nIts exposed to conditional pods at the moment and not regular taskruns. I opened https://github.com/tektoncd/pipeline/issues/1016 to track that.",
"Author": {
"Login": "dibyom",
"Name": "",
"Email": "",
"Avatar": "https://avatars2.githubusercontent.com/u/3316877?v=4",
"Link": "",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
},
"Link": "https://github.com/tektoncd/pipeline/pull/995#issuecomment-505923534",
"Created": "2019-06-26T15:22:42Z",
"Updated": "2019-06-26T15:22:42Z"
}
Loading

0 comments on commit f9e2515

Please sign in to comment.