diff options
-rw-r--r-- | _examples/README.md | 1 | ||||
-rw-r--r-- | _examples/tag-create-push/main.go | 161 |
2 files changed, 162 insertions, 0 deletions
diff --git a/_examples/README.md b/_examples/README.md index 1d82fbd..80d4dd5 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -17,6 +17,7 @@ Here you can find a list of annotated _go-git_ examples: - [log](log/main.go) - Emulate `git log` command output iterating all the commit history from HEAD reference. - [branch](branch/main.go) - How to create and remove branches or any other kind of reference. - [tag](tag/main.go) - List/print repository tags. +- [tag create and push](tag-create-push/main.go) - Create and push a new tag. - [remotes](remotes/main.go) - Working with remotes: adding, removing, etc. - [progress](progress/main.go) - Printing the progress information from the sideband. - [revision](revision/main.go) - Solve a revision into a commit. diff --git a/_examples/tag-create-push/main.go b/_examples/tag-create-push/main.go new file mode 100644 index 0000000..0d216da --- /dev/null +++ b/_examples/tag-create-push/main.go @@ -0,0 +1,161 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "time" + + "github.com/go-git/go-git/v5" + . "github.com/go-git/go-git/v5/_examples" + "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/plumbing/transport/ssh" +) + +func main() { + CheckArgs("<ssh-url>", "<directory>", "<tag>", "<name>", "<email>", "<public-key>") + url := os.Args[1] + directory := os.Args[2] + tag := os.Args[3] + name := os.Args[4] + email := os.Args[5] + key := os.Args[6] + + r, err := cloneRepo(url, directory, key) + + if err != nil { + log.Printf("clone repo error: %s", err) + return + } + + created, err := setTag(r, tag, defaultSignature(name, email)) + if err != nil { + log.Printf("create tag error: %s", err) + return + } + + if created { + err = pushTags(r, key) + if err != nil { + log.Printf("push tag error: %s", err) + return + } + } + +} + +func cloneRepo(url, dir, publicKeyPath string) (*git.Repository, error) { + + log.Printf("cloning %s into %s", url, dir) + auth, keyErr := publicKey(publicKeyPath) + if keyErr != nil { + return nil, keyErr + } + + Info("git clone %s", url) + r, err := git.PlainClone(dir, false, &git.CloneOptions{ + Progress: os.Stdout, + URL: url, + Auth: auth, + }) + + if err != nil { + log.Printf("clone git repo error: %s", err) + return nil, err + } + + return r, nil +} + +func publicKey(filePath string) (*ssh.PublicKeys, error) { + var publicKey *ssh.PublicKeys + sshKey, _ := ioutil.ReadFile(filePath) + publicKey, err := ssh.NewPublicKeys("git", []byte(sshKey), "") + if err != nil { + return nil, err + } + return publicKey, err +} + +func tagExists(tag string, r *git.Repository) bool { + tagFoundErr := "tag was found" + Info("git show-ref --tag") + tags, err := r.TagObjects() + if err != nil { + log.Printf("get tags error: %s", err) + return false + } + res := false + err = tags.ForEach(func(t *object.Tag) error { + if t.Name == tag { + res = true + return fmt.Errorf(tagFoundErr) + } + return nil + }) + if err != nil && err.Error() != tagFoundErr { + log.Printf("iterate tags error: %s", err) + return false + } + return res +} + +func setTag(r *git.Repository, tag string, tagger *object.Signature) (bool, error) { + if tagExists(tag, r) { + log.Printf("tag %s already exists", tag) + return false, nil + } + log.Printf("Set tag %s", tag) + h, err := r.Head() + if err != nil { + log.Printf("get HEAD error: %s", err) + return false, err + } + Info("git tag -a %s %s -m \"%s\"", tag, h.Hash(), tag) + _, err = r.CreateTag(tag, h.Hash(), &git.CreateTagOptions{ + Tagger: tagger, + Message: tag, + }) + + if err != nil { + log.Printf("create tag error: %s", err) + return false, err + } + + return true, nil +} + +func pushTags(r *git.Repository, publicKeyPath string) error { + + auth, _ := publicKey(publicKeyPath) + + po := &git.PushOptions{ + RemoteName: "origin", + Progress: os.Stdout, + RefSpecs: []config.RefSpec{config.RefSpec("refs/tags/*:refs/tags/*")}, + Auth: auth, + } + Info("git push --tags") + err := r.Push(po) + + if err != nil { + if err == git.NoErrAlreadyUpToDate { + log.Print("origin remote was up to date, no push done") + return nil + } + log.Printf("push to remote origin error: %s", err) + return err + } + + return nil +} + +func defaultSignature(name, email string) *object.Signature { + return &object.Signature{ + Name: name, + Email: email, + When: time.Now(), + } +} |