mirror of https://github.com/artifacthub/hub.git
Add experimental support for Tekton git versioning (#2337)
Signed-off-by: Sergio Castaño Arteaga <tegioz@icloud.com> Signed-off-by: Cintia Sanchez Garcia <cynthiasg@icloud.com> Co-authored-by: Sergio Castaño Arteaga <tegioz@icloud.com> Co-authored-by: Cintia Sanchez Garcia <cynthiasg@icloud.com>
This commit is contained in:
parent
86396bc406
commit
a138a2b19b
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -374,6 +375,7 @@ func lintTekton(basePath string, kind hub.RepositoryKind) *lintReport {
|
||||||
repository := &hub.Repository{
|
repository := &hub.Repository{
|
||||||
Kind: kind,
|
Kind: kind,
|
||||||
URL: "https://github.com/user/repo/path",
|
URL: "https://github.com/user/repo/path",
|
||||||
|
Data: json.RawMessage(fmt.Sprintf(`{"versioning": "%s"}`, hub.TektonDirBasedVersioning)),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read catalog path to get available packages
|
// Read catalog path to get available packages
|
||||||
|
|
@ -399,7 +401,8 @@ func lintTekton(basePath string, kind hub.RepositoryKind) *lintReport {
|
||||||
if !p.IsDir() {
|
if !p.IsDir() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, err := semver.NewVersion(v.Name()); err != nil {
|
sv, err := semver.NewVersion(v.Name())
|
||||||
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,7 +419,16 @@ func lintTekton(basePath string, kind hub.RepositoryKind) *lintReport {
|
||||||
e.result = multierror.Append(e.result, err)
|
e.result = multierror.Append(e.result, err)
|
||||||
} else {
|
} else {
|
||||||
// Prepare package version
|
// Prepare package version
|
||||||
e.pkg, err = tekton.PreparePackage(repository, manifest, manifestRaw, basePath, pkgPath)
|
e.pkg, err = tekton.PreparePackage(&tekton.PreparePackageInput{
|
||||||
|
R: repository,
|
||||||
|
Tag: "",
|
||||||
|
Manifest: manifest,
|
||||||
|
ManifestRaw: manifestRaw,
|
||||||
|
BasePath: basePath,
|
||||||
|
PkgName: pkgName,
|
||||||
|
PkgPath: pkgPath,
|
||||||
|
PkgVersion: sv.String(),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.result = multierror.Append(e.result, err)
|
e.result = multierror.Append(e.result, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,12 @@ const (
|
||||||
RepositoryOCIPrefix = "oci://"
|
RepositoryOCIPrefix = "oci://"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Tekton catalog versioning kinds
|
||||||
|
TektonDirBasedVersioning = "directory"
|
||||||
|
TektonGitBasedVersioning = "git"
|
||||||
|
)
|
||||||
|
|
||||||
// ContainerImageData represents some data specific to repositories of the
|
// ContainerImageData represents some data specific to repositories of the
|
||||||
// container image kind.
|
// container image kind.
|
||||||
type ContainerImageData struct {
|
type ContainerImageData struct {
|
||||||
|
|
@ -30,6 +36,12 @@ type ContainerImageTag struct {
|
||||||
Mutable bool `json:"mutable"`
|
Mutable bool `json:"mutable"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TektonData represents some data specific to repositories of the Tekton tasks
|
||||||
|
// or pipelines kinds.
|
||||||
|
type TektonData struct {
|
||||||
|
Versioning string `json:"versioning"` // Options: directory or git
|
||||||
|
}
|
||||||
|
|
||||||
// RepositoryKind represents the kind of a given repository.
|
// RepositoryKind represents the kind of a given repository.
|
||||||
type RepositoryKind int64
|
type RepositoryKind int64
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -554,6 +554,17 @@ func (m *Manager) GetRemoteDigest(ctx context.Context, r *hub.Repository) (strin
|
||||||
digest = desc.Digest.String()
|
digest = desc.Digest.String()
|
||||||
|
|
||||||
case GitRepoURLRE.MatchString(r.URL):
|
case GitRepoURLRE.MatchString(r.URL):
|
||||||
|
// Do not track repo's digest for Tekton repos using git based versioning
|
||||||
|
if 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)
|
||||||
|
}
|
||||||
|
if data.Versioning == hub.TektonGitBasedVersioning {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Digest is obtained from the last commit in the repository
|
// Digest is obtained from the last commit in the repository
|
||||||
matches := GitRepoURLRE.FindStringSubmatch(r.URL)
|
matches := GitRepoURLRE.FindStringSubmatch(r.URL)
|
||||||
repoBaseURL := matches[1]
|
repoBaseURL := matches[1]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package tekton
|
package tekton
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -15,6 +17,8 @@ import (
|
||||||
"github.com/artifacthub/hub/internal/tracker/source"
|
"github.com/artifacthub/hub/internal/tracker/source"
|
||||||
"github.com/artifacthub/hub/internal/tracker/source/generic"
|
"github.com/artifacthub/hub/internal/tracker/source/generic"
|
||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
|
"github.com/go-git/go-git/v5"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
|
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
|
||||||
)
|
)
|
||||||
|
|
@ -84,6 +88,29 @@ func NewTrackerSource(i *hub.TrackerSourceInput) *TrackerSource {
|
||||||
|
|
||||||
// GetPackagesAvailable implements the TrackerSource interface.
|
// GetPackagesAvailable implements the TrackerSource interface.
|
||||||
func (s *TrackerSource) GetPackagesAvailable() (map[string]*hub.Package, error) {
|
func (s *TrackerSource) GetPackagesAvailable() (map[string]*hub.Package, error) {
|
||||||
|
// Get repository's Tekton specific data
|
||||||
|
if s.i.Repository.Data == nil {
|
||||||
|
return nil, errors.New("required repository data field not provided")
|
||||||
|
}
|
||||||
|
var data *hub.TektonData
|
||||||
|
if err := json.Unmarshal(s.i.Repository.Data, &data); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid tekton repository data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process catalog based on the versioning option configured
|
||||||
|
switch data.Versioning {
|
||||||
|
case hub.TektonDirBasedVersioning:
|
||||||
|
return s.processDirBasedCatalog()
|
||||||
|
case hub.TektonGitBasedVersioning:
|
||||||
|
return s.processGitBasedCatalog()
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid catalog versioning option: %s", data.Versioning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// processDirBasedCatalog returns the packages available in the catalog using
|
||||||
|
// the directory based versioning.
|
||||||
|
func (s *TrackerSource) processDirBasedCatalog() (map[string]*hub.Package, error) {
|
||||||
packagesAvailable := make(map[string]*hub.Package)
|
packagesAvailable := make(map[string]*hub.Package)
|
||||||
|
|
||||||
// Read catalog path to get available packages
|
// Read catalog path to get available packages
|
||||||
|
|
@ -117,7 +144,8 @@ func (s *TrackerSource) GetPackagesAvailable() (map[string]*hub.Package, error)
|
||||||
if !p.IsDir() {
|
if !p.IsDir() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, err := semver.NewVersion(v.Name()); err != nil {
|
sv, err := semver.NewVersion(v.Name())
|
||||||
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,7 +158,16 @@ func (s *TrackerSource) GetPackagesAvailable() (map[string]*hub.Package, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare and store package version
|
// Prepare and store package version
|
||||||
p, err := PreparePackage(s.i.Repository, manifest, manifestRaw, s.i.BasePath, pkgPath)
|
p, err := PreparePackage(&PreparePackageInput{
|
||||||
|
R: s.i.Repository,
|
||||||
|
Tag: "",
|
||||||
|
Manifest: manifest,
|
||||||
|
ManifestRaw: manifestRaw,
|
||||||
|
BasePath: s.i.BasePath,
|
||||||
|
PkgName: pkgName,
|
||||||
|
PkgPath: pkgPath,
|
||||||
|
PkgVersion: sv.String(),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.warn(fmt.Errorf("error preparing package %s version %s: %w", pkgName, v.Name(), err))
|
s.warn(fmt.Errorf("error preparing package %s version %s: %w", pkgName, v.Name(), err))
|
||||||
continue
|
continue
|
||||||
|
|
@ -142,6 +179,87 @@ func (s *TrackerSource) GetPackagesAvailable() (map[string]*hub.Package, error)
|
||||||
return packagesAvailable, nil
|
return packagesAvailable, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// processGitBasedCatalog returns the packages available in the catalog using
|
||||||
|
// the git based versioning.
|
||||||
|
func (s *TrackerSource) processGitBasedCatalog() (map[string]*hub.Package, error) {
|
||||||
|
// Open git repository and get all tags
|
||||||
|
gr, err := git.PlainOpenWithOptions(s.i.BasePath, &git.PlainOpenOptions{
|
||||||
|
DetectDotGit: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error opening git repository: %w", err)
|
||||||
|
}
|
||||||
|
wt, err := gr.Worktree()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting worktree: %w", err)
|
||||||
|
}
|
||||||
|
tags, err := gr.Tags()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading tags references: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read packages available in the catalog for each tag/version
|
||||||
|
packagesAvailable := make(map[string]*hub.Package)
|
||||||
|
_ = tags.ForEach(func(tag *plumbing.Reference) error {
|
||||||
|
// Skip tags that cannot be parsed as ~valid semver
|
||||||
|
sv, err := semver.NewVersion(tag.Name().Short())
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checkout version tag
|
||||||
|
if err := wt.Checkout(&git.CheckoutOptions{
|
||||||
|
Hash: tag.Hash(),
|
||||||
|
}); err != nil {
|
||||||
|
s.warn(fmt.Errorf("error checking out tag %s: %w", tag.Name().Short(), err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process version packages
|
||||||
|
packages, err := os.ReadDir(s.i.BasePath)
|
||||||
|
if err != nil {
|
||||||
|
s.warn(fmt.Errorf("error reading catalog directory: %w", err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, p := range packages {
|
||||||
|
// If the path is not a directory, we skip it
|
||||||
|
if !p.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get package manifest
|
||||||
|
pkgName := p.Name()
|
||||||
|
pkgPath := path.Join(s.i.BasePath, pkgName)
|
||||||
|
manifest, manifestRaw, err := GetManifest(s.i.Repository.Kind, pkgName, pkgPath)
|
||||||
|
if err != nil {
|
||||||
|
s.warn(fmt.Errorf("error getting package manifest (path: %s): %w", pkgPath, err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare and store package version
|
||||||
|
p, err := PreparePackage(&PreparePackageInput{
|
||||||
|
R: s.i.Repository,
|
||||||
|
Tag: tag.Name().Short(),
|
||||||
|
Manifest: manifest,
|
||||||
|
ManifestRaw: manifestRaw,
|
||||||
|
BasePath: s.i.BasePath,
|
||||||
|
PkgName: pkgName,
|
||||||
|
PkgPath: pkgPath,
|
||||||
|
PkgVersion: sv.String(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
s.warn(fmt.Errorf("error preparing package %s version %s: %w", pkgName, sv.String(), err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
packagesAvailable[pkg.BuildKey(p)] = p
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return packagesAvailable, nil
|
||||||
|
}
|
||||||
|
|
||||||
// warn is a helper that sends the error provided to the errors collector and
|
// warn is a helper that sends the error provided to the errors collector and
|
||||||
// logs it as a warning.
|
// logs it as a warning.
|
||||||
func (s *TrackerSource) warn(err error) {
|
func (s *TrackerSource) warn(err error) {
|
||||||
|
|
@ -206,20 +324,27 @@ func validateManifest(manifest interface{}) error {
|
||||||
return errs.ErrorOrNil()
|
return errs.ErrorOrNil()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PreparePackageInput represents the information required to prepare a package
|
||||||
|
// of Tekton task and pipelines kinds.
|
||||||
|
type PreparePackageInput struct {
|
||||||
|
R *hub.Repository
|
||||||
|
Tag string
|
||||||
|
Manifest interface{}
|
||||||
|
ManifestRaw []byte
|
||||||
|
BasePath string
|
||||||
|
PkgName string
|
||||||
|
PkgPath string
|
||||||
|
PkgVersion string
|
||||||
|
}
|
||||||
|
|
||||||
// PreparePackage prepares a package version using the package manifest and the
|
// PreparePackage prepares a package version using the package manifest and the
|
||||||
// files in the path provided.
|
// files in the path provided.
|
||||||
func PreparePackage(
|
func PreparePackage(i *PreparePackageInput) (*hub.Package, error) {
|
||||||
r *hub.Repository,
|
|
||||||
manifest interface{},
|
|
||||||
manifestRaw []byte,
|
|
||||||
basePath string,
|
|
||||||
pkgPath string,
|
|
||||||
) (*hub.Package, error) {
|
|
||||||
// Extract some information from package manifest
|
// Extract some information from package manifest
|
||||||
var name, version, description, tektonKind string
|
var name, version, description, tektonKind string
|
||||||
var annotations map[string]string
|
var annotations map[string]string
|
||||||
var tasks []map[string]interface{}
|
var tasks []map[string]interface{}
|
||||||
switch m := manifest.(type) {
|
switch m := i.Manifest.(type) {
|
||||||
case *v1beta1.Task:
|
case *v1beta1.Task:
|
||||||
tektonKind = "task"
|
tektonKind = "task"
|
||||||
name = m.Name
|
name = m.Name
|
||||||
|
|
@ -246,6 +371,9 @@ func PreparePackage(
|
||||||
return nil, fmt.Errorf("invalid semver version (%s): %w", version, err)
|
return nil, fmt.Errorf("invalid semver version (%s): %w", version, err)
|
||||||
}
|
}
|
||||||
version = sv.String()
|
version = sv.String()
|
||||||
|
if version != i.PkgVersion {
|
||||||
|
return nil, fmt.Errorf("version mismatch (%s != %s)", version, i.PkgVersion)
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare keywords
|
// Prepare keywords
|
||||||
keywords := []string{
|
keywords := []string{
|
||||||
|
|
@ -264,16 +392,17 @@ func PreparePackage(
|
||||||
DisplayName: annotations[displayNameTKey],
|
DisplayName: annotations[displayNameTKey],
|
||||||
Description: description,
|
Description: description,
|
||||||
Keywords: keywords,
|
Keywords: keywords,
|
||||||
Repository: r,
|
Digest: fmt.Sprintf("%x", sha256.Sum256(i.ManifestRaw)),
|
||||||
|
Repository: i.R,
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
PipelinesMinVersionKey: annotations[pipelinesMinVersionTKey],
|
PipelinesMinVersionKey: annotations[pipelinesMinVersionTKey],
|
||||||
RawManifestKey: string(manifestRaw),
|
RawManifestKey: string(i.ManifestRaw),
|
||||||
TasksKey: tasks,
|
TasksKey: tasks,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include content and source links
|
// Include content and source links
|
||||||
contentURL, sourceURL := prepareContentAndSourceLinks(r, basePath, pkgPath, name)
|
contentURL, sourceURL := prepareContentAndSourceLinks(i)
|
||||||
p.ContentURL = contentURL
|
p.ContentURL = contentURL
|
||||||
if sourceURL != "" {
|
if sourceURL != "" {
|
||||||
p.Links = append(p.Links, &hub.Link{
|
p.Links = append(p.Links, &hub.Link{
|
||||||
|
|
@ -293,13 +422,13 @@ func PreparePackage(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include readme file
|
// Include readme file
|
||||||
readme, err := os.ReadFile(filepath.Join(pkgPath, "README.md"))
|
readme, err := os.ReadFile(filepath.Join(i.PkgPath, "README.md"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
p.Readme = string(readme)
|
p.Readme = string(readme)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include examples files
|
// Include examples files
|
||||||
examples, err := generic.GetFilesWithSuffix(".yaml", path.Join(pkgPath, examplesPath), nil)
|
examples, err := generic.GetFilesWithSuffix(".yaml", path.Join(i.PkgPath, examplesPath), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
return nil, fmt.Errorf("error getting examples files: %w", err)
|
return nil, fmt.Errorf("error getting examples files: %w", err)
|
||||||
|
|
@ -320,15 +449,10 @@ func PreparePackage(
|
||||||
|
|
||||||
// prepareContentAndSourceLinks prepares the content and source urls for the
|
// prepareContentAndSourceLinks prepares the content and source urls for the
|
||||||
// git provider identified from the host part in the repository url.
|
// git provider identified from the host part in the repository url.
|
||||||
func prepareContentAndSourceLinks(
|
func prepareContentAndSourceLinks(i *PreparePackageInput) (string, string) {
|
||||||
r *hub.Repository,
|
|
||||||
basePath string,
|
|
||||||
pkgPath string,
|
|
||||||
pkgName string,
|
|
||||||
) (string, string) {
|
|
||||||
// Parse repository url
|
// Parse repository url
|
||||||
var repoBaseURL, host, pkgsPath string
|
var repoBaseURL, host, pkgsPath string
|
||||||
matches := repo.GitRepoURLRE.FindStringSubmatch(r.URL)
|
matches := repo.GitRepoURLRE.FindStringSubmatch(i.R.URL)
|
||||||
if len(matches) >= 3 {
|
if len(matches) >= 3 {
|
||||||
repoBaseURL = matches[1]
|
repoBaseURL = matches[1]
|
||||||
host = matches[2]
|
host = matches[2]
|
||||||
|
|
@ -339,18 +463,21 @@ func prepareContentAndSourceLinks(
|
||||||
|
|
||||||
// Generate content and source url for the corresponding git provider
|
// Generate content and source url for the corresponding git provider
|
||||||
var contentURL, sourceURL string
|
var contentURL, sourceURL string
|
||||||
branch := repo.GetBranch(r)
|
branch := i.Tag
|
||||||
pkgRelativePath := strings.TrimPrefix(pkgPath, basePath)
|
if branch == "" {
|
||||||
|
branch = repo.GetBranch(i.R)
|
||||||
|
}
|
||||||
|
pkgRelativePath := strings.TrimPrefix(i.PkgPath, i.BasePath)
|
||||||
switch host {
|
switch host {
|
||||||
case "bitbucket.org":
|
case "bitbucket.org":
|
||||||
contentURL = fmt.Sprintf("%s/raw/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, pkgName)
|
contentURL = fmt.Sprintf("%s/raw/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, i.PkgName)
|
||||||
sourceURL = fmt.Sprintf("%s/src/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, pkgName)
|
sourceURL = fmt.Sprintf("%s/src/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, i.PkgName)
|
||||||
case "github.com":
|
case "github.com":
|
||||||
contentURL = fmt.Sprintf("%s/raw/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, pkgName)
|
contentURL = fmt.Sprintf("%s/raw/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, i.PkgName)
|
||||||
sourceURL = fmt.Sprintf("%s/blob/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, pkgName)
|
sourceURL = fmt.Sprintf("%s/blob/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, i.PkgName)
|
||||||
case "gitlab.com":
|
case "gitlab.com":
|
||||||
contentURL = fmt.Sprintf("%s/-/raw/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, pkgName)
|
contentURL = fmt.Sprintf("%s/-/raw/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, i.PkgName)
|
||||||
sourceURL = fmt.Sprintf("%s/-/blob/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, pkgName)
|
sourceURL = fmt.Sprintf("%s/-/blob/%s/%s%s/%s.yaml", repoBaseURL, branch, pkgsPath, pkgRelativePath, i.PkgName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return contentURL, sourceURL
|
return contentURL, sourceURL
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package tekton
|
package tekton
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -19,6 +21,7 @@ func TestTrackerSource(t *testing.T) {
|
||||||
i := &hub.TrackerSourceInput{
|
i := &hub.TrackerSourceInput{
|
||||||
Repository: &hub.Repository{
|
Repository: &hub.Repository{
|
||||||
Kind: hub.TektonTask,
|
Kind: hub.TektonTask,
|
||||||
|
Data: json.RawMessage(fmt.Sprintf(`{"versioning": "%s"}`, hub.TektonDirBasedVersioning)),
|
||||||
},
|
},
|
||||||
BasePath: "testdata/path1",
|
BasePath: "testdata/path1",
|
||||||
Svc: sw.Svc,
|
Svc: sw.Svc,
|
||||||
|
|
@ -39,6 +42,7 @@ func TestTrackerSource(t *testing.T) {
|
||||||
i := &hub.TrackerSourceInput{
|
i := &hub.TrackerSourceInput{
|
||||||
Repository: &hub.Repository{
|
Repository: &hub.Repository{
|
||||||
Kind: hub.TektonTask,
|
Kind: hub.TektonTask,
|
||||||
|
Data: json.RawMessage(fmt.Sprintf(`{"versioning": "%s"}`, hub.TektonDirBasedVersioning)),
|
||||||
},
|
},
|
||||||
BasePath: "testdata/path2",
|
BasePath: "testdata/path2",
|
||||||
Svc: sw.Svc,
|
Svc: sw.Svc,
|
||||||
|
|
@ -62,6 +66,7 @@ func TestTrackerSource(t *testing.T) {
|
||||||
Repository: &hub.Repository{
|
Repository: &hub.Repository{
|
||||||
Kind: hub.TektonTask,
|
Kind: hub.TektonTask,
|
||||||
URL: "https://github.com/user/repo/path",
|
URL: "https://github.com/user/repo/path",
|
||||||
|
Data: json.RawMessage(fmt.Sprintf(`{"versioning": "%s"}`, hub.TektonDirBasedVersioning)),
|
||||||
},
|
},
|
||||||
BasePath: "testdata/path3",
|
BasePath: "testdata/path3",
|
||||||
Svc: sw.Svc,
|
Svc: sw.Svc,
|
||||||
|
|
@ -79,6 +84,7 @@ func TestTrackerSource(t *testing.T) {
|
||||||
Version: "0.1.0",
|
Version: "0.1.0",
|
||||||
Provider: "Some organization",
|
Provider: "Some organization",
|
||||||
ContentURL: "https://github.com/user/repo/raw/master/path/task1/0.1/task1.yaml",
|
ContentURL: "https://github.com/user/repo/raw/master/path/task1/0.1/task1.yaml",
|
||||||
|
Digest: "d5ef3fb05c34644e5ba4fd5a5c3db13be13c11606e663f8583438c2a9d6d243f",
|
||||||
Repository: i.Repository,
|
Repository: i.Repository,
|
||||||
License: "Apache-2.0",
|
License: "Apache-2.0",
|
||||||
Links: []*hub.Link{
|
Links: []*hub.Link{
|
||||||
|
|
@ -151,6 +157,7 @@ func TestTrackerSource(t *testing.T) {
|
||||||
Repository: &hub.Repository{
|
Repository: &hub.Repository{
|
||||||
Kind: hub.TektonPipeline,
|
Kind: hub.TektonPipeline,
|
||||||
URL: "https://github.com/user/repo/path",
|
URL: "https://github.com/user/repo/path",
|
||||||
|
Data: json.RawMessage(fmt.Sprintf(`{"versioning": "%s"}`, hub.TektonDirBasedVersioning)),
|
||||||
},
|
},
|
||||||
BasePath: "testdata/path4",
|
BasePath: "testdata/path4",
|
||||||
Svc: sw.Svc,
|
Svc: sw.Svc,
|
||||||
|
|
@ -167,6 +174,7 @@ func TestTrackerSource(t *testing.T) {
|
||||||
Version: "0.1.0",
|
Version: "0.1.0",
|
||||||
Provider: "Some organization",
|
Provider: "Some organization",
|
||||||
ContentURL: "https://github.com/user/repo/raw/master/path/pipeline1/0.1/pipeline1.yaml",
|
ContentURL: "https://github.com/user/repo/raw/master/path/pipeline1/0.1/pipeline1.yaml",
|
||||||
|
Digest: "755a8708c075dbf62529d91495673ef45ad9eedf1cdf0798c97caf8761a69378",
|
||||||
Repository: i.Repository,
|
Repository: i.Repository,
|
||||||
License: "Apache-2.0",
|
License: "Apache-2.0",
|
||||||
Links: []*hub.Link{
|
Links: []*hub.Link{
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,15 @@ import { MdAddCircle } from 'react-icons/md';
|
||||||
|
|
||||||
import API from '../../../api';
|
import API from '../../../api';
|
||||||
import { AppCtx } from '../../../context/AppCtx';
|
import { AppCtx } from '../../../context/AppCtx';
|
||||||
import { ContainerTag, ErrorKind, RefInputField, Repository, RepositoryKind, ResourceKind } from '../../../types';
|
import {
|
||||||
|
ContainerTag,
|
||||||
|
ErrorKind,
|
||||||
|
RefInputField,
|
||||||
|
Repository,
|
||||||
|
RepositoryKind,
|
||||||
|
ResourceKind,
|
||||||
|
VersioningOption,
|
||||||
|
} from '../../../types';
|
||||||
import compoundErrorMessage from '../../../utils/compoundErrorMessage';
|
import compoundErrorMessage from '../../../utils/compoundErrorMessage';
|
||||||
import { OCI_PREFIX, RepoKindDef, REPOSITORY_KINDS } from '../../../utils/data';
|
import { OCI_PREFIX, RepoKindDef, REPOSITORY_KINDS } from '../../../utils/data';
|
||||||
import getMetaTag from '../../../utils/getMetaTag';
|
import getMetaTag from '../../../utils/getMetaTag';
|
||||||
|
|
@ -32,7 +40,9 @@ interface Props {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onAuthError: () => void;
|
onAuthError: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_SELECTED_REPOSITORY_KIND = RepositoryKind.Helm;
|
const DEFAULT_SELECTED_REPOSITORY_KIND = RepositoryKind.Helm;
|
||||||
|
const DEFAULT_VERSIONING_OPT = VersioningOption.Directory;
|
||||||
|
|
||||||
const RepositoryModal = (props: Props) => {
|
const RepositoryModal = (props: Props) => {
|
||||||
const { ctx } = useContext(AppCtx);
|
const { ctx } = useContext(AppCtx);
|
||||||
|
|
@ -74,6 +84,11 @@ const RepositoryModal = (props: Props) => {
|
||||||
|
|
||||||
const [containerTags, setContainerTags] = useState<ContainerTag[]>(prepareTags());
|
const [containerTags, setContainerTags] = useState<ContainerTag[]>(prepareTags());
|
||||||
const [repeatedTagNames, setRepeatedTagNames] = useState<boolean>(false);
|
const [repeatedTagNames, setRepeatedTagNames] = useState<boolean>(false);
|
||||||
|
const [versioning, setVersioning] = useState<VersioningOption>(
|
||||||
|
props.repository && props.repository.data && props.repository.data.versioning
|
||||||
|
? props.repository.data.versioning
|
||||||
|
: DEFAULT_VERSIONING_OPT
|
||||||
|
);
|
||||||
|
|
||||||
const onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
const onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
setIsValidInput(e.target.value === props.repository!.name);
|
setIsValidInput(e.target.value === props.repository!.name);
|
||||||
|
|
@ -175,6 +190,12 @@ const RepositoryModal = (props: Props) => {
|
||||||
tags: readyTags,
|
tags: readyTags,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ([RepositoryKind.TektonTask, RepositoryKind.TektonPipeline].includes(selectedKind)) {
|
||||||
|
repository.data = {
|
||||||
|
versioning: versioning,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setIsValidated(true);
|
setIsValidated(true);
|
||||||
return { isValid, repository };
|
return { isValid, repository };
|
||||||
|
|
@ -816,6 +837,49 @@ const RepositoryModal = (props: Props) => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{[RepositoryKind.TektonTask, RepositoryKind.TektonPipeline].includes(selectedKind) && (
|
||||||
|
<>
|
||||||
|
<label className={`form-label fw-bold ${styles.label}`}>Versioning</label>
|
||||||
|
|
||||||
|
<div className="d-flex flex-row mb-2">
|
||||||
|
{Object.entries(VersioningOption).map((opt: any) => {
|
||||||
|
return (
|
||||||
|
<div className="form-check me-4 mb-2" key={`versioning_${opt[1]}`}>
|
||||||
|
<input
|
||||||
|
className="form-check-input"
|
||||||
|
type="radio"
|
||||||
|
id={opt[1]}
|
||||||
|
name="payload"
|
||||||
|
value={opt[1]}
|
||||||
|
checked={versioning === opt[1]}
|
||||||
|
onChange={() => setVersioning(opt[1])}
|
||||||
|
/>
|
||||||
|
<label className={`form-check-label ${styles.label}`} htmlFor={opt[1]}>
|
||||||
|
{opt[0]}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4">
|
||||||
|
<small className="text-muted text-break">
|
||||||
|
<p className="mb-0">
|
||||||
|
Select which organization uses your Tekton catalog. For more details please see the{' '}
|
||||||
|
<ExternalLink
|
||||||
|
href="https://github.com/tektoncd/community/blob/main/teps/0115-tekton-catalog-git-based-versioning.md#tep-0115-tekton-catalog-git-based-versioning"
|
||||||
|
className="text-primary fw-bold"
|
||||||
|
label="Open Tekton docs"
|
||||||
|
>
|
||||||
|
Tekton docs
|
||||||
|
</ExternalLink>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{allowPrivateRepositories && (
|
{allowPrivateRepositories && (
|
||||||
<>
|
<>
|
||||||
{props.repository && props.repository.private ? (
|
{props.repository && props.repository.private ? (
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,11 @@ export enum Signature {
|
||||||
Cosign = 'cosign',
|
Cosign = 'cosign',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum VersioningOption {
|
||||||
|
Directory = 'directory',
|
||||||
|
Git = 'git',
|
||||||
|
}
|
||||||
|
|
||||||
export interface Repository {
|
export interface Repository {
|
||||||
repositoryId?: string;
|
repositoryId?: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -61,6 +66,7 @@ export interface Repository {
|
||||||
scannerDisabled?: boolean;
|
scannerDisabled?: boolean;
|
||||||
data?: {
|
data?: {
|
||||||
tags?: ContainerTag[];
|
tags?: ContainerTag[];
|
||||||
|
versioning?: VersioningOption;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue