Skip to content
This repository was archived by the owner on May 9, 2025. It is now read-only.

Commit df6be72

Browse files
Skarlsophoban01
andauthored
feat: create a status check and store the generated pr id (#43)
* feat: store the generated pr id and git repository value * create a pull request status check * Update pkg/providers/github/github.go Co-authored-by: Piaras Hoban <[email protected]> --------- Co-authored-by: Piaras Hoban <[email protected]>
1 parent dff3c3e commit df6be72

File tree

10 files changed

+84
-87
lines changed

10 files changed

+84
-87
lines changed

apis/delivery/v1alpha1/sync_types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ type SyncStatus struct {
5858
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description=""
5959
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description=""
6060
Conditions []metav1.Condition `json:"conditions,omitempty"`
61+
62+
// +optional
63+
PullRequestID int `json:"pullRequestID,omitempty"`
6164
}
6265

6366
// GetConditions returns the conditions of the ComponentVersion.

config/crd/bases/delivery.ocm.software_syncs.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ spec:
182182
description: ObservedGeneration is the last reconciled generation.
183183
format: int64
184184
type: integer
185+
pullRequestID:
186+
type: integer
185187
type: object
186188
type: object
187189
served: true

controllers/delivery/sync_controller.go

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,14 @@ import (
1313
"github.com/fluxcd/pkg/apis/meta"
1414
"github.com/fluxcd/pkg/runtime/conditions"
1515
"github.com/fluxcd/pkg/runtime/patch"
16-
sourcebeta2 "github.com/fluxcd/source-controller/api/v1beta2"
1716
corev1 "k8s.io/api/core/v1"
1817
apierrors "k8s.io/apimachinery/pkg/api/errors"
1918
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2019
"k8s.io/apimachinery/pkg/runtime"
2120
"k8s.io/apimachinery/pkg/types"
22-
"k8s.io/utils/pointer"
2321
ctrl "sigs.k8s.io/controller-runtime"
2422
"sigs.k8s.io/controller-runtime/pkg/builder"
2523
"sigs.k8s.io/controller-runtime/pkg/client"
26-
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2724
"sigs.k8s.io/controller-runtime/pkg/log"
2825
"sigs.k8s.io/controller-runtime/pkg/predicate"
2926

@@ -223,20 +220,15 @@ func (r *SyncReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resul
223220
if obj.Spec.AutomaticPullRequestCreation {
224221
log.Info("automatic pull-request creation is enabled, preparing to create a pull request")
225222

226-
if err = r.Provider.CreatePullRequest(ctx, targetBranch, *obj, *repository); err != nil {
223+
id, err := r.Provider.CreatePullRequest(ctx, targetBranch, *obj, *repository)
224+
if err != nil {
227225
err = fmt.Errorf("failed to create pull request: %w", err)
228226
conditions.MarkFalse(obj, meta.ReadyCondition, v1alpha1.CreatePullRequestFailedReason, err.Error())
229227

230228
return ctrl.Result{}, err
231229
}
232230

233-
// Create GitRepository to track values file changes.
234-
if err := r.createValueFileGitRepository(ctx, *obj, *repository, targetBranch); err != nil {
235-
err = fmt.Errorf("failed to create value tracking git repository object: %w", err)
236-
conditions.MarkFalse(obj, meta.ReadyCondition, v1alpha1.GitRepositoryCreateFailedReason, err.Error())
237-
238-
return ctrl.Result{}, err
239-
}
231+
obj.Status.PullRequestID = id
240232
}
241233

242234
// Remove any stale Ready condition, most likely False, set above. Its value
@@ -275,47 +267,3 @@ func (r *SyncReconciler) parseAuthSecret(secret *corev1.Secret, opts *pkg.PushOp
275267
},
276268
}
277269
}
278-
279-
// createValueFileGitRepository creates a GitRepository that tracks changes on a branch.
280-
func (r *SyncReconciler) createValueFileGitRepository(ctx context.Context, sync v1alpha1.Sync, repository mpasv1alpha1.Repository, branch string) error {
281-
owners := sync.GetOwnerReferences()
282-
if len(owners) != 1 {
283-
return fmt.Errorf("expected exactly one owner, got: %d", len(owners))
284-
}
285-
286-
repo := &sourcebeta2.GitRepository{
287-
ObjectMeta: metav1.ObjectMeta{
288-
Name: repository.Name + "values-repo",
289-
Namespace: repository.Namespace,
290-
},
291-
Spec: sourcebeta2.GitRepositorySpec{
292-
URL: repository.GetRepositoryURL(),
293-
SecretRef: &meta.LocalObjectReference{
294-
Name: repository.Spec.Credentials.SecretRef.Name,
295-
},
296-
Interval: metav1.Duration{Duration: 5 * time.Second},
297-
Reference: &sourcebeta2.GitRepositoryRef{
298-
Branch: branch,
299-
},
300-
Ignore: pointer.String(fmt.Sprintf(`# exclude all
301-
/*
302-
# include values.yaml
303-
!./products/%s/values.yaml
304-
`, owners[0].Name)),
305-
},
306-
}
307-
308-
if _, err := controllerutil.CreateOrUpdate(ctx, r.Client, repo, func() error {
309-
if repo.ObjectMeta.CreationTimestamp.IsZero() {
310-
if err := controllerutil.SetOwnerReference(&repository, repo, r.Scheme); err != nil {
311-
return fmt.Errorf("failed to set owner to git repository object: %w", err)
312-
}
313-
}
314-
315-
return nil
316-
}); err != nil {
317-
return fmt.Errorf("failed to create git repository: %w", err)
318-
}
319-
320-
return nil
321-
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ require (
1919
k8s.io/api v0.26.2
2020
k8s.io/apimachinery v0.26.2
2121
k8s.io/client-go v0.26.2
22-
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5
2322
sigs.k8s.io/controller-runtime v0.14.4
2423
)
2524

@@ -175,6 +174,7 @@ require (
175174
k8s.io/component-base v0.26.2 // indirect
176175
k8s.io/klog/v2 v2.90.0 // indirect
177176
k8s.io/kube-openapi v0.0.0-20230228151317-19cbebb19cb7 // indirect
177+
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect
178178
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
179179
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
180180
sigs.k8s.io/yaml v1.3.0 // indirect

pkg/providers/fakes/fake_provider.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type Provider struct {
1818
CreateRepositoryCalledWith map[int][]any
1919
CreateRepositoryCallCount int
2020
CreatePullRequestErr error
21+
CreatePullRequestID int
2122
CreatePullRequestCalledWith map[int][]any
2223
CreatePullRequestCallCount int
2324
}
@@ -34,14 +35,14 @@ func (p *Provider) CreateRepository(ctx context.Context, obj mpasv1alpha1.Reposi
3435
return p.CreateRepositoryErr
3536
}
3637

37-
func (p *Provider) CreatePullRequest(ctx context.Context, branch string, sync deliveryv1alpha1.Sync, repository mpasv1alpha1.Repository) error {
38+
func (p *Provider) CreatePullRequest(ctx context.Context, branch string, sync deliveryv1alpha1.Sync, repository mpasv1alpha1.Repository) (int, error) {
3839
if p.CreatePullRequestCalledWith == nil {
3940
p.CreatePullRequestCalledWith = make(map[int][]any)
4041
}
4142
p.CreatePullRequestCalledWith[p.CreatePullRequestCallCount] = append(p.CreatePullRequestCalledWith[p.CreatePullRequestCallCount], branch, sync, repository)
4243
p.CreatePullRequestCallCount++
4344

44-
return p.CreatePullRequestErr
45+
return p.CreatePullRequestID, p.CreatePullRequestErr
4546
}
4647

4748
func (p *Provider) CreatePullRequestCallArgsForNumber(i int) ([]any, error) {

pkg/providers/gitea/gitea.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,10 @@ func (f *fileCommitter) commitFile(client *gitea.Client, obj mpasv1alpha1.Reposi
143143
}
144144
}
145145

146-
func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deliveryv1alpha1.Sync, repository mpasv1alpha1.Repository) error {
146+
func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deliveryv1alpha1.Sync, repository mpasv1alpha1.Repository) (int, error) {
147147
if repository.Spec.Provider != providerType {
148148
if c.next == nil {
149-
return fmt.Errorf("can't handle provider type '%s' and no next provider is configured", repository.Spec.Provider)
149+
return -1, fmt.Errorf("can't handle provider type '%s' and no next provider is configured", repository.Spec.Provider)
150150
}
151151

152152
return c.next.CreatePullRequest(ctx, branch, sync, repository)
@@ -157,12 +157,12 @@ func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deli
157157
Name: repository.Spec.Credentials.SecretRef.Name,
158158
Namespace: repository.Namespace,
159159
}, secret); err != nil {
160-
return fmt.Errorf("failed to get secret: %w", err)
160+
return -1, fmt.Errorf("failed to get secret: %w", err)
161161
}
162162

163163
token, ok := secret.Data[tokenKey]
164164
if !ok {
165-
return fmt.Errorf("token '%s' not found in secret", tokenKey)
165+
return -1, fmt.Errorf("token '%s' not found in secret", tokenKey)
166166
}
167167

168168
domain := defaultDomain
@@ -172,7 +172,7 @@ func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deli
172172

173173
client, err := gitea.NewClient(domain, gitea.SetToken(string(token)))
174174
if err != nil {
175-
return fmt.Errorf("failed to create gitea client: %w", err)
175+
return -1, fmt.Errorf("failed to create gitea client: %w", err)
176176
}
177177

178178
var (
@@ -193,16 +193,17 @@ func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deli
193193
description = sync.Spec.PullRequestTemplate.Description
194194
}
195195

196-
if _, _, err := client.CreatePullRequest(repository.Spec.Owner, repository.GetName(), gitea.CreatePullRequestOption{
196+
pr, _, err := client.CreatePullRequest(repository.Spec.Owner, repository.GetName(), gitea.CreatePullRequestOption{
197197
Head: branch,
198198
Base: base,
199199
Title: title,
200200
Body: description,
201-
}); err != nil {
202-
return fmt.Errorf("failed to create pull request: %w", err)
201+
})
202+
if err != nil {
203+
return -1, fmt.Errorf("failed to create pull request: %w", err)
203204
}
204205

205-
return nil
206+
return int(pr.ID), nil
206207
}
207208

208209
func (c *Client) CreateBranchProtection(ctx context.Context, obj mpasv1alpha1.Repository) error {

pkg/providers/github/github.go

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,18 +130,18 @@ func (c *Client) retrieveAccessToken(ctx context.Context, obj mpasv1alpha1.Repos
130130
return token, nil
131131
}
132132

133-
func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deliveryv1alpha1.Sync, repository mpasv1alpha1.Repository) error {
133+
func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deliveryv1alpha1.Sync, repository mpasv1alpha1.Repository) (int, error) {
134134
if repository.Spec.Provider != providerType {
135135
if c.next == nil {
136-
return fmt.Errorf("can't handle provider type '%s' and no next provider is configured", repository.Spec.Provider)
136+
return -1, fmt.Errorf("can't handle provider type '%s' and no next provider is configured", repository.Spec.Provider)
137137
}
138138

139139
return c.next.CreatePullRequest(ctx, branch, sync, repository)
140140
}
141141

142142
authenticationOption, err := c.constructAuthenticationOption(ctx, repository)
143143
if err != nil {
144-
return err
144+
return -1, err
145145
}
146146

147147
domain := defaultDomain
@@ -151,12 +151,54 @@ func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deli
151151

152152
gc, err := github.NewClient(authenticationOption, gitprovider.WithDomain(domain))
153153
if err != nil {
154-
return fmt.Errorf("failed to create github client: %w", err)
154+
return -1, fmt.Errorf("failed to create github client: %w", err)
155155
}
156156

157+
var (
158+
id int
159+
createPullRequestFunc = gogit.CreateUserPullRequest
160+
)
161+
157162
if repository.Spec.IsOrganization {
158-
return gogit.CreateOrganizationPullRequest(ctx, gc, domain, branch, sync.Spec.PullRequestTemplate, repository)
163+
createPullRequestFunc = gogit.CreateOrganizationPullRequest
164+
}
165+
166+
if id, err = createPullRequestFunc(ctx, gc, domain, branch, sync.Spec.PullRequestTemplate, repository); err != nil {
167+
return 0, fmt.Errorf("failed to create pull request: %w", err)
168+
}
169+
170+
if err := c.createCheckRun(ctx, repository, id); err != nil {
171+
return 0, fmt.Errorf("failed to create check run: %w", err)
172+
}
173+
174+
return id, nil
175+
}
176+
177+
func (c *Client) createCheckRun(ctx context.Context, repository mpasv1alpha1.Repository, prID int) error {
178+
token, err := c.retrieveAccessToken(ctx, repository)
179+
if err != nil {
180+
return fmt.Errorf("failed to retrieve token: %w", err)
159181
}
160182

161-
return gogit.CreateUserPullRequest(ctx, gc, domain, branch, sync.Spec.PullRequestTemplate, repository)
183+
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: string(token)})
184+
tc := oauth2.NewClient(context.Background(), ts)
185+
186+
g := ggithub.NewClient(tc)
187+
//
188+
pr, _, err := g.PullRequests.Get(ctx, repository.Spec.Owner, repository.Name, prID)
189+
if err != nil {
190+
return fmt.Errorf("failed to find PR: %w", err)
191+
}
192+
193+
_, _, err = g.Repositories.CreateStatus(ctx, repository.Spec.Owner, repository.Name, *pr.Head.SHA, &ggithub.RepoStatus{
194+
State: ggithub.String("pending"),
195+
Description: ggithub.String("MPAS Validation Check"),
196+
Context: ggithub.String(statusCheckName),
197+
})
198+
199+
if err != nil {
200+
return fmt.Errorf("failed to create status for pr: %w", err)
201+
}
202+
203+
return nil
162204
}

pkg/providers/gitlab/gitlab.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,10 @@ func (c *Client) CreateRepository(ctx context.Context, obj mpasv1alpha1.Reposito
8686
return gogit.CreateUserRepository(ctx, gc, domain, obj)
8787
}
8888

89-
func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deliveryv1alpha1.Sync, repository mpasv1alpha1.Repository) error {
89+
func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deliveryv1alpha1.Sync, repository mpasv1alpha1.Repository) (int, error) {
9090
if repository.Spec.Provider != providerType {
9191
if c.next == nil {
92-
return fmt.Errorf("can't handle provider type '%s' and no next provider is configured", repository.Spec.Provider)
92+
return -1, fmt.Errorf("can't handle provider type '%s' and no next provider is configured", repository.Spec.Provider)
9393
}
9494

9595
return c.next.CreatePullRequest(ctx, branch, sync, repository)
@@ -100,12 +100,12 @@ func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deli
100100
Name: repository.Spec.Credentials.SecretRef.Name,
101101
Namespace: sync.Namespace,
102102
}, secret); err != nil {
103-
return fmt.Errorf("failed to get secret: %w", err)
103+
return -1, fmt.Errorf("failed to get secret: %w", err)
104104
}
105105

106106
token, ok := secret.Data[tokenKey]
107107
if !ok {
108-
return fmt.Errorf("token '%s' not found in secret", tokenKey)
108+
return -1, fmt.Errorf("token '%s' not found in secret", tokenKey)
109109
}
110110

111111
domain := defaultDomain
@@ -115,7 +115,7 @@ func (c *Client) CreatePullRequest(ctx context.Context, branch string, sync deli
115115

116116
gc, err := gitlab.NewClient(string(token), tokenType, gitprovider.WithDomain(domain))
117117
if err != nil {
118-
return fmt.Errorf("failed to create gitlab client: %w", err)
118+
return -1, fmt.Errorf("failed to create gitlab client: %w", err)
119119
}
120120

121121
if repository.Spec.IsOrganization {

pkg/providers/gogit/gogit.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func CreateUserRepository(ctx context.Context, gc gitprovider.Client, domain str
157157
}
158158

159159
// CreateOrganizationPullRequest creates a pull-request for an organization owned repository.
160-
func CreateOrganizationPullRequest(ctx context.Context, gc gitprovider.Client, domain, branch string, spec deliveryv1alpha1.PullRequestTemplate, repository mpasv1alpha1.Repository) error {
160+
func CreateOrganizationPullRequest(ctx context.Context, gc gitprovider.Client, domain, branch string, spec deliveryv1alpha1.PullRequestTemplate, repository mpasv1alpha1.Repository) (int, error) {
161161
// find the repository
162162
repo, err := gc.OrgRepositories().Get(ctx, gitprovider.OrgRepositoryRef{
163163
OrganizationRef: gitprovider.OrganizationRef{
@@ -167,7 +167,7 @@ func CreateOrganizationPullRequest(ctx context.Context, gc gitprovider.Client, d
167167
RepositoryName: repository.GetName(),
168168
})
169169
if err != nil {
170-
return fmt.Errorf("failed to find organization repository: %w", err)
170+
return -1, fmt.Errorf("failed to find organization repository: %w", err)
171171
}
172172

173173
var (
@@ -190,17 +190,17 @@ func CreateOrganizationPullRequest(ctx context.Context, gc gitprovider.Client, d
190190

191191
pr, err := repo.PullRequests().Create(ctx, title, branch, base, description)
192192
if err != nil {
193-
return fmt.Errorf("failed to create pull request: %w", err)
193+
return -1, fmt.Errorf("failed to create pull request: %w", err)
194194
}
195195

196196
logger := log.FromContext(ctx)
197197
logger.Info("created pull request for organization repository", "organization", repository.Spec.Owner, "pull-request", pr.Get().Number)
198198

199-
return nil
199+
return pr.Get().Number, nil
200200
}
201201

202202
// CreateUserPullRequest creates a pull-request for a user owned repository.
203-
func CreateUserPullRequest(ctx context.Context, gc gitprovider.Client, domain, branch string, spec deliveryv1alpha1.PullRequestTemplate, repository mpasv1alpha1.Repository) error {
203+
func CreateUserPullRequest(ctx context.Context, gc gitprovider.Client, domain, branch string, spec deliveryv1alpha1.PullRequestTemplate, repository mpasv1alpha1.Repository) (int, error) {
204204
// find the repository
205205
repo, err := gc.UserRepositories().Get(ctx, gitprovider.UserRepositoryRef{
206206
UserRef: gitprovider.UserRef{
@@ -210,7 +210,7 @@ func CreateUserPullRequest(ctx context.Context, gc gitprovider.Client, domain, b
210210
RepositoryName: repository.GetName(),
211211
})
212212
if err != nil {
213-
return fmt.Errorf("failed to find user repository: %w", err)
213+
return -1, fmt.Errorf("failed to find user repository: %w", err)
214214
}
215215

216216
var (
@@ -233,13 +233,13 @@ func CreateUserPullRequest(ctx context.Context, gc gitprovider.Client, domain, b
233233

234234
pr, err := repo.PullRequests().Create(ctx, title, branch, base, description)
235235
if err != nil {
236-
return fmt.Errorf("failed to create pull request: %w", err)
236+
return -1, fmt.Errorf("failed to create pull request: %w", err)
237237
}
238238

239239
logger := log.FromContext(ctx)
240240
logger.Info("created pull request for user repository", "user", repository.Spec.Owner, "pull-request", pr.Get().Number)
241241

242-
return nil
242+
return pr.Get().Number, nil
243243
}
244244

245245
// Repositories groups together a common functionality of both repository types.

pkg/providers/providers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ var NotSupportedError = errors.New("functionality not supported by provider")
2323
// Provider adds the ability to create repositories and pull requests.
2424
type Provider interface {
2525
CreateRepository(ctx context.Context, obj mpasv1alpha1.Repository) error
26-
CreatePullRequest(ctx context.Context, branch string, sync deliveryv1alpha1.Sync, repository mpasv1alpha1.Repository) error
26+
CreatePullRequest(ctx context.Context, branch string, sync deliveryv1alpha1.Sync, repository mpasv1alpha1.Repository) (int, error)
2727
CreateBranchProtection(ctx context.Context, obj mpasv1alpha1.Repository) error
2828
}

0 commit comments

Comments
 (0)