Skip to content
Open
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
34 changes: 16 additions & 18 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module github.com/openshift-pipelines/pipelines-as-code

go 1.24.0

toolchain go1.24.2
go 1.24.13

require (
code.gitea.io/gitea v1.24.6
Expand Down Expand Up @@ -30,14 +28,14 @@ require (
github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.10.1
github.com/stretchr/testify v1.11.1
github.com/tektoncd/pipeline v1.4.0
github.com/tektoncd/pipeline v1.6.2
gitlab.com/gitlab-org/api/client-go v0.145.0
go.opencensus.io v0.24.0
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20250911091902-df9299821621
golang.org/x/oauth2 v0.31.0
golang.org/x/sync v0.17.0
golang.org/x/text v0.29.0
golang.org/x/oauth2 v0.34.0
golang.org/x/sync v0.19.0
golang.org/x/text v0.32.0
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.5.2
k8s.io/api v0.34.1
Expand All @@ -50,15 +48,15 @@ require (
)

require (
cel.dev/expr v0.24.0 // indirect
cel.dev/expr v0.25.1 // indirect
github.com/42wim/httpsig v1.2.3 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
github.com/cert-manager/cert-manager v1.18.2 // indirect
github.com/cloudevents/sdk-go/sql/v2 v2.16.1 // indirect
github.com/coreos/go-oidc/v3 v3.15.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
github.com/go-jose/go-jose/v4 v4.1.2 // indirect
github.com/go-jose/go-jose/v3 v3.0.5 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
github.com/go-openapi/swag/cmdutils v0.24.0 // indirect
github.com/go-openapi/swag/conv v0.24.0 // indirect
github.com/go-openapi/swag/fileutils v0.24.0 // indirect
Expand Down Expand Up @@ -139,17 +137,17 @@ require (
github.com/xlzd/gotp v0.1.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.42.0 // indirect
golang.org/x/net v0.44.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/term v0.35.0
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/term v0.38.0
golang.org/x/time v0.13.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/api v0.249.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
google.golang.org/grpc v1.75.1 // indirect
google.golang.org/protobuf v1.36.9
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/grpc v1.79.3 // indirect
google.golang.org/protobuf v1.36.10
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.34.1 // indirect
Expand Down
88 changes: 44 additions & 44 deletions go.sum

Large diffs are not rendered by default.

97 changes: 97 additions & 0 deletions pkg/informer/transform/transform.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Package transform provides cache transform functions for reducing memory
// usage in the PAC watcher informer caches.
//
// Transform functions are applied to objects before they are stored in the
// informer cache, allowing us to strip large, unnecessary fields while
// preserving the data needed for reconciliation.
//
// DEVELOPER WARNING:
// If you add new reconciliation logic that reads a field from cached objects
// (via listers), you MUST verify that field is not stripped by these transforms.
// Fields stripped from cached objects will be nil/empty even though they exist
// in etcd. If you need a stripped field, fetch the full object via the API
// client instead of the lister.
package transform

import (
pacv1alpha1 "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"k8s.io/client-go/tools/cache"
)

// RepositoryForCache strips fields from Repository objects before they are
// stored in the informer cache to reduce memory usage.
//
// Fields stripped:
// - ManagedFields: written by the API server, not needed for reconciliation
// - Annotations: no reconciler logic reads Repository annotations from the
// lister; the largest annotation is kubectl.kubernetes.io/last-applied-configuration
// - Status: the reconciler always fetches Repository.Status via a direct API
// call before updating it; it is never read from the lister
func RepositoryForCache(obj any) (any, error) {
if tombstone, ok := obj.(cache.DeletedFinalStateUnknown); ok {
transformed, err := RepositoryForCache(tombstone.Obj)
if err != nil {
return obj, nil //nolint:nilerr // return original on error for graceful degradation
}
return cache.DeletedFinalStateUnknown{Key: tombstone.Key, Obj: transformed}, nil
}

repo, ok := obj.(*pacv1alpha1.Repository)
if !ok {
return obj, nil
}

repo.ManagedFields = nil
repo.Annotations = nil
repo.Status = nil

return repo, nil
}

// PipelineRunForCache strips fields from PipelineRun objects before they are
// stored in the informer cache to reduce memory usage.
//
// Fields the PAC watcher reads from cached PipelineRuns:
// - ObjectMeta: name, namespace, labels, annotations (PAC state/repo keys),
// finalizers, deletionTimestamp
// - Spec.Status: checked for PipelineRunSpecStatusPending
// - Status.Conditions: checked for completion state and reason
// - Status.StartTime, Status.CompletionTime: used for metrics
//
// All other Spec and Status fields are stripped. When the reconciler needs
// the full object (e.g. postFinalStatus, GetStatusFromTaskStatusOrFromAsking),
// it fetches it directly from the API server.
func PipelineRunForCache(obj any) (any, error) {
if tombstone, ok := obj.(cache.DeletedFinalStateUnknown); ok {
transformed, err := PipelineRunForCache(tombstone.Obj)
if err != nil {
return obj, nil //nolint:nilerr // return original on error for graceful degradation
}
return cache.DeletedFinalStateUnknown{Key: tombstone.Key, Obj: transformed}, nil
}

pr, ok := obj.(*tektonv1.PipelineRun)
if !ok {
return obj, nil
}

pr.ManagedFields = nil

// Strip large Spec fields β€” watcher only checks Spec.Status (pending state)
pr.Spec.PipelineRef = nil
pr.Spec.PipelineSpec = nil
pr.Spec.Params = nil
pr.Spec.Workspaces = nil
pr.Spec.TaskRunSpecs = nil
pr.Spec.TaskRunTemplate = tektonv1.PipelineTaskRunTemplate{}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

In Tekton v1, PipelineRunSpec.TaskRunTemplate is a pointer (*PipelineTaskRunTemplate). Assigning a zero-value struct (tektonv1.PipelineTaskRunTemplate{}) will cause a compilation error as you cannot assign a struct to a pointer field. It should be set to nil to maintain consistency with the other stripped pointer fields in this function. This in-place modification is the accepted pattern for informer TransformFuncs in this repository.

Suggested change
pr.Spec.TaskRunTemplate = tektonv1.PipelineTaskRunTemplate{}
pr.Spec.TaskRunTemplate = nil
References
  1. When implementing a Kubernetes informer TransformFunc, it is an accepted pattern to modify the object in-place to strip fields for cache optimization. A DeepCopy is not required as the modification is the intended behavior before the object is cached.

pr.Spec.Timeouts = nil

// Strip large Status fields β€” watcher only reads Conditions, StartTime, CompletionTime
pr.Status.PipelineSpec = nil
pr.Status.ChildReferences = nil
pr.Status.Provenance = nil
pr.Status.SpanContext = nil

return pr, nil
}
Loading
Loading