diff options
author | Maciej Wereski <m.wereski@partner.samsung.com> | 2017-03-07 15:20:39 +0100 |
---|---|---|
committer | Maciej Wereski <m.wereski@partner.samsung.com> | 2017-08-17 08:53:00 +0200 |
commit | 3f46b44061a4c7d6c80c9d24391e06babcb98f08 (patch) | |
tree | f237c89a608ab6dca10ac93fc7a78bc17b7984b8 | |
parent | 9c6b6ee0c7abea51b2d3526e634a515b4e993689 (diff) | |
download | snapsync-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.go | 94 | ||||
-rw-r--r-- | git/manager.go | 29 | ||||
-rw-r--r-- | snapsync.go | 20 |
3 files changed, 134 insertions, 9 deletions
@@ -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) } |