Skip to content

Commit 3da4112

Browse files
Shivam Mukhadechmouel
authored andcommitted
Reuses skipped checkrun, as we can't remove it
skipped runs were not getting removed a authorised user adds /ok-to-test on a pull req from a new user, this is to fix that case. we cannot delete a checkrun so we reuse it for the pipelinerun, when the CI is triggered later. as we execute pipelineruns parallely, to make sure only one pipelinerun uses that checkrunid we use mutex to store that checkrunid.
1 parent a2a110e commit 3da4112

File tree

10 files changed

+173
-33
lines changed

10 files changed

+173
-33
lines changed

pkg/adapter/adapter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ func (l listener) detectProvider(req *http.Request, reqBody string) (provider.In
212212
return nil, &log, fmt.Errorf("invalid event body format: %w", err)
213213
}
214214

215-
gitHub := &github.Provider{}
215+
gitHub := github.New()
216216
isGH, processReq, logger, reason, err := gitHub.Detect(req, reqBody, &log)
217217
if isGH {
218218
return l.processRes(processReq, gitHub, logger, reason, err)

pkg/adapter/incoming.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func (l *listener) processIncoming(targetRepo *v1alpha1.Repository) (provider.In
9898
var provider provider.Interface
9999
switch targetRepo.Spec.GitProvider.Type {
100100
case "github":
101-
provider = &github.Provider{}
101+
provider = github.New()
102102
case "gitlab":
103103
provider = &gitlab.Provider{}
104104
case "gitea":

pkg/adapter/incoming_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ func Test_listener_processIncoming(t *testing.T) {
429429
}{
430430
{
431431
name: "process/github",
432-
want: &github.Provider{},
432+
want: github.New(),
433433
wantOrg: "owner",
434434
wantRepo: "repo",
435435
targetRepo: &v1alpha1.Repository{

pkg/cmd/tknpac/resolve/resolve.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func resolveFilenames(cs *params.Run, filenames []string, params map[string]stri
148148
SkipInlining: skipInlining,
149149
}
150150
// We use github here but since we don't do remotetask we would not care
151-
providerintf := &github.Provider{}
151+
providerintf := github.New()
152152
event := info.NewEvent()
153153
prun, err := resolve.Resolve(ctx, cs, cs.Clients.Log, providerintf, event, allTemplates, ropt)
154154
if err != nil {

pkg/provider/github/github.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http"
99
"net/url"
1010
"strings"
11+
"sync"
1112

1213
"github.com/google/go-github/v47/github"
1314
"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
@@ -29,12 +30,25 @@ const (
2930
)
3031

3132
type Provider struct {
32-
Client *github.Client
33-
Logger *zap.SugaredLogger
34-
Token, APIURL *string
35-
ApplicationID *int64
36-
providerName string
37-
AutoConfigureNewRepos bool
33+
Client *github.Client
34+
Logger *zap.SugaredLogger
35+
Token, APIURL *string
36+
ApplicationID *int64
37+
providerName string
38+
skippedRun
39+
}
40+
41+
type skippedRun struct {
42+
mutex *sync.Mutex
43+
checkRunID int64
44+
}
45+
46+
func New() *Provider {
47+
return &Provider{
48+
skippedRun: skippedRun{
49+
mutex: &sync.Mutex{},
50+
},
51+
}
3852
}
3953

4054
// splitGithubURL Take a Github url and split it with org/repo path ref, supports rawURL

pkg/provider/github/status.go

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"path/filepath"
88
"strconv"
9+
"strings"
910
"time"
1011

1112
"github.com/google/go-github/v47/github"
@@ -58,6 +59,12 @@ func (v *Provider) getExistingCheckRunID(ctx context.Context, runevent *info.Eve
5859
}
5960

6061
for _, checkrun := range res.CheckRuns {
62+
// if it is a skipped checkrun then overwrite it
63+
if isSkippedCheckrun(checkrun) {
64+
if v.canIUseCheckrunID(checkrun.ID) {
65+
return checkrun.ID, nil
66+
}
67+
}
6168
if *checkrun.ExternalID == status.PipelineRunName {
6269
return checkrun.ID, nil
6370
}
@@ -66,6 +73,29 @@ func (v *Provider) getExistingCheckRunID(ctx context.Context, runevent *info.Eve
6673
return nil, nil
6774
}
6875

76+
func isSkippedCheckrun(run *github.CheckRun) bool {
77+
if run == nil || run.Output == nil {
78+
return false
79+
}
80+
if run.Output.Title != nil && *run.Output.Title == "Skipped" &&
81+
run.Output.Summary != nil &&
82+
strings.Contains(*run.Output.Summary, "is skipping this commit") {
83+
return true
84+
}
85+
return false
86+
}
87+
88+
func (v *Provider) canIUseCheckrunID(checkrunid *int64) bool {
89+
v.skippedRun.mutex.Lock()
90+
defer v.skippedRun.mutex.Unlock()
91+
92+
if v.skippedRun.checkRunID == 0 {
93+
v.skippedRun.checkRunID = *checkrunid
94+
return true
95+
}
96+
return false
97+
}
98+
6999
func (v *Provider) createCheckRunStatus(ctx context.Context, runevent *info.Event, pacopts *info.PacOpts, status provider.StatusOpts) (*int64, error) {
70100
now := github.Timestamp{Time: time.Now()}
71101
checkrunoption := github.CreateCheckRunOptions{
@@ -103,7 +133,6 @@ func (v *Provider) getOrUpdateCheckRunStatus(ctx context.Context, tekton version
103133
checkRunID = github.Int64(int64(checkID))
104134
}
105135
}
106-
107136
if !found {
108137
if checkRunID, _ = v.getExistingCheckRunID(ctx, runevent, status); checkRunID == nil {
109138
checkRunID, err = v.createCheckRunStatus(ctx, runevent, pacopts, status)
@@ -121,12 +150,17 @@ func (v *Provider) getOrUpdateCheckRunStatus(ctx context.Context, tekton version
121150
Summary: &status.Summary,
122151
Text: &status.Text,
123152
}
124-
125153
opts := github.UpdateCheckRunOptions{
126154
Name: getCheckName(status, pacopts),
127-
Status: &status.Status,
155+
Status: github.String(status.Status),
128156
Output: checkRunOutput,
129157
}
158+
if status.PipelineRunName != "" {
159+
opts.ExternalID = github.String(status.PipelineRunName)
160+
}
161+
if pacopts.LogURL != "" {
162+
opts.DetailsURL = github.String(pacopts.LogURL)
163+
}
130164

131165
if status.DetailsURL != "" {
132166
opts.DetailsURL = &status.DetailsURL

pkg/provider/github/status_test.go

Lines changed: 101 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
1717
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
1818
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
19+
testclient "github.com/openshift-pipelines/pipelines-as-code/pkg/test/clients"
1920
ghtesthelper "github.com/openshift-pipelines/pipelines-as-code/pkg/test/github"
2021
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
2122
"gotest.tools/v3/assert"
@@ -90,6 +91,45 @@ func TestGetExistingCheckRunIDFromMultiple(t *testing.T) {
9091
assert.Equal(t, *id, chosenID)
9192
}
9293

94+
func TestGetExistingSkippedCheckRunID(t *testing.T) {
95+
ctx, _ := rtesting.SetupFakeContext(t)
96+
client, mux, _, teardown := ghtesthelper.SetupGH()
97+
defer teardown()
98+
99+
cnx := New()
100+
cnx.Client = client
101+
102+
event := &info.Event{
103+
Organization: "owner",
104+
Repository: "repository",
105+
SHA: "sha",
106+
}
107+
108+
chosenOne := "chosenOne"
109+
chosenID := int64(55555)
110+
mux.HandleFunc(fmt.Sprintf("/repos/%v/%v/commits/%v/check-runs", event.Organization, event.Repository, event.SHA), func(w http.ResponseWriter, r *http.Request) {
111+
_, _ = fmt.Fprintf(w, `{
112+
"total_count": 1,
113+
"check_runs": [
114+
{
115+
"id": %v,
116+
"external_id": "%s",
117+
"output": {
118+
"title": "Skipped",
119+
"summary": "My CI is skipping this commit"
120+
}
121+
}
122+
]
123+
}`, chosenID, chosenOne)
124+
})
125+
126+
id, err := cnx.getExistingCheckRunID(ctx, event, provider.StatusOpts{
127+
PipelineRunName: chosenOne,
128+
})
129+
assert.NilError(t, err)
130+
assert.Equal(t, *id, chosenID)
131+
}
132+
93133
func TestGithubProviderCreateStatus(t *testing.T) {
94134
checkrunid := int64(2026)
95135
resultid := int64(666)
@@ -117,11 +157,13 @@ func TestGithubProviderCreateStatus(t *testing.T) {
117157
githubApps bool
118158
}
119159
tests := []struct {
120-
name string
121-
args args
122-
want *github.CheckRun
123-
wantErr bool
124-
notoken bool
160+
name string
161+
args args
162+
pr *v1beta1.PipelineRun
163+
want *github.CheckRun
164+
wantErr bool
165+
notoken bool
166+
addExistingCheckruns bool
125167
}{
126168
{
127169
name: "success",
@@ -137,6 +179,26 @@ func TestGithubProviderCreateStatus(t *testing.T) {
137179
want: &github.CheckRun{ID: &resultid},
138180
wantErr: false,
139181
},
182+
{
183+
name: "success with using existing skipped run checkrun",
184+
args: args{
185+
runevent: runEvent,
186+
status: "completed",
187+
conclusion: "success",
188+
text: "Yay",
189+
detailsURL: "https://cireport.com",
190+
titleSubstr: "Success",
191+
githubApps: true,
192+
},
193+
pr: &v1beta1.PipelineRun{
194+
ObjectMeta: metav1.ObjectMeta{
195+
Name: prname,
196+
},
197+
},
198+
addExistingCheckruns: true,
199+
want: &github.CheckRun{ID: &resultid},
200+
wantErr: false,
201+
},
140202
{
141203
name: "success coming from webhook",
142204
args: args{
@@ -219,9 +281,10 @@ func TestGithubProviderCreateStatus(t *testing.T) {
219281
defer teardown()
220282

221283
ctx, _ := rtesting.SetupFakeContext(t)
222-
gcvs := Provider{
223-
Client: fakeclient,
224-
}
284+
gcvs := New()
285+
gcvs.Client = fakeclient
286+
gcvs.Logger = getLogger()
287+
225288
mux.HandleFunc("/repos/check/run/statuses/sha", func(rw http.ResponseWriter, r *http.Request) {})
226289
mux.HandleFunc(fmt.Sprintf("/repos/check/run/check-runs/%d", checkrunid), func(rw http.ResponseWriter, r *http.Request) {
227290
bit, _ := io.ReadAll(r.Body)
@@ -242,6 +305,24 @@ func TestGithubProviderCreateStatus(t *testing.T) {
242305
_, err = fmt.Fprintf(rw, `{"id": %d}`, resultid)
243306
assert.NilError(t, err)
244307
})
308+
if tt.addExistingCheckruns {
309+
tt.args.runevent.SHA = "sha"
310+
mux.HandleFunc(fmt.Sprintf("/repos/%v/%v/commits/%v/check-runs", tt.args.runevent.Organization, tt.args.runevent.Repository, tt.args.runevent.SHA), func(w http.ResponseWriter, r *http.Request) {
311+
_, _ = fmt.Fprintf(w, `{
312+
"total_count": 1,
313+
"check_runs": [
314+
{
315+
"id": %v,
316+
"external_id": "%v",
317+
"output": {
318+
"title": "Skipped",
319+
"summary": "My CI is skipping this commit"
320+
}
321+
}
322+
]
323+
}`, checkrunid, resultid)
324+
})
325+
}
245326

246327
status := provider.StatusOpts{
247328
PipelineRunName: prname,
@@ -251,6 +332,9 @@ func TestGithubProviderCreateStatus(t *testing.T) {
251332
Text: tt.args.text,
252333
DetailsURL: tt.args.detailsURL,
253334
}
335+
if tt.pr != nil {
336+
status.PipelineRun = tt.pr
337+
}
254338
pacopts := &info.PacOpts{
255339
LogURL: "https://log",
256340
Settings: &settings.Settings{},
@@ -268,7 +352,15 @@ func TestGithubProviderCreateStatus(t *testing.T) {
268352
tt.args.runevent.SHA = "sha"
269353
}
270354
}
271-
err := gcvs.CreateStatus(ctx, nil, tt.args.runevent, pacopts, status)
355+
356+
testData := testclient.Data{}
357+
if tt.pr != nil {
358+
testData = testclient.Data{
359+
PipelineRuns: []*v1beta1.PipelineRun{tt.pr},
360+
}
361+
}
362+
stdata, _ := testclient.SeedTestData(t, ctx, testData)
363+
err := gcvs.CreateStatus(ctx, stdata.Pipeline, tt.args.runevent, pacopts, status)
272364
if (err != nil) != tt.wantErr {
273365
t.Errorf("GithubProvider.CreateStatus() error = %v, wantErr %v", err, tt.wantErr)
274366
return

pkg/reconciler/event.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (r *Reconciler) detectProvider(ctx context.Context, logger *zap.SugaredLogg
3030
var provider provider.Interface
3131
switch gitProvider {
3232
case "github", "github-enterprise":
33-
gh := &github.Provider{}
33+
gh := github.New()
3434
if event.InstallationID != 0 {
3535
if err := gh.InitAppClient(ctx, r.run.Clients.Kube, event); err != nil {
3636
return nil, nil, err

test/pkg/github/pr.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func PushFilesToRef(ctx context.Context, client *github.Client, commitMessage, b
8585
return commit.GetSHA(), nil
8686
}
8787

88-
func PRCreate(ctx context.Context, cs *params.Run, ghcnx ghprovider.Provider, owner, repo, targetRef, defaultBranch, title string) (int, error) {
88+
func PRCreate(ctx context.Context, cs *params.Run, ghcnx *ghprovider.Provider, owner, repo, targetRef, defaultBranch, title string) (int, error) {
8989
pr, _, err := ghcnx.Client.PullRequests.Create(ctx, owner, repo, &github.NewPullRequest{
9090
Title: &title,
9191
Head: &targetRef,
@@ -99,7 +99,7 @@ func PRCreate(ctx context.Context, cs *params.Run, ghcnx ghprovider.Provider, ow
9999
return pr.GetNumber(), nil
100100
}
101101

102-
func RunPullRequest(ctx context.Context, t *testing.T, label string, yamlFiles []string, webhook bool) (*params.Run, ghprovider.Provider, options.E2E, string, string, int, string) {
102+
func RunPullRequest(ctx context.Context, t *testing.T, label string, yamlFiles []string, webhook bool) (*params.Run, *ghprovider.Provider, options.E2E, string, string, int, string) {
103103
targetNS := names.SimpleNameGenerator.RestrictLengthWithRandomSuffix("pac-e2e-ns")
104104
runcnx, opts, ghcnx, err := Setup(ctx, webhook)
105105
assert.NilError(t, err)

0 commit comments

Comments
 (0)