summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej Wereski <m.wereski@partner.samsung.com>2017-03-07 15:20:39 +0100
committerMaciej Wereski <m.wereski@partner.samsung.com>2017-08-17 08:53:00 +0200
commit3f46b44061a4c7d6c80c9d24391e06babcb98f08 (patch)
treef237c89a608ab6dca10ac93fc7a78bc17b7984b8
parent9c6b6ee0c7abea51b2d3526e634a515b4e993689 (diff)
downloadsnapsync-3f46b44061a4c7d6c80c9d24391e06babcb98f08.tar.gz
snapsync-3f46b44061a4c7d6c80c9d24391e06babcb98f08.tar.bz2
snapsync-3f46b44061a4c7d6c80c9d24391e06babcb98f08.zip
Implement tagging
Tags were changed from lighweight to annotated tags, as SR tags must be annotated. User name and e-mail is taken from git config. Also snapsync is generating proper SR tag string if user hasn't given -tag option. Change-Id: If6a5f053c200ec93658545d0c0c68007ef3e5530 Signed-off-by: Maciej Wereski <m.wereski@partner.samsung.com>
-rw-r--r--git/git.go94
-rw-r--r--git/manager.go29
-rw-r--r--snapsync.go20
3 files changed, 134 insertions, 9 deletions
diff --git a/git/git.go b/git/git.go
index b36c9b0..92da3c6 100644
--- a/git/git.go
+++ b/git/git.go
@@ -24,6 +24,41 @@ import (
git "gopkg.in/libgit2/git2go.v24"
)
+// getSigFromGitConfig finds username and e-mail and uses them to create git signature.
+func getSigFromGitConfig() (*git.Signature, error) {
+ cfgFile, err := git.ConfigFindXDG()
+ if err != nil {
+ cfgFile, err = git.ConfigFindGlobal()
+ if err != nil {
+ return nil, err
+ }
+ }
+ gcfg, err := git.NewConfig()
+ if err != nil {
+ return nil, err
+ }
+ defer gcfg.Free()
+ gcfg, err = git.OpenOndisk(gcfg, cfgFile)
+ if err != nil {
+ return nil, err
+ }
+ // Add also contents of ~/.config, but don't fail on errors
+ cfgFile, err = git.ConfigFindGlobal()
+ if err == nil {
+ gcfg.AddFile(cfgFile, git.ConfigLevelGlobal, false)
+ }
+ sig := new(git.Signature)
+ sig.Name, err = gcfg.LookupString("user.name")
+ if err != nil {
+ return nil, err
+ }
+ sig.Email, err = gcfg.LookupString("user.email")
+ if err != nil {
+ return nil, err
+ }
+ return sig, nil
+}
+
// gitAddRemote is one of jobs that can be run by workers. It adds remote that
// is described in req in local git repository that can be found under localMirror/req.Repo.
func gitAddRemote(localMirror string, req *GitRepo) error {
@@ -52,7 +87,7 @@ func gitAddRemote(localMirror string, req *GitRepo) error {
defer remote.Free()
// in case of different URL generate new name and update req.RemoteName
if url := remote.Url(); url != req.RemoteURL {
- name := req.RemoteName + "." + req.Tag[strings.LastIndex(req.Tag, "/")+1:]
+ name := req.RemoteName + "." + req.Tag.Tag[strings.LastIndex(req.Tag.Tag, "/")+1:]
r, err := repo.Remotes.Create(name, req.RemoteURL)
if err != nil {
return fmt.Errorf("couldn't create remote %s: %s", name, err)
@@ -127,13 +162,66 @@ func gitCompare(localMirror string, req *GitRepo) error {
// gitTag is one of jobs that can be run by workers. It applies req.AnnotatedTag
// to local git repository that resides under localMirror/req.Repo path.
func gitTag(localMirror string, req *GitRepo) error {
- log.Println("Apply tag " + req.Tag + " in " + localMirror + req.Repo + ".")
+ switch req.Status {
+ case Submitted:
+ return nil
+ case Unknown:
+ fallthrough
+ case Invalid:
+ return fmt.Errorf("bad commit status: %s", req.Status)
+ }
+ if req.Tag.Tag == "" {
+ return fmt.Errorf("tagging requested, but tag is empty")
+ }
+ if req.Tag.Signature == nil {
+ return fmt.Errorf("annotated tag signature missing")
+ }
+
+ repo, err := git.OpenRepository(localMirror + req.Repo)
+ if err != nil {
+ return err
+ }
+ defer repo.Free()
+
+ id, err := git.NewOid(req.SourceCommit)
+ if err != nil {
+ return err
+ }
+
+ commit, err := repo.LookupCommit(id)
+ if err != nil {
+ return err
+ }
+ defer commit.Free()
+
+ _, err = repo.Tags.Create(req.Tag.Tag, commit, req.Tag.Signature, req.Tag.Message)
+ if err != nil {
+ // if the requested commit already has requested tag, then just go on.
+ if err.(*git.GitError).Code != git.ErrExists {
+ return err
+ }
+ obj, err := repo.RevparseSingle(req.Tag.Tag)
+ if err != nil {
+ return err
+ }
+ defer obj.Free()
+ cobj, err := obj.Peel(git.ObjectCommit)
+ if err != nil {
+ return err
+ }
+ defer cobj.Free()
+ if cobj.Id().String() != id.String() {
+ return fmt.Errorf("different commit (%s) already tagged with %s",
+ cobj.Id(), req.Tag.Tag)
+ }
+ }
+
return nil
}
// gitPush is one of jobs that can be run by workers. It pushes earlier applied tags into remote repository,
// which leads to submitting repository described by req to OBS server.
func gitPush(localMirror string, req *GitRepo) error {
- log.Println("Push tag " + req.Tag + " in " + localMirror + req.Repo + " to " + req.RemoteName + ".")
+ log.Println("Push tag " + req.Tag.Tag + " in " + localMirror + req.Repo + " to " + req.RemoteName + ".")
return nil
}
diff --git a/git/manager.go b/git/manager.go
index b76ba74..b0237a8 100644
--- a/git/manager.go
+++ b/git/manager.go
@@ -22,6 +22,8 @@ import (
"fmt"
"sync"
"time"
+
+ git "gopkg.in/libgit2/git2go.v24"
)
// RepoStatus stores result of comparison of given repository in source and target profiles.
@@ -57,6 +59,27 @@ func (rs RepoStatus) String() string {
panic("Illegal repoStatus value!")
}
+// AnnotatedTag represents git annotated tags (with message and signature).
+type AnnotatedTag struct {
+ Tag string
+ Message string
+ Signature *git.Signature
+}
+
+// PrepareAnnotatedTag takes tag and message which are used to create annotated tag.
+func PrepareAnnotatedTag(tag string, message string) (t AnnotatedTag, err error) {
+ var sig *git.Signature
+ sig, err = getSigFromGitConfig()
+ if err != nil {
+ return t, err
+ }
+ t.Tag = tag
+ t.Message = message
+ sig.When = time.Now().UTC()
+ t.Signature = sig
+ return
+}
+
// GitRepo stores information about git repositories. Workers get all necessary
// information to do their jobs.
type GitRepo struct {
@@ -72,8 +95,8 @@ type GitRepo struct {
TargetCommit string
// Result of comparison of TargetCommit and SourceCommit
Status RepoStatus
- // Tag to use when tagging.
- Tag string
+ // Annotated tag to use when tagging.
+ Tag AnnotatedTag
}
func (r *GitRepo) String() string {
@@ -81,7 +104,7 @@ func (r *GitRepo) String() string {
r.RemoteName + " " + r.RemoteURL +
"\nSOURCE COMMIT:\t" + r.SourceCommit +
"\nTARGET COMMIT:\t" + r.TargetCommit +
- "\nSTATUS:\t" + r.Status.String() + "\nTAG:\t" + r.Tag
+ "\nSTATUS:\t" + r.Status.String() + "\nTAG:\t" + r.Tag.Tag
}
// JobType describes what kind of job worker should do.
diff --git a/snapsync.go b/snapsync.go
index ff46d0a..eefbb65 100644
--- a/snapsync.go
+++ b/snapsync.go
@@ -76,6 +76,13 @@ var (
timeout time.Duration
)
+// generateTag takes profile name and generates SR tag (as a string).
+func generateTag(project string) (tag string) {
+ timestamp := time.Now().UTC().Format("20060102.150405")
+ tag = "submit/tizen_" + project + "/" + timestamp
+ return
+}
+
// report prints git repositories summary (if given) and asks user what to do. Returns answer.
func report(repos *map[string]*gitMgr.GitRepo) (bool, error) {
var ans rune
@@ -293,8 +300,6 @@ func setup() error {
localMirror += "/"
}
- tagStr = getValue(tagStr, "tag/tmp", false)
-
// If target profile wasn't set and SR tag was set, then new profile is spun off.
if target == "" {
if tagStr == "" {
@@ -306,6 +311,8 @@ func setup() error {
}
}
+ tagStr = getValue(tagStr, generateTag(target), false)
+
return nil
}
@@ -342,6 +349,11 @@ func main() {
status = gitMgr.New
}
addr := sshURL.Scheme + "://" + username + "@" + sshURL.Host + "/"
+ message := fmt.Sprintf("snapsync: synchronize with profile: %s; snapshot: %s", source, sourceSnapshot)
+ tag, err := gitMgr.PrepareAnnotatedTag(tagStr, message)
+ if err != nil {
+ log.Fatalln("Couldn't prepare annotated tag:", err)
+ }
for repoName, commit := range repoList {
repos[repoName] = &gitMgr.GitRepo{
Repo: repoName,
@@ -350,7 +362,7 @@ func main() {
SourceCommit: commit,
TargetCommit: submitted[repoName],
Status: status,
- Tag: tagStr,
+ Tag: tag,
}
}
@@ -419,4 +431,6 @@ func main() {
dispatchAndGather(gitMgr.AddRemote)
dispatchAndGather(gitMgr.Tag)
dispatchAndGather(gitMgr.Push)
+
+ log.Println("SR tag:", tagStr)
}