From 2ab809f4e3ac2b266e4d88520e1a20d6420c6c6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Casta=C3=B1o=20Arteaga?= Date: Tue, 2 Apr 2024 12:18:14 +0200 Subject: [PATCH] Add support for Tekton StepActions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sergio Castaño Arteaga Signed-off-by: Cintia Sanchez Garcia Co-authored-by: Sergio Castaño Arteaga Co-authored-by: Cintia Sanchez Garcia --- .ct.yaml | 1 + README.md | 2 +- charts/artifact-hub/Chart.yaml | 2 +- charts/artifact-hub/values.schema.json | 2 +- cmd/ah/lint.go | 10 +- .../schema/057_tekton_stepactions.sql | 5 + database/tests/schema/schema.sql | 3 +- docs/api/openapi.yaml | 78 ++++++++++++++++ docs/repositories.md | 1 + docs/security_report.md | 4 +- docs/tekton_stepactions_repositories.md | 3 + .../headers/tekton_stepactions_repositories | 6 ++ internal/handlers/handlers.go | 4 +- internal/handlers/pkg/handlers_test.go | 11 +++ internal/hub/repo.go | 7 ++ internal/repo/manager.go | 12 ++- internal/tracker/helpers.go | 2 +- internal/tracker/source/tekton/tekton.go | 21 ++++- internal/tracker/source/tekton/tekton_test.go | 93 +++++++++++++++++++ .../testdata/path5/stepaction1/0.1/README.md | 1 + .../stepaction1/0.1/samples/sample1.yaml | 1 + .../path5/stepaction1/0.1/stepaction1.yaml | 37 ++++++++ internal/tracker/tracker.go | 3 +- scripts/prepare-docs.sh | 1 + web/src/layout/common/Image.tsx | 1 + web/src/layout/common/RepositoryIcon.test.tsx | 7 ++ web/src/layout/common/RepositoryIcon.tsx | 4 + web/src/layout/common/badges/Signed.tsx | 1 + .../controlPanel/repositories/Modal.tsx | 24 ++++- .../__snapshots__/Modal.test.tsx.snap | 5 + .../home/__snapshots__/index.test.tsx.snap | 4 +- web/src/layout/home/index.tsx | 8 +- web/src/layout/package/Details.tsx | 1 + .../package/RecommendedPackages/index.tsx | 2 +- web/src/layout/package/index.tsx | 1 + .../package/installation/TektonInstall.tsx | 22 ++++- web/src/types.ts | 1 + web/src/utils/data.tsx | 11 ++- web/src/utils/getInstallMethods.ts | 1 + web/src/utils/repoKind.test.tsx | 8 ++ web/src/utils/repoKind.ts | 4 + widget/public/index.html | 1 + widget/src/layout/Widget.tsx | 2 + widget/src/layout/common/Image.test.tsx | 7 ++ widget/src/layout/common/Image.tsx | 1 + widget/src/layout/common/RepositoryIcon.tsx | 1 + .../src/layout/common/RepositoryIconLabel.tsx | 4 + widget/src/types.ts | 1 + 48 files changed, 399 insertions(+), 33 deletions(-) create mode 100644 database/migrations/schema/057_tekton_stepactions.sql create mode 100644 docs/tekton_stepactions_repositories.md create mode 100644 docs/www/headers/tekton_stepactions_repositories create mode 100644 internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/README.md create mode 100644 internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/samples/sample1.yaml create mode 100644 internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/stepaction1.yaml diff --git a/.ct.yaml b/.ct.yaml index 952b8b0b5..cec5553db 100644 --- a/.ct.yaml +++ b/.ct.yaml @@ -1,3 +1,4 @@ helm-extra-args: --timeout 180s chart-repos: - stable=https://charts.helm.sh/stable +validate-maintainers: false diff --git a/README.md b/README.md index 7928b94a5..dedd6f0c7 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ At the moment, the following artifacts kinds are supported *(with plans to suppo - [Kyverno policies](https://kyverno.io) - [OLM operators](https://github.com/operator-framework) - [Open Policy Agent (OPA) policies](https://www.openpolicyagent.org/) -- [Tekton tasks and pipelines](https://tekton.dev/) +- [Tekton tasks, pipelines and stepactions](https://tekton.dev/) - [Tinkerbell actions](https://tinkerbell.org/) You can use Artifact Hub to: diff --git a/charts/artifact-hub/Chart.yaml b/charts/artifact-hub/Chart.yaml index 97cfaedde..aaee10a39 100644 --- a/charts/artifact-hub/Chart.yaml +++ b/charts/artifact-hub/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: artifact-hub description: Artifact Hub is a web-based application that enables finding, installing, and publishing Kubernetes packages. type: application -version: 1.17.1-0 +version: 1.17.1-1 appVersion: 1.17.0 kubeVersion: ">= 1.19.0-0" home: https://artifacthub.io diff --git a/charts/artifact-hub/values.schema.json b/charts/artifact-hub/values.schema.json index ac80f47c8..ec13c53fe 100644 --- a/charts/artifact-hub/values.schema.json +++ b/charts/artifact-hub/values.schema.json @@ -1162,7 +1162,7 @@ }, "repositoriesKinds": { "title": "Repositories kinds to process ([] = all)", - "description": "The following kinds are supported at the moment: falco, helm, olm, opa, tbaction, krew, helm-plugin, tekton-task, keda-scaler, coredns, keptn, tekton-pipeline, container, kubewarden, gatekeeper, kyverno, knative-client-plugin, backstage, argo-template, kubearmor, kcl, headlamp, inspektor-gadget", + "description": "The following kinds are supported at the moment: falco, helm, olm, opa, tbaction, krew, helm-plugin, tekton-task, keda-scaler, coredns, keptn, tekton-pipeline, container, kubewarden, gatekeeper, kyverno, knative-client-plugin, backstage, argo-template, kubearmor, kcl, headlamp, inspektor-gadget, tekton-stepaction", "type": "array", "items": { "type": "string" diff --git a/cmd/ah/lint.go b/cmd/ah/lint.go index c56721c0f..f82d17cea 100644 --- a/cmd/ah/lint.go +++ b/cmd/ah/lint.go @@ -90,7 +90,7 @@ func newLintCmd() *cobra.Command { return lint(opts, &output{cmd.OutOrStdout()}) }, } - lintCmd.Flags().StringVarP(&opts.kind, "kind", "k", "helm", "repository kind: argo-template, backstage, coredns, falco, gatekeeper, headlamp, helm, helm-plugin, inspektor-gadget, kcl, keda-scaler, keptn, knative-client-plugin, krew, kubearmor, kubewarden, kyverno, olm, opa, tbaction, tekton-task, tekton-pipeline") + lintCmd.Flags().StringVarP(&opts.kind, "kind", "k", "helm", "repository kind: argo-template, backstage, coredns, falco, gatekeeper, headlamp, helm, helm-plugin, inspektor-gadget, kcl, keda-scaler, keptn, knative-client-plugin, krew, kubearmor, kubewarden, kyverno, olm, opa, tbaction, tekton-task, tekton-pipeline, tekton-stepaction") lintCmd.Flags().StringVarP(&opts.path, "path", "p", ".", "repository's packages path") return lintCmd } @@ -134,7 +134,7 @@ func lint(opts *lintOptions, out *output) error { report = lintKrew(opts.path) case hub.OLM: report = lintOLM(opts.path) - case hub.TektonTask, hub.TektonPipeline: + case hub.TektonTask, hub.TektonPipeline, hub.TektonStepAction: report = lintTekton(opts.path, kind) default: return errors.New("kind not supported yet") @@ -376,9 +376,9 @@ func lintOLM(basePath string) *lintReport { return report } -// lintTekton checks if the Tekton tasks or pipelines available in the path -// provided are ready to be processed by the Tekton tracker source and listed -// on Artifact Hub. +// lintTekton checks if the Tekton tasks, pipelines or stepactions available in +// the path provided are ready to be processed by the Tekton tracker source and +// listed on Artifact Hub. func lintTekton(basePath string, kind hub.RepositoryKind) *lintReport { report := &lintReport{} repository := &hub.Repository{ diff --git a/database/migrations/schema/057_tekton_stepactions.sql b/database/migrations/schema/057_tekton_stepactions.sql new file mode 100644 index 000000000..07322d4d2 --- /dev/null +++ b/database/migrations/schema/057_tekton_stepactions.sql @@ -0,0 +1,5 @@ +insert into repository_kind values (23, 'Tekton stepactions'); + +---- create above / drop below ---- + +delete from repository_kind where repository_kind_id = 23; diff --git a/database/tests/schema/schema.sql b/database/tests/schema/schema.sql index 8d525a5f9..9f77bbe14 100644 --- a/database/tests/schema/schema.sql +++ b/database/tests/schema/schema.sql @@ -564,7 +564,8 @@ select results_eq( (19, 'KubeArmor policies'), (20, 'KCL modules'), (21, 'Headlamp plugins'), - (22, 'Inspektor gadgets') + (22, 'Inspektor gadgets'), + (23, 'Tekton stepactions') $$, 'Repository kinds should exist' ); diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml index 0cff89c78..898fb2aaf 100644 --- a/docs/api/openapi.yaml +++ b/docs/api/openapi.yaml @@ -1621,6 +1621,30 @@ paths: $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalServerError" + "/packages/tekton-stepaction/{repoName}/{packageName}": + get: + tags: + - Packages + summary: Get package details + description: Get package details + operationId: getTektonStepActionDetails + parameters: + - $ref: "#/components/parameters/RepoNameParam" + - $ref: "#/components/parameters/PackageNameParam" + responses: + "200": + description: "" + content: + application/json: + schema: + $ref: "#/components/schemas/TektonStepActionPackage" + "404": + $ref: "#/components/responses/NotFoundResponse" + "429": + $ref: "#/components/responses/TooManyRequests" + "500": + $ref: "#/components/responses/InternalServerError" + "/packages/tekton-task/{repoName}/{packageName}": get: tags: @@ -2172,6 +2196,30 @@ paths: $ref: "#/components/responses/TooManyRequests" "500": $ref: "#/components/responses/InternalServerError" + "/packages/tekton-stepaction/{repoName}/{packageName}/{version}": + get: + tags: + - Packages + summary: Get package version details + description: Get package version details + operationId: getTektonStepActionVersionDetails + parameters: + - $ref: "#/components/parameters/RepoNameParam" + - $ref: "#/components/parameters/PackageNameParam" + - $ref: "#/components/parameters/VersionParam" + responses: + "200": + description: "" + content: + application/json: + schema: + $ref: "#/components/schemas/TektonStepActionPackage" + "404": + $ref: "#/components/responses/NotFoundResponse" + "429": + $ref: "#/components/responses/TooManyRequests" + "500": + $ref: "#/components/responses/InternalServerError" "/packages/tekton-task/{repoName}/{packageName}/{version}": get: tags: @@ -4396,6 +4444,32 @@ components: type: string nullable: false example: darwin/amd64 + TektonStepActionPackage: + allOf: + - $ref: "#/components/schemas/Package" + - type: object + properties: + data: + type: object + properties: + pipelines.minVersion: + type: string + example: 2.0.0 + manifestRaw: + type: string + additionalProperties: + type: string + example: "apiVersion: tekton.dev/v1beta1" + examples: + type: object + nullable: false + additionalProperties: true + platforms: + type: array + items: + type: string + nullable: false + example: darwin/amd64 TektonTaskPackage: allOf: - $ref: "#/components/schemas/Package" @@ -4832,6 +4906,7 @@ components: * `20` - KCL packages * `21` - Headlamp plugins * `22` - Inspektor gadgets + * `23` - Tekton stepactions RepositoryKindParam: type: string enum: @@ -4858,6 +4933,7 @@ components: - kcl - headlamp - inspektor-gadget + - tekton-stepaction description: | Repository kind name: * `helm` - Helm charts @@ -4883,6 +4959,7 @@ components: * `kcl` - KCL packages * `headlamp` - Headlamp plugins * `inspektor-gadget` - Inspektor gadgets + * `tekton-stepaction` - Tekton stepactions RepositorySummary: type: object required: @@ -5425,6 +5502,7 @@ components: * `20` - KCL packages * `21` - Headlamp plugins * `22` - Inspektor gadgets + * `23` - Tekton stepactions PackageNameParam: in: path name: packageName diff --git a/docs/repositories.md b/docs/repositories.md index 50cda202b..228ba1b89 100644 --- a/docs/repositories.md +++ b/docs/repositories.md @@ -25,6 +25,7 @@ The following repositories kinds are supported at the moment: - [OPA policies repositories](https://github.com/artifacthub/hub/blob/master/docs/opa_policies_repositories.md) - [Tekton pipelines repositories](https://github.com/artifacthub/hub/blob/master/docs/tekton_pipelines_repositories.md) - [Tekton tasks repositories](https://github.com/artifacthub/hub/blob/master/docs/tekton_tasks_repositories.md) +- [Tekton stepactions repositories](https://github.com/artifacthub/hub/blob/master/docs/tekton_stepactions_repositories.md) - [Tinkerbell actions repositories](https://github.com/artifacthub/hub/blob/master/docs/tinkerbell_actions_repositories.md) This guide also contains additional information about the following repositories topics: diff --git a/docs/security_report.md b/docs/security_report.md index c25c74d4a..f37b0711b 100644 --- a/docs/security_report.md +++ b/docs/security_report.md @@ -18,9 +18,9 @@ Artifact Hub will try to extract the containers images used by Helm charts from The images used by an OLM operator are extracted from the `containerImage` annotation in the [CSV file metadata section](https://github.com/operator-framework/community-operators/blob/master/docs/packaging-required-fields.md), as well as from the `related images` section in the CSV spec. Most of the OLM operators currently listed in Artifact Hub provide that information already, so security reports for them are already available in Artifact Hub with no extra effort required. -### Tekton tasks and pipelines +### Tekton tasks, pipelines and stepactions -The images used by Tekton tasks and pipelines are extracted from the [`task.step.image`](https://github.com/tektoncd/pipeline/blob/main/docs/tasks.md#running-scripts-within-steps) fields of the resource yaml file. If the `image` value is specified by [`params`](https://github.com/tektoncd/pipeline/blob/main/docs/tasks.md#specifying-parameters), the default value of the params (if provided) is used to run the security report. You can find examples with explanations [here](https://github.com/tektoncd/community/blob/main/teps/0079-tekton-catalog-support-tiers.md#extract-container-images-from-catalogs). Please note that the security reports do not include user-provided container images if the default value of the image `params` are overwritten by `pipelineRun` or `taskRun` at run time. +The images used by Tekton tasks, pipelines and stepactions are extracted from the [`task.step.image`](https://github.com/tektoncd/pipeline/blob/main/docs/tasks.md#running-scripts-within-steps) fields of the resource yaml file. If the `image` value is specified by [`params`](https://github.com/tektoncd/pipeline/blob/main/docs/tasks.md#specifying-parameters), the default value of the params (if provided) is used to run the security report. You can find examples with explanations [here](https://github.com/tektoncd/community/blob/main/teps/0079-tekton-catalog-support-tiers.md#extract-container-images-from-catalogs). Please note that the security reports do not include user-provided container images if the default value of the image `params` are overwritten by `pipelineRun` or `taskRun` at run time. ### CoreDNS plugins, KEDA scalers, Keptn integrations, OPA policies and Tinkerbell actions diff --git a/docs/tekton_stepactions_repositories.md b/docs/tekton_stepactions_repositories.md new file mode 100644 index 000000000..a1fac6f58 --- /dev/null +++ b/docs/tekton_stepactions_repositories.md @@ -0,0 +1,3 @@ +## Tekton stepactions repositories + +Tekton stepactions repositories are expected to follow the same rules as Tekton tasks repositories. Please see the [Tekton tasks repositories](https://github.com/artifacthub/hub/blob/master/docs/tekton_tasks_repositories.md) documentation for more details. diff --git a/docs/www/headers/tekton_stepactions_repositories b/docs/www/headers/tekton_stepactions_repositories new file mode 100644 index 000000000..ef6e1fc95 --- /dev/null +++ b/docs/www/headers/tekton_stepactions_repositories @@ -0,0 +1,6 @@ +--- +title: "Tekton stepactions" +aliases: [ + "/tekton_stepactions_repositories", +] +--- diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index 60e140ad5..7695f7cc9 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -265,7 +265,7 @@ func (h *Handlers) setupRouter() { r.Get("/stats", h.Packages.GetStats) r.With(corsMW).Get("/search", h.Packages.Search) r.With(h.Users.RequireLogin).Get("/starred", h.Packages.GetStarredByUser) - r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl|^headlamp|^inspektor-gadget$}/{repoName}/{packageName}", func(r chi.Router) { + r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl|^headlamp|^inspektor-gadget|^tekton-stepaction$}/{repoName}/{packageName}", func(r chi.Router) { r.Get("/feed/rss", h.Packages.RssFeed) r.With(corsMW).Get("/summary", h.Packages.GetSummary) r.Get("/{version}", h.Packages.Get) @@ -430,7 +430,7 @@ func (h *Handlers) setupRouter() { // Index special entry points r.Route("/packages", func(r chi.Router) { - r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl|^headlamp|^inspektor-gadget$}/{repoName}/{packageName}", func(r chi.Router) { + r.Route("/{^helm$|^falco$|^opa$|^olm|^tbaction|^krew|^helm-plugin|^tekton-task|^keda-scaler|^coredns|^keptn|^tekton-pipeline|^container|^kubewarden|^gatekeeper|^kyverno|^knative-client-plugin|^backstage|^argo-template|^kubearmor|^kcl|^headlamp|^inspektor-gadget|^tekton-stepaction$}/{repoName}/{packageName}", func(r chi.Router) { r.With(h.Packages.InjectIndexMeta).Get("/{version}", h.Static.Index) r.With(h.Packages.InjectIndexMeta).Get("/", h.Static.Index) }) diff --git a/internal/handlers/pkg/handlers_test.go b/internal/handlers/pkg/handlers_test.go index 36571337b..1faaa5c6b 100644 --- a/internal/handlers/pkg/handlers_test.go +++ b/internal/handlers/pkg/handlers_test.go @@ -2177,6 +2177,17 @@ func TestBuildURL(t *testing.T) { "2.0.0", baseURL + "/packages/inspektor-gadget/repo1/pkg1/2.0.0", }, + { + &hub.Package{ + NormalizedName: "pkg1", + Repository: &hub.Repository{ + Kind: hub.TektonStepAction, + Name: "repo1", + }, + }, + "2.0.0", + baseURL + "/packages/tekton-stepaction/repo1/pkg1/2.0.0", + }, } for _, tc := range testCases { tc := tc diff --git a/internal/hub/repo.go b/internal/hub/repo.go index 25eaed2c5..145a5b907 100644 --- a/internal/hub/repo.go +++ b/internal/hub/repo.go @@ -115,6 +115,9 @@ const ( // InspektorGadget represents a repository with Inspektor Gadgets. InspektorGadget RepositoryKind = 22 + + // TektonStepAction represents a repository with Tekton stepactions. + TektonStepAction RepositoryKind = 23 ) // GetKindName returns the name of the provided repository kind. @@ -166,6 +169,8 @@ func GetKindName(kind RepositoryKind) string { return "tekton-pipeline" case TektonTask: return "tekton-task" + case TektonStepAction: + return "tekton-stepaction" default: return "" } @@ -221,6 +226,8 @@ func GetKindFromName(kind string) (RepositoryKind, error) { return TektonPipeline, nil case "tekton-task": return TektonTask, nil + case "tekton-stepaction": + return TektonStepAction, nil default: return -1, errors.New("invalid kind name") } diff --git a/internal/repo/manager.go b/internal/repo/manager.go index 0854d098c..e7d71eedb 100644 --- a/internal/repo/manager.go +++ b/internal/repo/manager.go @@ -101,6 +101,7 @@ var ( hub.TBAction, hub.TektonPipeline, hub.TektonTask, + hub.TektonStepAction, } ) @@ -300,7 +301,8 @@ func (m *Manager) ClaimOwnership(ctx context.Context, repoName, orgName string) hub.OPA, hub.TBAction, hub.TektonPipeline, - hub.TektonTask: + hub.TektonTask, + hub.TektonStepAction: tmpDir, packagesPath, err := m.rc.CloneRepository(ctx, r) if err != nil { return err @@ -480,7 +482,8 @@ func (m *Manager) locateMetadataFile(r *hub.Repository, basePath string) string hub.OPA, hub.TBAction, hub.TektonPipeline, - hub.TektonTask: + hub.TektonTask, + hub.TektonStepAction: mdFile = filepath.Join(basePath, hub.RepositoryMetadataFile) } return mdFile @@ -579,7 +582,7 @@ func (m *Manager) GetRemoteDigest(ctx context.Context, r *hub.Repository) (strin case GitRepoURLRE.MatchString(r.URL): // Do not track repo's digest for Tekton repos using git based versioning - if (r.Kind == hub.TektonTask || r.Kind == hub.TektonPipeline) && r.Data != nil { + if (r.Kind == hub.TektonTask || r.Kind == hub.TektonPipeline || r.Kind == hub.TektonStepAction) && r.Data != nil { var data *hub.TektonData if err := json.Unmarshal(r.Data, &data); err != nil { return "", fmt.Errorf("invalid tekton repository data: %w", err) @@ -844,7 +847,8 @@ func (m *Manager) validateURL(r *hub.Repository) error { hub.OPA, hub.TBAction, hub.TektonPipeline, - hub.TektonTask: + hub.TektonTask, + hub.TektonStepAction: if SchemeIsHTTP(u) && !GitRepoURLRE.MatchString(r.URL) { return errors.New("invalid url format") } diff --git a/internal/tracker/helpers.go b/internal/tracker/helpers.go index 2ea1cc050..c16a54d2a 100644 --- a/internal/tracker/helpers.go +++ b/internal/tracker/helpers.go @@ -129,7 +129,7 @@ func SetupSource(i *hub.TrackerSourceInput) hub.TrackerSource { hub.OPA, hub.TBAction: source = generic.NewTrackerSource(i) - case hub.TektonTask, hub.TektonPipeline: + case hub.TektonTask, hub.TektonPipeline, hub.TektonStepAction: source = tekton.NewTrackerSource(i) } return source diff --git a/internal/tracker/source/tekton/tekton.go b/internal/tracker/source/tekton/tekton.go index b2959d3c6..482508a5f 100644 --- a/internal/tracker/source/tekton/tekton.go +++ b/internal/tracker/source/tekton/tekton.go @@ -22,6 +22,7 @@ import ( "github.com/go-git/go-git/v5/plumbing" "github.com/hashicorp/go-multierror" v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" + v1alpha "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" pipelinerun "github.com/tektoncd/pipeline/pkg/reconciler/pipelinerun/resources" taskrun "github.com/tektoncd/pipeline/pkg/reconciler/taskrun/resources" "sigs.k8s.io/yaml" @@ -278,7 +279,7 @@ func (s *TrackerSource) warn(err error) { } // GetManifest reads, parses and validates the package manifest, which can be a -// Tekton task or a pipeline manifest. +// Tekton task, pipeline or stepaction manifest. func GetManifest(kind hub.RepositoryKind, pkgName, pkgPath string) (interface{}, []byte, error) { manifestPath := path.Join(pkgPath, pkgName+".yaml") manifestData, err := os.ReadFile(manifestPath) @@ -291,6 +292,8 @@ func GetManifest(kind hub.RepositoryKind, pkgName, pkgPath string) (interface{}, manifest = &v1.Task{} case hub.TektonPipeline: manifest = &v1.Pipeline{} + case hub.TektonStepAction: + manifest = &v1alpha.StepAction{} } if err := yaml.Unmarshal(manifestData, &manifest); err != nil { return nil, nil, err @@ -316,6 +319,10 @@ func validateManifest(manifest interface{}) error { name = m.Name version = m.Labels[versionLabelTKey] description = m.Spec.Description + case *v1alpha.StepAction: + name = m.Name + version = m.Labels[versionLabelTKey] + description = "Tekton StepAction" // TODO: description missing in v1alpha.StepAction } // Validate manifest data @@ -335,7 +342,7 @@ func validateManifest(manifest interface{}) error { } // PreparePackageInput represents the information required to prepare a package -// of Tekton task and pipelines kinds. +// of Tekton task, pipeline and stepaction kinds. type PreparePackageInput struct { R *hub.Repository Tag string @@ -388,6 +395,16 @@ func PreparePackage(i *PreparePackageInput) (*hub.Package, error) { "run_after": mts.RunAfter, }) } + case *v1alpha.StepAction: + tektonKind = "stepaction" + name = m.Name + version = m.Labels[versionLabelTKey] + descriptionPrefix := m.Annotations[displayNameTKey] + if descriptionPrefix == "" { + descriptionPrefix = name + } + description = fmt.Sprintf("%s StepAction", descriptionPrefix) + annotations = m.Annotations } // Prepare version diff --git a/internal/tracker/source/tekton/tekton_test.go b/internal/tracker/source/tekton/tekton_test.go index f45af4adb..bd78a6993 100644 --- a/internal/tracker/source/tekton/tekton_test.go +++ b/internal/tracker/source/tekton/tekton_test.go @@ -271,4 +271,97 @@ func TestTrackerSource(t *testing.T) { assert.NoError(t, err) sw.AssertExpectations(t) }) + + t.Run("one package returned (tekton-stepaction), no errors", func(t *testing.T) { + t.Parallel() + + // Setup services and expectations + sw := source.NewTestsServicesWrapper() + i := &hub.TrackerSourceInput{ + Repository: &hub.Repository{ + Kind: hub.TektonStepAction, + URL: "https://github.com/user/repo/path", + Data: json.RawMessage(fmt.Sprintf(`{"versioning": "%s"}`, hub.TektonDirBasedVersioning)), + }, + BasePath: "testdata/path5", + Svc: sw.Svc, + } + + // Run test and check expectations + manifestRaw, _ := os.ReadFile("testdata/path5/stepaction1/0.1/stepaction1.yaml") + var tasks []map[string]interface{} + p := &hub.Package{ + Name: "stepaction1", + DisplayName: "StepAction 1", + Description: "StepAction 1 StepAction", + Keywords: []string{"tekton", "stepaction", "tag1", "tag2"}, + Readme: "This is just a test stepaction\n", + Version: "0.1.0", + Provider: "Some organization", + ContentURL: "https://github.com/user/repo/raw/master/path/stepaction1/0.1/stepaction1.yaml", + Digest: "530682380f55de185372b1f2c776c0ef82b75273e33f9af34fa0279a9fb8ee0f", + Repository: i.Repository, + License: "Apache-2.0", + Links: []*hub.Link{ + { + Name: "source", + URL: "https://github.com/user/repo/blob/master/path/stepaction1/0.1/stepaction1.yaml", + }, + { + Name: "link1", + URL: "https://link1.url", + }, + { + Name: "link2", + URL: "https://link2.url", + }, + }, + Maintainers: []*hub.Maintainer{ + { + Name: "user1", + Email: "user1@email.com", + }, + { + Name: "user2", + Email: "user2@email.com", + }, + }, + Changes: []*hub.Change{ + { + Description: "Added cool feature", + }, + { + Description: "Fixed minor bug", + }, + }, + Recommendations: []*hub.Recommendation{ + { + URL: "https://artifacthub.io/packages/helm/artifact-hub/artifact-hub", + }, + }, + Screenshots: []*hub.Screenshot{ + { + Title: "Screenshot 1", + URL: "https://artifacthub.io/screenshot1.jpg", + }, + }, + Data: map[string]interface{}{ + PipelinesMinVersionKey: "0.54.0", + RawManifestKey: string(manifestRaw), + TasksKey: tasks, + PlatformsKey: []string{"linux/amd64", "linux/arm64"}, + ExamplesKey: map[string]string{ + "sample1.yaml": "sample content\n", + }, + }, + Signatures: []string{tekton}, + Signed: true, + } + packages, err := NewTrackerSource(i).GetPackagesAvailable() + assert.Equal(t, map[string]*hub.Package{ + pkg.BuildKey(p): p, + }, packages) + assert.NoError(t, err) + sw.AssertExpectations(t) + }) } diff --git a/internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/README.md b/internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/README.md new file mode 100644 index 000000000..6f15f8320 --- /dev/null +++ b/internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/README.md @@ -0,0 +1 @@ +This is just a test stepaction diff --git a/internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/samples/sample1.yaml b/internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/samples/sample1.yaml new file mode 100644 index 000000000..4b4f223d5 --- /dev/null +++ b/internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/samples/sample1.yaml @@ -0,0 +1 @@ +sample content diff --git a/internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/stepaction1.yaml b/internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/stepaction1.yaml new file mode 100644 index 000000000..dc200ba27 --- /dev/null +++ b/internal/tracker/source/tekton/testdata/path5/stepaction1/0.1/stepaction1.yaml @@ -0,0 +1,37 @@ +apiVersion: tekton.dev/v1alpha1 +kind: StepAction +metadata: + name: stepaction1 + labels: + app.kubernetes.io/version: "0.1.0" + annotations: + artifacthub.io/changes: | + - Added cool feature + - Fixed minor bug + artifacthub.io/license: Apache-2.0 + artifacthub.io/links: | + - name: link1 + url: https://link1.url + - name: link2 + url: https://link2.url + artifacthub.io/maintainers: | + - name: user1 + email: user1@email.com + - name: user2 + email: user2@email.com + artifacthub.io/provider: Some organization + artifacthub.io/recommendations: | + - url: https://artifacthub.io/packages/helm/artifact-hub/artifact-hub + artifacthub.io/screenshots: | + - title: Screenshot 1 + url: https://artifacthub.io/screenshot1.jpg + tekton.dev/pipelines.minVersion: "0.54.0" + tekton.dev/platforms: "linux/amd64,linux/arm64" + tekton.dev/tags: tag1, tag2 + tekton.dev/displayName: "StepAction 1" + tekton.dev/signature: "stepaction signature val" +spec: + description: Test stepaction + params: + - name: param1 + description: param1 description diff --git a/internal/tracker/tracker.go b/internal/tracker/tracker.go index 68a17b096..91279fbd3 100644 --- a/internal/tracker/tracker.go +++ b/internal/tracker/tracker.go @@ -203,7 +203,8 @@ func (t *Tracker) cloneRepository() (string, string, error) { hub.OPA, hub.TBAction, hub.TektonPipeline, - hub.TektonTask: + hub.TektonTask, + hub.TektonStepAction: tmpDir, packagesPath, err = t.svc.Rc.CloneRepository(t.svc.Ctx, t.r) } diff --git a/scripts/prepare-docs.sh b/scripts/prepare-docs.sh index 524e7a701..7dff928f1 100755 --- a/scripts/prepare-docs.sh +++ b/scripts/prepare-docs.sh @@ -28,6 +28,7 @@ cat docs/www/headers/olm_operators_repositories docs/olm_operators_repositories. cat docs/www/headers/opa_policies_repositories docs/opa_policies_repositories.md > docs/www/content/topics/repositories/opa-policies.md cat docs/www/headers/tekton_pipelines_repositories docs/tekton_pipelines_repositories.md > docs/www/content/topics/repositories/tekton-pipelines.md cat docs/www/headers/tekton_tasks_repositories docs/tekton_tasks_repositories.md > docs/www/content/topics/repositories/tekton-tasks.md +cat docs/www/headers/tekton_stepactions_repositories docs/tekton_stepactions_repositories.md > docs/www/content/topics/repositories/tekton-stepactions.md cat docs/www/headers/tinkerbell_actions_repositories docs/tinkerbell_actions_repositories.md > docs/www/content/topics/repositories/tinkerbell-actions.md cat docs/www/headers/security_report docs/security_report.md > docs/www/content/topics/security_report.md cat docs/www/headers/cli docs/cli.md > docs/www/content/topics/cli.md diff --git a/web/src/layout/common/Image.tsx b/web/src/layout/common/Image.tsx index 794b084bc..1d9de4942 100644 --- a/web/src/layout/common/Image.tsx +++ b/web/src/layout/common/Image.tsx @@ -45,6 +45,7 @@ const Image = (props: Props) => { return '/static/media/placeholder_pkg_krew.png'; case RepositoryKind.TektonTask: case RepositoryKind.TektonPipeline: + case RepositoryKind.TektonStepAction: return '/static/media/placeholder_pkg_tekton-task.png'; case RepositoryKind.KedaScaler: return '/static/media/placeholder_pkg_keda-scaler.png'; diff --git a/web/src/layout/common/RepositoryIcon.test.tsx b/web/src/layout/common/RepositoryIcon.test.tsx index 4da459bfd..cba03bbf6 100644 --- a/web/src/layout/common/RepositoryIcon.test.tsx +++ b/web/src/layout/common/RepositoryIcon.test.tsx @@ -142,6 +142,13 @@ describe('RepositoryIcon', () => { expect(icon).toHaveProperty('src', 'http://localhost/static/media/inspektor-gadget-light.svg'); }); + it('renders Tekton StepAction icon', () => { + render(); + const icon = screen.getByAltText('Icon'); + expect(icon).toBeInTheDocument(); + expect(icon).toHaveProperty('src', 'http://localhost/static/media/tekton-pkg-light.svg'); + }); + it('renders empty icon', () => { render(); expect(() => screen.getByAltText('Icon')).toThrow(); diff --git a/web/src/layout/common/RepositoryIcon.tsx b/web/src/layout/common/RepositoryIcon.tsx index 061bd436e..7f6bebc56 100644 --- a/web/src/layout/common/RepositoryIcon.tsx +++ b/web/src/layout/common/RepositoryIcon.tsx @@ -101,6 +101,10 @@ const ICONS = { default: '/static/media/inspektor-gadget.svg', white: '/static/media/inspektor-gadget-light.svg', }, + [RepositoryKind.TektonStepAction]: { + default: '/static/media/tekton-pkg.svg', + white: '/static/media/tekton-pkg-light.svg', + }, }; const RepositoryIcon = (props: Props) => { diff --git a/web/src/layout/common/badges/Signed.tsx b/web/src/layout/common/badges/Signed.tsx index 3bb1dae20..acf10943a 100644 --- a/web/src/layout/common/badges/Signed.tsx +++ b/web/src/layout/common/badges/Signed.tsx @@ -30,6 +30,7 @@ const Signed = (props: Props) => { RepositoryKind.Kubewarden, RepositoryKind.TektonPipeline, RepositoryKind.TektonTask, + RepositoryKind.TektonStepAction, ].includes(props.repoKind); return ( diff --git a/web/src/layout/controlPanel/repositories/Modal.tsx b/web/src/layout/controlPanel/repositories/Modal.tsx index 4bf4eba8c..df29fe255 100644 --- a/web/src/layout/controlPanel/repositories/Modal.tsx +++ b/web/src/layout/controlPanel/repositories/Modal.tsx @@ -191,7 +191,11 @@ const RepositoryModal = (props: Props) => { }; } - if ([RepositoryKind.TektonTask, RepositoryKind.TektonPipeline].includes(selectedKind)) { + if ( + [RepositoryKind.TektonTask, RepositoryKind.TektonPipeline, RepositoryKind.TektonStepAction].includes( + selectedKind + ) + ) { repository.data = { versioning: versioning, }; @@ -497,6 +501,17 @@ const RepositoryModal = (props: Props) => { ); break; + case RepositoryKind.TektonStepAction: + link = ( + + Tekton stepactions + + ); + break; } if (isUndefined(link)) return; @@ -527,6 +542,7 @@ const RepositoryModal = (props: Props) => { case RepositoryKind.KCL: case RepositoryKind.Headlamp: case RepositoryKind.InspektorGadget: + case RepositoryKind.TektonStepAction: return ( <>

