Skip to content

Commit

Permalink
Implement GetTaskURI for GitLab provider
Browse files Browse the repository at this point in the history
This will be using the token when fetching tasks if the fetched URL is
on the same host of where the Repository URL is.

Signed-off-by: Chmouel Boudjnah <[email protected]>
  • Loading branch information
chmouel authored and vdemeester committed Jun 21, 2024
1 parent f80c589 commit afeee53
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 12 deletions.
26 changes: 20 additions & 6 deletions docs/content/docs/guide/resolver.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,21 +139,23 @@ will fetch the task directly from that remote URL :
pipelinesascode.tekton.dev/task: "[https://remote.url/task.yaml]"
```

### Remote HTTP URL from a private GitHub repository
### Remote HTTP URL from a private repository

If you are using `GitHub` and If the remote task URL uses the same host as where
the repository CRD is, Pipelines-as-Code will use the GitHub token and fetch the URL using the
GitHub API.
If you are using the `GitHub` or the `GitLab` provider and If the remote task
URL uses the same host as where the repository CRD is, Pipelines-as-Code will
use the provided token to fetch the URL using the GitHub or GitLab API.

For example if you have a repository URL looking like this :
#### GitHub

When using the GitHub provider if you have a repository URL looking like this :

<https://github.com/organization/repository>

and the remote HTTP URLs is a referenced GitHub "blob" URL:

<https://github.com/organization/repository/blob/mainbranch/path/file>

if the remote HTTP URL has a slash (/) in the branch name you will need to HTML
If the remote HTTP URL has a slash (/) in the branch name you will need to HTML
encode with the `%2F` character, example:

<https://github.com/organization/repository/blob/feature%2Fmainbranch/path/file>
Expand All @@ -169,6 +171,18 @@ There is settings you can set in the Pipelines-as-Code `Configmap` to control th
`secret-github-app-token-scoped` and `secret-github-app-scope-extra-repos` settings in the
[settings documentation](/docs/install/settings).

#### GitLab

This same applies to `GitLab` URL as directly copied from `GitLab` UI like this:

<https://gitlab.com/organization/repository/-/blob/mainbranch/path/file>

or `GitLab` raw URL like this:

<https://gitlab.com/organization/repository/-/raw/mainbranch/path/file>

The GitLab token as provider in the Repository CR will be used to fetch the file.

### Tasks or Pipelines inside the repository

Additionally, you can as well have a reference to a task or pipeline from a YAML file inside
Expand Down
7 changes: 1 addition & 6 deletions pkg/provider/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@ func (v *Provider) SetPacInfo(pacInfo *info.PacOpts) {
v.pacInfo = pacInfo
}

// GetTaskURI TODO: Implement me.
func (v *Provider) GetTaskURI(_ context.Context, _ *info.Event, _ string) (bool, string, error) {
return false, "", nil
}

// CheckPolicyAllowing TODO: Implement ME.
func (v *Provider) CheckPolicyAllowing(_ context.Context, _ *info.Event, _ []string) (bool, string) {
return false, ""
Expand Down Expand Up @@ -253,7 +248,7 @@ func (v *Provider) GetTektonDir(_ context.Context, event *info.Event, path, prov
}

objects, resp, err := v.Client.Repositories.ListTree(v.sourceProjectID, opt)
if resp != nil && resp.Response.StatusCode == http.StatusNotFound {
if resp != nil && resp.StatusCode == http.StatusNotFound {
return "", nil
}
if err != nil {
Expand Down
86 changes: 86 additions & 0 deletions pkg/provider/gitlab/task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package gitlab

import (
"context"
"fmt"
"net/url"
"regexp"

"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
)

type gitLabInfo struct {
Host string
GroupOrUser string
Repository string
Revision string
FilePath string
}

// extractGitLabInfo generated with chatGPT https://chatgpt.com/share/e3c06a7e-3f16-4891-85c7-832b3e7f25c5
func extractGitLabInfo(gitlabURL string) (*gitLabInfo, error) {
parsedURL, err := url.Parse(gitlabURL)
if err != nil {
return nil, err
}

// Regular expression to match the specific GitLab URL pattern
re := regexp.MustCompile(`^/([^/]+(?:/[^/]+)*)/([^/]+)/-/blob/([^/]+)(/.*)?|^/([^/]+(?:/[^/]+)*)/([^/]+)/-/raw/([^/]+)(/.*)?`)
matches := re.FindStringSubmatch(parsedURL.Path)

if len(matches) == 0 {
return nil, fmt.Errorf("URL does not match the expected GitLab pattern")
}

groupOrUser := ""
repoName := ""
revision := ""
filePath := ""

if matches[1] != "" { // For /blob/ URLs
groupOrUser = matches[1]
repoName = matches[2]
revision = matches[3]
if len(matches) >= 5 && matches[4] != "" {
filePath = matches[4][1:] // Remove initial slash
}
} else if matches[5] != "" { // For /raw/ URLs
groupOrUser = matches[5]
repoName = matches[6]
revision = matches[7]
if len(matches) >= 9 && matches[8] != "" {
filePath = matches[8][1:] // Remove initial slash
}
}

return &gitLabInfo{
Host: parsedURL.Host,
GroupOrUser: groupOrUser,
Repository: repoName,
Revision: revision,
FilePath: filePath,
}, nil
}

// GetTaskURI if we are getting a URL from the same URL where the provider is,
// it means we can try to get the file with the provider token.
func (v *Provider) GetTaskURI(ctx context.Context, event *info.Event, uri string) (bool, string, error) {
if ret := provider.CompareHostOfURLS(uri, event.URL); !ret {
return false, "", nil
}
extracted, err := extractGitLabInfo(uri)
if err != nil {
return false, "", err
}

nEvent := info.NewEvent()
nEvent.Organization = extracted.GroupOrUser
nEvent.Repository = extracted.Repository
nEvent.BaseBranch = extracted.Revision
ret, err := v.GetFileInsideRepo(ctx, nEvent, extracted.FilePath, extracted.Revision)
if err != nil {
return false, "", err
}
return true, ret, nil
}
57 changes: 57 additions & 0 deletions pkg/provider/gitlab/task_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package gitlab

import (
"testing"

"gotest.tools/v3/assert"
)

func TestExtractGitLabInfo(t *testing.T) {
tests := []struct {
url string
name string
expected *gitLabInfo
}{
{
name: "custom host",
url: "https://gitlab.chmouel.com/group/subgroup/repo/-/blob/main/README.md?ref_type=heads",
expected: &gitLabInfo{
Host: "gitlab.chmouel.com",
GroupOrUser: "group/subgroup",
Repository: "repo",
Revision: "main",
FilePath: "README.md",
},
},
{
name: "org repo",
url: "https://gitlab.com/org/repo/-/blob/main/README.md",
expected: &gitLabInfo{
Host: "gitlab.com",
GroupOrUser: "org",
Repository: "repo",
Revision: "main",
FilePath: "README.md",
},
},
{
name: "long group and subgroups",
url: "https://gitlab.com/gitlab-com/partners/alliance/corp/sandbox/another/foo-foo/-/raw/main/hello.txt?ref_type=heads",
expected: &gitLabInfo{
Host: "gitlab.com",
GroupOrUser: "gitlab-com/partners/alliance/corp/sandbox/another",
Repository: "foo-foo",
Revision: "main",
FilePath: "hello.txt",
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
info, err := extractGitLabInfo(tt.url)
assert.NilError(t, err)
assert.DeepEqual(t, info, tt.expected)
})
}
}

0 comments on commit afeee53

Please sign in to comment.