[cli] check main after master (#8463)

* Allow specifying a branch with url#branch

* Probe for master and main

* Update CHANGELOG

* Fix linter errors

* Remove unnecessary feature

* Fix lint

* Update changelog to reflect new limited scope.

We only talk about the master -> main probing, because that is all the
PR does. It used to duplicate another feature.
This commit is contained in:
Ian Wahbe 2021-11-19 13:49:59 -08:00 committed by GitHub
parent dbc8ab9ad6
commit 7222e5570a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 33 deletions

View file

@ -1,5 +1,9 @@
### Improvements
- [cli] - When running `pulumi new https://github.com/name/repo`, check
for branch `main` if branch `master` doesn't exist.
[#8463](https://github.com/pulumi/pulumi/pull/8463)
- [codegen/python] - Program generator now uses `fn_output` forms where
appropriate, simplifying auto-generated examples.
[#8433](https://github.com/pulumi/pulumi/pull/8433)

View file

@ -296,6 +296,35 @@ func GitCloneOrPull(url string, referenceName plumbing.ReferenceName, path strin
return nil
}
// We currently accept Gist URLs in the form: https://gist.github.com/owner/id.
// We may want to consider supporting https://gist.github.com/id at some point,
// as well as arbitrary revisions, e.g. https://gist.github.com/owner/id/commit.
func parseGistURL(u *url.URL) (string, error) {
path := strings.Trim(u.Path, "/")
paths := strings.Split(path, "/")
if len(paths) != 2 {
return "", errors.New("invalid Gist URL")
}
owner := paths[0]
if owner == "" {
return "", errors.New("invalid Gist URL; no owner")
}
id := paths[1]
if id == "" {
return "", errors.New("invalid Gist URL; no id")
}
if !strings.HasSuffix(id, ".git") {
id = id + ".git"
}
resultURL := u.Scheme + "://" + u.Host + "/" + id
return resultURL, nil
}
// ParseGitRepoURL returns the URL to the Git repository and path from a raw URL.
// For example, an input of "https://github.com/pulumi/templates/templates/javascript" returns
// "https://github.com/pulumi/templates.git" and "templates/javascript".
@ -309,37 +338,16 @@ func ParseGitRepoURL(rawurl string) (string, string, error) {
return "", "", errors.New("invalid URL scheme")
}
path := strings.TrimPrefix(u.Path, "/")
// Special case Gists.
if u.Hostname() == "gist.github.com" {
// We currently accept Gist URLs in the form: https://gist.github.com/owner/id.
// We may want to consider supporting https://gist.github.com/id at some point,
// as well as arbitrary revisions, e.g. https://gist.github.com/owner/id/commit.
path = strings.TrimSuffix(path, "/")
paths := strings.Split(path, "/")
if len(paths) != 2 {
return "", "", errors.New("invalid Gist URL")
repo, err := parseGistURL(u)
if err != nil {
return "", "", err
}
owner := paths[0]
if owner == "" {
return "", "", errors.New("invalid Gist URL; no owner")
}
id := paths[1]
if id == "" {
return "", "", errors.New("invalid Gist URL; no id")
}
if !strings.HasSuffix(id, ".git") {
id = id + ".git"
}
resultURL := u.Scheme + "://" + u.Host + "/" + id
return resultURL, "", nil
return repo, "", nil
}
path := strings.TrimPrefix(u.Path, "/")
paths := strings.Split(path, "/")
if len(paths) < 2 {
return "", "", errors.New("invalid Git URL")
@ -361,6 +369,7 @@ func ParseGitRepoURL(rawurl string) (string, string, error) {
resultURL := u.Scheme + "://" + u.Host + "/" + owner + "/" + repo
resultPath := strings.TrimSuffix(strings.Join(paths[2:], "/"), "/")
return resultURL, resultPath, nil
}

View file

@ -25,7 +25,7 @@ import (
)
func TestParseGitRepoURL(t *testing.T) {
test := func(expectedURL string, expectedURLPath string, rawurl string) {
test := func(expectedURL, expectedURLPath string, rawurl string) {
actualURL, actualURLPath, err := ParseGitRepoURL(rawurl)
assert.NoError(t, err)
assert.Equal(t, expectedURL, actualURL)

View file

@ -287,7 +287,7 @@ func retrieveURLTemplates(rawurl string, offline bool, templateKind TemplateKind
var fullPath string
if fullPath, err = RetrieveGitFolder(rawurl, temp); err != nil {
return TemplateRepository{}, err
return TemplateRepository{}, fmt.Errorf("Failed to retrieve git folder: %w", err)
}
return TemplateRepository{
@ -372,16 +372,35 @@ func RetrieveGitFolder(rawurl string, path string) (string, error) {
ref, commit, subDirectory, err := gitutil.GetGitReferenceNameOrHashAndSubDirectory(url, urlPath)
if err != nil {
return "", err
return "", fmt.Errorf("failed to get git ref: %w", err)
}
if ref != "" {
if cloneErr := gitutil.GitCloneOrPull(url, ref, path, true /*shallow*/); cloneErr != nil {
return "", cloneErr
// Different reference attempts to cycle through
// We default to master then main in that order. We need to order them to avoid breaking
// already existing processes for repos that already have a master and main branch.
refAttempts := []plumbing.ReferenceName{plumbing.Master, plumbing.NewBranchReferenceName("main")}
if ref != plumbing.HEAD {
// If we have a non-default reference, we just use it
refAttempts = []plumbing.ReferenceName{ref}
}
var cloneErr error
for _, ref := range refAttempts {
// Attempt the clone. If it succeeds, break
cloneErr := gitutil.GitCloneOrPull(url, ref, path, true /*shallow*/)
if cloneErr == nil {
break
}
}
if cloneErr != nil {
return "", fmt.Errorf("failed to clone ref '%s': %w", refAttempts[len(refAttempts)-1], cloneErr)
}
} else {
if cloneErr := gitutil.GitCloneAndCheckoutCommit(url, commit, path); cloneErr != nil {
return "", cloneErr
return "", fmt.Errorf("failed to clone and checkout %s(%s): %w", url, commit, cloneErr)
}
}