{ RepositoryKind.KCL, RepositoryKind.Headlamp, RepositoryKind.InspektorGadget, + RepositoryKind.TektonStepAction, ].includes(selectedKind) && (

{
)} - {[RepositoryKind.TektonTask, RepositoryKind.TektonPipeline].includes(selectedKind) && ( + {[RepositoryKind.TektonTask, RepositoryKind.TektonPipeline, RepositoryKind.TektonStepAction].includes( + selectedKind + ) && ( <> @@ -1068,6 +1087,7 @@ const RepositoryModal = (props: Props) => { RepositoryKind.KCL, RepositoryKind.Headlamp, RepositoryKind.InspektorGadget, + RepositoryKind.TektonStepAction, ].includes(selectedKind) && (
diff --git a/web/src/layout/controlPanel/repositories/__snapshots__/Modal.test.tsx.snap b/web/src/layout/controlPanel/repositories/__snapshots__/Modal.test.tsx.snap index c3e900ac5..07aa68f29 100644 --- a/web/src/layout/controlPanel/repositories/__snapshots__/Modal.test.tsx.snap +++ b/web/src/layout/controlPanel/repositories/__snapshots__/Modal.test.tsx.snap @@ -164,6 +164,11 @@ exports[`Repository Modal - repositories section creates snapshot 1`] = ` > Tekton pipelines +