Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat()!: supporting workflowRunFile per repository #5

Merged
merged 1 commit into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ ENVTEST ?= $(LOCALBIN)/setup-envtest

## Tool Versions
KUSTOMIZE_VERSION ?= v4.5.5
CONTROLLER_TOOLS_VERSION ?= v0.8.0
CONTROLLER_TOOLS_VERSION ?= v0.14.0

KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"
.PHONY: kustomize
Expand Down
3 changes: 3 additions & 0 deletions api/v1alpha1/repository_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ type RepositorySpec struct {

// Whether the controller should sync all the pull requests belonging to the repository
SyncPullRequests SyncPullRequests `json:"syncPullRequests"`

// The names of the workflow files that should be checked when the status is updated
WorkflowFileNames []string `json:"workflowFileNames,omitempty"`
}

// RepositoryStatus defines the observed state of Repository
Expand Down
6 changes: 5 additions & 1 deletion api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion charts/github-pr-controller/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ version: 0.1.0
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "v0.1.4"
appVersion: "v0.1.5"
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.14.0
name: pullrequests.github.colossyan.com
spec:
group: github.colossyan.com
Expand All @@ -21,14 +20,19 @@ spec:
description: PullRequest is the Schema for the pullrequests API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
Expand Down Expand Up @@ -115,9 +119,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.14.0
name: repositories.github.colossyan.com
spec:
group: github.colossyan.com
Expand All @@ -21,14 +20,19 @@ spec:
description: Repository is the Schema for the repositories API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
Expand All @@ -42,8 +46,9 @@ spec:
description: The owner of the repository
type: string
secretName:
description: The name of the Kubernetes secret containing the OAuth
token required for the controller to access private repositories
description: |-
The name of the Kubernetes secret containing the OAuth token required
for the controller to access private repositories
type: string
syncPullRequests:
description: Whether the controller should sync all the pull requests
Expand All @@ -61,6 +66,12 @@ spec:
required:
- enabled
type: object
workflowFileNames:
description: The names of the workflow files that should be checked
when the status is updated
items:
type: string
type: array
required:
- name
- owner
Expand All @@ -81,9 +92,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
26 changes: 12 additions & 14 deletions config/crd/bases/github.colossyan.com_pullrequests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.14.0
name: pullrequests.github.colossyan.com
spec:
group: github.colossyan.com
Expand All @@ -21,14 +20,19 @@ spec:
description: PullRequest is the Schema for the pullrequests API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
Expand Down Expand Up @@ -115,9 +119,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
37 changes: 21 additions & 16 deletions config/crd/bases/github.colossyan.com_repositories.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.14.0
name: repositories.github.colossyan.com
spec:
group: github.colossyan.com
Expand All @@ -21,14 +20,19 @@ spec:
description: Repository is the Schema for the repositories API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
Expand All @@ -42,8 +46,9 @@ spec:
description: The owner of the repository
type: string
secretName:
description: The name of the Kubernetes secret containing the OAuth
token required for the controller to access private repositories
description: |-
The name of the Kubernetes secret containing the OAuth token required
for the controller to access private repositories
type: string
syncPullRequests:
description: Whether the controller should sync all the pull requests
Expand All @@ -61,6 +66,12 @@ spec:
required:
- enabled
type: object
workflowFileNames:
description: The names of the workflow files that should be checked
when the status is updated
items:
type: string
type: array
required:
- name
- owner
Expand All @@ -81,9 +92,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
1 change: 0 additions & 1 deletion config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
Expand Down
2 changes: 1 addition & 1 deletion controllers/repository_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (r *RepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}

logger.Info("syncing repository")
syncer := pkg.NewRepositorySyncer(logger, r.cache)
syncer := pkg.NewRepositorySyncer(logger, repository.Spec.WorkflowFileNames, r.cache)
repRequest := pkg.RepositorySyncInput{
Repository: repository,
Token: token,
Expand Down
49 changes: 36 additions & 13 deletions pkg/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"
"time"

"github.com/adamantal/github-pr-controller/api/v1alpha1"
githubv1alpha1 "github.com/adamantal/github-pr-controller/api/v1alpha1"
"github.com/go-logr/logr"
"github.com/google/go-github/v45/github"
Expand All @@ -13,8 +14,7 @@ import (
)

const (
pullRequestWorkflowFileName = "pull-request.yml"
maxPages = 20 // let's not rate-limit ourselves
maxPages = 20 // let's not rate-limit ourselves

day = 24 * time.Hour
week = 7 * day
Expand All @@ -23,8 +23,10 @@ const (

type RepositorySyncer struct {
logger logr.Logger
client *github.Client // lazy initialized
cache *RepositorySyncerCache // cache

workflowFileNames []string
client *github.Client // lazy initialized
cache *RepositorySyncerCache // cache
}

type RepositorySyncerCache struct {
Expand All @@ -42,10 +44,15 @@ type RepositorySyncOutput struct {
WorkflowRuns []*github.WorkflowRun
}

func NewRepositorySyncer(logger logr.Logger, cache *RepositorySyncerCache) RepositorySyncer {
func NewRepositorySyncer(
logger logr.Logger,
workflowFileNames []string,
cache *RepositorySyncerCache,
) RepositorySyncer {
return RepositorySyncer{
logger: logger,
cache: cache,
logger: logger,
workflowFileNames: workflowFileNames,
cache: cache,
}
}

Expand Down Expand Up @@ -142,6 +149,22 @@ func (rs *RepositorySyncer) sync(
}
rs.logger.V(1).Info("determined earliest timestamp", "ts", earliestTS)

for _, workflowFileName := range rs.workflowFileNames {
if err := rs.extractWorkflowRuns(ctx, client, req.Repository.Spec, workflowFileName, earliestTS); err != nil {
return nil, nil, errors.Wrap(err, "failed to extract ")
}
}

return prs, rs.cache.GetAllRuns(), nil
}

func (rs *RepositorySyncer) extractWorkflowRuns(
ctx context.Context,
client *github.Client,
repositorySpec v1alpha1.RepositorySpec,
pullRequestWorkflowFileName string,
earliestTS time.Time,
) error {
page := 1
for ; page < maxPages; page++ {
opts := github.ListWorkflowRunsOptions{
Expand All @@ -152,16 +175,16 @@ func (rs *RepositorySyncer) sync(
}

workflowRuns, _, err := client.Actions.ListWorkflowRunsByFileName(
ctx, req.Repository.Spec.Owner, req.Repository.Spec.Name, pullRequestWorkflowFileName, &opts)
ctx, repositorySpec.Owner, repositorySpec.Name, pullRequestWorkflowFileName, &opts)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to list workflows in repo")
return errors.Wrap(err, "failed to list workflows in repo")
}

if workflowRuns.WorkflowRuns == nil {
return nil, nil, errors.New("unexpected workflowruns returned from github API")
return errors.New("unexpected workflowruns returned from github API")
}
if len(workflowRuns.WorkflowRuns) == 0 {
return nil, nil, errors.New("empty workflowruns returned")
return errors.New("empty workflowruns returned")
}

cacheHit := rs.cache.SaveInCache(workflowRuns.WorkflowRuns)
Expand All @@ -170,9 +193,9 @@ func (rs *RepositorySyncer) sync(
break
}
}
rs.logger.V(1).Info("paginated workflow runs collected", "pages", page)
rs.logger.V(1).Info("paginated workflow runs collected", "workflowFileName", pullRequestWorkflowFileName, "pages", page)

return prs, rs.cache.GetAllRuns(), nil
return nil
}

func createGithubClient(ctx context.Context, token string) *github.Client {
Expand Down