Skip to content
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
9 changes: 9 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,13 @@ resources:
kind: JobRequest
path: github.com/alphagov/govuk-job-request-operator/api/v1
version: v1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: publishing.service.gov.uk
group: platform
kind: JobRequestReview
path: github.com/alphagov/govuk-job-request-operator/api/v1
version: v1
version: "3"
72 changes: 72 additions & 0 deletions api/v1/jobrequestreview_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
Copyright 2026.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// JobRequestReviewSpec defines the desired state of JobRequestReview
type JobRequestReviewSpec struct {
// Name of the JobRequest resource being reviewed.
JobRequestName string `json:"jobRequestName"`
// +kubebuilder:validation:Enum=Approved;Rejected
Decision string `json:"decision"`
// A description of the review decision.
// +optional
Description string `json:"description,omitempty"`
}

// JobRequestReviewStatus defines the observed state of JobRequestReview.
type JobRequestReviewStatus struct {
// Kubernetes username of the reviewer.
ReviewedBy string `json:"reviewedBy,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:resource:shortName=jrr
// +kubebuilder:subresource:status

// JobRequestReview is the Schema for the jobrequestreviews API
type JobRequestReview struct {
metav1.TypeMeta `json:",inline"`

// metadata is a standard object metadata
// +optional
metav1.ObjectMeta `json:"metadata,omitzero"`

// spec defines the desired state of JobRequestReview
// +required
Spec JobRequestReviewSpec `json:"spec"`

// status defines the observed state of JobRequestReview
// +optional
Status JobRequestReviewStatus `json:"status,omitzero"`
}

// +kubebuilder:object:root=true

// JobRequestReviewList contains a list of JobRequestReview
type JobRequestReviewList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitzero"`
Items []JobRequestReview `json:"items"`
}

func init() {
SchemeBuilder.Register(&JobRequestReview{}, &JobRequestReviewList{})
}
89 changes: 89 additions & 0 deletions api/v1/zz_generated.deepcopy.go

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

7 changes: 7 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@ func main() {
setupLog.Error(err, "Failed to create controller", "controller", "jobrequest")
os.Exit(1)
}
if err := (&controller.JobRequestReviewReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "Failed to create controller", "controller", "jobrequestreview")
os.Exit(1)
}
// +kubebuilder:scaffold:builder

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.20.1
name: jobrequestreviews.platform.publishing.service.gov.uk
spec:
group: platform.publishing.service.gov.uk
names:
kind: JobRequestReview
listKind: JobRequestReviewList
plural: jobrequestreviews
shortNames:
- jrr
singular: jobrequestreview
scope: Namespaced
versions:
- name: v1
schema:
openAPIV3Schema:
description: JobRequestReview is the Schema for the jobrequestreviews 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
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
type: string
metadata:
type: object
spec:
description: spec defines the desired state of JobRequestReview
properties:
decision:
enum:
- Approved
- Rejected
type: string
description:
description: A description of the review decision.
type: string
jobRequestName:
description: Name of the JobRequest resource being reviewed.
type: string
required:
- decision
- jobRequestName
type: object
status:
description: status defines the observed state of JobRequestReview
properties:
reviewedBy:
description: Kubernetes username of the reviewer.
type: string
type: object
required:
- spec
type: object
served: true
storage: true
subresources:
status: {}
63 changes: 63 additions & 0 deletions internal/controller/jobrequestreview_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
Copyright 2026.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controller

import (
"context"

"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"

platformv1 "github.com/alphagov/govuk-job-request-operator/api/v1"
)

// JobRequestReviewReconciler reconciles a JobRequestReview object
type JobRequestReviewReconciler struct {
client.Client
Scheme *runtime.Scheme
}

// +kubebuilder:rbac:groups=platform.publishing.service.gov.uk,resources=jobrequestreviews,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=platform.publishing.service.gov.uk,resources=jobrequestreviews/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=platform.publishing.service.gov.uk,resources=jobrequestreviews/finalizers,verbs=update

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the JobRequestReview object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.23.3/pkg/reconcile
func (r *JobRequestReviewReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = logf.FromContext(ctx)

// TODO(user): your logic here

return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *JobRequestReviewReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&platformv1.JobRequestReview{}).
Named("jobrequestreview").
Complete(r)
}
Loading