Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds refspec support for func repo add #1558

Merged
merged 6 commits into from
Feb 16, 2023
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
24 changes: 16 additions & 8 deletions cmd/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,32 +108,40 @@ EXAMPLES
$ {{rootCmdUse}} repository -c

o Add a repository and create a new function using a template from it:
$ {{rootCmdUse}} repository add boson https://github.com/boson-project/templates
$ {{rootCmdUse}} repository add functastic https://github.com/knative-sandbox/func-tastic
$ {{rootCmdUse}} repository list
default
boson
$ {{rootCmdUse}} create -l go -t boson/hello-world
functastic
$ {{rootCmdUse}} create -l go -t functastic/hello-world
...

o Add a repository specifying the branch to use (metacontroller):
$ {{rootCmdUse}} repository add metacontroller https://github.com/knative-sandbox/func-tastic#metacontroler
$ {{rootCmdUse}} repository list
default
metacontroller
$ {{rootCmdUse}} create -l node -t metacontroller/metacontroller
...

o List all repositories including the URL from which remotes were installed
$ {{rootCmdUse}} repository list -v
default
boson https://github.com/boson-project/templates
metacontroller https://github.com/knative-sandbox/func-tastic#metacontroller

o Rename an installed repository
$ {{rootCmdUse}} repository list
default
boson
$ {{rootCmdUse}} repository rename boson boson-examples
$ {{rootCmdUse}} repository rename boson functastic
$ {{rootCmdUse}} repository list
default
boson-examples
functastic

