Skip to content

Commit f40bd41

Browse files
committed
fix: GitLab provider getting a URL on same host
Refactored the GitLab provider to correctly handle project IDs and fetch raw files with our token. We were fetching the URL as is when there are URLs don't work like GitHub which allows passing a token and getting a private raw URL directly. Jira: https://issues.redhat.com/browse/SRVKP-7357 AI-assisted-by: Google Gemini 3 Signed-off-by: Chmouel Boudjnah <[email protected]>
1 parent 6200043 commit f40bd41

File tree

2 files changed

+102
-8
lines changed

2 files changed

+102
-8
lines changed

pkg/provider/gitlab/task.go

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ package gitlab
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67
"net/url"
78
"regexp"
89

910
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
1011
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
12+
gl "gitlab.com/gitlab-org/api/client-go"
1113
)
1214

1315
type gitLabInfo struct {
16+
Scheme string
1417
Host string
1518
GroupOrUser string
1619
Repository string
@@ -55,6 +58,7 @@ func extractGitLabInfo(gitlabURL string) (*gitLabInfo, error) {
5558
}
5659

5760
return &gitLabInfo{
61+
Scheme: parsedURL.Scheme,
5862
Host: parsedURL.Host,
5963
GroupOrUser: groupOrUser,
6064
Repository: repoName,
@@ -65,7 +69,7 @@ func extractGitLabInfo(gitlabURL string) (*gitLabInfo, error) {
6569

6670
// GetTaskURI if we are getting a URL from the same URL where the provider is,
6771
// it means we can try to get the file with the provider token.
68-
func (v *Provider) GetTaskURI(ctx context.Context, event *info.Event, uri string) (bool, string, error) {
72+
func (v *Provider) GetTaskURI(_ context.Context, event *info.Event, uri string) (bool, string, error) {
6973
if ret := provider.CompareHostOfURLS(uri, event.URL); !ret {
7074
return false, "", nil
7175
}
@@ -74,13 +78,37 @@ func (v *Provider) GetTaskURI(ctx context.Context, event *info.Event, uri string
7478
return false, "", err
7579
}
7680

77-
nEvent := info.NewEvent()
78-
nEvent.Organization = extracted.GroupOrUser
79-
nEvent.Repository = extracted.Repository
80-
nEvent.BaseBranch = extracted.Revision
81-
ret, err := v.GetFileInsideRepo(ctx, nEvent, extracted.FilePath, extracted.Revision)
81+
// Use the existing client if available, otherwise create a temporary one.
82+
// We avoid storing it to prevent side effects on the provider's state.
83+
client := v.gitlabClient
84+
if client == nil {
85+
baseURL := fmt.Sprintf("%s://%s", extracted.Scheme, extracted.Host)
86+
var clientErr error
87+
client, clientErr = gl.NewClient(event.Provider.Token, gl.WithHTTPClient(http.DefaultClient), gl.WithBaseURL(baseURL))
88+
if clientErr != nil {
89+
return false, "", fmt.Errorf("failed to create gitlab client: %w", clientErr)
90+
}
91+
}
92+
93+
// Construct the project slug for the remote repository
94+
projectSlug := extracted.GroupOrUser + "/" + extracted.Repository
95+
96+
// Get the project ID for the remote repository
97+
project, _, err := client.Projects.GetProject(projectSlug, &gl.GetProjectOptions{})
8298
if err != nil {
83-
return false, "", err
99+
return false, "", fmt.Errorf("failed to get project ID for %s: %w", projectSlug, err)
100+
}
101+
102+
// Fetch the file from the remote repository
103+
opt := &gl.GetRawFileOptions{
104+
Ref: gl.Ptr(extracted.Revision),
105+
}
106+
file, resp, err := client.RepositoryFiles.GetRawFile(project.ID, extracted.FilePath, opt)
107+
if err != nil {
108+
return false, "", fmt.Errorf("failed to get file %s from remote repository: %w", extracted.FilePath, err)
109+
}
110+
if resp != nil && resp.StatusCode == http.StatusNotFound {
111+
return false, "", nil
84112
}
85-
return true, ret, nil
113+
return true, string(file), nil
86114
}

pkg/provider/gitlab/task_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
package gitlab
22

33
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"net/http/httptest"
8+
"net/url"
49
"testing"
510

11+
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
12+
gl "gitlab.com/gitlab-org/api/client-go"
613
"gotest.tools/v3/assert"
714
)
815

@@ -16,6 +23,7 @@ func TestExtractGitLabInfo(t *testing.T) {
1623
name: "custom host",
1724
url: "https://gitlab.chmouel.com/group/subgroup/repo/-/blob/main/README.md?ref_type=heads",
1825
expected: &gitLabInfo{
26+
Scheme: "https",
1927
Host: "gitlab.chmouel.com",
2028
GroupOrUser: "group/subgroup",
2129
Repository: "repo",
@@ -27,6 +35,7 @@ func TestExtractGitLabInfo(t *testing.T) {
2735
name: "org repo",
2836
url: "https://gitlab.com/org/repo/-/blob/main/README.md",
2937
expected: &gitLabInfo{
38+
Scheme: "https",
3039
Host: "gitlab.com",
3140
GroupOrUser: "org",
3241
Repository: "repo",
@@ -38,6 +47,7 @@ func TestExtractGitLabInfo(t *testing.T) {
3847
name: "long group and subgroups",
3948
url: "https://gitlab.com/gitlab-com/partners/alliance/corp/sandbox/another/foo-foo/-/raw/main/hello.txt?ref_type=heads",
4049
expected: &gitLabInfo{
50+
Scheme: "https",
4151
Host: "gitlab.com",
4252
GroupOrUser: "gitlab-com/partners/alliance/corp/sandbox/another",
4353
Repository: "foo-foo",
@@ -55,3 +65,59 @@ func TestExtractGitLabInfo(t *testing.T) {
5565
})
5666
}
5767
}
68+
69+
func TestGetTaskURI(t *testing.T) {
70+
ctx := context.Background()
71+
72+
// Expected project and raw file content
73+
projectID := 12345
74+
projectSlug := "chmouel/dazgo"
75+
repoName := "dazgo"
76+
groupOrUser := "chmouel"
77+
revision := "main"
78+
filePath := "task.yaml"
79+
expectedContent := "apiVersion: tekton.dev/v1beta1\nkind: Pipeline\nmetadata:\n name: test-pipeline\nspec:\n tasks:\n - name: echo-task\n taskSpec:\n steps:\n - name: echo\n image: ubuntu\n script: |\n echo \"Hello from remote pipeline!\"\n"
80+
81+
// Set up a mock HTTP server that GetTaskURI will connect to
82+
mux := http.NewServeMux()
83+
84+
// Mock the GetProject API call
85+
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/%s", gl.PathEscape(projectSlug)), func(w http.ResponseWriter, _ *http.Request) {
86+
fmt.Fprintf(w, `{"id": %d, "path_with_namespace": "%s"}`, projectID, projectSlug)
87+
})
88+
89+
// Mock the GetRawFile API call
90+
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/%d/repository/files/%s/raw", projectID, gl.PathEscape(filePath)), func(w http.ResponseWriter, r *http.Request) {
91+
assert.Equal(t, "token", r.Header.Get("Private-Token"), "Expected Private-Token header to be 'token'")
92+
assert.Equal(t, revision, r.URL.Query().Get("ref"), "Expected 'ref' query parameter to be 'main'")
93+
fmt.Fprint(w, expectedContent)
94+
})
95+
96+
// Start the test server
97+
server := httptest.NewServer(mux)
98+
defer server.Close()
99+
100+
// Create a GitLab provider (GetTaskURI creates its own client internally)
101+
v := &Provider{}
102+
103+
// Create an info.Event with the provider token
104+
// The URL must match the test server's host so GetTaskURI proceeds
105+
event := info.NewEvent()
106+
event.URL = server.URL
107+
event.Provider = &info.Provider{
108+
Token: "token",
109+
}
110+
111+
// Parse the server URL to get the host for constructing the remote pipeline URL
112+
serverURL, err := url.Parse(server.URL)
113+
assert.NilError(t, err)
114+
115+
// The remote pipeline URL - use the test server's scheme and host
116+
remotePipelineURL := fmt.Sprintf("%s://%s/%s/%s/-/raw/%s/%s", serverURL.Scheme, serverURL.Host, groupOrUser, repoName, revision, filePath)
117+
118+
// Call GetTaskURI
119+
found, content, err := v.GetTaskURI(ctx, event, remotePipelineURL)
120+
assert.NilError(t, err)
121+
assert.Assert(t, found, "Expected remote pipeline to be found")
122+
assert.Equal(t, expectedContent, content, "Returned content mismatch")
123+
}

0 commit comments

Comments
 (0)