From d7eda0e2b82dcbdac8ab8c7d1f6571d9ccbadb05 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 15:01:32 -0400 Subject: [PATCH 01/20] Fixes #2738 - /git/tags API --- models/repo_tag.go | 2 +- modules/git/repo_ref.go | 12 ++-- modules/git/repo_tag.go | 116 +++++++++++++++++++++++++++--- modules/structs/repo_tag.go | 21 +++++- routers/api/v1/api.go | 1 + routers/api/v1/convert/convert.go | 63 ++++++++++++---- routers/api/v1/repo/git_ref.go | 3 +- routers/api/v1/repo/tag.go | 45 ++++++++++++ routers/api/v1/swagger/repo.go | 9 ++- templates/swagger/v1_json.tmpl | 52 +++++++++++++- 10 files changed, 292 insertions(+), 32 deletions(-) diff --git a/models/repo_tag.go b/models/repo_tag.go index fa3f19bb292cb..3864b7a12a7c9 100644 --- a/models/repo_tag.go +++ b/models/repo_tag.go @@ -8,7 +8,7 @@ import ( "code.gitea.io/gitea/modules/git" ) -// GetTagsByPath returns repo tags by it's path +// GetTagsByPath returns repo tags by its path func GetTagsByPath(path string) ([]*git.Tag, error) { gitRepo, err := git.OpenRepository(path) if err != nil { diff --git a/modules/git/repo_ref.go b/modules/git/repo_ref.go index e1ab46e0902dc..95a6c2ae69390 100644 --- a/modules/git/repo_ref.go +++ b/modules/git/repo_ref.go @@ -31,15 +31,19 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) { if err = refsIter.ForEach(func(ref *plumbing.Reference) error { if ref.Name() != plumbing.HEAD && !ref.Name().IsRemote() && (pattern == "" || strings.HasPrefix(ref.Name().String(), pattern)) { + refType := string(ObjectCommit) + if ref.Name().IsTag() { + // tags can be of type `commit` (lightweight) or `tag` (annotated) + if tagType, _ := repo.GetTagType(SHA1(ref.Hash())); err == nil { + refType = tagType + } + } r := &Reference{ Name: ref.Name().String(), Object: SHA1(ref.Hash()), - Type: string(ObjectCommit), + Type: refType, repo: repo, } - if ref.Name().IsTag() { - r.Type = string(ObjectTag) - } refs = append(refs, r) } return nil diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 8c72528933ccd..af72cda19f680 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -6,6 +6,7 @@ package git import ( + "fmt" "strings" "github.com/mcuadros/go-version" @@ -42,19 +43,44 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return t.(*Tag), nil } - // Get tag type - tp, err := NewCommand("cat-file", "-t", id.String()).RunInDir(repo.Path) + // Get tag name + name, err := repo.GetTagNameBySHA(id.String()) if err != nil { return nil, err } - tp = strings.TrimSpace(tp) - // Tag is a commit. + tp, err := repo.GetTagType(id) + if err != nil { + return nil, err + } + + // The id passed in could be a tag object ID or a commit ID, so getting both + tagID := id + if tagIDStr, _ := repo.GetTagID(name); tagIDStr != "" { + if tID, err := NewIDFromString(tagIDStr); err == nil { + tagID = tID + } + } + commitID := id + if commitIDStr, _ := repo.GetTagCommitID(name); commitIDStr != "" { + if cID, err := NewIDFromString(commitIDStr); err == nil { + commitID = cID + } + } + + // If type is "commit, the tag is a lightweight tag if ObjectType(tp) == ObjectCommit { + commit, err := repo.GetCommit(id.String()) + if err != nil { + return nil, err + } tag := &Tag{ - ID: id, - Object: id, + Name: name, + ID: tagID, + Object: commitID, Type: string(ObjectCommit), + Tagger: commit.Committer, + Message: commit.Message(), repo: repo, } @@ -62,7 +88,7 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return tag, nil } - // Tag with message. + // The tag is an annotated tag with a message. data, err := NewCommand("cat-file", "-p", id.String()).RunInDirBytes(repo.Path) if err != nil { return nil, err @@ -73,6 +99,7 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return nil, err } + tag.Name = name tag.ID = id tag.repo = repo @@ -80,6 +107,45 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return tag, nil } +// GetTagNameBySHA returns the name of a tag from its tag object SHA or commit SHA +func (repo *Repository) GetTagNameBySHA(sha string) (string, error) { + if len(sha) < 5 { + return "", fmt.Errorf("SHA is too short: %s", sha) + } + + stdout, err := NewCommand("show-ref", "--tags", "-d").RunInDir(repo.Path) + if err != nil { + return "", err + } + + tagRefs := strings.Split(stdout, "\n") + for _, tagRef := range tagRefs { + if len(strings.TrimSpace(tagRef)) > 0 { + fields := strings.Fields(tagRef) + if strings.HasPrefix(fields[0], sha) && strings.HasPrefix(fields[1], "refs/tags/") { + name := strings.Split(fields[1], "/")[2] + // annotated tags show up twice, their name for commit ID is suffixed with ^{} + name = strings.TrimSuffix(name, "^{}") + return name, nil + } + } + } + return "", ErrNotExist{ID: sha} +} + +// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA) +func (repo *Repository) GetTagID(name string) (string, error) { + stdout, err := NewCommand("show-ref", name).RunInDir(repo.Path) + if err != nil { + return "", err + } + fields := strings.Fields(stdout) + if len(fields) != 2 { + return "", ErrNotExist{ID: name} + } + return fields[0], nil +} + // GetTag returns a Git tag by given name. func (repo *Repository) GetTag(name string) (*Tag, error) { idStr, err := repo.GetTagCommitID(name) @@ -96,7 +162,6 @@ func (repo *Repository) GetTag(name string) (*Tag, error) { if err != nil { return nil, err } - tag.Name = name return tag, nil } @@ -150,3 +215,38 @@ func (repo *Repository) GetTags() ([]string, error) { return tagNames, nil } + +// GetTagType gets the type of the tag, either commit (simple) or tag (annotated) +func (repo *Repository) GetTagType(id SHA1) (string, error) { + // Get tag type + stdout, err := NewCommand("cat-file", "-t", id.String()).RunInDir(repo.Path) + if err != nil { + return "", err + } + if len(stdout) == 0 { + return "", ErrNotExist{ID: id.String()} + } + return strings.TrimSpace(stdout), nil +} + +// GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag +func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) { + id, err := NewIDFromString(sha) + if err != nil { + return nil, err + } + + // Tag type must be "tag" (annotated) and not a "commit" (lightweight) tag + if tagType, err := repo.GetTagType(id); err != nil { + return nil, err + } else if ObjectType(tagType) != ObjectTag { + // not an annotated tag + return nil, ErrNotExist{ID: id.String()} + } + + tag, err := repo.getTag(id) + if err != nil { + return nil, err + } + return tag, nil +} diff --git a/modules/structs/repo_tag.go b/modules/structs/repo_tag.go index 6294a8099db10..dcebfd80c2504 100644 --- a/modules/structs/repo_tag.go +++ b/modules/structs/repo_tag.go @@ -4,9 +4,10 @@ package structs -// Tag represents a repository tag +// Tag represents a repository tag for the /tags API endpoint type Tag struct { Name string `json:"name"` + ID string `json:"id"` Commit struct { SHA string `json:"sha"` URL string `json:"url"` @@ -14,3 +15,21 @@ type Tag struct { ZipballURL string `json:"zipball_url"` TarballURL string `json:"tarball_url"` } + +// GitTag represents a git tag for the /git/tags API endpoint +type GitTag struct { + Tag string `json:"tag"` + SHA string `json:"sha"` + URL string `json:"url"` + Message string `json:"message"` + Tagger *CommitUser `json:"tagger"` + Object *GitTagObject `json:"object"` + Verification *PayloadCommitVerification `json:"verification"` +} + +// GitTagObject contains meta information of the tag object +type GitTagObject struct { + Type string `json:"type"` + URL string `json:"url"` + SHA string `json:"sha"` +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index ae64e887caabd..38bc401d4be3f 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -761,6 +761,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/refs/*", repo.GetGitRefs) m.Get("/trees/:sha", context.RepoRef(), repo.GetTree) m.Get("/blobs/:sha", context.RepoRef(), repo.GetBlob) + m.Get("/tags/:sha", context.RepoRef(), repo.GetTag) }, reqRepoReader(models.UnitTypeCode)) m.Group("/contents", func() { m.Get("/*", repo.GetFileContents) diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index 74fd9b3afd354..158bc47cf185a 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -6,6 +6,7 @@ package convert import ( "fmt" + "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" @@ -38,6 +39,7 @@ func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit) *api.Branch func ToTag(repo *models.Repository, t *git.Tag) *api.Tag { return &api.Tag{ Name: t.Name, + ID: t.ID.String(), Commit: struct { SHA string `json:"sha"` URL string `json:"url"` @@ -66,13 +68,6 @@ func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit { log.Error("GetUserByEmail: %v", err) } - verif := models.ParseCommitWithSignature(c) - var signature, payload string - if c.Signature != nil { - signature = c.Signature.Signature - payload = c.Signature.Payload - } - return &api.PayloadCommit{ ID: c.ID.String(), Message: c.Message(), @@ -87,13 +82,23 @@ func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit { Email: c.Committer.Email, UserName: committerUsername, }, - Timestamp: c.Author.When, - Verification: &api.PayloadCommitVerification{ - Verified: verif.Verified, - Reason: verif.Reason, - Signature: signature, - Payload: payload, - }, + Timestamp: c.Author.When, + Verification: ToVerification(c), + } +} + +func ToVerification(c *git.Commit) *api.PayloadCommitVerification { + verif := models.ParseCommitWithSignature(c) + var signature, payload string + if c.Signature != nil { + signature = c.Signature.Signature + payload = c.Signature.Payload + } + return &api.PayloadCommitVerification{ + Verified: verif.Verified, + Reason: verif.Reason, + Signature: signature, + Payload: payload, } } @@ -241,3 +246,33 @@ func ToUser(user *models.User, signed, admin bool) *api.User { } return result } + +// ToGitTag convert git.Tag to api.GitTag +func ToGitTag(repo *models.Repository, t *git.Tag, c *git.Commit) *api.GitTag { + return &api.GitTag{ + Tag: t.Name, + SHA: t.ID.String(), + Object: ToGitTagObject(repo, c), + Message: t.Message, + Tagger: ToCommitUser(t.Tagger), + Verification: ToVerification(c), + } +} + +func ToGitTagObject(repo *models.Repository, commit *git.Commit) *api.GitTagObject { + return &api.GitTagObject{ + SHA: commit.ID.String(), + Type: string(git.ObjectCommit), + URL: util.URLJoin(repo.Link(), "git/commits", commit.ID.String()), + } +} + +func ToCommitUser(sig *git.Signature) *api.CommitUser { + return &api.CommitUser{ + Identity: api.Identity{ + Name: sig.Name, + Email: sig.Email, + }, + Date: sig.When.UTC().Format(time.RFC3339), + } +} diff --git a/routers/api/v1/repo/git_ref.go b/routers/api/v1/repo/git_ref.go index 2ec8749058a8b..e15f699a1dae8 100644 --- a/routers/api/v1/repo/git_ref.go +++ b/routers/api/v1/repo/git_ref.go @@ -100,8 +100,7 @@ func getGitRefsInternal(ctx *context.APIContext, filter string) { Object: &api.GitObject{ SHA: refs[i].Object.String(), Type: refs[i].Type, - // TODO: Add commit/tag info URL - //URL: ctx.Repo.Repository.APIURL() + "/git/" + refs[i].Type + "s/" + refs[i].Object.String(), + URL: ctx.Repo.Repository.APIURL() + "/git/" + refs[i].Type + "s/" + refs[i].Object.String(), }, } } diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index dd1b5aa7c1892..dcd288b13f7bf 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -7,6 +7,7 @@ package repo import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/routers/api/v1/convert" + "net/http" api "code.gitea.io/gitea/modules/structs" ) @@ -45,3 +46,47 @@ func ListTags(ctx *context.APIContext) { ctx.JSON(200, &apiTags) } + +// GetTag get the tag of a repository. +func GetTag(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/git/tags/{sha} repository GetTag + // --- + // summary: Gets the tag of a repository. + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: sha + // in: path + // description: sha of the tag + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/Tag" + + sha := ctx.Params("sha") + if len(sha) == 0 { + ctx.Error(http.StatusBadRequest, "", "SHA not provided") + return + } + + if tag, err := ctx.Repo.GitRepo.GetAnnotatedTag(sha); err != nil { + ctx.Error(http.StatusBadRequest, "GetTag", err) + } else { + commit, err := tag.Commit() + if err != nil { + ctx.Error(http.StatusBadRequest, "GetTag", err) + } + ctx.JSON(http.StatusOK, convert.ToGitTag(ctx.Repo.Repository, tag, commit)) + } +} diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go index e7df0b8f71134..721a54ae8d834 100644 --- a/routers/api/v1/swagger/repo.go +++ b/routers/api/v1/swagger/repo.go @@ -38,11 +38,18 @@ type swaggerResponseBranchList struct { // TagList // swagger:response TagList -type swaggerReponseTagList struct { +type swaggerResponseTagList struct { // in:body Body []api.Tag `json:"body"` } +// Tag +// swagger:response Tag +type swaggerResponseTag struct { + // in:body + Body api.Tag `json:"body"` +} + // Reference // swagger:response Reference type swaggerResponseReference struct { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index c0790ac23edff..ac5ed9d545c1e 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -1990,6 +1990,46 @@ } } }, + "/repos/{owner}/{repo}/git/tags/{sha}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Gets the tag of a repository.", + "operationId": "GetTag", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "sha of the tag", + "name": "sha", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/Tag" + } + } + } + }, "/repos/{owner}/{repo}/git/trees/{sha}": { "get": { "produces": [ @@ -9250,7 +9290,7 @@ "x-go-package": "code.gitea.io/gitea/modules/structs" }, "Tag": { - "description": "Tag represents a repository tag", + "description": "Tag represents a repository tag for the /tags API endpoint", "type": "object", "properties": { "commit": { @@ -9267,6 +9307,10 @@ }, "x-go-name": "Commit" }, + "id": { + "type": "string", + "x-go-name": "ID" + }, "name": { "type": "string", "x-go-name": "Name" @@ -9848,6 +9892,12 @@ } } }, + "Tag": { + "description": "Tag", + "schema": { + "$ref": "#/definitions/Tag" + } + }, "TagList": { "description": "TagList", "schema": { From 4b84785a46287653ae9ce1fde732a055fe725159 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 15:51:15 -0400 Subject: [PATCH 02/20] proper URLs --- modules/git/repo_tag.go | 12 ++++++------ modules/structs/repo_tag.go | 13 +++++-------- routers/api/v1/api.go | 1 + routers/api/v1/convert/convert.go | 28 +++++++++++++++------------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index af72cda19f680..a1c4d4e60b41c 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -75,13 +75,13 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return nil, err } tag := &Tag{ - Name: name, - ID: tagID, - Object: commitID, - Type: string(ObjectCommit), - Tagger: commit.Committer, + Name: name, + ID: tagID, + Object: commitID, + Type: string(ObjectCommit), + Tagger: commit.Committer, Message: commit.Message(), - repo: repo, + repo: repo, } repo.tagCache.Set(id.String(), tag) diff --git a/modules/structs/repo_tag.go b/modules/structs/repo_tag.go index dcebfd80c2504..309da77e002de 100644 --- a/modules/structs/repo_tag.go +++ b/modules/structs/repo_tag.go @@ -6,14 +6,11 @@ package structs // Tag represents a repository tag for the /tags API endpoint type Tag struct { - Name string `json:"name"` - ID string `json:"id"` - Commit struct { - SHA string `json:"sha"` - URL string `json:"url"` - } `json:"commit"` - ZipballURL string `json:"zipball_url"` - TarballURL string `json:"tarball_url"` + Name string `json:"name"` + ID string `json:"id"` + Commit *CommitMeta `json:"commit"` + ZipballURL string `json:"zipball_url"` + TarballURL string `json:"tarball_url"` } // GitTag represents a git tag for the /git/tags API endpoint diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 463aec262bc0d..2268c1be38e05 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -751,6 +751,7 @@ func RegisterRoutes(m *macaron.Macaron) { Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus) }, reqRepoReader(models.UnitTypeCode)) m.Group("/commits/:ref", func() { + // TODO: Add m.Get("") for single commit (https://developer.github.com/v3/repos/commits/#get-a-single-commit) m.Get("/status", repo.GetCombinedCommitStatusByRef) m.Get("/statuses", repo.GetCommitStatusesByRef) }, reqRepoReader(models.UnitTypeCode)) diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index 76081736f04cd..28787a2280919 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -38,17 +38,11 @@ func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit) *api.Branch // ToTag convert a tag to an api.Tag func ToTag(repo *models.Repository, t *git.Tag) *api.Tag { return &api.Tag{ - Name: t.Name, - ID: t.ID.String(), - Commit: struct { - SHA string `json:"sha"` - URL string `json:"url"` - }{ - SHA: t.ID.String(), - URL: util.URLJoin(repo.Link(), "commit", t.ID.String()), - }, - ZipballURL: util.URLJoin(repo.Link(), "archive", t.Name+".zip"), - TarballURL: util.URLJoin(repo.Link(), "archive", t.Name+".tar.gz"), + Name: t.Name, + ID: t.ID.String(), + Commit: ToCommitMeta(repo, t), + ZipballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".zip"), + TarballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".tar.gz"), } } @@ -71,7 +65,7 @@ func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit { return &api.PayloadCommit{ ID: c.ID.String(), Message: c.Message(), - URL: util.URLJoin(repo.Link(), "commit", c.ID.String()), + URL: util.URLJoin(repo.HTMLURL(), "commit", c.ID.String()), Author: &api.PayloadUser{ Name: c.Author.Name, Email: c.Author.Email, @@ -264,7 +258,7 @@ func ToGitTagObject(repo *models.Repository, commit *git.Commit) *api.GitTagObje return &api.GitTagObject{ SHA: commit.ID.String(), Type: string(git.ObjectCommit), - URL: util.URLJoin(repo.Link(), "git/commits", commit.ID.String()), + URL: util.URLJoin(repo.APIURL(), "git/commits", commit.ID.String()), } } @@ -277,3 +271,11 @@ func ToCommitUser(sig *git.Signature) *api.CommitUser { Date: sig.When.UTC().Format(time.RFC3339), } } + +func ToCommitMeta(repo *models.Repository, tag *git.Tag) *api.CommitMeta { + return &api.CommitMeta{ + SHA: tag.ID.String(), + // TODO: Add the /commits API endpoint and use it here (https://developer.github.com/v3/repos/commits/#get-a-single-commit) + URL: util.URLJoin(repo.APIURL(), "git/commits", tag.ID.String()), + } +} From ab588c76b506796f0aeec8d1a31ef3cf862d7a38 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 15:59:06 -0400 Subject: [PATCH 03/20] Adds function comments --- routers/api/v1/convert/convert.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index 28787a2280919..7f5ae9562c80a 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -27,7 +27,7 @@ func ToEmail(email *models.EmailAddress) *api.Email { } } -// ToBranch convert a commit and branch to an api.Branch +// ToBranch convert a git.Commit and git.Branch to an api.Branch func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit) *api.Branch { return &api.Branch{ Name: b.Name, @@ -35,7 +35,7 @@ func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit) *api.Branch } } -// ToTag convert a tag to an api.Tag +// ToTag convert a git.Tag to an api.Tag func ToTag(repo *models.Repository, t *git.Tag) *api.Tag { return &api.Tag{ Name: t.Name, @@ -46,7 +46,7 @@ func ToTag(repo *models.Repository, t *git.Tag) *api.Tag { } } -// ToCommit convert a commit to api.PayloadCommit +// ToCommit convert a git.Commit to api.PayloadCommit func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit { authorUsername := "" if author, err := models.GetUserByEmail(c.Author.Email); err == nil { @@ -81,6 +81,7 @@ func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit { } } +// ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification func ToVerification(c *git.Commit) *api.PayloadCommitVerification { verif := models.ParseCommitWithSignature(c) var signature, payload string @@ -254,6 +255,7 @@ func ToGitTag(repo *models.Repository, t *git.Tag, c *git.Commit) *api.GitTag { } } +// ToGitTagObject convert a git.Commit to an api.GitTagObject func ToGitTagObject(repo *models.Repository, commit *git.Commit) *api.GitTagObject { return &api.GitTagObject{ SHA: commit.ID.String(), @@ -262,6 +264,7 @@ func ToGitTagObject(repo *models.Repository, commit *git.Commit) *api.GitTagObje } } +// ToCommitUser convert a git.Signature to an api.CommitUser func ToCommitUser(sig *git.Signature) *api.CommitUser { return &api.CommitUser{ Identity: api.Identity{ @@ -272,6 +275,7 @@ func ToCommitUser(sig *git.Signature) *api.CommitUser { } } +// ToCommitMeta convert a git.Tag to an api.CommitMeta func ToCommitMeta(repo *models.Repository, tag *git.Tag) *api.CommitMeta { return &api.CommitMeta{ SHA: tag.ID.String(), From 716e76cb80b85f21fd564a31f1f3f45e84e73815 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 16:00:32 -0400 Subject: [PATCH 04/20] Updates swagger --- templates/swagger/v1_json.tmpl | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index c7ccb9c886f30..29b0acb0f63d6 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -9492,18 +9492,7 @@ "type": "object", "properties": { "commit": { - "type": "object", - "properties": { - "sha": { - "type": "string", - "x-go-name": "SHA" - }, - "url": { - "type": "string", - "x-go-name": "URL" - } - }, - "x-go-name": "Commit" + "$ref": "#/definitions/CommitMeta" }, "id": { "type": "string", From 861df65792fee3cdeaa3ac442d91a8c2dfa8a4b4 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 16:27:09 -0400 Subject: [PATCH 05/20] Removes newline from tag message --- modules/git/tag.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/git/tag.go b/modules/git/tag.go index 500fd274914c4..c97f574fa62b9 100644 --- a/modules/git/tag.go +++ b/modules/git/tag.go @@ -7,6 +7,7 @@ package git import ( "bytes" "sort" + "strings" ) // Tag represents a Git tag. @@ -59,7 +60,7 @@ l: } nextline += eol + 1 case eol == 0: - tag.Message = string(data[nextline+1:]) + tag.Message = strings.TrimRight(string(data[nextline+1:]), "\n") break l default: break l From 157d6b667e6d39fc77265a39663cc1b158f43631 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 16:46:58 -0400 Subject: [PATCH 06/20] Removes trailing newline from commit message --- modules/git/repo_commit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index b631f9341e18e..b9846ec52933b 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -94,7 +94,7 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) { commit.repo = repo if tagObject != nil { - commit.CommitMessage = strings.TrimSpace(tagObject.Message) + commit.CommitMessage = strings.TrimRight(strings.TrimSpace(tagObject.Message), "\n") commit.Author = &tagObject.Tagger commit.Signature = convertPGPSignatureForTag(tagObject) } From 41bb6aa0c767951d67fa12094360dc483be98d93 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 21:18:33 -0400 Subject: [PATCH 07/20] Adds integration test --- integrations/api_repo_file_create_test.go | 4 +- integrations/api_repo_file_update_test.go | 8 +-- integrations/api_repo_git_ref_test.go | 4 +- integrations/api_repo_git_tags_test.go | 59 +++++++++++++++++++++++ integrations/api_repo_tags_test.go | 7 ++- modules/git/repo_commit.go | 2 +- modules/git/repo_tag.go | 8 ++- routers/api/v1/convert/convert.go | 1 + 8 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 integrations/api_repo_git_tags_test.go diff --git a/integrations/api_repo_file_create_test.go b/integrations/api_repo_file_create_test.go index 28097179a060d..259174a4d3dfe 100644 --- a/integrations/api_repo_file_create_test.go +++ b/integrations/api_repo_file_create_test.go @@ -146,8 +146,8 @@ func TestAPICreateFile(t *testing.T) { var fileResponse api.FileResponse DecodeJSON(t, resp, &fileResponse) expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf" - expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/new/file%d.txt", fileID) - expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID) + expectedHTMLURL := fmt.Sprintf(setting.AppURL + "user2/repo1/blob/new_branch/new/file%d.txt", fileID) + expectedDownloadURL := fmt.Sprintf(setting.AppURL + "user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) diff --git a/integrations/api_repo_file_update_test.go b/integrations/api_repo_file_update_test.go index 37438339bbd31..2e8540190d888 100644 --- a/integrations/api_repo_file_update_test.go +++ b/integrations/api_repo_file_update_test.go @@ -136,8 +136,8 @@ func TestAPIUpdateFile(t *testing.T) { var fileResponse api.FileResponse DecodeJSON(t, resp, &fileResponse) expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136" - expectedHTMLURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/new_branch/update/file%d.txt", fileID) - expectedDownloadURL := fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID) + expectedHTMLURL := fmt.Sprintf(setting.AppURL + "user2/repo1/blob/new_branch/update/file%d.txt", fileID) + expectedDownloadURL := fmt.Sprintf(setting.AppURL + "user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) @@ -155,8 +155,8 @@ func TestAPIUpdateFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &fileResponse) expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136" - expectedHTMLURL = fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/blob/master/rename/update/file%d.txt", fileID) - expectedDownloadURL = fmt.Sprintf("http://localhost:"+setting.HTTPPort+"/user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID) + expectedHTMLURL = fmt.Sprintf(setting.AppURL + "user2/repo1/blob/master/rename/update/file%d.txt", fileID) + expectedDownloadURL = fmt.Sprintf(setting.AppURL + "user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) diff --git a/integrations/api_repo_git_ref_test.go b/integrations/api_repo_git_ref_test.go index 1a7864a7c10da..10daca0203506 100644 --- a/integrations/api_repo_git_ref_test.go +++ b/integrations/api_repo_git_ref_test.go @@ -5,6 +5,7 @@ package integrations import ( + "github.com/davecgh/go-spew/spew" "net/http" "testing" @@ -23,7 +24,8 @@ func TestAPIReposGitRefs(t *testing.T) { "refs/tags/v1.1", // Tag } { req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/%s?token="+token, user.Name, ref) - session.MakeRequest(t, req, http.StatusOK) + res := session.MakeRequest(t, req, http.StatusOK) + spew.Dump(res.Body) } // Test getting all refs req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/refs?token="+token, user.Name) diff --git a/integrations/api_repo_git_tags_test.go b/integrations/api_repo_git_tags_test.go new file mode 100644 index 0000000000000..b6bb383cd9c0a --- /dev/null +++ b/integrations/api_repo_git_tags_test.go @@ -0,0 +1,59 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package integrations + +import ( + "net/http" + "testing" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" + + "github.com/stretchr/testify/assert" +) + +func TestAPIGitTags(t *testing.T) { + prepareTestEnv(t) + user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User) + repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) + // Login as User2. + session := loginUser(t, user.Name) + token := getTokenForLoggedInUser(t, session) + + // Set up git config for the tagger + git.NewCommand("config", "user.name", user.Name).RunInDir(repo.RepoPath()) + git.NewCommand("config", "user.email", user.Email).RunInDir(repo.RepoPath()) + + gitRepo, _ := git.OpenRepository(repo.RepoPath()) + commit, _ := gitRepo.GetBranchCommit("master") + lTagName := "lightweightTag" + gitRepo.CreateTag(lTagName, commit.ID.String()) + + aTagName := "annotatedTag" + aTagMessage := "my annotated message" + gitRepo.CreateAnnotatedTag(aTagName, aTagMessage, commit.ID.String()) + aTag, _ := gitRepo.GetTag(aTagName) + + // SHOULD work for annotated tags + req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/tags/%s?token=%s", user.Name, repo.Name, aTag.ID.String(), token) + res := session.MakeRequest(t, req, http.StatusOK) + + var tag *api.GitTag + DecodeJSON(t, res, &tag) + + assert.Equal(t, aTagName, tag.Tag) + assert.Equal(t, aTag.ID.String(), tag.SHA) + assert.Equal(t, commit.ID.String(), tag.Object.SHA) + assert.Equal(t, aTagMessage, tag.Message) + assert.Equal(t, user.Name, tag.Tagger.Name) + assert.Equal(t, user.Email, tag.Tagger.Email) + assert.Equal(t, util.URLJoin(repo.APIURL(), "git/tags", aTag.ID.String()), tag.URL) + + // Should NOT work for lightweight tags + badReq := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/tags/%s?token=%s", user.Name, repo.Name, commit.ID.String(), token) + session.MakeRequest(t, badReq, http.StatusBadRequest) +} diff --git a/integrations/api_repo_tags_test.go b/integrations/api_repo_tags_test.go index 13b446fb9637c..1e6757baed824 100644 --- a/integrations/api_repo_tags_test.go +++ b/integrations/api_repo_tags_test.go @@ -6,7 +6,6 @@ package integrations import ( "net/http" - "path" "testing" "code.gitea.io/gitea/models" @@ -32,7 +31,7 @@ func TestAPIReposGetTags(t *testing.T) { assert.EqualValues(t, 1, len(tags)) assert.Equal(t, "v1.1", tags[0].Name) assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.SHA) - assert.Equal(t, path.Join(setting.AppSubURL, "/user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d"), tags[0].Commit.URL) - assert.Equal(t, path.Join(setting.AppSubURL, "/user2/repo1/archive/v1.1.zip"), tags[0].ZipballURL) - assert.Equal(t, path.Join(setting.AppSubURL, "/user2/repo1/archive/v1.1.tar.gz"), tags[0].TarballURL) + assert.Equal(t, setting.AppURL + "api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.URL) + assert.Equal(t, setting.AppURL + "user2/repo1/archive/v1.1.zip", tags[0].ZipballURL) + assert.Equal(t, setting.AppURL + "user2/repo1/archive/v1.1.tar.gz", tags[0].TarballURL) } diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index b9846ec52933b..b631f9341e18e 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -94,7 +94,7 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) { commit.repo = repo if tagObject != nil { - commit.CommitMessage = strings.TrimRight(strings.TrimSpace(tagObject.Message), "\n") + commit.CommitMessage = strings.TrimSpace(tagObject.Message) commit.Author = &tagObject.Tagger commit.Signature = convertPGPSignatureForTag(tagObject) } diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index a1c4d4e60b41c..d38227300e327 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -36,6 +36,12 @@ func (repo *Repository) CreateTag(name, revision string) error { return err } +// CreateAnnotatedTag create one annotated tag in the repository +func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error { + _, err := NewCommand("tag", "-a", "-m", message, name, revision).RunInDir(repo.Path) + return err +} + func (repo *Repository) getTag(id SHA1) (*Tag, error) { t, ok := repo.tagCache.Get(id.String()) if ok { @@ -148,7 +154,7 @@ func (repo *Repository) GetTagID(name string) (string, error) { // GetTag returns a Git tag by given name. func (repo *Repository) GetTag(name string) (*Tag, error) { - idStr, err := repo.GetTagCommitID(name) + idStr, err := repo.GetTagID(name) if err != nil { return nil, err } diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index 7f5ae9562c80a..b2f8ccf60ceae 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -250,6 +250,7 @@ func ToGitTag(repo *models.Repository, t *git.Tag, c *git.Commit) *api.GitTag { SHA: t.ID.String(), Object: ToGitTagObject(repo, c), Message: t.Message, + URL: util.URLJoin(repo.APIURL(), "git/tags", t.ID.String()), Tagger: ToCommitUser(t.Tagger), Verification: ToVerification(c), } From fae950f6e9697a10c9ea40d639b18f01e0e51c18 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 21:19:28 -0400 Subject: [PATCH 08/20] Removed debugging --- integrations/api_repo_git_ref_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/integrations/api_repo_git_ref_test.go b/integrations/api_repo_git_ref_test.go index 10daca0203506..4971279d5c580 100644 --- a/integrations/api_repo_git_ref_test.go +++ b/integrations/api_repo_git_ref_test.go @@ -5,7 +5,6 @@ package integrations import ( - "github.com/davecgh/go-spew/spew" "net/http" "testing" @@ -25,7 +24,6 @@ func TestAPIReposGitRefs(t *testing.T) { } { req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/%s?token="+token, user.Name, ref) res := session.MakeRequest(t, req, http.StatusOK) - spew.Dump(res.Body) } // Test getting all refs req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/refs?token="+token, user.Name) From a5208ca61baa91f8f08bbebd5ead9dc219e622bf Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 23:22:35 -0400 Subject: [PATCH 09/20] Adds tests --- modules/git/repo_tag.go | 1 + modules/git/repo_tag_test.go | 80 +++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index d38227300e327..2cef798580423 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -108,6 +108,7 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { tag.Name = name tag.ID = id tag.repo = repo + tag.Type = tp repo.tagCache.Set(id.String(), tag) return tag, nil diff --git a/modules/git/repo_tag_test.go b/modules/git/repo_tag_test.go index ccb2d57ac2401..49cdc35bce61a 100644 --- a/modules/git/repo_tag_test.go +++ b/modules/git/repo_tag_test.go @@ -21,8 +21,8 @@ func TestRepository_GetTags(t *testing.T) { assert.NoError(t, err) assert.Len(t, tags, 1) assert.EqualValues(t, "test", tags[0].Name) - assert.EqualValues(t, "37991dec2c8e592043f47155ce4808d4580f9123", tags[0].ID.String()) - assert.EqualValues(t, "commit", tags[0].Type) + assert.EqualValues(t, "3ad28a9149a2864384548f3d17ed7f38014c9e8a", tags[0].ID.String()) + assert.EqualValues(t, "tag", tags[0].Type) } func TestRepository_GetTag(t *testing.T) { @@ -35,10 +35,78 @@ func TestRepository_GetTag(t *testing.T) { bareRepo1, err := OpenRepository(clonedPath) assert.NoError(t, err) - tag, err := bareRepo1.GetTag("test") + lTagCommitID := "6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1" + lTagName := "lightweightTag" + bareRepo1.CreateTag(lTagName, lTagCommitID) + + aTagCommitID := "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0" + aTagName := "annotatedTag" + aTagMessage := "my annotated message" + bareRepo1.CreateAnnotatedTag(aTagName, aTagMessage, aTagCommitID) + aTagID, _ := bareRepo1.GetTagID(aTagName) + + lTag, err := bareRepo1.GetTag(lTagName) + lTag.repo =nil + assert.NoError(t, err) + assert.NotNil(t, lTag) + assert.EqualValues(t, lTagName, lTag.Name) + assert.EqualValues(t, lTagCommitID, lTag.ID.String()) + assert.EqualValues(t, lTagCommitID, lTag.Object.String()) + assert.EqualValues(t, "commit", lTag.Type) + + aTag, err := bareRepo1.GetTag(aTagName) + assert.NoError(t, err) + assert.NotNil(t, aTag) + assert.EqualValues(t, aTagName, aTag.Name) + assert.EqualValues(t, aTagID, aTag.ID.String()) + assert.NotEqual(t, aTagID, aTag.Object.String()) + assert.EqualValues(t, aTagCommitID, aTag.Object.String()) + assert.EqualValues(t, "tag", aTag.Type) +} + +func TestRepository_GetAnnotatedTag(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") + + clonedPath, err := cloneRepo(bareRepo1Path, testReposDir, "repo1_TestRepository_GetTag") + assert.NoError(t, err) + defer os.RemoveAll(clonedPath) + + bareRepo1, err := OpenRepository(clonedPath) + assert.NoError(t, err) + + lTagCommitID := "6fbd69e9823458e6c4a2fc5c0f6bc022b2f2acd1" + lTagName := "lightweightTag" + bareRepo1.CreateTag(lTagName, lTagCommitID) + + aTagCommitID := "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0" + aTagName := "annotatedTag" + aTagMessage := "my annotated message" + bareRepo1.CreateAnnotatedTag(aTagName, aTagMessage, aTagCommitID) + aTagID, _ := bareRepo1.GetTagID(aTagName) + + // Try an annotated tag + tag, err := bareRepo1.GetAnnotatedTag(aTagID) assert.NoError(t, err) assert.NotNil(t, tag) - assert.EqualValues(t, "test", tag.Name) - assert.EqualValues(t, "37991dec2c8e592043f47155ce4808d4580f9123", tag.ID.String()) - assert.EqualValues(t, "commit", tag.Type) + assert.EqualValues(t, aTagName, tag.Name) + assert.EqualValues(t, aTagID, tag.ID.String()) + assert.EqualValues(t, "tag", tag.Type) + + // Annotated tag's Commit ID should fail + tag2, err := bareRepo1.GetAnnotatedTag(aTagCommitID) + assert.Error(t, err) + assert.True(t, IsErrNotExist(err)) + assert.Nil(t, tag2) + + // Annotated tag's name should fail + tag3, err := bareRepo1.GetAnnotatedTag(aTagName) + assert.Error(t, err) + assert.Errorf(t, err, "Length must be 40: %d", len(aTagName)) + assert.Nil(t, tag3) + + // Lightweight Tag should fail + tag4, err := bareRepo1.GetAnnotatedTag(lTagCommitID) + assert.Error(t, err) + assert.True(t, IsErrNotExist(err)) + assert.Nil(t, tag4) } From 171ea7011e0d10d11c35aed83b691fd4e4917ae4 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 23:48:41 -0400 Subject: [PATCH 10/20] Fixes bug where multiple tags of same commit show wrong tag name --- modules/git/repo_tag.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 2cef798580423..69de140e92280 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -46,7 +46,8 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { t, ok := repo.tagCache.Get(id.String()) if ok { log("Hit cache: %s", id) - return t.(*Tag), nil + tagClone := *t.(*Tag) + return &tagClone, nil } // Get tag name @@ -180,7 +181,7 @@ func (repo *Repository) GetTagInfos() ([]*Tag, error) { return nil, err } - tagNames := strings.Split(stdout, "\n") + tagNames := strings.Split(strings.TrimRight(stdout, "\n"), "\n") var tags = make([]*Tag, 0, len(tagNames)) for _, tagName := range tagNames { tagName = strings.TrimSpace(tagName) @@ -192,6 +193,7 @@ func (repo *Repository) GetTagInfos() ([]*Tag, error) { if err != nil { return nil, err } + tag.Name = tagName tags = append(tags, tag) } sortTagsByTime(tags) From ad3f04c2800f717d73562f918320906d02779d6e Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Wed, 5 Jun 2019 23:51:24 -0400 Subject: [PATCH 11/20] Fix formatting --- integrations/api_repo_file_create_test.go | 4 ++-- integrations/api_repo_file_update_test.go | 8 ++++---- integrations/api_repo_tags_test.go | 6 +++--- modules/git/repo_tag_test.go | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/integrations/api_repo_file_create_test.go b/integrations/api_repo_file_create_test.go index 259174a4d3dfe..3bb2ecb812860 100644 --- a/integrations/api_repo_file_create_test.go +++ b/integrations/api_repo_file_create_test.go @@ -146,8 +146,8 @@ func TestAPICreateFile(t *testing.T) { var fileResponse api.FileResponse DecodeJSON(t, resp, &fileResponse) expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf" - expectedHTMLURL := fmt.Sprintf(setting.AppURL + "user2/repo1/blob/new_branch/new/file%d.txt", fileID) - expectedDownloadURL := fmt.Sprintf(setting.AppURL + "user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID) + expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/blob/new_branch/new/file%d.txt", fileID) + expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) diff --git a/integrations/api_repo_file_update_test.go b/integrations/api_repo_file_update_test.go index 2e8540190d888..eab7090df68f5 100644 --- a/integrations/api_repo_file_update_test.go +++ b/integrations/api_repo_file_update_test.go @@ -136,8 +136,8 @@ func TestAPIUpdateFile(t *testing.T) { var fileResponse api.FileResponse DecodeJSON(t, resp, &fileResponse) expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136" - expectedHTMLURL := fmt.Sprintf(setting.AppURL + "user2/repo1/blob/new_branch/update/file%d.txt", fileID) - expectedDownloadURL := fmt.Sprintf(setting.AppURL + "user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID) + expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/blob/new_branch/update/file%d.txt", fileID) + expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) @@ -155,8 +155,8 @@ func TestAPIUpdateFile(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &fileResponse) expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136" - expectedHTMLURL = fmt.Sprintf(setting.AppURL + "user2/repo1/blob/master/rename/update/file%d.txt", fileID) - expectedDownloadURL = fmt.Sprintf(setting.AppURL + "user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID) + expectedHTMLURL = fmt.Sprintf(setting.AppURL+"user2/repo1/blob/master/rename/update/file%d.txt", fileID) + expectedDownloadURL = fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID) assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA) assert.EqualValues(t, expectedHTMLURL, fileResponse.Content.HTMLURL) assert.EqualValues(t, expectedDownloadURL, fileResponse.Content.DownloadURL) diff --git a/integrations/api_repo_tags_test.go b/integrations/api_repo_tags_test.go index 1e6757baed824..252037bd4a570 100644 --- a/integrations/api_repo_tags_test.go +++ b/integrations/api_repo_tags_test.go @@ -31,7 +31,7 @@ func TestAPIReposGetTags(t *testing.T) { assert.EqualValues(t, 1, len(tags)) assert.Equal(t, "v1.1", tags[0].Name) assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.SHA) - assert.Equal(t, setting.AppURL + "api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.URL) - assert.Equal(t, setting.AppURL + "user2/repo1/archive/v1.1.zip", tags[0].ZipballURL) - assert.Equal(t, setting.AppURL + "user2/repo1/archive/v1.1.tar.gz", tags[0].TarballURL) + assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.URL) + assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.zip", tags[0].ZipballURL) + assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.tar.gz", tags[0].TarballURL) } diff --git a/modules/git/repo_tag_test.go b/modules/git/repo_tag_test.go index 49cdc35bce61a..4f727c6c66fa8 100644 --- a/modules/git/repo_tag_test.go +++ b/modules/git/repo_tag_test.go @@ -46,7 +46,7 @@ func TestRepository_GetTag(t *testing.T) { aTagID, _ := bareRepo1.GetTagID(aTagName) lTag, err := bareRepo1.GetTag(lTagName) - lTag.repo =nil + lTag.repo = nil assert.NoError(t, err) assert.NotNil(t, lTag) assert.EqualValues(t, lTagName, lTag.Name) From 582c6cca78104dafca1ae1d4651e58695ad7b3b3 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Thu, 6 Jun 2019 00:30:06 -0400 Subject: [PATCH 12/20] Removes unused varaible --- integrations/api_repo_git_ref_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/api_repo_git_ref_test.go b/integrations/api_repo_git_ref_test.go index 4971279d5c580..1a7864a7c10da 100644 --- a/integrations/api_repo_git_ref_test.go +++ b/integrations/api_repo_git_ref_test.go @@ -23,7 +23,7 @@ func TestAPIReposGitRefs(t *testing.T) { "refs/tags/v1.1", // Tag } { req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/%s?token="+token, user.Name, ref) - res := session.MakeRequest(t, req, http.StatusOK) + session.MakeRequest(t, req, http.StatusOK) } // Test getting all refs req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/refs?token="+token, user.Name) From 9c5275141fe0afb302c367643680e70514442dd8 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Thu, 6 Jun 2019 00:45:57 -0400 Subject: [PATCH 13/20] Fix to annotated tag function names and response --- integrations/api_repo_git_tags_test.go | 2 +- modules/structs/repo_tag.go | 12 ++--- routers/api/v1/convert/convert.go | 14 +++--- routers/api/v1/repo/tag.go | 4 +- routers/api/v1/swagger/repo.go | 7 +++ templates/swagger/v1_json.tmpl | 61 +++++++++++++++++++++++++- 6 files changed, 82 insertions(+), 18 deletions(-) diff --git a/integrations/api_repo_git_tags_test.go b/integrations/api_repo_git_tags_test.go index b6bb383cd9c0a..ae519249e03b0 100644 --- a/integrations/api_repo_git_tags_test.go +++ b/integrations/api_repo_git_tags_test.go @@ -42,7 +42,7 @@ func TestAPIGitTags(t *testing.T) { req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/tags/%s?token=%s", user.Name, repo.Name, aTag.ID.String(), token) res := session.MakeRequest(t, req, http.StatusOK) - var tag *api.GitTag + var tag *api.AnnotatedTag DecodeJSON(t, res, &tag) assert.Equal(t, aTagName, tag.Tag) diff --git a/modules/structs/repo_tag.go b/modules/structs/repo_tag.go index 309da77e002de..b62395cac4983 100644 --- a/modules/structs/repo_tag.go +++ b/modules/structs/repo_tag.go @@ -4,7 +4,7 @@ package structs -// Tag represents a repository tag for the /tags API endpoint +// Tag represents a repository tag type Tag struct { Name string `json:"name"` ID string `json:"id"` @@ -13,19 +13,19 @@ type Tag struct { TarballURL string `json:"tarball_url"` } -// GitTag represents a git tag for the /git/tags API endpoint -type GitTag struct { +// AnnotatedTag represents an annotated tag +type AnnotatedTag struct { Tag string `json:"tag"` SHA string `json:"sha"` URL string `json:"url"` Message string `json:"message"` Tagger *CommitUser `json:"tagger"` - Object *GitTagObject `json:"object"` + Object *AnnotatedTagObject `json:"object"` Verification *PayloadCommitVerification `json:"verification"` } -// GitTagObject contains meta information of the tag object -type GitTagObject struct { +// AnnotatedTagObject contains meta information of the tag object +type AnnotatedTagObject struct { Type string `json:"type"` URL string `json:"url"` SHA string `json:"sha"` diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index b2f8ccf60ceae..a982cb8d371eb 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -243,12 +243,12 @@ func ToUser(user *models.User, signed, admin bool) *api.User { return result } -// ToGitTag convert git.Tag to api.GitTag -func ToGitTag(repo *models.Repository, t *git.Tag, c *git.Commit) *api.GitTag { - return &api.GitTag{ +// ToAnnotatedTag convert git.Tag to api.AnnotatedTag +func ToAnnotatedTag(repo *models.Repository, t *git.Tag, c *git.Commit) *api.AnnotatedTag { + return &api.AnnotatedTag{ Tag: t.Name, SHA: t.ID.String(), - Object: ToGitTagObject(repo, c), + Object: ToAnnotatedTagObject(repo, c), Message: t.Message, URL: util.URLJoin(repo.APIURL(), "git/tags", t.ID.String()), Tagger: ToCommitUser(t.Tagger), @@ -256,9 +256,9 @@ func ToGitTag(repo *models.Repository, t *git.Tag, c *git.Commit) *api.GitTag { } } -// ToGitTagObject convert a git.Commit to an api.GitTagObject -func ToGitTagObject(repo *models.Repository, commit *git.Commit) *api.GitTagObject { - return &api.GitTagObject{ +// ToAnnotatedTagObject convert a git.Commit to an api.AnnotatedTagObject +func ToAnnotatedTagObject(repo *models.Repository, commit *git.Commit) *api.AnnotatedTagObject { + return &api.AnnotatedTagObject{ SHA: commit.ID.String(), Type: string(git.ObjectCommit), URL: util.URLJoin(repo.APIURL(), "git/commits", commit.ID.String()), diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index dcd288b13f7bf..ecf580e1b08c4 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -72,7 +72,7 @@ func GetTag(ctx *context.APIContext) { // required: true // responses: // "200": - // "$ref": "#/responses/Tag" + // "$ref": "#/responses/AnnotatedTag" sha := ctx.Params("sha") if len(sha) == 0 { @@ -87,6 +87,6 @@ func GetTag(ctx *context.APIContext) { if err != nil { ctx.Error(http.StatusBadRequest, "GetTag", err) } - ctx.JSON(http.StatusOK, convert.ToGitTag(ctx.Repo.Repository, tag, commit)) + ctx.JSON(http.StatusOK, convert.ToAnnotatedTag(ctx.Repo.Repository, tag, commit)) } } diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go index 721a54ae8d834..25354b3d66698 100644 --- a/routers/api/v1/swagger/repo.go +++ b/routers/api/v1/swagger/repo.go @@ -50,6 +50,13 @@ type swaggerResponseTag struct { Body api.Tag `json:"body"` } +// AnnotatedTag +// swagger:response AnnotatedTag +type swaggerResponseAnnotatedTag struct { + // in:body + Body api.AnnotatedTag `json:"body"` +} + // Reference // swagger:response Reference type swaggerResponseReference struct { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 8efab5439d0e7..2b40c89791a05 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -2071,7 +2071,7 @@ ], "responses": { "200": { - "$ref": "#/responses/Tag" + "$ref": "#/responses/AnnotatedTag" } } } @@ -6802,6 +6802,57 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "AnnotatedTag": { + "description": "AnnotatedTag represents an annotated tag", + "type": "object", + "properties": { + "message": { + "type": "string", + "x-go-name": "Message" + }, + "object": { + "$ref": "#/definitions/AnnotatedTagObject" + }, + "sha": { + "type": "string", + "x-go-name": "SHA" + }, + "tag": { + "type": "string", + "x-go-name": "Tag" + }, + "tagger": { + "$ref": "#/definitions/CommitUser" + }, + "url": { + "type": "string", + "x-go-name": "URL" + }, + "verification": { + "$ref": "#/definitions/PayloadCommitVerification" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, + "AnnotatedTagObject": { + "description": "AnnotatedTagObject contains meta information of the tag object", + "type": "object", + "properties": { + "sha": { + "type": "string", + "x-go-name": "SHA" + }, + "type": { + "type": "string", + "x-go-name": "Type" + }, + "url": { + "type": "string", + "x-go-name": "URL" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "Attachment": { "description": "Attachment a generic attachment", "type": "object", @@ -9494,7 +9545,7 @@ "x-go-package": "code.gitea.io/gitea/modules/structs" }, "Tag": { - "description": "Tag represents a repository tag for the /tags API endpoint", + "description": "Tag represents a repository tag", "type": "object", "properties": { "commit": { @@ -9768,6 +9819,12 @@ "AccessTokenList": { "description": "AccessTokenList represents a list of API access token." }, + "AnnotatedTag": { + "description": "AnnotatedTag", + "schema": { + "$ref": "#/definitions/AnnotatedTag" + } + }, "Attachment": { "description": "Attachment", "schema": { From 1df581d2abd332abfba3fec380bcf95b3f137559 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Thu, 6 Jun 2019 13:11:41 -0400 Subject: [PATCH 14/20] Update modules/git/repo_tag.go Co-Authored-By: Lauris BH --- modules/git/repo_tag.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 69de140e92280..2520b96ebf8db 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -131,7 +131,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) { if len(strings.TrimSpace(tagRef)) > 0 { fields := strings.Fields(tagRef) if strings.HasPrefix(fields[0], sha) && strings.HasPrefix(fields[1], "refs/tags/") { - name := strings.Split(fields[1], "/")[2] + name := fields[1][len(git.TagPrefix):] // annotated tags show up twice, their name for commit ID is suffixed with ^{} name = strings.TrimSuffix(name, "^{}") return name, nil From 6547bfc723340235b3c02cd17a810cad59beea9b Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Thu, 6 Jun 2019 13:15:03 -0400 Subject: [PATCH 15/20] Uses TagPrefix --- modules/git/repo_tag.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 69de140e92280..c63944bb2458e 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -130,7 +130,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) { for _, tagRef := range tagRefs { if len(strings.TrimSpace(tagRef)) > 0 { fields := strings.Fields(tagRef) - if strings.HasPrefix(fields[0], sha) && strings.HasPrefix(fields[1], "refs/tags/") { + if strings.HasPrefix(fields[0], sha) && strings.HasPrefix(fields[1], TagPrefix) { name := strings.Split(fields[1], "/")[2] // annotated tags show up twice, their name for commit ID is suffixed with ^{} name = strings.TrimSuffix(name, "^{}") From dcce6bf385ad07113f79036f006c4bed95b7e200 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Fri, 7 Jun 2019 23:48:21 -0400 Subject: [PATCH 16/20] Changes per review, better error handling for getting tag and commit IDs --- modules/git/repo_tag.go | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index db0ec282fd99b..8a9627a560e15 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -61,18 +61,30 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return nil, err } - // The id passed in could be a tag object ID or a commit ID, so getting both - tagID := id - if tagIDStr, _ := repo.GetTagID(name); tagIDStr != "" { - if tID, err := NewIDFromString(tagIDStr); err == nil { - tagID = tID + var commitID SHA1 + if commitIDStr, _ := repo.GetTagCommitID(name); err != nil { + // every tag should have a commit ID so return all errors + return nil, err + } else { + cID, err := NewIDFromString(commitIDStr) + if err != nil { + return nil, err } + commitID = cID } - commitID := id - if commitIDStr, _ := repo.GetTagCommitID(name); commitIDStr != "" { - if cID, err := NewIDFromString(commitIDStr); err == nil { - commitID = cID + tagID := commitID // defaults to the commit ID as the tag ID and then tries to get a tag ID (only annotated tags) + if tagIDStr, err := repo.GetTagID(name); err != nil { + // if the err is NotExist then we can ignore and just keep tagID as ID (is lightweight tag) + // all other errors we return + if !IsErrNotExist(err) { + return nil, err + } + } else { + tID, err := NewIDFromString(tagIDStr) + if err != nil { + return nil, err } + tagID = tID } // If type is "commit, the tag is a lightweight tag From 9bc4e19b5dc48f30f12568646d579193703b341a Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Fri, 7 Jun 2019 23:58:41 -0400 Subject: [PATCH 17/20] Fix to getting commit ID --- modules/git/repo_tag.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 8a9627a560e15..daf9ee2090236 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -61,18 +61,20 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return nil, err } - var commitID SHA1 - if commitIDStr, _ := repo.GetTagCommitID(name); err != nil { + // Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object + commitIDStr, err := repo.GetTagCommitID(name) + if err != nil { // every tag should have a commit ID so return all errors return nil, err - } else { - cID, err := NewIDFromString(commitIDStr) - if err != nil { - return nil, err - } - commitID = cID } - tagID := commitID // defaults to the commit ID as the tag ID and then tries to get a tag ID (only annotated tags) + cID, err := NewIDFromString(commitIDStr) + if err != nil { + return nil, err + } + commitID := cID + + // defaults to the commit ID as the tag ID and then tries to get a tag ID (only annotated tags) + tagID := commitID if tagIDStr, err := repo.GetTagID(name); err != nil { // if the err is NotExist then we can ignore and just keep tagID as ID (is lightweight tag) // all other errors we return From 49e43495cbdc7b1eacd8d5ef476b1c45d3f0daab Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Fri, 7 Jun 2019 23:59:17 -0400 Subject: [PATCH 18/20] Fix to getting commit ID --- modules/git/repo_tag.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index daf9ee2090236..a1a874f460f8d 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -67,11 +67,10 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { // every tag should have a commit ID so return all errors return nil, err } - cID, err := NewIDFromString(commitIDStr) + commitID, err := NewIDFromString(commitIDStr) if err != nil { return nil, err } - commitID := cID // defaults to the commit ID as the tag ID and then tries to get a tag ID (only annotated tags) tagID := commitID From 8897b75a383afe2a352e17ffb902701e31d1b942 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Sat, 8 Jun 2019 00:00:36 -0400 Subject: [PATCH 19/20] Fix to getting commit ID --- modules/git/repo_tag.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index a1a874f460f8d..230ccead94d06 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -81,11 +81,10 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return nil, err } } else { - tID, err := NewIDFromString(tagIDStr) + tagID, err = NewIDFromString(tagIDStr) if err != nil { return nil, err } - tagID = tID } // If type is "commit, the tag is a lightweight tag From 03218443cbc5499d3639f727c201547ae025ab47 Mon Sep 17 00:00:00 2001 From: Richard Mahn Date: Sat, 8 Jun 2019 00:01:00 -0400 Subject: [PATCH 20/20] Fix to getting commit ID --- modules/git/repo_tag.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go index 230ccead94d06..08d66262c17d1 100644 --- a/modules/git/repo_tag.go +++ b/modules/git/repo_tag.go @@ -72,7 +72,7 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { return nil, err } - // defaults to the commit ID as the tag ID and then tries to get a tag ID (only annotated tags) + // tagID defaults to the commit ID as the tag ID and then tries to get a tag ID (only annotated tags) tagID := commitID if tagIDStr, err := repo.GetTagID(name); err != nil { // if the err is NotExist then we can ignore and just keep tagID as ID (is lightweight tag)