o Remove an installed repository
$ {{rootCmdUse}} repository list
default
boson-examples
$ {{rootCmdUse}} repository remove boson-examples
functastic
$ {{rootCmdUse}} repository remove functastic
$ {{rootCmdUse}} repository list
default
`,
Expand Down
3 changes: 2 additions & 1 deletion cmd/repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ func TestRepository_List(t *testing.T) {
// arguments, respects the repositories' path flag, and the expected name is echoed
// upon subsequent 'list'.
func TestRepository_Add(t *testing.T) {
url := ServeRepo("repository.git", t)
url := ServeRepo("repository.git#main", t)
_ = fromTempDirectory(t)
t.Log(url)

var (
add = NewRepositoryAddCmd(NewClient)
Expand Down
24 changes: 16 additions & 8 deletions docs/reference/func_repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,32 +91,40 @@ EXAMPLES
$ func repository -c

o Add a repository and create a new function using a template from it:
$ func repository add boson https://github.com/boson-project/templates
$ func repository add functastic https://github.com/knative-sandbox/func-tastic
$ func repository list
default
boson
$ func create -l go -t boson/hello-world
functastic
$ func create -l go -t functastic/hello-world
...

o Add a repository specifying the branch to use (metacontroller):
$ func repository add metacontroller https://github.com/knative-sandbox/func-tastic#metacontroler
$ func repository list
default
metacontroller
$ func create -l node -t metacontroller/metacontroller
...

o List all repositories including the URL from which remotes were installed
$ func repository list -v
default
boson https://github.com/boson-project/templates
metacontroller https://github.com/knative-sandbox/func-tastic#metacontroller

o Rename an installed repository
$ func repository list
default
boson
$ func repository rename boson boson-examples
$ func repository rename boson functastic
$ func repository list
default
boson-examples
functastic

o Remove an installed repository
$ func repository list
default
boson-examples
$ func repository remove boson-examples
functastic
$ func repository remove functastic
$ func repository list
default

Expand Down
6 changes: 3 additions & 3 deletions pkg/functions/repositories_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,9 +331,9 @@ func TestRepositories_URL(t *testing.T) {
t.Fatal(err)
}

// Assert it includes the correct URL
if r.URL() != uri {
t.Fatalf("expected repository URL '%v', got '%v'", uri, r.URL())
// Assert it includes the correct URL, including the refspec fragment
if r.URL() != uri+"#master" {
t.Fatalf("expected repository URL '%v#master', got '%v'", uri, r.URL())
}
}

Expand Down
45 changes: 34 additions & 11 deletions pkg/functions/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/storage/memory"
"gopkg.in/yaml.v2"

Expand Down Expand Up @@ -123,12 +124,10 @@ type templateConfig = funcDefaults
// NewRepository creates a repository instance from any of: a path on disk, a
// remote or local URI, or from the embedded default repo if uri not provided.
// Name (optional), if provided takes precedence over name derived from repo at
// the given URI.
//
// the given URI.
//
// URI (optional), the path either locally or remote from which to load
//
// the repository files. If not provided, the internal default is assumed.
// uri (optional), the path either locally or remote from which to load
// the repository files. If not provided, the internal default is assumed.
func NewRepository(name, uri string) (r Repository, err error) {
r = Repository{
uri: uri,
Expand Down Expand Up @@ -224,13 +223,15 @@ func FilesystemFromRepo(uri string) (filesystem.Filesystem, error) {
clone, err := git.Clone(
memory.NewStorage(),
memfs.New(),
&git.CloneOptions{URL: uri, Depth: 1, Tags: git.NoTags,
RecurseSubmodules: git.NoRecurseSubmodules,
})
getGitCloneOptions(uri),
)
if err != nil {
if isRepoNotFoundError(err) {
return nil, nil
}
if isBranchNotFoundError(err) {
return nil, fmt.Errorf("failed to clone repository: branch not found for uri %s", uri)
}
return nil, fmt.Errorf("failed to clone repository: %w", err)
}
wt, err := clone.Worktree()
Expand All @@ -248,6 +249,12 @@ func isRepoNotFoundError(err error) bool {
return (err != nil && err.Error() == "repository not found")
}

func isBranchNotFoundError(err error) bool {
// This would be better if the error being tested for was typed, but it is
// currently a simple string value comparison.
return (err != nil && err.Error() == "reference not found")
}

// filesystemFromPath attempts to return a filesystem from a URI as a file:// path
func filesystemFromPath(uri string) (f filesystem.Filesystem, err error) {
parsed, err := url.Parse(uri)
Expand Down Expand Up @@ -440,6 +447,22 @@ func checkDir(fs filesystem.Filesystem, path string) error {
return err
}

func getGitCloneOptions(uri string) *git.CloneOptions {
branch := ""
splitUri := strings.Split(uri, "#")
if len(splitUri) > 1 {
uri = splitUri[0]
branch = splitUri[1]
}

opt := &git.CloneOptions{URL: uri, Depth: 1, Tags: git.NoTags,
RecurseSubmodules: git.NoRecurseSubmodules}
if branch != "" {
opt.ReferenceName = plumbing.NewBranchReferenceName(branch)
}
return opt
}

// Template from repo for given runtime.
func (r *Repository) Template(runtimeName, name string) (t Template, err error) {
runtime, err := r.Runtime(runtimeName)
Expand Down Expand Up @@ -506,8 +529,7 @@ func (r *Repository) Write(path string) (err error) {
return
}
if clone, err = git.PlainClone(tempDir, false, // not bare
&git.CloneOptions{URL: r.uri, Depth: 1, Tags: git.NoTags,
RecurseSubmodules: git.NoRecurseSubmodules}); err != nil {
getGitCloneOptions(r.uri)); err != nil {
return fmt.Errorf("failed to plain clone repository: %w", err)
}
if wt, err = clone.Worktree(); err != nil {
Expand Down Expand Up @@ -546,10 +568,11 @@ func (r *Repository) URL() string {
return "" // Has no .git/config or other error.
}

ref, _ := repo.Head()
if _, ok := c.Remotes["origin"]; ok {
urls := c.Remotes["origin"].URLs
if len(urls) > 0 {
return urls[0]
return urls[0] + "#" + ref.Name().Short()
}
}
return ""
Expand Down