forked from Gitlink/gitea-1156
update code.gitea.io/git (#450)
This commit is contained in:
parent
0c5c34d7dd
commit
47a7529d96
|
@ -121,7 +121,7 @@ func handleUpdateTask(uuid string, user, repoUser *models.User, reponame string,
|
|||
|
||||
// Ask for running deliver hook and test pull request tasks.
|
||||
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)
|
||||
|
||||
resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
|
||||
|
|
|
@ -494,12 +494,12 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
|||
isNewBranch := false
|
||||
opType := ActionCommitRepo
|
||||
// Check it's tag push or branch.
|
||||
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
|
||||
if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
|
||||
opType = ActionPushTag
|
||||
opts.Commits = &PushCommits{}
|
||||
} else {
|
||||
// if not the first commit, set the compare URL.
|
||||
if opts.OldCommitID == git.EMPTY_SHA {
|
||||
if opts.OldCommitID == git.EmptySHA {
|
||||
isNewBranch = true
|
||||
} else {
|
||||
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)
|
||||
|
||||
p := &api.PushPayload{
|
||||
Ref: git.BRANCH_PREFIX + pr.BaseBranch,
|
||||
Ref: git.BranchPrefix + pr.BaseBranch,
|
||||
Before: pr.MergeBase,
|
||||
After: 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
|
||||
if opts.NewBranch != opts.OldBranch {
|
||||
oldCommitID = git.EMPTY_SHA
|
||||
oldCommitID = git.EmptySHA
|
||||
}
|
||||
if err := CommitRepoAction(CommitRepoActionOptions{
|
||||
PusherName: doer.Name,
|
||||
RepoOwnerID: repo.MustOwner().ID,
|
||||
RepoName: repo.Name,
|
||||
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
|
||||
RefFullName: git.BranchPrefix + opts.NewBranch,
|
||||
OldCommitID: oldCommitID,
|
||||
NewCommitID: commit.ID.String(),
|
||||
Commits: pushCommits,
|
||||
|
@ -297,7 +297,7 @@ func (repo *Repository) DeleteRepoFile(doer *User, opts DeleteRepoFileOptions) (
|
|||
PusherName: doer.Name,
|
||||
RepoOwnerID: repo.MustOwner().ID,
|
||||
RepoName: repo.Name,
|
||||
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
|
||||
RefFullName: git.BranchPrefix + opts.NewBranch,
|
||||
OldCommitID: opts.LastCommitID,
|
||||
NewCommitID: commit.ID.String(),
|
||||
Commits: pushCommits,
|
||||
|
@ -533,7 +533,7 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
|
|||
PusherName: doer.Name,
|
||||
RepoOwnerID: repo.MustOwner().ID,
|
||||
RepoName: repo.Name,
|
||||
RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
|
||||
RefFullName: git.BranchPrefix + opts.NewBranch,
|
||||
OldCommitID: opts.LastCommitID,
|
||||
NewCommitID: commit.ID.String(),
|
||||
Commits: pushCommits,
|
||||
|
|
|
@ -91,10 +91,10 @@ type PushUpdateOptions struct {
|
|||
// PushUpdate must be called for any push actions in order to
|
||||
// generates necessary push action history feeds.
|
||||
func PushUpdate(opts PushUpdateOptions) (err error) {
|
||||
isNewRef := opts.OldCommitID == git.EMPTY_SHA
|
||||
isDelRef := opts.NewCommitID == git.EMPTY_SHA
|
||||
isNewRef := opts.OldCommitID == git.EmptySHA
|
||||
isDelRef := opts.NewCommitID == git.EmptySHA
|
||||
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)
|
||||
|
@ -127,7 +127,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
|||
}
|
||||
|
||||
// Push tags.
|
||||
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
|
||||
if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
|
||||
if err := CommitRepoAction(CommitRepoActionOptions{
|
||||
PusherName: opts.PusherName,
|
||||
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,
|
||||
RepoName: reponame,
|
||||
}); 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 {
|
||||
ghost := models.NewGhostUser()
|
||||
commit = &git.Commit{
|
||||
ID: git.MustIDFromString(git.EMPTY_SHA),
|
||||
ID: git.MustIDFromString(git.EmptySHA),
|
||||
Author: ghost.NewGitSig(),
|
||||
Committer: ghost.NewGitSig(),
|
||||
CommitMessage: "This is a fake commit",
|
||||
|
@ -370,7 +370,7 @@ func TestWebhook(ctx *context.Context) {
|
|||
|
||||
apiUser := ctx.User.APIFormat()
|
||||
p := &api.PushPayload{
|
||||
Ref: git.BRANCH_PREFIX + ctx.Repo.Repository.DefaultBranch,
|
||||
Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch,
|
||||
Before: commit.ID.String(),
|
||||
After: commit.ID.String(),
|
||||
Commits: []*api.PayloadCommit{
|
||||
|
|
|
@ -66,7 +66,7 @@ func renderWikiPage(ctx *context.Context, isViewPage bool) (*git.Repository, str
|
|||
}
|
||||
pages := make([]PageMeta, 0, len(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")
|
||||
pages = append(pages, PageMeta{
|
||||
Name: name,
|
||||
|
@ -171,7 +171,7 @@ func WikiPages(ctx *context.Context) {
|
|||
}
|
||||
pages := make([]PageMeta, 0, len(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())
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetCommit", err)
|
||||
|
|
|
@ -2,161 +2,85 @@
|
|||
|
||||
## Introduction
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
## Bug reports
|
||||
|
||||
Please search the issues on the issue tracker with a variety of keywords
|
||||
to ensure your bug is not already reported.
|
||||
Please search the issues on the issue tracker with a variety of keywords to ensure your bug is not already reported.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
Please be kind, remember that Gitea comes at no cost to you, and you're
|
||||
getting free help.
|
||||
Please be kind, remember that Gitea comes at no cost to you, and you're getting free help.
|
||||
|
||||
## Discuss your design
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Testing redux
|
||||
|
||||
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:
|
||||
|
||||
After running for a while, the command should print
|
||||
|
||||
```
|
||||
ALL TESTS PASSED
|
||||
```
|
||||
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.
|
||||
|
||||
## Code review
|
||||
|
||||
Changes to Gitea must be reviewed before they are accepted, no matter
|
||||
who makes the change even if an owners or a maintainer. We use github's
|
||||
pull request workflow to do that and use [lgtm](http://lgtm.co) to ensure
|
||||
every PR is reviewed by at least 2 maintainers.
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
* Make small pull requests. The smaller, the faster to review and the more likely it will be merged soon.
|
||||
* 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.
|
||||
* Split big pull requests in multiple small ones. An incremental change will be faster to review than a huge PR.
|
||||
|
||||
## Sign your work
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
```
|
||||
Signed-off-by: Joe Smith <joe.smith@email.com>
|
||||
```
|
||||
|
||||
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`.
|
||||
|
||||
## 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).
|
||||
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`.
|
||||
|
||||
## Maintainers
|
||||
|
||||
To make sure every PR have been checked, we make a team maintainers. Any
|
||||
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.
|
||||
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.
|
||||
|
||||
## Owners
|
||||
|
||||
Since Gitea is a pure community organization without any company
|
||||
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.
|
||||
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.
|
||||
|
||||
After the election, the new owners should say he agrees with these
|
||||
rules on the [CONTRIBUTING](CONTRIBUTING.md) on the [Gitter Gitea
|
||||
Channel](https://gitter.im/go-gitea/gitea). Below is the word to speak
|
||||
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:
|
||||
|
||||
```
|
||||
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'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.
|
||||
```
|
||||
|
||||
For a honor to the owners, this document will add the history owners
|
||||
below:
|
||||
To honor the past owners, here's the history of the owners and the time they served:
|
||||
|
||||
2016-11-04 ~ 2017-12-31
|
||||
|
||||
- lunny <xiaolunwen@gmail.com>
|
||||
- tboerger <thomas@webhippie.de>
|
||||
- bkcsoft <kim.carlbacker@gmail.com>
|
||||
* 2016-11-04 ~ 2017-12-31
|
||||
* [Lunny Xiao](https://github.com/lunny) <xiaolunwen@gmail.com>
|
||||
* [Thomas Boerger](https://github.com/tboerger) <thomas@webhippie.de>
|
||||
* [Kim Carlbäcker](https://github.com/bkcsoft) <kim.carlbacker@gmail.com>
|
||||
|
||||
## Versions
|
||||
|
||||
Gitea has one master as a tip branch and have many version 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.
|
||||
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.
|
||||
|
||||
Branch master is a tip version, so if you wish a production usage,
|
||||
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.
|
||||
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.
|
||||
|
||||
## Copyright
|
||||
|
||||
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
|
||||
// license that can be found in the LICENSE file.
|
||||
```
|
||||
|
||||
Files in the repository are copyright the year they are added and the
|
||||
year they are last changed. If the copyright author is changed, just
|
||||
copy the head below the old one.
|
||||
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.
|
||||
|
|
|
@ -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)
|
||||
LefsFlare <nobody@nobody.tld> (@LefsFlarey)
|
||||
Lunny Xiao <xiaolunwen@gmail.com> (@lunny)
|
||||
|
@ -6,5 +8,5 @@ Matthias Loibl <mail@matthiasloibl.com> (@metalmatze)
|
|||
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)
|
||||
Thibault Meyer <meyer.thibault@gmail.com> (@0xbaadf00d)
|
||||
Thomas Boerger <thomas@webhippie.de> (@tboerger)
|
||||
|
|
|
@ -10,6 +10,15 @@
|
|||
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).
|
||||
|
||||
## 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
|
||||
|
||||
This project is under the MIT License. See the [LICENSE](LICENSE) file for the
|
||||
|
|
|
@ -25,6 +25,7 @@ func (b *Blob) Data() (io.Reader, error) {
|
|||
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 {
|
||||
return NewCommand("show", b.ID.String()).RunInDirPipeline(b.repo.Path, stdout, stderr)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,11 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// GlobalCommandArgs global command args for external package setting
|
||||
GlobalCommandArgs []string
|
||||
)
|
||||
|
||||
// Command represents a command with its subcommands or arguments.
|
||||
type Command struct {
|
||||
name string
|
||||
|
@ -30,7 +35,7 @@ func (c *Command) String() string {
|
|||
func NewCommand(args ...string) *Command {
|
||||
return &Command{
|
||||
name: "git",
|
||||
args: args,
|
||||
args: append(GlobalCommandArgs, args...),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,13 +45,11 @@ func (c *Command) AddArguments(args ...string) *Command {
|
|||
return c
|
||||
}
|
||||
|
||||
const DEFAULT_TIMEOUT = 60 * time.Second
|
||||
|
||||
// RunInDirTimeoutPipeline executes the command in given directory with given timeout,
|
||||
// it pipes stdout and stderr to given io.Writer.
|
||||
func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, stdout, stderr io.Writer) error {
|
||||
if timeout == -1 {
|
||||
timeout = DEFAULT_TIMEOUT
|
||||
timeout = 60 * time.Second
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// RunInDir executes the command in given directory
|
||||
// RunInDirBytes executes the command in given directory
|
||||
// and returns stdout in []byte and error (combined with stderr).
|
||||
func (c *Command) RunInDirBytes(dir string) ([]byte, error) {
|
||||
return c.RunInDirTimeout(-1, dir)
|
||||
|
|
|
@ -18,13 +18,13 @@ import (
|
|||
// Commit represents a git commit.
|
||||
type Commit struct {
|
||||
Tree
|
||||
ID sha1 // The ID of this commit object
|
||||
ID SHA1 // The ID of this commit object
|
||||
Author *Signature
|
||||
Committer *Signature
|
||||
CommitMessage string
|
||||
|
||||
parents []sha1 // SHA1 strings
|
||||
submoduleCache *objectCache
|
||||
parents []SHA1 // SHA1 strings
|
||||
submoduleCache *ObjectCache
|
||||
}
|
||||
|
||||
// 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).
|
||||
// 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) {
|
||||
return sha1{}, ErrNotExist{"", ""}
|
||||
return SHA1{}, ErrNotExist{"", ""}
|
||||
}
|
||||
return c.parents[n], nil
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ func isImageFile(data []byte) (string, bool) {
|
|||
return contentType, false
|
||||
}
|
||||
|
||||
// IsImageFile is a file image type
|
||||
func (c *Commit) IsImageFile(name string) bool {
|
||||
blob, err := c.GetBlobByPath(name)
|
||||
if err != nil {
|
||||
|
@ -95,7 +96,7 @@ func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) {
|
|||
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 {
|
||||
cmd := NewCommand("add")
|
||||
if all {
|
||||
|
@ -105,6 +106,7 @@ func AddChanges(repoPath string, all bool, files ...string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// CommitChangesOptions the options when a commit created
|
||||
type CommitChangesOptions struct {
|
||||
Committer *Signature
|
||||
Author *Signature
|
||||
|
@ -166,22 +168,27 @@ func CommitsCount(repoPath, revision string) (int64, error) {
|
|||
return commitsCount(repoPath, revision, "")
|
||||
}
|
||||
|
||||
// CommitsCount returns number of total commits of until current revision.
|
||||
func (c *Commit) CommitsCount() (int64, error) {
|
||||
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) {
|
||||
return c.repo.commitsByRange(c.ID, page)
|
||||
}
|
||||
|
||||
// CommitsBefore returns all the commits before current revision
|
||||
func (c *Commit) CommitsBefore() (*list.List, error) {
|
||||
return c.repo.getCommitsBefore(c.ID)
|
||||
}
|
||||
|
||||
// CommitsBeforeLimit returns num commits before current revision
|
||||
func (c *Commit) CommitsBeforeLimit(num int) (*list.List, error) {
|
||||
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) {
|
||||
endCommit, err := c.repo.GetCommit(commitID)
|
||||
if err != nil {
|
||||
|
@ -190,15 +197,18 @@ func (c *Commit) CommitsBeforeUntil(commitID string) (*list.List, error) {
|
|||
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) {
|
||||
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) {
|
||||
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 {
|
||||
return c.submoduleCache, nil
|
||||
}
|
||||
|
@ -236,6 +246,7 @@ func (c *Commit) GetSubModules() (*objectCache, error) {
|
|||
return c.submoduleCache, nil
|
||||
}
|
||||
|
||||
// GetSubModule get the sub module according entryname
|
||||
func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
|
||||
modules, err := c.GetSubModules()
|
||||
if err != nil {
|
||||
|
|
|
@ -10,13 +10,17 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// ArchiveType archive types
|
||||
type ArchiveType int
|
||||
|
||||
const (
|
||||
// ZIP zip archive type
|
||||
ZIP ArchiveType = iota + 1
|
||||
// TARGZ tar gz archive type
|
||||
TARGZ
|
||||
)
|
||||
|
||||
// CreateArchive create archive content to the target path
|
||||
func (c *Commit) CreateArchive(target string, archiveType ArchiveType) error {
|
||||
var format string
|
||||
switch archiveType {
|
||||
|
|
|
@ -9,10 +9,12 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// ErrExecTimeout error when exec timed out
|
||||
type ErrExecTimeout struct {
|
||||
Duration time.Duration
|
||||
}
|
||||
|
||||
// IsErrExecTimeout if some error is ErrExecTimeout
|
||||
func IsErrExecTimeout(err error) bool {
|
||||
_, ok := err.(ErrExecTimeout)
|
||||
return ok
|
||||
|
@ -22,11 +24,13 @@ func (err ErrExecTimeout) Error() string {
|
|||
return fmt.Sprintf("execution is timeout [duration: %v]", err.Duration)
|
||||
}
|
||||
|
||||
// ErrNotExist commit not exist error
|
||||
type ErrNotExist struct {
|
||||
ID string
|
||||
RelPath string
|
||||
}
|
||||
|
||||
// IsErrNotExist if some error is ErrNotExist
|
||||
func IsErrNotExist(err error) bool {
|
||||
_, ok := err.(ErrNotExist)
|
||||
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)
|
||||
}
|
||||
|
||||
// ErrUnsupportedVersion error when required git version not matched
|
||||
type ErrUnsupportedVersion struct {
|
||||
Required string
|
||||
}
|
||||
|
||||
// IsErrUnsupportedVersion if some error is ErrUnsupportedVersion
|
||||
func IsErrUnsupportedVersion(err error) bool {
|
||||
_, ok := err.(ErrUnsupportedVersion)
|
||||
return ok
|
||||
|
|
|
@ -10,16 +10,16 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const _VERSION = "0.4.2"
|
||||
|
||||
// Version return this package's current version
|
||||
func Version() string {
|
||||
return _VERSION
|
||||
return "0.4.2"
|
||||
}
|
||||
|
||||
var (
|
||||
// Debug enables verbose logging on everything.
|
||||
// This should be false in case Gogs starts in SSH mode.
|
||||
Debug = false
|
||||
Debug = false
|
||||
// Prefix the log prefix
|
||||
Prefix = "[git-module] "
|
||||
)
|
||||
|
||||
|
@ -38,7 +38,7 @@ func log(format string, args ...interface{}) {
|
|||
|
||||
var gitVersion string
|
||||
|
||||
// Version returns current Git version from shell.
|
||||
// BinVersion returns current Git version from shell.
|
||||
func BinVersion() (string, error) {
|
||||
if len(gitVersion) > 0 {
|
||||
return gitVersion, nil
|
||||
|
|
|
@ -22,6 +22,7 @@ var hookNames = []string{
|
|||
}
|
||||
|
||||
var (
|
||||
// ErrNotValidHook error when a git hook is not valid
|
||||
ErrNotValidHook = errors.New("not a valid Git hook")
|
||||
)
|
||||
|
||||
|
@ -70,6 +71,7 @@ func GetHook(repoPath, name string) (*Hook, error) {
|
|||
return h, nil
|
||||
}
|
||||
|
||||
// Name return the name of the hook
|
||||
func (h *Hook) Name() string {
|
||||
return h.name
|
||||
}
|
||||
|
@ -102,6 +104,7 @@ func ListHooks(repoPath string) (_ []*Hook, err error) {
|
|||
}
|
||||
|
||||
const (
|
||||
// HookPathUpdate hook update path
|
||||
HookPathUpdate = "hooks/update"
|
||||
)
|
||||
|
||||
|
|
|
@ -18,11 +18,11 @@ import (
|
|||
type Repository struct {
|
||||
Path string
|
||||
|
||||
commitCache *objectCache
|
||||
tagCache *objectCache
|
||||
commitCache *ObjectCache
|
||||
tagCache *ObjectCache
|
||||
}
|
||||
|
||||
const _PRETTY_LOG_FORMAT = `--pretty=format:%H`
|
||||
const prettyLogFormat = `--pretty=format:%H`
|
||||
|
||||
func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, error) {
|
||||
l := list.New()
|
||||
|
@ -32,8 +32,8 @@ func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, err
|
|||
|
||||
parts := bytes.Split(logs, []byte{'\n'})
|
||||
|
||||
for _, commitId := range parts {
|
||||
commit, err := repo.GetCommit(string(commitId))
|
||||
for _, commitID := range parts {
|
||||
commit, err := repo.GetCommit(string(commitID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ func OpenRepository(repoPath string) (*Repository, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// CloneRepoOptions options when clone a repository
|
||||
type CloneRepoOptions struct {
|
||||
Timeout time.Duration
|
||||
Mirror bool
|
||||
|
@ -118,6 +119,7 @@ func Clone(from, to string, opts CloneRepoOptions) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// PullRemoteOptions options when pull from remote
|
||||
type PullRemoteOptions struct {
|
||||
Timeout time.Duration
|
||||
All bool
|
||||
|
@ -153,6 +155,7 @@ func Push(repoPath, remote, branch string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// CheckoutOptions options when heck out some branch
|
||||
type CheckoutOptions struct {
|
||||
Timeout time.Duration
|
||||
Branch string
|
||||
|
|
|
@ -11,7 +11,8 @@ import (
|
|||
"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.
|
||||
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.
|
||||
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 {
|
||||
return IsBranchExist(repo.Path, name)
|
||||
}
|
||||
|
@ -42,12 +44,12 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) {
|
|||
}
|
||||
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 &Branch{
|
||||
Name: stdout[len(BRANCH_PREFIX):],
|
||||
Name: stdout[len(BranchPrefix):],
|
||||
Path: stdout,
|
||||
}, nil
|
||||
}
|
||||
|
@ -58,7 +60,7 @@ func (repo *Repository) SetDefaultBranch(name string) error {
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -76,12 +78,12 @@ func (repo *Repository) GetBranches() ([]string, error) {
|
|||
if len(fields) != 2 {
|
||||
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
|
||||
}
|
||||
|
||||
// Option(s) for delete branch
|
||||
// DeleteBranchOptions Option(s) for delete branch
|
||||
type DeleteBranchOptions struct {
|
||||
Force bool
|
||||
}
|
||||
|
|
|
@ -28,12 +28,12 @@ func (repo *Repository) getRefCommitID(name string) (string, error) {
|
|||
|
||||
// GetBranchCommitID returns last commit ID string of given branch.
|
||||
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.
|
||||
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
|
||||
|
@ -41,7 +41,7 @@ func (repo *Repository) GetTagCommitID(name string) (string, error) {
|
|||
// \n\n separate headers from message
|
||||
func parseCommitData(data []byte) (*Commit, error) {
|
||||
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...
|
||||
nextline := 0
|
||||
l:
|
||||
|
@ -90,7 +90,7 @@ l:
|
|||
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())
|
||||
if ok {
|
||||
log("Hit cache: %s", id)
|
||||
|
@ -142,6 +142,7 @@ func (repo *Repository) GetBranchCommit(name string) (*Commit, error) {
|
|||
return repo.GetCommit(commitID)
|
||||
}
|
||||
|
||||
// GetTagCommit get the commit of the specific tag via name
|
||||
func (repo *Repository) GetTagCommit(name string) (*Commit, error) {
|
||||
commitID, err := repo.GetTagCommitID(name)
|
||||
if err != nil {
|
||||
|
@ -150,13 +151,13 @@ func (repo *Repository) GetTagCommit(name string) (*Commit, error) {
|
|||
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.
|
||||
if relpath[0] == ':' {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -171,7 +172,7 @@ func (repo *Repository) getCommitByPathWithID(id sha1, relpath string) (*Commit,
|
|||
|
||||
// GetCommitByPath returns the last commit of relative path.
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -183,19 +184,20 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
|
|||
return commits.Front().Value.(*Commit), nil
|
||||
}
|
||||
|
||||
// CommitsRangeSize the default commits range size
|
||||
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),
|
||||
"--max-count="+strconv.Itoa(CommitsRangeSize), _PRETTY_LOG_FORMAT).RunInDirBytes(repo.Path)
|
||||
"--max-count="+strconv.Itoa(CommitsRangeSize), prettyLogFormat).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.parsePrettyFormatLogToList(stdout)
|
||||
}
|
||||
|
||||
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)
|
||||
func (repo *Repository) searchCommits(id SHA1, keyword string) (*list.List, error) {
|
||||
stdout, err := NewCommand("log", id.String(), "-100", "-i", "--grep="+keyword, prettyLogFormat).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -210,19 +212,22 @@ func (repo *Repository) getFilesChanged(id1 string, id2 string) ([]string, error
|
|||
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) {
|
||||
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) {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return repo.parsePrettyFormatLogToList(stdout)
|
||||
}
|
||||
|
||||
// FilesCountBetween return the number of files changed between two commits
|
||||
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
|
||||
stdout, err := NewCommand("diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
|
@ -266,6 +271,7 @@ func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List
|
|||
return l, nil
|
||||
}
|
||||
|
||||
// CommitsBetweenIDs return commits between twoe commits
|
||||
func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, error) {
|
||||
lastCommit, err := repo.GetCommit(last)
|
||||
if err != nil {
|
||||
|
@ -278,12 +284,13 @@ func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, erro
|
|||
return repo.CommitsBetween(lastCommit, beforeCommit)
|
||||
}
|
||||
|
||||
// CommitsCountBetween return numbers of commits between two commits
|
||||
func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
|
||||
return commitsCount(repo.Path, start+"..."+end, "")
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// 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 {
|
||||
// Reach the limit
|
||||
if limit > 0 && current > limit {
|
||||
return nil
|
||||
|
@ -342,12 +349,12 @@ func (repo *Repository) commitsBefore(l *list.List, parent *list.Element, id sha
|
|||
return nil
|
||||
}
|
||||
|
||||
func (repo *Repository) getCommitsBefore(id sha1) (*list.List, error) {
|
||||
func (repo *Repository) getCommitsBefore(id SHA1) (*list.List, error) {
|
||||
l := list.New()
|
||||
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()
|
||||
return l, repo.commitsBefore(l, nil, id, 1, num)
|
||||
}
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
|
||||
package git
|
||||
|
||||
// GetHook get one hook accroding the name on a repository
|
||||
func (repo *Repository) GetHook(name string) (*Hook, error) {
|
||||
return GetHook(repo.Path, name)
|
||||
}
|
||||
|
||||
// Hooks get all the hooks on the repository
|
||||
func (repo *Repository) Hooks() ([]*Hook, error) {
|
||||
return ListHooks(repo.Path)
|
||||
}
|
||||
|
|
|
@ -4,11 +4,16 @@
|
|||
|
||||
package git
|
||||
|
||||
// ObjectType git object type
|
||||
type ObjectType string
|
||||
|
||||
const (
|
||||
OBJECT_COMMIT ObjectType = "commit"
|
||||
OBJECT_TREE ObjectType = "tree"
|
||||
OBJECT_BLOB ObjectType = "blob"
|
||||
OBJECT_TAG ObjectType = "tag"
|
||||
// ObjectCommit commit object type
|
||||
ObjectCommit ObjectType = "commit"
|
||||
// ObjectTree tree object type
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -10,23 +10,26 @@ import (
|
|||
"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.
|
||||
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 {
|
||||
return IsTagExist(repo.Path, name)
|
||||
}
|
||||
|
||||
// CreateTag create one tag in the repository
|
||||
func (repo *Repository) CreateTag(name, revision string) error {
|
||||
_, err := NewCommand("tag", name, revision).RunInDir(repo.Path)
|
||||
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())
|
||||
if ok {
|
||||
log("Hit cache: %s", id)
|
||||
|
@ -41,11 +44,11 @@ func (repo *Repository) getTag(id sha1) (*Tag, error) {
|
|||
tp = strings.TrimSpace(tp)
|
||||
|
||||
// Tag is a commit.
|
||||
if ObjectType(tp) == OBJECT_COMMIT {
|
||||
if ObjectType(tp) == ObjectCommit {
|
||||
tag := &Tag{
|
||||
ID: id,
|
||||
Object: id,
|
||||
Type: string(OBJECT_COMMIT),
|
||||
Type: string(ObjectCommit),
|
||||
repo: repo,
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package git
|
||||
|
||||
func (repo *Repository) getTree(id sha1) (*Tree, error) {
|
||||
func (repo *Repository) getTree(id SHA1) (*Tree, error) {
|
||||
treePath := filepathFromSHA1(repo.Path, id.String())
|
||||
if isFile(treePath) {
|
||||
_, 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
|
||||
}
|
||||
|
||||
// Find the tree object in the repository.
|
||||
// GetTree find the tree object in the repository.
|
||||
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
|
||||
id, err := NewIDFromString(idStr)
|
||||
if err != nil {
|
||||
|
|
|
@ -10,13 +10,15 @@ import (
|
|||
"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.
|
||||
// Support 40-length-string, []byte, sha1.
|
||||
func (id sha1) Equal(s2 interface{}) bool {
|
||||
// Equal returns true if s has the same SHA1 as caller.
|
||||
// Support 40-length-string, []byte, SHA1.
|
||||
func (id SHA1) Equal(s2 interface{}) bool {
|
||||
switch v := s2.(type) {
|
||||
case string:
|
||||
if len(v) != 40 {
|
||||
|
@ -32,7 +34,7 @@ func (id sha1) Equal(s2 interface{}) bool {
|
|||
return false
|
||||
}
|
||||
}
|
||||
case sha1:
|
||||
case SHA1:
|
||||
for i, v := range v {
|
||||
if id[i] != v {
|
||||
return false
|
||||
|
@ -45,42 +47,42 @@ func (id sha1) Equal(s2 interface{}) bool {
|
|||
}
|
||||
|
||||
// String returns string (hex) representation of the Oid.
|
||||
func (s sha1) String() string {
|
||||
func (id SHA1) String() string {
|
||||
result := make([]byte, 0, 40)
|
||||
hexvalues := []byte("0123456789abcdef")
|
||||
for i := 0; i < 20; i++ {
|
||||
result = append(result, hexvalues[s[i]>>4])
|
||||
result = append(result, hexvalues[s[i]&0xf])
|
||||
result = append(result, hexvalues[id[i]>>4])
|
||||
result = append(result, hexvalues[id[i]&0xf])
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// MustID always creates a new sha1 from a [20]byte array with no validation of input.
|
||||
func MustID(b []byte) sha1 {
|
||||
var id sha1
|
||||
// MustID always creates a new SHA1 from a [20]byte array with no validation of input.
|
||||
func MustID(b []byte) SHA1 {
|
||||
var id SHA1
|
||||
for i := 0; i < 20; i++ {
|
||||
id[i] = b[i]
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// NewID creates a new sha1 from a [20]byte array.
|
||||
func NewID(b []byte) (sha1, error) {
|
||||
// NewID creates a new SHA1 from a [20]byte array.
|
||||
func NewID(b []byte) (SHA1, error) {
|
||||
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
|
||||
}
|
||||
|
||||
// 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)
|
||||
return MustID(b)
|
||||
}
|
||||
|
||||
// NewIDFromString creates a new sha1 from a ID string of length 40.
|
||||
func NewIDFromString(s string) (sha1, error) {
|
||||
var id sha1
|
||||
// NewIDFromString creates a new SHA1 from a ID string of length 40.
|
||||
func NewIDFromString(s string) (SHA1, error) {
|
||||
var id SHA1
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) != 40 {
|
||||
return id, fmt.Errorf("Length must be 40: %s", s)
|
||||
|
|
|
@ -6,6 +6,7 @@ package git
|
|||
|
||||
import "strings"
|
||||
|
||||
// SubModule submodule is a reference on git repository
|
||||
type SubModule struct {
|
||||
Name string
|
||||
URL string
|
||||
|
@ -19,6 +20,7 @@ type SubModuleFile struct {
|
|||
refID string
|
||||
}
|
||||
|
||||
// NewSubModuleFile create a new submodule file
|
||||
func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile {
|
||||
return &SubModuleFile{
|
||||
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
|
||||
if strings.Contains(urlPrefix, url[i+1:j]) {
|
||||
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
|
||||
|
|
|
@ -9,14 +9,15 @@ import "bytes"
|
|||
// Tag represents a Git tag.
|
||||
type Tag struct {
|
||||
Name string
|
||||
ID sha1
|
||||
ID SHA1
|
||||
repo *Repository
|
||||
Object sha1 // The id of this commit object
|
||||
Object SHA1 // The id of this commit object
|
||||
Type string
|
||||
Tagger *Signature
|
||||
Message string
|
||||
}
|
||||
|
||||
// Commit return the commit of the tag reference
|
||||
func (tag *Tag) Commit() (*Commit, error) {
|
||||
return tag.repo.getCommit(tag.Object)
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
// Tree represents a flat directory listing.
|
||||
type Tree struct {
|
||||
ID sha1
|
||||
ID SHA1
|
||||
repo *Repository
|
||||
|
||||
// parent tree
|
||||
|
@ -22,7 +22,8 @@ type Tree struct {
|
|||
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{
|
||||
ID: id,
|
||||
repo: repo,
|
||||
|
@ -63,22 +64,22 @@ func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
|
|||
step := 6
|
||||
switch string(data[pos : pos+step]) {
|
||||
case "100644":
|
||||
entry.mode = ENTRY_MODE_BLOB
|
||||
entry.Type = OBJECT_BLOB
|
||||
entry.mode = EntryModeBlob
|
||||
entry.Type = ObjectBlob
|
||||
case "100755":
|
||||
entry.mode = ENTRY_MODE_EXEC
|
||||
entry.Type = OBJECT_BLOB
|
||||
entry.mode = EntryModeExec
|
||||
entry.Type = ObjectBlob
|
||||
case "120000":
|
||||
entry.mode = ENTRY_MODE_SYMLINK
|
||||
entry.Type = OBJECT_BLOB
|
||||
entry.mode = EntryModeSymlink
|
||||
entry.Type = ObjectBlob
|
||||
case "160000":
|
||||
entry.mode = ENTRY_MODE_COMMIT
|
||||
entry.Type = OBJECT_COMMIT
|
||||
entry.mode = EntryModeCommit
|
||||
entry.Type = ObjectCommit
|
||||
|
||||
step = 8
|
||||
case "040000":
|
||||
entry.mode = ENTRY_MODE_TREE
|
||||
entry.Type = OBJECT_TREE
|
||||
entry.mode = EntryModeTree
|
||||
entry.Type = ObjectTree
|
||||
default:
|
||||
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
|
||||
}
|
||||
entry.ID = id
|
||||
pos += step + 1 // Skip half of sha1.
|
||||
pos += step + 1 // Skip half of SHA1.
|
||||
|
||||
step = bytes.IndexByte(data[pos:], '\n')
|
||||
|
||||
|
@ -107,6 +108,7 @@ func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
|
|||
return entries, nil
|
||||
}
|
||||
|
||||
// SubTree get a sub tree by the sub dir path
|
||||
func (t *Tree) SubTree(rpath string) (*Tree, error) {
|
||||
if len(rpath) == 0 {
|
||||
return t, nil
|
||||
|
|
|
@ -9,12 +9,13 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// GetTreeEntryByPath get the tree entries accroding the sub dir
|
||||
func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
|
||||
if len(relpath) == 0 {
|
||||
return &TreeEntry{
|
||||
ID: t.ID,
|
||||
Type: OBJECT_TREE,
|
||||
mode: ENTRY_MODE_TREE,
|
||||
Type: ObjectTree,
|
||||
mode: EntryModeTree,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -43,6 +44,7 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
|
|||
return nil, ErrNotExist{"", relpath}
|
||||
}
|
||||
|
||||
// GetBlobByPath get the blob object accroding the path
|
||||
func (t *Tree) GetBlobByPath(relpath string) (*Blob, error) {
|
||||
entry, err := t.GetTreeEntryByPath(relpath)
|
||||
if err != nil {
|
||||
|
|
|
@ -14,20 +14,27 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// EntryMode the type of the object in the git tree
|
||||
type EntryMode int
|
||||
|
||||
// There are only a few file modes in Git. They look like unix file modes, but they can only be
|
||||
// one of these.
|
||||
const (
|
||||
ENTRY_MODE_BLOB EntryMode = 0100644
|
||||
ENTRY_MODE_EXEC EntryMode = 0100755
|
||||
ENTRY_MODE_SYMLINK EntryMode = 0120000
|
||||
ENTRY_MODE_COMMIT EntryMode = 0160000
|
||||
ENTRY_MODE_TREE EntryMode = 0040000
|
||||
// EntryModeBlob
|
||||
EntryModeBlob EntryMode = 0100644
|
||||
// EntryModeExec
|
||||
EntryModeExec EntryMode = 0100755
|
||||
// EntryModeSymlink
|
||||
EntryModeSymlink EntryMode = 0120000
|
||||
// EntryModeCommit
|
||||
EntryModeCommit EntryMode = 0160000
|
||||
// EntryModeTree
|
||||
EntryModeTree EntryMode = 0040000
|
||||
)
|
||||
|
||||
// TreeEntry the leaf in the git tree
|
||||
type TreeEntry struct {
|
||||
ID sha1
|
||||
ID SHA1
|
||||
Type ObjectType
|
||||
|
||||
mode EntryMode
|
||||
|
@ -41,10 +48,12 @@ type TreeEntry struct {
|
|||
sized bool
|
||||
}
|
||||
|
||||
// Name returns the name of the entry
|
||||
func (te *TreeEntry) Name() string {
|
||||
return te.name
|
||||
}
|
||||
|
||||
// Size returns the size of the entry
|
||||
func (te *TreeEntry) Size() int64 {
|
||||
if te.IsDir() {
|
||||
return 0
|
||||
|
@ -62,14 +71,22 @@ func (te *TreeEntry) Size() int64 {
|
|||
return te.size
|
||||
}
|
||||
|
||||
// IsSubModule if the entry is a sub module
|
||||
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 {
|
||||
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 {
|
||||
return &Blob{
|
||||
repo: te.ptree.repo,
|
||||
|
@ -77,6 +94,7 @@ func (te *TreeEntry) Blob() *Blob {
|
|||
}
|
||||
}
|
||||
|
||||
// Entries a list of entry
|
||||
type Entries []*TreeEntry
|
||||
|
||||
var sorter = []func(t1, t2 *TreeEntry) bool{
|
||||
|
@ -105,6 +123,7 @@ func (tes Entries) Less(i, j int) bool {
|
|||
return sorter[k](t1, t2)
|
||||
}
|
||||
|
||||
// Sort sort the list of entry
|
||||
func (tes Entries) Sort() {
|
||||
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.
|
||||
taskChan <- true
|
||||
|
||||
if tes[i].Type != OBJECT_COMMIT {
|
||||
if tes[i].Type != ObjectCommit {
|
||||
go func(i int) {
|
||||
cinfo := commitInfo{entryName: tes[i].Name()}
|
||||
c, err := commit.GetCommitByPath(filepath.Join(treePath, tes[i].Name()))
|
||||
|
|
|
@ -12,26 +12,28 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
// objectCache provides thread-safe cache opeations.
|
||||
type objectCache struct {
|
||||
// ObjectCache provides thread-safe cache opeations.
|
||||
type ObjectCache struct {
|
||||
lock sync.RWMutex
|
||||
cache map[string]interface{}
|
||||
}
|
||||
|
||||
func newObjectCache() *objectCache {
|
||||
return &objectCache{
|
||||
func newObjectCache() *ObjectCache {
|
||||
return &ObjectCache{
|
||||
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()
|
||||
defer oc.lock.Unlock()
|
||||
|
||||
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()
|
||||
defer oc.lock.RUnlock()
|
||||
|
||||
|
@ -80,13 +82,14 @@ func filepathFromSHA1(rootdir, sha1 string) string {
|
|||
return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:])
|
||||
}
|
||||
|
||||
// RefEndName return the end name of a ref name
|
||||
func RefEndName(refStr string) string {
|
||||
if strings.HasPrefix(refStr, BRANCH_PREFIX) {
|
||||
return refStr[len(BRANCH_PREFIX):]
|
||||
if strings.HasPrefix(refStr, BranchPrefix) {
|
||||
return refStr[len(BranchPrefix):]
|
||||
}
|
||||
|
||||
if strings.HasPrefix(refStr, TAG_PREFIX) {
|
||||
return refStr[len(TAG_PREFIX):]
|
||||
if strings.HasPrefix(refStr, TagPrefix) {
|
||||
return refStr[len(TagPrefix):]
|
||||
}
|
||||
|
||||
return refStr
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
"ignore": "test",
|
||||
"package": [
|
||||
{
|
||||
"checksumSHA1": "X4WaxEtgFkM4VHg6TcNk2xkrqCI=",
|
||||
"checksumSHA1": "OWuUWQ8sWC8n+eTQttx+3vfES8g=",
|
||||
"path": "code.gitea.io/git",
|
||||
"revision": "0807b517283977be34f0ff5510b21e676fc1527c",
|
||||
"revisionTime": "2016-11-13T14:20:52Z"
|
||||
"revision": "634abd6a61c350a95f6b146c3a5fc323282608ae",
|
||||
"revisionTime": "2016-12-22T08:49:21Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "KZEYDYPzVc12f0770V++kIHhfa0=",
|
||||
|
|
Loading…
Reference in New Issue