Skip to content

Commit

Permalink
PullRequest Resource: Derive API URL from PR URL.
Browse files Browse the repository at this point in the history
Currently, we always use the default API URL for all requests, which
means that the PR resource cannot be used with GitHub Enterprise or self
hosted GitLab instances. This changes the behavior to build the API Base
URL from the PR resource if the URL is not the default:

PR URL                     | API Base URL
---------------------------|-------------
https://github.com         | https://api.github.com
https://github.example.com | https://github.example.com/v3/api
https://gitlab.com         | https://gitlab.com
https://gitlab.example.com | https://gitlab.example.com

GitHub Documentation: https://developer.github.com/v3/#schema
GitHub Enterprise Documentation:
https://developer.github.com/enterprise/2.17/v3/#schema
GitLab Documentation: https://developer.github.com/enterprise/2.17/v3/#current-version

Fixes #1816
  • Loading branch information
wlynch committed Jan 7, 2020
1 parent f9e303a commit b06dfd6
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 57 deletions.
80 changes: 52 additions & 28 deletions docs/resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ For example:

- [Syntax](#syntax)
- [Using Resources](#using-resources)
- [Variable substitution](#variable-substitution)
- [Controlling where resources are mounted](#controlling-where-resources-are-mounted)
- [Overriding where resources are copied from](#overriding-where-resources-are-copied-from)
- [Resource Status](#resource-status)
- [Optional Resources](#optional-resources)
- [Variable substitution](#variable-substitution)
- [Controlling where resources are mounted](#controlling-where-resources-are-mounted)
- [Overriding where resources are copied from](#overriding-where-resources-are-copied-from)
- [Resource Status](#resource-status)
- [Optional Resources](#optional-resources)
- [Resource types](#resource-types)
- [Git Resource](#git-resource)
- [Pull Request Resource](#pull-request-resource)
Expand Down Expand Up @@ -51,8 +51,9 @@ following fields:
- Optional:
- [`params`](#resource-types) - Parameters which are specific to each type
of `PipelineResource`
- [`optional`](#optional-resources) - Boolean flag to mark a resource optional
(by default, `optional` is set to `false` making resources mandatory).
- [`optional`](#optional-resources) - Boolean flag to mark a resource
optional (by default, `optional` is set to `false` making resources
mandatory).

[kubernetes-overview]:
https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields
Expand Down Expand Up @@ -227,8 +228,9 @@ resourcesResult:

### Optional Resources

By default, a resource is declared as mandatory unless `optional` is set `true` for that resource.
Resources declared as `optional` in a `Task` does not have be specified in `TaskRun`.
By default, a resource is declared as mandatory unless `optional` is set `true`
for that resource. Resources declared as `optional` in a `Task` does not have be
specified in `TaskRun`.

```yaml
apiVersion: tekton.dev/v1alpha1
Expand All @@ -243,11 +245,12 @@ spec:
optional: true
```

You can refer to different examples demonstrating usage of optional resources in `Task` and `Condition`:
You can refer to different examples demonstrating usage of optional resources in
`Task` and `Condition`:

- [Task](../examples/taskruns/optional-resources.yaml)
- [Cluster Task](../examples/taskruns/optional-resources-with-clustertask.yaml)
- [Condition](../examples/pipelineruns/conditional-pipelinerun-with-optional-resources.yaml)
- [Task](../examples/taskruns/optional-resources.yaml)
- [Cluster Task](../examples/taskruns/optional-resources-with-clustertask.yaml)
- [Condition](../examples/pipelineruns/conditional-pipelinerun-with-optional-resources.yaml)

## Resource Types

Expand Down Expand Up @@ -283,14 +286,15 @@ Params that can be added are the following:
clone. You can use this to control what commit [or branch](#using-a-branch)
is used. _If no revision is specified, the resource will default to `latest`
from `master`._
1. `submodules`: defines if the resource should initialize and
fetch the submodules, value is either `true` or `false`. _If not
specified, this will default to true_
1. `submodules`: defines if the resource should initialize and fetch the
submodules, value is either `true` or `false`. _If not specified, this will
default to true_
1. `depth`: performs a [shallow clone][git-depth] where only the most recent
commit(s) will be fetched. If set to `'0'`, all commits will be fetched.
_If not specified, the default depth is 1._
1. `sslVerify`: defines if [http.sslVerify][git-http.sslVerify] should be set to `true` or `false`
in the global git config. _Defaults to `true` if omitted._
commit(s) will be fetched. If set to `'0'`, all commits will be fetched. _If
not specified, the default depth is 1._
1. `sslVerify`: defines if [http.sslVerify][git-http.sslVerify] should be set
to `true` or `false` in the global git config. _Defaults to `true` if
omitted._

[git-rev]: https://git-scm.com/docs/gitrevisions#_specifying_revisions
[git-depth]: https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---depthltdepthgt
Expand Down Expand Up @@ -396,10 +400,11 @@ Comments describe a pull request comment. They are represented as a set of json
files.

Other pull request information can be found in `pr.json`. This is a read-only
resource. Users should use other subresources (labels, comments, etc)
to interact with the PR.
resource. Users should use other subresources (labels, comments, etc) to
interact with the PR.

For an example of the output this resource provides, see [`example`](../cmd/pullrequest-init/example).
For an example of the output this resource provides, see
[`example`](../cmd/pullrequest-init/example).

To create a pull request resource using the `PipelineResource` CRD:

Expand All @@ -426,14 +431,13 @@ metadata:
type: Opaque
data:
token: github_personal_access_token_secret # in base64 encoded form
```

Params that can be added are the following:

1. `url`: represents the location of the pull request to fetch.
1. `provider`: represents the SCM provider to use. This will be "guessed" based on the url if not set.
Valid values are `github` or `gitlab` today.
1. `provider`: represents the SCM provider to use. This will be "guessed" based
on the url if not set. Valid values are `github` or `gitlab` today.

#### Statuses

Expand All @@ -442,11 +446,31 @@ https://godoc.org/github.com/jenkins-x/go-scm/scm#State

#### Pull Request

The `pullRequest` resource will look for GitHub or Gitlab OAuth authentication tokens in
spec secrets with a field name called `authToken`.
The `pullRequest` resource will look for GitHub or Gitlab OAuth authentication
tokens in spec secrets with a field name called `authToken`.

URLs should be of the form: https://github.com/tektoncd/pipeline/pull/1

#### Self hosted / Enterprise instances

The PullRequest resource works with self hosted or enterprise GitHub/GitLab
instance. Simply provide the pull request URL and set the `provider` parameter.

```yaml
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: wizzbang-pr
namespace: default
spec:
type: pullRequest
params:
- name: url
value: https://github.example.com/wizzbangcorp/wizzbang/pulls/1
- name: provider
value: github
```

### Image Resource

An `image` resource represents an image that lives in a remote repository. It is
Expand Down
14 changes: 14 additions & 0 deletions pkg/pullrequest/scm.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ func githubHandlerFromURL(u *url.URL, token string, logger *zap.SugaredLogger) (
)

client := github.NewDefault()
if u.Host != "github.com" {
var err error
client, err = github.New(fmt.Sprintf("%s://%s/api/v3", u.Scheme, u.Host))
if err != nil {
return nil, fmt.Errorf("error creating client: %w", err)
}
}
ownerRepo := fmt.Sprintf("%s/%s", owner, repo)
h := NewHandler(logger, client, ownerRepo, prNumber)
if token != "" {
Expand Down Expand Up @@ -110,6 +117,13 @@ func gitlabHandlerFromURL(u *url.URL, token string, logger *zap.SugaredLogger) (
zap.String("pr", prNum),
)
client := gitlab.NewDefault()
if u.Host != "gitlab.com" {
var err error
client, err = gitlab.New(fmt.Sprintf("%s://%s", u.Scheme, u.Host))
if err != nil {
return nil, fmt.Errorf("error creating client: %w", err)
}
}
if token != "" {
client.Client = &http.Client{
Transport: &gitlabClient{
Expand Down
66 changes: 37 additions & 29 deletions pkg/pullrequest/scm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,44 @@ import (

func TestNewSCMHandler(t *testing.T) {
tests := []struct {
name string
raw string
wantRepo string
wantNum int
wantErr bool
name string
raw string
wantBaseURL string
wantRepo string
wantNum int
wantErr bool
}{
{
name: "github",
raw: "https://github.com/foo/bar/pull/1",
wantRepo: "foo/bar",
wantNum: 1,
wantErr: false,
name: "github",
raw: "https://github.com/foo/bar/pull/1",
wantBaseURL: "https://api.github.com/",
wantRepo: "foo/bar",
wantNum: 1,
wantErr: false,
},
{
name: "custom github",
raw: "https://github.tekton.dev/foo/baz/pull/2",
wantRepo: "foo/baz",
wantNum: 2,
wantErr: false,
name: "custom github",
raw: "https://github.tekton.dev/foo/baz/pull/2",
wantBaseURL: "https://github.tekton.dev/api/v3/",
wantRepo: "foo/baz",
wantNum: 2,
wantErr: false,
},
{
name: "gitlab",
raw: "https://gitlab.com/foo/bar/merge_requests/3",
wantRepo: "foo/bar",
wantNum: 3,
wantErr: false,
name: "gitlab",
raw: "https://gitlab.com/foo/bar/merge_requests/3",
wantBaseURL: "https://gitlab.com/",
wantRepo: "foo/bar",
wantNum: 3,
wantErr: false,
},
{
name: "gitlab multi-level",
raw: "https://gitlab.com/foo/bar/baz/merge_requests/3",
wantRepo: "foo/bar/baz",
wantNum: 3,
wantErr: false,
name: "gitlab multi-level",
raw: "https://gitlab.com/foo/bar/baz/merge_requests/3",
wantBaseURL: "https://gitlab.com/",
wantRepo: "foo/bar/baz",
wantNum: 3,
wantErr: false,
},
{
name: "unsupported",
Expand All @@ -77,11 +82,14 @@ func TestNewSCMHandler(t *testing.T) {
}
return
}
if !(got.prNum == tt.wantNum) {
t.Errorf("NewSCMHandler() = %v, want %v", got, tt.wantNum)
if got.prNum != tt.wantNum {
t.Errorf("NewSCMHandler() [pr num] = %v, want %v", got, tt.wantNum)
}
if !(got.repo == tt.wantRepo) {
t.Errorf("NewSCMHandler() = %v, want %v", got, tt.wantRepo)
if got.repo != tt.wantRepo {
t.Errorf("NewSCMHandler() [repo] = %v, want %v", got, tt.wantRepo)
}
if baseURL := got.client.BaseURL.String(); baseURL != tt.wantBaseURL {
t.Errorf("NewSCMHandler() [base url] = %v, want %v", baseURL, tt.wantBaseURL)
}
})
}
Expand Down

0 comments on commit b06dfd6

Please sign in to comment.