瀏覽代碼

Merge pull request #76 from achilleas-k/doi-badge-from-tag

Get DOI badge from tag
Michael Sonntag 5 年之前
父節點
當前提交
7d7a0d69bd
共有 2 個文件被更改,包括 84 次插入14 次删除
  1. 83 13
      internal/route/repo/repo_gin.go
  2. 1 1
      templates/repo/header.tmpl

+ 83 - 13
internal/route/repo/repo_gin.go

@@ -14,6 +14,7 @@ import (
 
 
 	"github.com/G-Node/git-module"
 	"github.com/G-Node/git-module"
 	"github.com/G-Node/gogs/internal/context"
 	"github.com/G-Node/gogs/internal/context"
+	"github.com/G-Node/gogs/internal/db"
 	"github.com/G-Node/gogs/internal/setting"
 	"github.com/G-Node/gogs/internal/setting"
 	"github.com/G-Node/gogs/internal/tool"
 	"github.com/G-Node/gogs/internal/tool"
 	"github.com/G-Node/libgin/libgin"
 	"github.com/G-Node/libgin/libgin"
@@ -94,23 +95,92 @@ func readDataciteFile(entry *git.TreeEntry, c *context.Context) {
 	}
 	}
 	c.Data["DOIInfo"] = &doiInfo
 	c.Data["DOIInfo"] = &doiInfo
 
 
-	doi := calcRepoDOI(c, setting.DOI.Base)
-	//ddata, err := ginDoi.GDoiMData(doi, "https://api.datacite.org/works/") //todo configure URL?
-
-	c.Data["DOIReg"] = libgin.IsRegisteredDOI(doi)
-	c.Data["DOI"] = doi
+	if doi := getRepoDOI(c); doi != "" && libgin.IsRegisteredDOI(doi) {
+		c.Data["DOI"] = doi
+	}
 }
 }
 
 
-// calcRepoDOI calculates the theoretical DOI for a repository. If the repository
-// belongs to the DOI user (and is a fork) it uses the name for the base
-// repository.
-func calcRepoDOI(c *context.Context, doiBase string) string {
-	repoN := c.Repo.Repository.FullName()
-	// check whether this repo belongs to DOI and is a fork
+// getRepoDOI returns the DOI for the repository based on the following rules:
+// - if the repository belongs to the DOI user and has a tag that matches the
+// DOI prefix, returns the tag.
+// - if the repo is forked by the DOI user, check the DOI fork for the tag as above.
+// - if the repo is forked by the DOI user and the fork doesn't have a tag,
+// returns the (old-style) calculated DOI, based on the hash of the repository
+// path.
+// - An empty string is returned if it is not not forked by the DOI user.
+// If an error occurs at any point, returns an empty string (the error is logged).
+// Tag retrieval is allowed to fail and falls back on the hashed DOI method.
+func getRepoDOI(c *context.Context) string {
+	repo := c.Repo.Repository
+	var doiFork *db.Repository
+	if repo.Owner.Name == "doi" {
+		doiFork = repo
+	} else {
+		if forks, err := repo.GetForks(); err == nil {
+			for _, fork := range forks {
+				if fork.MustOwner().Name == "doi" {
+					doiFork = fork
+					break
+				}
+			}
+		} else {
+			log.Error(2, "failed to get forks for repository %q (%d): %v", repo.FullName(), repo.ID, err)
+			return ""
+		}
+	}
+
+	if doiFork == nil {
+		// not owned or forked by DOI, so not registered
+		return ""
+	}
+
+	// check the DOI fork for a tag that matches our DOI prefix
+	// if multiple exit, get the latest one
+	doiBase := setting.DOI.Base
+
+	doiForkGit, err := git.OpenRepository(doiFork.RepoPath())
+	if err != nil {
+		log.Error(2, "failed to open git repository at %q (%d): %v", doiFork.RepoPath(), doiFork.ID, err)
+		return ""
+	}
+	if tags, err := doiForkGit.GetTags(); err == nil {
+		var latestTime int64
+		latestTag := ""
+		for _, tagName := range tags {
+			if strings.Contains(tagName, doiBase) {
+				tag, err := doiForkGit.GetTag(tagName)
+				if err != nil {
+					// log the error and continue to the next tag
+					log.Error(2, "failed to get information for tag %q for repository at %q: %v", tagName, doiForkGit.Path, err)
+					continue
+				}
+				commit, err := tag.Commit()
+				if err != nil {
+					// log the error and continue to the next tag
+					log.Error(2, "failed to get commit for tag %q for repository at %q: %v", tagName, doiForkGit.Path, err)
+					continue
+				}
+				commitTime := commit.Committer.When.Unix()
+				if commitTime > latestTime {
+					latestTag = tagName
+					latestTime = commitTime
+				}
+				return latestTag
+			}
+		}
+	} else {
+		// this shouldn't happen even if there are no tags
+		// log the error, but fall back to the old method anyway
+		log.Error(2, "failed to get tags for repository at %q: %v", doiForkGit.Path, err)
+	}
+
+	// Has DOI fork but isn't tagged: return old style has-based DOI
+	repoPath := repo.FullName()
+	// get base repo name if it's a DOI fork
 	if c.Repo.Repository.IsFork && c.Repo.Owner.Name == "doi" {
 	if c.Repo.Repository.IsFork && c.Repo.Owner.Name == "doi" {
-		repoN = c.Repo.Repository.BaseRepo.FullName()
+		repoPath = c.Repo.Repository.BaseRepo.FullName()
 	}
 	}
-	uuid := libgin.RepoPathToUUID(repoN)
+	uuid := libgin.RepoPathToUUID(repoPath)
 	return doiBase + uuid[:6]
 	return doiBase + uuid[:6]
 }
 }
 
 

+ 1 - 1
templates/repo/header.tmpl

@@ -42,7 +42,7 @@
 									</a>
 									</a>
 								</div>
 								</div>
 							{{end}}
 							{{end}}
-							{{if not $.DOIReg}}
+							{{if not $.DOI}}
 								{{if and (and $.HasDatacite $.IsRepositoryAdmin) (not .IsPrivate)}}
 								{{if and (and $.HasDatacite $.IsRepositoryAdmin) (not .IsPrivate)}}
 								<div class="ui labeled button" tabindex="0">
 								<div class="ui labeled button" tabindex="0">
 									<a class="ui basic button"
 									<a class="ui basic button"