Skip to content

Commit

Permalink
TEP-0154: Enable concise resolver syntax
Browse files Browse the repository at this point in the history
This PR enables concise resolver syntax as per TEP 0154.
It allows users to pass a url like string to Taskref/name field. In turn, the Tekton controller passes the string to the Resolution Request under the name `resolutionName` which the resolvers can parse and resolve.
  • Loading branch information
chitrangpatel committed Apr 5, 2024
1 parent d46d66b commit 4d90033
Show file tree
Hide file tree
Showing 50 changed files with 536 additions and 157 deletions.
2 changes: 2 additions & 0 deletions config/config-feature-flags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,5 @@ data:
enable-artifacts: "false"
# Setting this flag to "true" will enable the built-in param input validation via param enum.
enable-param-enum: "false"
# Setting this flag to "true" will enable the use of concise resolver syntax
enable-concise-resolver-syntax: "false"
30 changes: 28 additions & 2 deletions docs/how-to-write-a-resolver.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,32 @@ func (r *resolver) ValidateParams(ctx context.Context, params map[string]string)
You'll also need to add the `"errors"` package to your list of imports at
the top of the file.

## The `ValidateResolutionName` method

The `ValidateResolutionName` method checks that the `resolutionName` submitted as part of
a resolution request is valid and can be parsed by the resolver. Our example resolver expects
format for the `resolutionName` to be `demoscheme://<path>` so we'll validate this format.

```go
// ValidateResolutionName ensures resolutionName from a request is as expected.
func (r *resolver) ValidateResolutionName(ctx context.Context, resolutionName string) error {
u, err := url.ParseRequestURI(resolutionName)
if err != nil {
return err
}
if u.Scheme != "demoscheme" {
return errors.New("Invalid Scheme. Want %s, Got %s", "demoscheme", u.Scheme)
}
if u.Path == "" {
return errors.New("Empty path.")
}
return nil
}
```

You'll also need to add the `net/url` and `"errors"` package to your list of imports at
the top of the file.

## The `Resolve` method

We implement the `Resolve` method to do the heavy lifting of fetching
Expand All @@ -233,8 +259,8 @@ The method signature we're implementing here has a
is another type we have to implement but it has a small footprint:

