update code.gitea.io/git (#450)

tokarchuk/v1.17
Lunny Xiao 8 years ago committed by Thomas Boerger
parent 0c5c34d7dd
commit 47a7529d96
  1. 2
      cmd/serve.go
  2. 4
      models/action.go
  3. 2
      models/pull.go
  4. 8
      models/repo_editor.go
  5. 8
      models/update.go
  6. 479
      modules/bindata/bindata.go
  7. 2
      routers/repo/http.go
  8. 4
      routers/repo/webhook.go
  9. 4
      routers/repo/wiki.go
  10. 136
      vendor/code.gitea.io/git/CONTRIBUTING.md
  11. 9
      vendor/code.gitea.io/git/CONTRIBUTORS
  12. 6
      vendor/code.gitea.io/git/MAINTAINERS
  13. 9
      vendor/code.gitea.io/git/README.md
  14. 1
      vendor/code.gitea.io/git/blob.go
  15. 13
      vendor/code.gitea.io/git/command.go
  16. 25
      vendor/code.gitea.io/git/commit.go
  17. 4
      vendor/code.gitea.io/git/commit_archive.go
  18. 6
      vendor/code.gitea.io/git/error.go
  19. 10
      vendor/code.gitea.io/git/git.go
  20. 3
      vendor/code.gitea.io/git/hook.go
  21. 13
      vendor/code.gitea.io/git/repo.go
  22. 16
      vendor/code.gitea.io/git/repo_branch.go
  23. 39
      vendor/code.gitea.io/git/repo_commit.go
  24. 2
      vendor/code.gitea.io/git/repo_hook.go
  25. 13
      vendor/code.gitea.io/git/repo_object.go
  26. 2
      vendor/code.gitea.io/git/repo_pull.go
  27. 13
      vendor/code.gitea.io/git/repo_tag.go
  28. 4
      vendor/code.gitea.io/git/repo_tree.go
  29. 40
      vendor/code.gitea.io/git/sha1.go
  30. 5
      vendor/code.gitea.io/git/submodule.go
  31. 5
      vendor/code.gitea.io/git/tag.go
  32. 28
      vendor/code.gitea.io/git/tree.go
  33. 6
      vendor/code.gitea.io/git/tree_blob.go
  34. 37
      vendor/code.gitea.io/git/tree_entry.go
  35. 23
      vendor/code.gitea.io/git/utils.go
  36. 6
      vendor/vendor.json

@ -121,7 +121,7 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
// Ask for running deliver hook and test pull request tasks. // Ask for running deliver hook and test pull request tasks.
reqURL := setting.LocalURL + repoUser.Name + "/" + reponame + "/tasks/trigger?branch=" + reqURL := setting.LocalURL + repoUser.Name + "/" + reponame + "/tasks/trigger?branch=" +
strings.TrimPrefix(task.RefName, git.BRANCH_PREFIX) + "&secret=" + base.EncodeMD5(repoUser.Salt) + "&pusher=" + com.ToStr(user.ID) strings.TrimPrefix(task.RefName, git.BranchPrefix) + "&secret=" + base.EncodeMD5(repoUser.Salt) + "&pusher=" + com.ToStr(user.ID)
log.GitLogger.Trace("Trigger task: %s", reqURL) log.GitLogger.Trace("Trigger task: %s", reqURL)
resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{ resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{

@ -494,12 +494,12 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
isNewBranch := false isNewBranch := false
opType := ActionCommitRepo opType := ActionCommitRepo
// Check it's tag push or branch. // Check it's tag push or branch.
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) { if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
opType = ActionPushTag opType = ActionPushTag
opts.Commits = &PushCommits{} opts.Commits = &PushCommits{}
} else { } else {
// if not the first commit, set the compare URL. // if not the first commit, set the compare URL.
if opts.OldCommitID == git.EMPTY_SHA { if opts.OldCommitID == git.EmptySHA {
isNewBranch = true isNewBranch = true
} else { } else {
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID) opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)

@ -380,7 +380,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error
l.PushFront(mergeCommit) l.PushFront(mergeCommit)
p := &api.PushPayload{ p := &api.PushPayload{
Ref: git.BRANCH_PREFIX + pr.BaseBranch, Ref: git.BranchPrefix + pr.BaseBranch,
Before: pr.MergeBase, Before: pr.MergeBase,
After: pr.MergedCommitID, After: pr.MergedCommitID,
CompareURL: setting.AppURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID), CompareURL: setting.AppURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),

@ -158,13 +158,13 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
} }
oldCommitID := opts.LastCommitID oldCommitID := opts.LastCommitID
if opts.NewBranch != opts.OldBranch { if opts.NewBranch != opts.OldBranch {
oldCommitID = git.EMPTY_SHA oldCommitID = git.EmptySHA
} }
if err := CommitRepoAction(CommitRepoActionOptions{ if err := CommitRepoAction(CommitRepoActionOptions{
PusherName: doer.Name, PusherName: doer.Name,
RepoOwnerID: repo.MustOwner().ID, RepoOwnerID: repo.MustOwner().ID,
RepoName: repo.Name, RepoName: repo.Name,
RefFullName: git.BRANCH_PREFIX + opts.NewBranch, RefFullName: git.BranchPrefix + opts.NewBranch,
OldCommitID: oldCommitID, OldCommitID: oldCommitID,
NewCommitID: commit.ID.String(), NewCommitID: commit.ID.String(),
Commits: pushCommits, Commits: pushCommits,
@ -297,7 +297,7 @@ func (repo *Repository) DeleteRepoFile(doer *User, opts DeleteRepoFileOptions) (
PusherName: doer.Name, PusherName: doer.Name,
RepoOwnerID: repo.MustOwner().ID, RepoOwnerID: repo.MustOwner().ID,
RepoName: repo.Name, RepoName: repo.Name,
RefFullName: git.BRANCH_PREFIX + opts.NewBranch, RefFullName: git.BranchPrefix + opts.NewBranch,
OldCommitID: opts.LastCommitID, OldCommitID: opts.LastCommitID,
NewCommitID: commit.ID.String(), NewCommitID: commit.ID.String(),
Commits: pushCommits, Commits: pushCommits,
@ -533,7 +533,7 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
PusherName: doer.Name, PusherName: doer.Name,
RepoOwnerID: repo.MustOwner().ID, RepoOwnerID: repo.MustOwner().ID,
RepoName: repo.Name, RepoName: repo.Name,
RefFullName: git.BRANCH_PREFIX + opts.NewBranch, RefFullName: git.BranchPrefix + opts.NewBranch,
OldCommitID: opts.LastCommitID, OldCommitID: opts.LastCommitID,
NewCommitID: commit.ID.String(), NewCommitID: commit.ID.String(),
Commits: pushCommits, Commits: pushCommits,

@ -91,10 +91,10 @@ type PushUpdateOptions struct {
// PushUpdate must be called for any push actions in order to // PushUpdate must be called for any push actions in order to
// generates necessary push action history feeds. // generates necessary push action history feeds.
func PushUpdate(opts PushUpdateOptions) (err error) { func PushUpdate(opts PushUpdateOptions) (err error) {
isNewRef := opts.OldCommitID == git.EMPTY_SHA isNewRef := opts.OldCommitID == git.EmptySHA
isDelRef := opts.NewCommitID == git.EMPTY_SHA isDelRef := opts.NewCommitID == git.EmptySHA
if isNewRef && isDelRef { if isNewRef && isDelRef {
return fmt.Errorf("Old and new revisions are both %s", git.EMPTY_SHA) return fmt.Errorf("Old and new revisions are both %s", git.EmptySHA)
} }
repoPath := RepoPath(opts.RepoUserName, opts.RepoName) repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
@ -127,7 +127,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
} }
// Push tags. // Push tags.
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) { if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
if err := CommitRepoAction(CommitRepoActionOptions{ if err := CommitRepoAction(CommitRepoActionOptions{
PusherName: opts.PusherName, PusherName: opts.PusherName,
RepoOwnerID: owner.ID, RepoOwnerID: owner.ID,

File diff suppressed because one or more lines are too long

@ -208,7 +208,7 @@ func HTTP(ctx *context.Context) {
RepoUserName: username, RepoUserName: username,
RepoName: reponame, RepoName: reponame,
}); err == nil { }); err == nil {
go models.AddTestPullRequestTask(authUser, repo.ID, strings.TrimPrefix(refFullName, git.BRANCH_PREFIX), true) go models.AddTestPullRequestTask(authUser, repo.ID, strings.TrimPrefix(refFullName, git.BranchPrefix), true)
} }
} }

@ -361,7 +361,7 @@ func TestWebhook(ctx *context.Context) {
if commit == nil { if commit == nil {
ghost := models.NewGhostUser() ghost := models.NewGhostUser()
commit = &git.Commit{ commit = &git.Commit{
ID: git.MustIDFromString(git.EMPTY_SHA), ID: git.MustIDFromString(git.EmptySHA),
Author: ghost.NewGitSig(), Author: ghost.NewGitSig(),
Committer: ghost.NewGitSig(), Committer: ghost.NewGitSig(),
CommitMessage: "This is a fake commit", CommitMessage: "This is a fake commit",
@ -370,7 +370,7 @@ func TestWebhook(ctx *context.Context) {
apiUser := ctx.User.APIFormat() apiUser := ctx.User.APIFormat()
p := &api.PushPayload{ p := &api.PushPayload{
Ref: git.BRANCH_PREFIX + ctx.Repo.Repository.DefaultBranch, Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch,
Before: commit.ID.String(), Before: commit.ID.String(),
After: commit.ID.String(), After: commit.ID.String(),
Commits: []*api.PayloadCommit{ Commits: []*api.PayloadCommit{

@ -66,7 +66,7 @@ func renderWikiPage(ctx *context.Context, isViewPage bool) (*git.Repository, str
} }
pages := make([]PageMeta, 0, len(entries)) pages := make([]PageMeta, 0, len(entries))
for i := range entries { for i := range entries {
if entries[i].Type == git.OBJECT_BLOB && strings.HasSuffix(entries[i].Name(), ".md") { if entries[i].Type == git.ObjectBlob && strings.HasSuffix(entries[i].Name(), ".md") {
name := strings.TrimSuffix(entries[i].Name(), ".md") name := strings.TrimSuffix(entries[i].Name(), ".md")
pages = append(pages, PageMeta{ pages = append(pages, PageMeta{
Name: name, Name: name,
@ -171,7 +171,7 @@ func WikiPages(ctx *context.Context) {
} }
pages := make([]PageMeta, 0, len(entries)) pages := make([]PageMeta, 0, len(entries))
for i := range entries { for i := range entries {
if entries[i].Type == git.OBJECT_BLOB && strings.HasSuffix(entries[i].Name(), ".md") { if entries[i].Type == git.ObjectBlob && strings.HasSuffix(entries[i].Name(), ".md") {
c, err := wikiRepo.GetCommitByPath(entries[i].Name()) c, err := wikiRepo.GetCommitByPath(entries[i].Name())
if err != nil { if err != nil {
ctx.Handle(500, "GetCommit", err) ctx.Handle(500, "GetCommit", err)

@ -2,161 +2,85 @@
## Introduction ## Introduction
This document explains how to contribute changes to the Gitea This document explains how to contribute changes to the Gitea project. It assumes you have followed the [installation instructions](https://github.com/go-gitea/docs/tree/master/en-US/installation). Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io).
project. It assumes you have followed the [installation
instructions](https://github.com/go-gitea/docs/tree/master/en-US/installation)
Sensitive security-related issues should be reported to
[security@gitea.io](mailto:security@gitea.io).
## Bug reports ## Bug reports
Please search the issues on the issue tracker with a variety of keywords Please search the issues on the issue tracker with a variety of keywords to ensure your bug is not already reported.
to ensure your bug is not already reported.
If unique, [open an issue](https://github.com/go-gitea/gitea/issues/new) If unique, [open an issue](https://github.com/go-gitea/gitea/issues/new) and answer the questions so we can understand and reproduce the problematic behavior.
and answer the questions so we can understand and reproduce the
problematic behavior.
The burden is on you to convince us that it is actually a bug The burden is on you to convince us that it is actually a bug in Gitea. This is easiest to do when you write clear, concise instructions so we can reproduce the behavior (even if it seems obvious). The more detailed and specific you are, the faster we will be able to help you. Check out [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html).
in Gitea. This is easiest to do when you write clear, concise
instructions so we can reproduce the behavior (even if it seems
obvious). The more detailed and specific you are, the faster
we will be able to help you. Check out [How to Report Bugs
Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html).
Please be kind, remember that Gitea comes at no cost to you, and you're Please be kind, remember that Gitea comes at no cost to you, and you're getting free help.
getting free help.
## Discuss your design ## Discuss your design
The project welcomes submissions but please let everyone know what The project welcomes submissions but please let everyone know what you're working on if you want to change or add something to the Gitea repositories.
you're working on if you want to change or add something to the Gitea
repositories.
Before starting to write something new for the Gitea project, please Before starting to write something new for the Gitea project, please [file an issue](https://github.com/go-gitea/gitea/issues/new). Significant changes must go through the [change proposal process](https://github.com/go-gitea/proposals) before they can be accepted.
[file an issue](https://github.com/go-gitea/gitea/issues/new).
Significant changes must go through the [change proposal
process](https://github.com/go-gitea/proposals) before they can be
accepted.
This process gives everyone a chance to validate the design, helps This process gives everyone a chance to validate the design, helps prevent duplication of effort, and ensures that the idea fits inside the goals for the project and tools. It also checks that the design is sound before code is written; the code review tool is not the place for high-level discussions.
prevent duplication of effort, and ensures that the idea fits inside
the goals for the project and tools. It also checks that the design is
sound before code is written; the code review tool is not the place for
high-level discussions.
## Testing redux ## Testing redux
Before sending code out for review, run all the tests for the whole Before sending code out for review, run all the tests for the whole tree to make sure the changes don't break other usage and keep the compatibility on upgrade. To make sure you are running the test suite exactly like we do you should install the CLI for [Drone CI](https://github.com/drone/drone), as we are using the server for continous testing, following [these instructions](http://readme.drone.io/0.5/install/cli/). After that you can simply call `drone exec` within your working directory and it will try to run the test suite locally.
tree to make sure the changes don't break other usage and keep the
compatibility on upgrade:
After running for a while, the command should print ## Code review
``` Changes to Gitea must be reviewed before they are accepted, no matter who makes the change even if it is an owner or a maintainer. We use GitHub's pull request workflow to do that and we also use [LGTM](http://lgtm.co) to ensure every PR is reviewed by at least 2 maintainers.
ALL TESTS PASSED
```
## Code review Please try to make your pull request easy to review for us. Please read the "[How to get faster PR reviews](https://github.com/kubernetes/kubernetes/blob/master/docs/devel/faster_reviews.md)" guide, it has lots of useful tips for any project you may want to contribute. Some of the key points:
Changes to Gitea must be reviewed before they are accepted, no matter * Make small pull requests. The smaller, the faster to review and the more likely it will be merged soon.
who makes the change even if an owners or a maintainer. We use github's * Don't make changes unrelated to your PR. Maybe there are typos on some comments, maybe refactoring would be welcome on a function... but if that is not related to your PR, please make *another* PR for that.
pull request workflow to do that and use [lgtm](http://lgtm.co) to ensure * Split big pull requests in multiple small ones. An incremental change will be faster to review than a huge PR.
every PR is reviewed by at least 2 maintainers.
## Sign your work ## Sign your work
The sign-off is a simple line at the end of the explanation for the The sign-off is a simple line at the end of the explanation for the patch. Your signature certifies that you wrote the patch or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: If you can certify [DCO](DCO), then you just add a line to every git commit message:
patch. Your signature certifies that you wrote the patch or otherwise
have the right to pass it on as an open-source patch. The rules are
pretty simple: If you can certify [DCO](DCO), then you just add a line
to every git commit message:
``` ```
Signed-off-by: Joe Smith <joe.smith@email.com> Signed-off-by: Joe Smith <joe.smith@email.com>
``` ```
Please use your real name, we really dislike pseudonyms or anonymous Please use your real name, we really dislike pseudonyms or anonymous contributions. We are in the opensource world without secrets. If you set your `user.name` and `user.email` git configs, you can sign your commit automatically with `git commit -s`.
contributions. We are in the opensource world without secrets. If you
set your `user.name` and `user.email` git configs, you can sign your
commit automatically with `git commit -s`.
## Contributors
Everyone who sent a PR to Gitea that gets accepted will
be as a contributor. Please send a PR to add your name to
[CONTRIBUTORS](CONTRIBUTORS). For the format, see the
[CONTRIBUTORS](CONTRIBUTORS).
## Maintainers ## Maintainers
To make sure every PR have been checked, we make a team maintainers. Any To make sure every PR is checked, we got team maintainers. Every PR **MUST** be reviewed by at least two maintainers (or owners) before it can get merged. A maintainer should be a contributor of Gitea (or Gogs) and contributed at least 4 accepted PRs. A contributor should apply as a maintainer in the [Gitter develop channel](https://gitter.im/go-gitea/develop). The owners or the team maintainers may invite the contributor. A maintainer should spend some time on code reviews. If a maintainer has no time to do that, they should apply to leave the maintainers team and we will give them the honor of being a member of the advisors team. Of course, if an advisor has time to code review, we will gladly welcome them back to maintainers team. If someone has no time to code review and forgets to leave the maintainers team, the owners have the power to move him from maintainers team to advisors team.
PR MUST be reviewed and by at least two maintainers before it can
get merged. Maintainers should be a contributor of gitea(or gogs) and
contributed at least 4 accepted PRs. And a contributor should apply as a
maintainer in [gitter Gitea develop](https://gitter.im/go-gitea/develop).
And the owners or the team maintainer could invite the contributor. A
maintainer should spend some time on code reviews. If some maintainer
have no time to do that, he should apply to leave maintainers team and
we will give him an honor to be as a member of advisor team. Of course,
if an advisor have time to code view, welcome it back to maintainers team.
If some one have no time to code view and forget to leave the maintainers,
the owners have the power to move him from maintainers team to advisors
team.
## Owners ## Owners
Since Gitea is a pure community organization without any company Since Gitea is a pure community organization without any company support, to keep the development healthy we will elect the owners every year. Every time we will elect three owners. All the contributors may vote up to three people, one of which is the main owner, and the others are assistant owners. When the new owners have been elected, the old owners MUST move the power to the new ones. If an owner don't obey these rules, the others are allowed to revoke his owner status.
support, to keep the development healthly We will elect the owners every
year. Every time we will elect three owners. All the contributers could
vote for three owners, one is the main owner, the other two are assistant
owners. When the new owners have been elected, the old owners MUST move
the power to the new owners. If some owner don't obey these rules,
the other owners are allowed to revoke his owner status.
After the election, the new owners should say he agrees with these After the election, the new owners should say they agree with these rules on the [CONTRIBUTING](CONTRIBUTING.md) on the [Gitter main channel](https://gitter.im/go-gitea/gitea). Below are the words to speak:
rules on the [CONTRIBUTING](CONTRIBUTING.md) on the [Gitter Gitea
Channel](https://gitter.im/go-gitea/gitea). Below is the word to speak
``` ```
I'm glad to be an owner of Gitea, I'm glad to be an owner of Gitea, I agree with [CONTRIBUTING](CONTRIBUTING.md). I will spend part of my time on Gitea and lead the development of Gitea.
I agree with [CONTRIBUTING](CONTRIBUTING.md).
I will spend part of my time on gitea
and lead the development of gitea.
``` ```
For a honor to the owners, this document will add the history owners To honor the past owners, here's the history of the owners and the time they served:
below:
2016-11-04 ~ 2017-12-31
- lunny <xiaolunwen@gmail.com> * 2016-11-04 ~ 2017-12-31
- tboerger <thomas@webhippie.de> * [Lunny Xiao](https://github.com/lunny) <xiaolunwen@gmail.com>
- bkcsoft <kim.carlbacker@gmail.com> * [Thomas Boerger](https://github.com/tboerger) <thomas@webhippie.de>
* [Kim Carlbäcker](https://github.com/bkcsoft) <kim.carlbacker@gmail.com>
## Versions ## Versions
Gitea has one master as a tip branch and have many version branch Gitea has the `master` branch as a tip branch and has version branches such as `v0.9`. `v0.9` is a release branch and we will tag `v0.9.0` for binary download. If `v0.9.0` has bugs, we will accept pull requests on the `v0.9` branch and publish a `v0.9.1` tag, after bringing the bug fix also to the master branch.
such as v0.9. v0.9 is a release branch and we will tag v0.9.0 both for
binary download. If v0.9.0 have some bugs, we will accept PR on v0.9
and publish v0.9.1 and merge bug PR to master.
Branch master is a tip version, so if you wish a production usage, Since the `master` branch is a tip version, if you wish to use Gitea in production, please download the latest release tag version. All the branches will be protected via GitHub, all the PRs to every branch must be reviewed by two maintainers and must pass the automatic tests.
please download the latest release tag version. All the branch will be
protected via github, All the PRs to all the branches should be review
by two maintainers and pass the automatic tests.
## Copyright ## Copyright
Code that you contribute should use the standard copyright header: Code that you contribute should use the standard copyright header:
``` ```
// Copyright 2016 - 2017 The Gitea Authors. All rights reserved. // Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
``` ```
Files in the repository are copyright the year they are added and the Files in the repository contain copyright from the year they are added to the year they are last changed. If the copyright author is changed, just paste the header below the old one.
year they are last changed. If the copyright author is changed, just
copy the head below the old one.

@ -1,9 +0,0 @@
Andrey Nering <nobody@nobody.tld> (@andreynering)
Kim Carlbäcker <kim.carlbacker@gmail.com> (@bkcsoft)
LefsFlare <nobody@nobody.tld> (@LefsFlarey)
Lunny Xiao <xiaolunwen@gmail.com> (@lunny)
Rachid Zarouali <nobody@nobody.tld> (@xinity)
Rémy Boulanouar <admin@dblk.org> (@DblK)
Sandro Santilli <strk@kbt.io> (@strk)
Thibault Meyer <nobody@nobody.tld> (@0xbaadf00d)
Thomas Boerger <thomas@webhippie.de> (@tboerger)

@ -1,4 +1,6 @@
Andrey Nering <nobody@nobody.tld> (@andreynering) Alexey Makhov <amakhov@avito.ru> (@makhov)
Andrey Nering <andrey.nering@gmail.com> (@andreynering)
Kees de Vries <bouwko@gmail.com> (@Bwko)
Kim Carlbäcker <kim.carlbacker@gmail.com> (@bkcsoft) Kim Carlbäcker <kim.carlbacker@gmail.com> (@bkcsoft)
LefsFlare <nobody@nobody.tld> (@LefsFlarey) LefsFlare <nobody@nobody.tld> (@LefsFlarey)
Lunny Xiao <xiaolunwen@gmail.com> (@lunny) Lunny Xiao <xiaolunwen@gmail.com> (@lunny)
@ -6,5 +8,5 @@ Matthias Loibl <mail@matthiasloibl.com> (@metalmatze)
Rachid Zarouali <nobody@nobody.tld> (@xinity) Rachid Zarouali <nobody@nobody.tld> (@xinity)
Rémy Boulanouar <admin@dblk.org> (@DblK) Rémy Boulanouar <admin@dblk.org> (@DblK)
Sandro Santilli <strk@kbt.io> (@strk) Sandro Santilli <strk@kbt.io> (@strk)
Thibault Meyer <nobody@nobody.tld> (@0xbaadf00d) Thibault Meyer <meyer.thibault@gmail.com> (@0xbaadf00d)
Thomas Boerger <thomas@webhippie.de> (@tboerger) Thomas Boerger <thomas@webhippie.de> (@tboerger)

@ -10,6 +10,15 @@
This project is a Go module to access Git through shell commands. For further This project is a Go module to access Git through shell commands. For further
informations take a look at the current [documentation](https://godoc.org/code.gitea.io/git). informations take a look at the current [documentation](https://godoc.org/code.gitea.io/git).
## Contributing
Fork -> Patch -> Push -> Pull Request
## Authors
* [Maintainers](https://github.com/orgs/go-gitea/people)
* [Contributors](https://github.com/go-gitea/git/graphs/contributors)
## License ## License
This project is under the MIT License. See the [LICENSE](LICENSE) file for the This project is under the MIT License. See the [LICENSE](LICENSE) file for the

1
vendor/code.gitea.io/git/blob.go generated vendored

@ -25,6 +25,7 @@ func (b *Blob) Data() (io.Reader, error) {
return bytes.NewBuffer(stdout), nil return bytes.NewBuffer(stdout), nil
} }
// DataPipeline gets content of blob and write the result or error to stdout or stderr
func (b *Blob) DataPipeline(stdout, stderr io.Writer) error { func (b *Blob) DataPipeline(stdout, stderr io.Writer) error {
return NewCommand("show", b.ID.String()).RunInDirPipeline(b.repo.Path, stdout, stderr) return NewCommand("show", b.ID.String()).RunInDirPipeline(b.repo.Path, stdout, stderr)
} }

@ -13,6 +13,11 @@ import (
"time" "time"
) )
var (
// GlobalCommandArgs global command args for external package setting
GlobalCommandArgs []string
)
// Command represents a command with its subcommands or arguments. // Command represents a command with its subcommands or arguments.
type Command struct { type Command struct {
name string name string
@ -30,7 +35,7 @@ func (c *Command) String() string {
func NewCommand(args ...string) *Command { func NewCommand(args ...string) *Command {
return &Command{ return &Command{
name: "git", name: "git",
args: args, args: append(GlobalCommandArgs, args...),
} }
} }
@ -40,13 +45,11 @@ func (c *Command) AddArguments(args ...string) *Command {
return c return c
} }
const DEFAULT_TIMEOUT = 60 * time.Second
// RunInDirTimeoutPipeline executes the command in given directory with given timeout, // RunInDirTimeoutPipeline executes the command in given directory with given timeout,
// it pipes stdout and stderr to given io.Writer. // it pipes stdout and stderr to given io.Writer.
func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, stdout, stderr io.Writer) error { func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, stdout, stderr io.Writer) error {
if timeout == -1 { if timeout == -1 {
timeout = DEFAULT_TIMEOUT timeout = 60 * time.Second
} }
if len(dir) == 0 { if len(dir) == 0 {
@ -106,7 +109,7 @@ func (c *Command) RunInDirPipeline(dir string, stdout, stderr io.Writer) error {
return c.RunInDirTimeoutPipeline(-1, dir, stdout, stderr) return c.RunInDirTimeoutPipeline(-1, dir, stdout, stderr)
} }
// RunInDir executes the command in given directory // RunInDirBytes executes the command in given directory
// and returns stdout in []byte and error (combined with stderr). // and returns stdout in []byte and error (combined with stderr).
func (c *Command) RunInDirBytes(dir string) ([]byte, error) { func (c *Command) RunInDirBytes(dir string) ([]byte, error) {
return c.RunInDirTimeout(-1, dir) return c.RunInDirTimeout(-1, dir)

@ -18,13 +18,13 @@ import (
// Commit represents a git commit. // Commit represents a git commit.
type Commit struct { type Commit struct {
Tree Tree
ID sha1 // The ID of this commit object ID SHA1 // The ID of this commit object
Author *Signature Author *Signature
Committer *Signature Committer *Signature
CommitMessage string CommitMessage string
parents []sha1 // SHA1 strings parents []SHA1 // SHA1 strings
submoduleCache *objectCache submoduleCache *ObjectCache
} }
// Message returns the commit message. Same as retrieving CommitMessage directly. // Message returns the commit message. Same as retrieving CommitMessage directly.
@ -39,9 +39,9 @@ func (c *Commit) Summary() string {
// ParentID returns oid of n-th parent (0-based index). // ParentID returns oid of n-th parent (0-based index).
// It returns nil if no such parent exists. // It returns nil if no such parent exists.
func (c *Commit) ParentID(n int) (sha1, error) { func (c *Commit) ParentID(n int) (SHA1, error) {
if n >= len(c.parents) { if n >= len(c.parents) {
return sha1{}, ErrNotExist{"", ""} return SHA1{}, ErrNotExist{"", ""}
} }
return c.parents[n], nil return c.parents[n], nil
} }
@ -73,6 +73,7 @@ func isImageFile(data []byte) (string, bool) {
return contentType, false return contentType, false
} }
// IsImageFile is a file image type
func (c *Commit) IsImageFile(name string) bool { func (c *Commit) IsImageFile(name string) bool {
blob, err := c.GetBlobByPath(name) blob, err := c.GetBlobByPath(name)
if err != nil { if err != nil {
@ -95,7 +96,7 @@ func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) {
return c.repo.getCommitByPathWithID(c.ID, relpath) return c.repo.getCommitByPathWithID(c.ID, relpath)
} }
// AddAllChanges marks local changes to be ready for commit. // AddChanges marks local changes to be ready for commit.
func AddChanges(repoPath string, all bool, files ...string) error { func AddChanges(repoPath string, all bool, files ...string) error {
cmd := NewCommand("add") cmd := NewCommand("add")
if all { if all {
@ -105,6 +106,7 @@ func AddChanges(repoPath string, all bool, files ...string) error {
return err return err
} }
// CommitChangesOptions the options when a commit created
type CommitChangesOptions struct { type CommitChangesOptions struct {
Committer *Signature Committer *Signature
Author *Signature Author *Signature
@ -166,22 +168,27 @@ func CommitsCount(repoPath, revision string) (int64, error) {
return commitsCount(repoPath, revision, "") return commitsCount(repoPath, revision, "")
} }
// CommitsCount returns number of total commits of until current revision.
func (c *Commit) CommitsCount() (int64, error) { func (c *Commit) CommitsCount() (int64, error) {
return CommitsCount(c.repo.Path, c.ID.String()) return CommitsCount(c.repo.Path, c.ID.String())
} }
// CommitsByRange returns the specific page commits before current revision, every page's number default by CommitsRangeSize
func (c *Commit) CommitsByRange(page int) (*list.List, error) { func (c *Commit) CommitsByRange(page int) (*list.List, error) {
return c.repo.commitsByRange(c.ID, page) return c.repo.commitsByRange(c.ID, page)
} }
// CommitsBefore returns all the commits before current revision
func (c *Commit) CommitsBefore() (*list.List, error) { func (c *Commit) CommitsBefore() (*list.List, error) {
return c.repo.getCommitsBefore(c.ID) return c.repo.getCommitsBefore(c.ID)
} }
// CommitsBeforeLimit returns num commits before current revision
func (c *Commit) CommitsBeforeLimit(num int) (*list.List, error) { func (c *Commit) CommitsBeforeLimit(num int) (*list.List, error) {
return c.repo.getCommitsBeforeLimit(c.ID, num) return c.repo.getCommitsBeforeLimit(c.ID, num)
} }
// CommitsBeforeUntil returns the commits between commitID to current revision
func (c *Commit) CommitsBeforeUntil(commitID string) (*list.List, error) { func (c *Commit) CommitsBeforeUntil(commitID string) (*list.List, error) {
endCommit, err := c.repo.GetCommit(commitID) endCommit, err := c.repo.GetCommit(commitID)
if err != nil { if err != nil {
@ -190,15 +197,18 @@ func (c *Commit) CommitsBeforeUntil(commitID string) (*list.List, error) {
return c.repo.CommitsBetween(c, endCommit) return c.repo.CommitsBetween(c, endCommit)
} }
// SearchCommits returns the commits match the keyword before current revision
func (c *Commit) SearchCommits(keyword string) (*list.List, error) { func (c *Commit) SearchCommits(keyword string) (*list.List, error) {
return c.repo.searchCommits(c.ID, keyword) return c.repo.searchCommits(c.ID, keyword)
} }
// GetFilesChangedSinceCommit get all changed file names between pastCommit to current revision
func (c *Commit) GetFilesChangedSinceCommit(pastCommit string) ([]string, error) { func (c *Commit) GetFilesChangedSinceCommit(pastCommit string) ([]string, error) {
return c.repo.getFilesChanged(pastCommit, c.ID.String()) return c.repo.getFilesChanged(pastCommit, c.ID.String())
} }
func (c *Commit) GetSubModules() (*objectCache, error) { // GetSubModules get all the sub modules of current revision git tree
func (c *Commit) GetSubModules() (*ObjectCache, error) {
if c.submoduleCache != nil { if c.submoduleCache != nil {
return c.submoduleCache, nil return c.submoduleCache, nil
} }
@ -236,6 +246,7 @@ func (c *Commit) GetSubModules() (*objectCache, error) {
return c.submoduleCache, nil return c.submoduleCache, nil
} }
// GetSubModule get the sub module according entryname
func (c *Commit) GetSubModule(entryname string) (*SubModule, error) { func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
modules, err := c.GetSubModules() modules, err := c.GetSubModules()
if err != nil { if err != nil {

@ -10,13 +10,17 @@ import (
"strings" "strings"
) )
// ArchiveType archive types
type ArchiveType int type ArchiveType int
const ( const (
// ZIP zip archive type
ZIP ArchiveType = iota + 1 ZIP ArchiveType = iota + 1
// TARGZ tar gz archive type
TARGZ TARGZ
) )
// CreateArchive create archive content to the target path
func (c *Commit) CreateArchive(target string, archiveType ArchiveType) error { func (c *Commit) CreateArchive(target string, archiveType ArchiveType) error {
var format string var format string
switch archiveType { switch archiveType {

@ -9,10 +9,12 @@ import (
"time" "time"
) )
// ErrExecTimeout error when exec timed out
type ErrExecTimeout struct { type ErrExecTimeout struct {
Duration time.Duration Duration time.Duration
} }
// IsErrExecTimeout if some error is ErrExecTimeout
func IsErrExecTimeout(err error) bool { func IsErrExecTimeout(err error) bool {
_, ok := err.(ErrExecTimeout) _, ok := err.(ErrExecTimeout)
return ok return ok
@ -22,11 +24,13 @@ func (err ErrExecTimeout) Error() string {
return fmt.Sprintf("execution is timeout [duration: %v]", err.Duration) return fmt.Sprintf("execution is timeout [duration: %v]", err.Duration)
} }
// ErrNotExist commit not exist error
type ErrNotExist struct { type ErrNotExist struct {
ID string ID string
RelPath string RelPath string
} }
// IsErrNotExist if some error is ErrNotExist
func IsErrNotExist(err error) bool { func IsErrNotExist(err error) bool {
_, ok := err.(ErrNotExist) _, ok := err.(ErrNotExist)
return ok return ok
@ -36,10 +40,12 @@ func (err ErrNotExist) Error() string {
return fmt.Sprintf("object does not exist [id: %s, rel_path: %s]", err.ID, err.RelPath) return fmt.Sprintf("object does not exist [id: %s, rel_path: %s]", err.ID, err.RelPath)
} }
// ErrUnsupportedVersion error when required git version not matched
type ErrUnsupportedVersion struct { type ErrUnsupportedVersion struct {
Required string Required string
} }
// IsErrUnsupportedVersion if some error is ErrUnsupportedVersion
func IsErrUnsupportedVersion(err error) bool { func IsErrUnsupportedVersion(err error) bool {
_, ok := err.(ErrUnsupportedVersion) _, ok := err.(ErrUnsupportedVersion)
return ok return ok

10
vendor/code.gitea.io/git/git.go generated vendored

@ -10,16 +10,16 @@ import (
"time" "time"
) )
const _VERSION = "0.4.2" // Version return this package's current version
func Version() string { func Version() string {
return _VERSION return "0.4.2"
} }
var ( var (
// Debug enables verbose logging on everything. // Debug enables verbose logging on everything.
// This should be false in case Gogs starts in SSH mode. // This should be false in case Gogs starts in SSH mode.
Debug = false Debug = false
// Prefix the log prefix
Prefix = "[git-module] " Prefix = "[git-module] "
) )
@ -38,7 +38,7 @@ func log(format string, args ...interface{}) {
var gitVersion string var gitVersion string
// Version returns current Git version from shell. // BinVersion returns current Git version from shell.
func BinVersion() (string, error) { func BinVersion() (string, error) {
if len(gitVersion) > 0 { if len(gitVersion) > 0 {
return gitVersion, nil return gitVersion, nil

3
vendor/code.gitea.io/git/hook.go generated vendored

@ -22,6 +22,7 @@ var hookNames = []string{
} }
var ( var (
// ErrNotValidHook error when a git hook is not valid
ErrNotValidHook = errors.New("not a valid Git hook") ErrNotValidHook = errors.New("not a valid Git hook")
) )
@ -70,6 +71,7 @@ func GetHook(repoPath, name string) (*Hook, error) {
return h, nil return h, nil
} }
// Name return the name of the hook
func (h *Hook) Name() string { func (h *Hook) Name() string {
return h.name return h.name
} }
@ -102,6 +104,7 @@ func ListHooks(repoPath string) (_ []*Hook, err error) {
} }
const ( const (
// HookPathUpdate hook update path
HookPathUpdate = "hooks/update" HookPathUpdate = "hooks/update"
) )

13
vendor/code.gitea.io/git/repo.go generated vendored

@ -18,11 +18,11 @@ import (
type Repository struct { type Repository struct {
Path string Path string
commitCache *objectCache commitCache *ObjectCache
tagCache *objectCache tagCache *ObjectCache
} }
const _PRETTY_LOG_FORMAT = `--pretty=format:%H` const prettyLogFormat = `--pretty=format:%H`
func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, error) { func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, error) {
l := list.New() l := list.New()
@ -32,8 +32,8 @@ func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, err
parts := bytes.Split(logs, []byte{'\n'}) parts := bytes.Split(logs, []byte{'\n'})
for _, commitId := range parts { for _, commitID := range parts {
commit, err := repo.GetCommit(string(commitId)) commit, err := repo.GetCommit(string(commitID))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -80,6 +80,7 @@ func OpenRepository(repoPath string) (*Repository, error) {
}, nil }, nil
} }
// CloneRepoOptions options when clone a repository
type CloneRepoOptions struct { type CloneRepoOptions struct {
Timeout time.Duration Timeout time.Duration
Mirror bool Mirror bool
@ -118,6 +119,7 @@ func Clone(from, to string, opts CloneRepoOptions) (err error) {
return err return err
} }
// PullRemoteOptions options when pull from remote
type PullRemoteOptions struct { type PullRemoteOptions struct {
Timeout time.Duration Timeout time.Duration
All bool All bool
@ -153,6 +155,7 @@ func Push(repoPath, remote, branch string) error {
return err return err
} }
// CheckoutOptions options when heck out some branch
type CheckoutOptions struct { type CheckoutOptions struct {
Timeout time.Duration Timeout time.Duration
Branch string Branch string

@ -11,7 +11,8 @@ import (
"github.com/mcuadros/go-version" "github.com/mcuadros/go-version"
) )
const BRANCH_PREFIX = "refs/heads/" // BranchPrefix base dir of the branch information file store on git
const BranchPrefix = "refs/heads/"
// IsReferenceExist returns true if given reference exists in the repository. // IsReferenceExist returns true if given reference exists in the repository.
func IsReferenceExist(repoPath, name string) bool { func IsReferenceExist(repoPath, name string) bool {
@ -21,9 +22,10 @@ func IsReferenceExist(repoPath, name string) bool {
// IsBranchExist returns true if given branch exists in the repository. // IsBranchExist returns true if given branch exists in the repository.
func IsBranchExist(repoPath, name string) bool { func IsBranchExist(repoPath, name string) bool {
return IsReferenceExist(repoPath, BRANCH_PREFIX+name) return IsReferenceExist(repoPath, BranchPrefix+name)
} }
// IsBranchExist returns true if given branch exists in current repository.
func (repo *Repository) IsBranchExist(name string) bool { func (repo *Repository) IsBranchExist(name string) bool {
return IsBranchExist(repo.Path, name) return IsBranchExist(repo.Path, name)
} }
@ -42,12 +44,12 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) {
} }
stdout = strings.TrimSpace(stdout) stdout = strings.TrimSpace(stdout)
if !strings.HasPrefix(stdout, BRANCH_PREFIX) { if !strings.HasPrefix(stdout, BranchPrefix) {
return nil, fmt.Errorf("invalid HEAD branch: %v", stdout) return nil, fmt.Errorf("invalid HEAD branch: %v", stdout)
} }
return &Branch{ return &Branch{
Name: stdout[len(BRANCH_PREFIX):], Name: stdout[len(BranchPrefix):],
Path: stdout, Path: stdout,
}, nil }, nil
} }
@ -58,7 +60,7 @@ func (repo *Repository) SetDefaultBranch(name string) error {
return ErrUnsupportedVersion{"1.7.10"} return ErrUnsupportedVersion{"1.7.10"}
} }
_, err := NewCommand("symbolic-ref", "HEAD", BRANCH_PREFIX+name).RunInDir(repo.Path) _, err := NewCommand("symbolic-ref", "HEAD", BranchPrefix+name).RunInDir(repo.Path)
return err return err
} }
@ -76,12 +78,12 @@ func (repo *Repository) GetBranches() ([]string, error) {
if len(fields) != 2 { if len(fields) != 2 {
continue // NOTE: I should believe git will not give me wrong string. continue // NOTE: I should believe git will not give me wrong string.
} }
branches[i] = strings.TrimPrefix(fields[1], BRANCH_PREFIX) branches[i] = strings.TrimPrefix(fields[1], BranchPrefix)
} }
return branches, nil return branches, nil
} }
// Option(s) for delete branch // DeleteBranchOptions Option(s) for delete branch
type DeleteBranchOptions struct { type DeleteBranchOptions struct {
Force bool Force bool
} }

@ -28,12 +28,12 @@ func (repo *Repository) getRefCommitID(name string) (string, error) {
// GetBranchCommitID returns last commit ID string of given branch. // GetBranchCommitID returns last commit ID string of given branch.
func (repo *Repository) GetBranchCommitID(name string) (string, error) { func (repo *Repository) GetBranchCommitID(name string) (string, error) {
return repo.getRefCommitID(BRANCH_PREFIX + name) return repo.getRefCommitID(BranchPrefix + name)
} }
// GetTagCommitID returns last commit ID string of given tag. // GetTagCommitID returns last commit ID string of given tag.
func (repo *Repository) GetTagCommitID(name string) (string, error) { func (repo *Repository) GetTagCommitID(name string) (string, error) {
return repo.getRefCommitID(TAG_PREFIX + name) return repo.getRefCommitID(TagPrefix + name)
} }
// parseCommitData parses commit information from the (uncompressed) raw // parseCommitData parses commit information from the (uncompressed) raw
@ -41,7 +41,7 @@ func (repo *Repository) GetTagCommitID(name string) (string, error) {
// \n\n separate headers from message // \n\n separate headers from message
func parseCommitData(data []byte) (*Commit, error) { func parseCommitData(data []byte) (*Commit, error) {
commit := new(Commit) commit := new(Commit)
commit.parents = make([]sha1, 0, 1) commit.parents = make([]SHA1, 0, 1)
// we now have the contents of the commit object. Let's investigate... // we now have the contents of the commit object. Let's investigate...
nextline := 0 nextline := 0
l: l:
@ -90,7 +90,7 @@ l:
return commit, nil return commit, nil
} }
func (repo *Repository) getCommit(id sha1) (*Commit, error) { func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
c, ok := repo.commitCache.Get(id.String()) c, ok := repo.commitCache.Get(id.String())
if ok { if ok {
log("Hit cache: %s", id) log("Hit cache: %s", id)
@ -142,6 +142,7 @@ func (repo *Repository) GetBranchCommit(name string) (*Commit, error) {
return repo.GetCommit(commitID) return repo.GetCommit(commitID)
} }
// GetTagCommit get the commit of the specific tag via name
func (repo *Repository) GetTagCommit(name string) (*Commit, error) { func (repo *Repository) GetTagCommit(name string) (*Commit, error) {
commitID, err := repo.GetTagCommitID(name) commitID, err := repo.GetTagCommitID(name)
if err != nil { if err != nil {
@ -150,13 +151,13 @@ func (repo *Repository) GetTagCommit(name string) (*Commit, error) {
return repo.GetCommit(commitID) return repo.GetCommit(commitID)
} }
func (repo *Repository) getCommitByPathWithID(id sha1, relpath string) (*Commit, error) { func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit, error) {
// File name starts with ':' must be escaped. // File name starts with ':' must be escaped.
if relpath[0] == ':' { if relpath[0] == ':' {
relpath = `\` + relpath relpath = `\` + relpath
} }
stdout, err := NewCommand("log", "-1", _PRETTY_LOG_FORMAT, id.String(), "--", relpath).RunInDir(repo.Path) stdout, err := NewCommand("log", "-1", prettyLogFormat, id.String(), "--", relpath).RunInDir(repo.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -171,7 +172,7 @@ func (repo *Repository) getCommitByPathWithID(id sha1, relpath string) (*Commit,
// GetCommitByPath returns the last commit of relative path. // GetCommitByPath returns the last commit of relative path.
func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) { func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
stdout, err := NewCommand("log", "-1", _PRETTY_LOG_FORMAT, "--", relpath).RunInDirBytes(repo.Path) stdout, err := NewCommand("log", "-1", prettyLogFormat, "--", relpath).RunInDirBytes(repo.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -183,19 +184,20 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
return commits.Front().Value.(*Commit), nil return commits.Front().Value.(*Commit), nil
} }
// CommitsRangeSize the default commits range size
var CommitsRangeSize = 50 var CommitsRangeSize = 50
func (repo *Repository) commitsByRange(id sha1, page int) (*list.List, error) { func (repo *Repository) commitsByRange(id SHA1, page int) (*list.List, error) {
stdout, err := NewCommand("log", id.String(), "--skip="+strconv.Itoa((page-1)*CommitsRangeSize), stdout, err := NewCommand("log", id.String(), "--skip="+strconv.Itoa((page-1)*CommitsRangeSize),
"--max-count="+strconv.Itoa(CommitsRangeSize), _PRETTY_LOG_FORMAT).RunInDirBytes(repo.Path) "--max-count="+strconv.Itoa(CommitsRangeSize), prettyLogFormat).RunInDirBytes(repo.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return repo.parsePrettyFormatLogToList(stdout) return repo.parsePrettyFormatLogToList(stdout)
} }
func (repo *Repository) searchCommits(id sha1, keyword string) (*list.List, error) { func (repo *Repository) searchCommits(id SHA1, keyword string) (*list.List, error) {
stdout, err := NewCommand("log", id.String(), "-100", "-i", "--grep="+keyword, _PRETTY_LOG_FORMAT).RunInDirBytes(repo.Path) stdout, err := NewCommand("log", id.String(), "-100", "-i", "--grep="+keyword, prettyLogFormat).RunInDirBytes(repo.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -210,19 +212,22 @@ func (repo *Repository) getFilesChanged(id1 string, id2 string) ([]string, error
return strings.Split(string(stdout), "\n"), nil return strings.Split(string(stdout), "\n"), nil
} }
// FileCommitsCount return the number of files at a revison
func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) { func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) {
return commitsCount(repo.Path, revision, file) return commitsCount(repo.Path, revision, file)
} }
// CommitsByFileAndRange return the commits accroding revison file and the page
func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (*list.List, error) { func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (*list.List, error) {
stdout, err := NewCommand("log", revision, "--skip="+strconv.Itoa((page-1)*50), stdout, err := NewCommand("log", revision, "--skip="+strconv.Itoa((page-1)*50),
"--max-count="+strconv.Itoa(CommitsRangeSize), _PRETTY_LOG_FORMAT, "--", file).RunInDirBytes(repo.Path) "--max-count="+strconv.Itoa(CommitsRangeSize), prettyLogFormat, "--", file).RunInDirBytes(repo.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return repo.parsePrettyFormatLogToList(stdout) return repo.parsePrettyFormatLogToList(stdout)
} }
// FilesCountBetween return the number of files changed between two commits
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) { func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
stdout, err := NewCommand("diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path) stdout, err := NewCommand("diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path)
if err != nil { if err != nil {
@ -266,6 +271,7 @@ func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List
return l, nil return l, nil
} }
// CommitsBetweenIDs return commits between twoe commits
func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, error) { func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, error) {
lastCommit, err := repo.GetCommit(last) lastCommit, err := repo.GetCommit(last)
if err != nil { if err != nil {
@ -278,12 +284,13 @@ func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, erro
return repo.CommitsBetween(lastCommit, beforeCommit) return repo.CommitsBetween(lastCommit, beforeCommit)
} }
// CommitsCountBetween return numbers of commits between two commits
func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) { func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
return commitsCount(repo.Path, start+"..."+end, "") return commitsCount(repo.Path, start+"..."+end, "")
} }
// The limit is depth, not total number of returned commits. // commitsBefore the limit is depth, not total number of returned commits.
func (repo *Repository) commitsBefore(l *list.List, parent *list.Element, id sha1, current, limit int) error { func (repo *Repository) commitsBefore(l *list.List, parent *list.Element, id SHA1, current, limit int) error {
// Reach the limit // Reach the limit
if limit > 0 && current > limit { if limit > 0 && current > limit {
return nil return nil
@ -342,12 +349,12 @@ func (repo *Repository) commitsBefore(l *list.List, parent *list.Element, id sha
return nil return nil
} }
func (repo *Repository) getCommitsBefore(id sha1) (*list.List, error) { func (repo *Repository) getCommitsBefore(id SHA1) (*list.List, error) {
l := list.New() l := list.New()
return l, repo.commitsBefore(l, nil, id, 1, 0) return l, repo.commitsBefore(l, nil, id, 1, 0)
} }
func (repo *Repository) getCommitsBeforeLimit(id sha1, num int) (*list.List, error) { func (repo *Repository) getCommitsBeforeLimit(id SHA1, num int) (*list.List, error) {
l := list.New() l := list.New()
return l, repo.commitsBefore(l, nil, id, 1, num) return l, repo.commitsBefore(l, nil, id, 1, num)
} }

@ -4,10 +4,12 @@
package git package git
// GetHook get one hook accroding the name on a repository
func (repo *Repository) GetHook(name string) (*Hook, error) { func (repo *Repository) GetHook(name string) (*Hook, error) {
return GetHook(repo.Path, name) return GetHook(repo.Path, name)
} }
// Hooks get all the hooks on the repository
func (repo *Repository) Hooks() ([]*Hook, error) { func (repo *Repository) Hooks() ([]*Hook, error) {
return ListHooks(repo.Path) return ListHooks(repo.Path)
} }

@ -4,11 +4,16 @@
package git package git
// ObjectType git object type
type ObjectType string type ObjectType string
const ( const (
OBJECT_COMMIT ObjectType = "commit" // ObjectCommit commit object type
OBJECT_TREE ObjectType = "tree" ObjectCommit ObjectType = "commit"
OBJECT_BLOB ObjectType = "blob" // ObjectTree tree object type
OBJECT_TAG ObjectType = "tag" ObjectTree ObjectType = "tree"
// ObjectBlob blob object type
ObjectBlob ObjectType = "blob"
// ObjectTag tag object type
ObjectTag ObjectType = "tag"
) )

@ -50,7 +50,7 @@ func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch stri
return nil, fmt.Errorf("GetMergeBase: %v", err) return nil, fmt.Errorf("GetMergeBase: %v", err)
} }
logs, err := NewCommand("log", prInfo.MergeBase+"..."+headBranch, _PRETTY_LOG_FORMAT).RunInDirBytes(repo.Path) logs, err := NewCommand("log", prInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -10,23 +10,26 @@ import (
"github.com/mcuadros/go-version" "github.com/mcuadros/go-version"
) )
const TAG_PREFIX = "refs/tags/" // TagPrefix tags prefix path on the repository
const TagPrefix = "refs/tags/"
// IsTagExist returns true if given tag exists in the repository. // IsTagExist returns true if given tag exists in the repository.
func IsTagExist(repoPath, name string) bool { func IsTagExist(repoPath, name string) bool {
return IsReferenceExist(repoPath, TAG_PREFIX+name) return IsReferenceExist(repoPath, TagPrefix+name)
} }
// IsTagExist returns true if given tag exists in the repository.
func (repo *Repository) IsTagExist(name string) bool { func (repo *Repository) IsTagExist(name string) bool {
return IsTagExist(repo.Path, name) return IsTagExist(repo.Path, name)
} }
// CreateTag create one tag in the repository
func (repo *Repository) CreateTag(name, revision string) error { func (repo *Repository) CreateTag(name, revision string) error {
_, err := NewCommand("tag", name, revision).RunInDir(repo.Path) _, err := NewCommand("tag", name, revision).RunInDir(repo.Path)
return err return err
} }
func (repo *Repository) getTag(id sha1) (*Tag, error) { func (repo *Repository) getTag(id SHA1) (*Tag, error) {
t, ok := repo.tagCache.Get(id.String()) t, ok := repo.tagCache.Get(id.String())
if ok { if ok {
log("Hit cache: %s", id) log("Hit cache: %s", id)
@ -41,11 +44,11 @@ func (repo *Repository) getTag(id sha1) (*Tag, error) {
tp = strings.TrimSpace(tp) tp = strings.TrimSpace(tp)
// Tag is a commit. // Tag is a commit.
if ObjectType(tp) == OBJECT_COMMIT { if ObjectType(tp) == ObjectCommit {
tag := &Tag{ tag := &Tag{
ID: id, ID: id,
Object: id, Object: id,
Type: string(OBJECT_COMMIT), Type: string(ObjectCommit),
repo: repo, repo: repo,
} }

@ -4,7 +4,7 @@
package git package git
func (repo *Repository) getTree(id sha1) (*Tree, error) { func (repo *Repository) getTree(id SHA1) (*Tree, error) {
treePath := filepathFromSHA1(repo.Path, id.String()) treePath := filepathFromSHA1(repo.Path, id.String())
if isFile(treePath) { if isFile(treePath) {
_, err := NewCommand("ls-tree", id.String()).RunInDir(repo.Path) _, err := NewCommand("ls-tree", id.String()).RunInDir(repo.Path)
@ -16,7 +16,7 @@ func (repo *Repository) getTree(id sha1) (*Tree, error) {
return NewTree(repo, id), nil return NewTree(repo, id), nil
} }
// Find the tree object in the repository. // GetTree find the tree object in the repository.
func (repo *Repository) GetTree(idStr string) (*Tree, error) { func (repo *Repository) GetTree(idStr string) (*Tree, error) {
id, err := NewIDFromString(idStr) id, err := NewIDFromString(idStr)
if err != nil { if err != nil {

40
vendor/code.gitea.io/git/sha1.go generated vendored

@ -10,13 +10,15 @@ import (
"strings" "strings"
) )
const EMPTY_SHA = "0000000000000000000000000000000000000000" // EmptySHA defines empty git SHA
const EmptySHA = "0000000000000000000000000000000000000000"
type sha1 [20]byte // SHA1 a git commit name
type SHA1 [20]byte
// Equal returns true if s has the same sha1 as caller. // Equal returns true if s has the same SHA1 as caller.
// Support 40-length-string, []byte, sha1. // Support 40-length-string, []byte, SHA1.
func (id sha1) Equal(s2 interface{}) bool { func (id SHA1) Equal(s2 interface{}) bool {
switch v := s2.(type) { switch v := s2.(type) {
case string: case string:
if len(v) != 40 { if len(v) != 40 {
@ -32,7 +34,7 @@ func (id sha1) Equal(s2 interface{}) bool {
return false return false
} }
} }
case sha1: case SHA1:
for i, v := range v { for i, v := range v {
if id[i] != v { if id[i] != v {
return false return false
@ -45,42 +47,42 @@ func (id sha1) Equal(s2 interface{}) bool {
} }
// String returns string (hex) representation of the Oid. // String returns string (hex) representation of the Oid.
func (s sha1) String() string { func (id SHA1) String() string {
result := make([]byte, 0, 40) result := make([]byte, 0, 40)
hexvalues := []byte("0123456789abcdef") hexvalues := []byte("0123456789abcdef")
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
result = append(result, hexvalues[s[i]>>4]) result = append(result, hexvalues[id[i]>>4])
result = append(result, hexvalues[s[i]&0xf]) result = append(result, hexvalues[id[i]&0xf])
} }
return string(result) return string(result)
} }
// MustID always creates a new sha1 from a [20]byte array with no validation of input. // MustID always creates a new SHA1 from a [20]byte array with no validation of input.
func MustID(b []byte) sha1 { func MustID(b []byte) SHA1 {
var id sha1 var id SHA1
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
id[i] = b[i] id[i] = b[i]
} }
return id return id
} }
// NewID creates a new sha1 from a [20]byte array. // NewID creates a new SHA1 from a [20]byte array.
func NewID(b []byte) (sha1, error) { func NewID(b []byte) (SHA1, error) {
if len(b) != 20 { if len(b) != 20 {
return sha1{}, fmt.Errorf("Length must be 20: %v", b) return SHA1{}, fmt.Errorf("Length must be 20: %v", b)
} }
return MustID(b), nil return MustID(b), nil
} }
// MustIDFromString always creates a new sha from a ID with no validation of input. // MustIDFromString always creates a new sha from a ID with no validation of input.
func MustIDFromString(s string) sha1 { func MustIDFromString(s string) SHA1 {
b, _ := hex.DecodeString(s) b, _ := hex.DecodeString(s)
return MustID(b) return MustID(b)
} }
// NewIDFromString creates a new sha1 from a ID string of length 40. // NewIDFromString creates a new SHA1 from a ID string of length 40.
func NewIDFromString(s string) (sha1, error) { func NewIDFromString(s string) (SHA1, error) {
var id sha1 var id SHA1
s = strings.TrimSpace(s) s = strings.TrimSpace(s)
if len(s) != 40 { if len(s) != 40 {
return id, fmt.Errorf("Length must be 40: %s", s) return id, fmt.Errorf("Length must be 40: %s", s)

@ -6,6 +6,7 @@ package git
import "strings" import "strings"
// SubModule submodule is a reference on git repository
type SubModule struct { type SubModule struct {
Name string Name string
URL string URL string
@ -19,6 +20,7 @@ type SubModuleFile struct {
refID string refID string
} }
// NewSubModuleFile create a new submodule file
func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile { func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile {
return &SubModuleFile{ return &SubModuleFile{
Commit: c, Commit: c,
@ -64,9 +66,8 @@ func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string {
// fix problem with reverse proxy works only with local server // fix problem with reverse proxy works only with local server
if strings.Contains(urlPrefix, url[i+1:j]) { if strings.Contains(urlPrefix, url[i+1:j]) {
return urlPrefix + url[j+1:] return urlPrefix + url[j+1:]
} else {
return "http://" + url[i+1:j] + "/" + url[j+1:]
} }
return "http://" + url[i+1:j] + "/" + url[j+1:]
} }
return url return url

5
vendor/code.gitea.io/git/tag.go generated vendored

@ -9,14 +9,15 @@ import "bytes"
// Tag represents a Git tag. // Tag represents a Git tag.
type Tag struct { type Tag struct {
Name string Name string
ID sha1 ID SHA1
repo *Repository repo *Repository
Object sha1 // The id of this commit object Object SHA1 // The id of this commit object
Type string Type string
Tagger *Signature Tagger *Signature
Message string Message string
} }
// Commit return the commit of the tag reference
func (tag *Tag) Commit() (*Commit, error) { func (tag *Tag) Commit() (*Commit, error) {
return tag.repo.getCommit(tag.Object) return tag.repo.getCommit(tag.Object)
} }

28
vendor/code.gitea.io/git/tree.go generated vendored

@ -12,7 +12,7 @@ import (
// Tree represents a flat directory listing. // Tree represents a flat directory listing.
type Tree struct { type Tree struct {
ID sha1 ID SHA1
repo *Repository repo *Repository
// parent tree // parent tree
@ -22,7 +22,8 @@ type Tree struct {
entriesParsed bool entriesParsed bool
} }
func NewTree(repo *Repository, id sha1) *Tree { // NewTree create a new tree according the repository and commit id
func NewTree(repo *Repository, id SHA1) *Tree {
return &Tree{ return &Tree{
ID: id, ID: id,
repo: repo, repo: repo,
@ -63,22 +64,22 @@ func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
step := 6 step := 6
switch string(data[pos : pos+step]) { switch string(data[pos : pos+step]) {
case "100644": case "100644":
entry.mode = ENTRY_MODE_BLOB entry.mode = EntryModeBlob
entry.Type = OBJECT_BLOB entry.Type = ObjectBlob
case "100755": case "100755":
entry.mode = ENTRY_MODE_EXEC entry.mode = EntryModeExec
entry.Type = OBJECT_BLOB entry.Type = ObjectBlob
case "120000": case "120000":
entry.mode = ENTRY_MODE_SYMLINK entry.mode = EntryModeSymlink
entry.Type = OBJECT_BLOB entry.Type = ObjectBlob
case "160000": case "160000":
entry.mode = ENTRY_MODE_COMMIT entry.mode = EntryModeCommit
entry.Type = OBJECT_COMMIT entry.Type = ObjectCommit
step = 8 step = 8
case "040000": case "040000":
entry.mode = ENTRY_MODE_TREE entry.mode = EntryModeTree
entry.Type = OBJECT_TREE entry.Type = ObjectTree
default: default:
return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+step])) return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+step]))
} }
@ -90,7 +91,7 @@ func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
return nil, err return nil, err
} }
entry.ID = id entry.ID = id
pos += step + 1 // Skip half of sha1. pos += step + 1 // Skip half of SHA1.
step = bytes.IndexByte(data[pos:], '\n') step = bytes.IndexByte(data[pos:], '\n')
@ -107,6 +108,7 @@ func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
return entries, nil return entries, nil
} }
// SubTree get a sub tree by the sub dir path
func (t *Tree) SubTree(rpath string) (*Tree, error) { func (t *Tree) SubTree(rpath string) (*Tree, error) {
if len(rpath) == 0 { if len(rpath) == 0 {
return t, nil return t, nil

@ -9,12 +9,13 @@ import (
"strings" "strings"
) )
// GetTreeEntryByPath get the tree entries accroding the sub dir
func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) { func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
if len(relpath) == 0 { if len(relpath) == 0 {
return &TreeEntry{ return &TreeEntry{
ID: t.ID, ID: t.ID,
Type: OBJECT_TREE, Type: ObjectTree,
mode: ENTRY_MODE_TREE, mode: EntryModeTree,
}, nil }, nil
} }
@ -43,6 +44,7 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
return nil, ErrNotExist{"", relpath} return nil, ErrNotExist{"", relpath}
} }
// GetBlobByPath get the blob object accroding the path
func (t *Tree) GetBlobByPath(relpath string) (*Blob, error) { func (t *Tree) GetBlobByPath(relpath string) (*Blob, error) {
entry, err := t.GetTreeEntryByPath(relpath) entry, err := t.GetTreeEntryByPath(relpath)
if err != nil { if err != nil {

@ -14,20 +14,27 @@ import (
"strings" "strings"
) )
// EntryMode the type of the object in the git tree
type EntryMode int type EntryMode int
// There are only a few file modes in Git. They look like unix file modes, but they can only be // There are only a few file modes in Git. They look like unix file modes, but they can only be
// one of these. // one of these.
const ( const (
ENTRY_MODE_BLOB EntryMode = 0100644 // EntryModeBlob
ENTRY_MODE_EXEC EntryMode = 0100755 EntryModeBlob EntryMode = 0100644
ENTRY_MODE_SYMLINK EntryMode = 0120000 // EntryModeExec
ENTRY_MODE_COMMIT EntryMode = 0160000 EntryModeExec EntryMode = 0100755
ENTRY_MODE_TREE EntryMode = 0040000 // EntryModeSymlink
EntryModeSymlink EntryMode = 0120000
// EntryModeCommit
EntryModeCommit EntryMode = 0160000
// EntryModeTree
EntryModeTree EntryMode = 0040000
) )
// TreeEntry the leaf in the git tree
type TreeEntry struct { type TreeEntry struct {
ID sha1 ID SHA1
Type ObjectType Type ObjectType
mode EntryMode mode EntryMode
@ -41,10 +48,12 @@ type TreeEntry struct {
sized bool sized bool
} }
// Name returns the name of the entry
func (te *TreeEntry) Name() string { func (te *TreeEntry) Name() string {
return te.name return te.name
} }
// Size returns the size of the entry
func (te *TreeEntry) Size() int64 { func (te *TreeEntry) Size() int64 {
if te.IsDir() { if te.IsDir() {
return 0 return 0
@ -62,14 +71,22 @@ func (te *TreeEntry) Size() int64 {
return te.size return te.size
} }
// IsSubModule if the entry is a sub module
func (te *TreeEntry) IsSubModule() bool { func (te *TreeEntry) IsSubModule() bool {
return te.mode == ENTRY_MODE_COMMIT return te.mode == EntryModeCommit
} }
// IsDir if the entry is a sub dir
func (te *TreeEntry) IsDir() bool { func (te *TreeEntry) IsDir() bool {
return te.mode == ENTRY_MODE_TREE return te.mode == EntryModeTree
} }
// IsLink if the entry is a symlink
func (te *TreeEntry) IsLink() bool {
return te.mode == EntryModeSymlink
}
// Blob retrun the blob object the entry
func (te *TreeEntry) Blob() *Blob { func (te *TreeEntry) Blob() *Blob {
return &Blob{ return &Blob{
repo: te.ptree.repo, repo: te.ptree.repo,
@ -77,6 +94,7 @@ func (te *TreeEntry) Blob() *Blob {
} }
} }
// Entries a list of entry
type Entries []*TreeEntry type Entries []*TreeEntry
var sorter = []func(t1, t2 *TreeEntry) bool{ var sorter = []func(t1, t2 *TreeEntry) bool{
@ -105,6 +123,7 @@ func (tes Entries) Less(i, j int) bool {
return sorter[k](t1, t2) return sorter[k](t1, t2)
} }
// Sort sort the list of entry
func (tes Entries) Sort() { func (tes Entries) Sort() {
sort.Sort(tes) sort.Sort(tes)
} }
@ -167,7 +186,7 @@ func (tes Entries) GetCommitsInfoWithCustomConcurrency(commit *Commit, treePath
// However when taskChan is full, code will block and wait any running goroutines to finish. // However when taskChan is full, code will block and wait any running goroutines to finish.
taskChan <- true taskChan <- true
if tes[i].Type != OBJECT_COMMIT { if tes[i].Type != ObjectCommit {
go func(i int) { go func(i int) {
cinfo := commitInfo{entryName: tes[i].Name()} cinfo := commitInfo{entryName: tes[i].Name()}
c, err := commit.GetCommitByPath(filepath.Join(treePath, tes[i].Name())) c, err := commit.GetCommitByPath(filepath.Join(treePath, tes[i].Name()))

23
vendor/code.gitea.io/git/utils.go generated vendored

@ -12,26 +12,28 @@ import (
"sync" "sync"
) )
// objectCache provides thread-safe cache opeations. // ObjectCache provides thread-safe cache opeations.
type objectCache struct { type ObjectCache struct {
lock sync.RWMutex lock sync.RWMutex
cache map[string]interface{} cache map[string]interface{}
} }
func newObjectCache() *objectCache { func newObjectCache() *ObjectCache {
return &objectCache{ return &ObjectCache{
cache: make(map[string]interface{}, 10), cache: make(map[string]interface{}, 10),
} }
} }
func (oc *objectCache) Set(id string, obj interface{}) { // Set add obj to cache
func (oc *ObjectCache) Set(id string, obj interface{}) {
oc.lock.Lock() oc.lock.Lock()
defer oc.lock.Unlock() defer oc.lock.Unlock()
oc.cache[id] = obj oc.cache[id] = obj
} }
func (oc *objectCache) Get(id string) (interface{}, bool) { // Get get cached obj by id
func (oc *ObjectCache) Get(id string) (interface{}, bool) {
oc.lock.RLock() oc.lock.RLock()
defer oc.lock.RUnlock() defer oc.lock.RUnlock()
@ -80,13 +82,14 @@ func filepathFromSHA1(rootdir, sha1 string) string {
return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:]) return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:])
} }
// RefEndName return the end name of a ref name
func RefEndName(refStr string) string { func RefEndName(refStr string) string {
if strings.HasPrefix(refStr, BRANCH_PREFIX) { if strings.HasPrefix(refStr, BranchPrefix) {
return refStr[len(BRANCH_PREFIX):] return refStr[len(BranchPrefix):]
} }
if strings.HasPrefix(refStr, TAG_PREFIX) { if strings.HasPrefix(refStr, TagPrefix) {
return refStr[len(TAG_PREFIX):] return refStr[len(TagPrefix):]
} }
return refStr return refStr

@ -3,10 +3,10 @@
"ignore": "test", "ignore": "test",
"package": [ "package": [
{ {
"checksumSHA1": "X4WaxEtgFkM4VHg6TcNk2xkrqCI=", "checksumSHA1": "OWuUWQ8sWC8n+eTQttx+3vfES8g=",
"path": "code.gitea.io/git", "path": "code.gitea.io/git",
"revision": "0807b517283977be34f0ff5510b21e676fc1527c", "revision": "634abd6a61c350a95f6b146c3a5fc323282608ae",
"revisionTime": "2016-11-13T14:20:52Z" "revisionTime": "2016-12-22T08:49:21Z"
}, },
{ {
"checksumSHA1": "KZEYDYPzVc12f0770V++kIHhfa0=", "checksumSHA1": "KZEYDYPzVc12f0770V++kIHhfa0=",

Loading…
Cancel
Save