```go
// Resolve uses the given params to resolve the requested file or resource.
func (r *resolver) Resolve(ctx context.Context, params map[string]string) (framework.ResolvedResource, error) {
// Resolve uses the given resolutionName or params to resolve the requested file or resource.
func (r *resolver) Resolve(ctx context.Context, resolutionName string, params map[string]string) (framework.ResolvedResource, error) {
return &myResolvedResource{}, nil
}

Expand Down
4 changes: 4 additions & 0 deletions docs/pipeline-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3494,6 +3494,10 @@ Example: &ldquo;task/git-clone/0.8/git-clone.yaml&rdquo;</p>
</tr>
</tbody>
</table>
<h3 id="tekton.dev/v1.RemoteResolutionUrl">RemoteResolutionUrl
(<code>string</code> alias)</h3>
<div>
</div>
<h3 id="tekton.dev/v1.ResolverName">ResolverName
(<code>string</code> alias)</h3>
<p>
Expand Down
19 changes: 18 additions & 1 deletion docs/resolver-template/cmd/demoresolver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package main
import (
"context"
"errors"
"fmt"
"net/url"

pipelinev1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"github.com/tektoncd/pipeline/pkg/apis/resolution/v1beta1"
Expand Down Expand Up @@ -51,6 +53,21 @@ func (r *resolver) GetSelector(context.Context) map[string]string {
}
}

// ValidateResolutionName ensures resolutionName from a request is as expected.
func (r *resolver) ValidateResolutionName(ctx context.Context, resolutionName string) error {
u, err := url.ParseRequestURI(resolutionName)
if err != nil {
return err
}
if u.Scheme != "demoscheme" {
return errors.New(fmt.Sprintf("Invalid Scheme. Want %s, Got %s", "demoscheme", u.Scheme))
}
if u.Path == "" {
return errors.New("Empty path.")
}
return nil
}

// ValidateParams ensures parameters from a request are as expected.
func (r *resolver) ValidateParams(ctx context.Context, params []pipelinev1.Param) error {
if len(params) > 0 {
Expand All @@ -60,7 +77,7 @@ func (r *resolver) ValidateParams(ctx context.Context, params []pipelinev1.Param
}

// Resolve uses the given params to resolve the requested file or resource.
func (r *resolver) Resolve(ctx context.Context, params []pipelinev1.Param) (framework.ResolvedResource, error) {
func (r *resolver) Resolve(ctx context.Context, resolutionName string, params []pipelinev1.Param) (framework.ResolvedResource, error) {
return &myResolvedResource{}, nil
}

Expand Down
50 changes: 49 additions & 1 deletion docs/resolver-template/cmd/demoresolver/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package main

import (
"encoding/base64"
"errors"
"testing"
"time"

Expand All @@ -27,6 +28,7 @@ import (
frtesting "github.com/tektoncd/pipeline/pkg/resolution/resolver/framework/testing"
"github.com/tektoncd/pipeline/test"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "knative.dev/pkg/apis/duck/v1"
_ "knative.dev/pkg/system/testing"
)

Expand All @@ -48,7 +50,9 @@ func TestResolver(t *testing.T) {
resolutioncommon.LabelKeyResolverType: "demo",
},
},
Spec: v1beta1.ResolutionRequestSpec{},
Spec: v1beta1.ResolutionRequestSpec{
ResolutionName: "demoscheme://foo/bar",
},
}
d := test.Data{
ResolutionRequests: []*v1beta1.ResolutionRequest{request},
Expand All @@ -65,3 +69,47 @@ func TestResolver(t *testing.T) {

frtesting.RunResolverReconcileTest(ctx, t, d, r, request, expectedStatus, expectedErr)
}

func TestResolver_Failure(t *testing.T) {
ctx, _ := ttesting.SetupFakeContext(t)

r := &resolver{}

request := &v1beta1.ResolutionRequest{
TypeMeta: metav1.TypeMeta{
APIVersion: "resolution.tekton.dev/v1beta1",
Kind: "ResolutionRequest",
},
ObjectMeta: metav1.ObjectMeta{
Name: "rr",
Namespace: "foo",
CreationTimestamp: metav1.Time{Time: time.Now()},
Labels: map[string]string{
resolutioncommon.LabelKeyResolverType: "demo",
},
},
Spec: v1beta1.ResolutionRequestSpec{
ResolutionName: "wrongscheme://foo/bar",
},
}
d := test.Data{
ResolutionRequests: []*v1beta1.ResolutionRequest{request},
}

expectedStatus := &v1beta1.ResolutionRequestStatus{
Status: v1.Status{
Conditions: v1.Conditions{
{
Type: "Succeeded",
Status: "False",
Reason: "ResolutionFailed",
Message: `invalid resource request "foo/rr": Invalid Scheme. Want demoscheme, Got wrongscheme`,
},
},
},
}

// If you want to test scenarios where an error should occur, pass a non-nil error to RunResolverReconcileTest
expectedErr := errors.New(`invalid resource request "foo/rr": Invalid Scheme. Want demoscheme, Got wrongscheme`)
frtesting.RunResolverReconcileTest(ctx, t, d, r, request, expectedStatus, expectedErr)
}
25 changes: 25 additions & 0 deletions go.sum

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

36 changes: 23 additions & 13 deletions pkg/apis/config/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ const (
EnableCELInWhenExpression = "enable-cel-in-whenexpression"
// EnableStepActions is the flag to enable the use of StepActions in Steps
EnableStepActions = "enable-step-actions"

// EnableArtifacts is the flag to enable the use of Artifacts in Steps
EnableArtifacts = "enable-artifacts"

// EnableParamEnum is the flag to enabled enum in params
EnableParamEnum = "enable-param-enum"
// EnableConciseResolverSyntax is the flag to enable concise resolver syntax
EnableConciseResolverSyntax = "enable-concise-resolver-syntax"

disableAffinityAssistantKey = "disable-affinity-assistant"
disableCredsInitKey = "disable-creds-init"
Expand Down Expand Up @@ -160,6 +160,13 @@ var (
Stability: AlphaAPIFields,
Enabled: DefaultAlphaFeatureEnabled,
}

// DefaultEnableConciseResolverSyntax is the default PerFeatureFlag value for EnableConciseResolverSyntax
DefaultEnableConciseResolverSyntax = PerFeatureFlag{
Name: EnableConciseResolverSyntax,
Stability: AlphaAPIFields,
Enabled: DefaultAlphaFeatureEnabled,
}
)

// FeatureFlags holds the features configurations
Expand All @@ -183,16 +190,17 @@ type FeatureFlags struct {
// ignore: skip trusted resources verification when no matching verification policies found
// warn: skip trusted resources verification when no matching verification policies found and log a warning
// fail: fail the taskrun or pipelines run if no matching verification policies found
VerificationNoMatchPolicy string
EnableProvenanceInStatus bool
ResultExtractionMethod string
MaxResultSize int
SetSecurityContext bool
Coschedule string
EnableCELInWhenExpression bool
EnableStepActions bool
EnableParamEnum bool
EnableArtifacts bool
VerificationNoMatchPolicy string
EnableProvenanceInStatus bool
ResultExtractionMethod string
MaxResultSize int
SetSecurityContext bool
Coschedule string
EnableCELInWhenExpression bool
EnableStepActions bool
EnableParamEnum bool
EnableArtifacts bool
EnableConciseResolverSyntax bool
}

// GetFeatureFlagsConfigName returns the name of the configmap containing all
Expand Down Expand Up @@ -287,10 +295,12 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) {
if err := setPerFeatureFlag(EnableParamEnum, DefaultEnableParamEnum, &tc.EnableParamEnum); err != nil {
return nil, err
}

if err := setPerFeatureFlag(EnableArtifacts, DefaultEnableArtifacts, &tc.EnableArtifacts); err != nil {
return nil, err
}
if err := setPerFeatureFlag(EnableConciseResolverSyntax, DefaultEnableConciseResolverSyntax, &tc.EnableConciseResolverSyntax); err != nil {
return nil, err
}
// Given that they are alpha features, Tekton Bundles and Custom Tasks should be switched on if
// enable-api-fields is "alpha". If enable-api-fields is not "alpha" then fall back to the value of
// each feature's individual flag.
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/config/feature_flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
EnableCELInWhenExpression: config.DefaultEnableCELInWhenExpression.Enabled,
EnableStepActions: config.DefaultEnableStepActions.Enabled,
EnableParamEnum: config.DefaultEnableParamEnum.Enabled,
EnableConciseResolverSyntax: config.DefaultEnableConciseResolverSyntax.Enabled,
},
fileName: config.GetFeatureFlagsConfigName(),
},
Expand All @@ -81,6 +82,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
EnableStepActions: true,
EnableArtifacts: true,
EnableParamEnum: true,
EnableConciseResolverSyntax: true,
},
fileName: "feature-flags-all-flags-set",
},
Expand Down Expand Up @@ -307,6 +309,9 @@ func TestNewFeatureFlagsConfigMapErrors(t *testing.T) {
}, {
fileName: "feature-flags-invalid-enable-artifacts",
want: `failed parsing feature flags config "invalid": strconv.ParseBool: parsing "invalid": invalid syntax for feature enable-artifacts`,
}, {
fileName: "feature-flags-invalid-enable-concise-resolver-syntax",
want: `failed parsing feature flags config "invalid": strconv.ParseBool: parsing "invalid": invalid syntax for feature enable-concise-resolver-syntax`,
}} {
t.Run(tc.fileName, func(t *testing.T) {
cm := test.ConfigMapFromTestFile(t, tc.fileName)
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/config/testdata/feature-flags-all-flags-set.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ data:
enable-step-actions: "true"
enable-param-enum: "true"
enable-artifacts: "true"
enable-concise-resolver-syntax: "true"
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2024 The Tekton Authors
#
# 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
#
# https://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.

apiVersion: v1
kind: ConfigMap
metadata:
name: feature-flags
namespace: tekton-pipelines
data:
enable-concise-resolver-syntax: "invalid"
Loading

0 comments on commit 4d90033

Please sign in to comment.