diff options
author | Sandro Santilli <strk@kbt.io> | 2016-11-10 17:24:48 +0100 |
---|---|---|
committer | Thibault Meyer <0xbaadf00d@users.noreply.github.com> | 2016-11-10 17:24:48 +0100 |
commit | 4247304f5aeb791e3e201947478eef4964744146 (patch) | |
tree | 47a27cdaafe235512921fb1aba4a5c6738e4c384 /vendor/code.gitea.io | |
parent | 1c0a4e166fc3c37ebed528fc41b1cbca5a00556d (diff) | |
download | gitea-4247304f5aeb791e3e201947478eef4964744146.tar.gz gitea-4247304f5aeb791e3e201947478eef4964744146.zip |
Update import paths from github.com/go-gitea to code.gitea.io (#135)
- Update import paths from github.com/go-gitea to code.gitea.io
- Fix import path for travis
See https://docs.travis-ci.com/user/languages/go#Go-Import-Path
Diffstat (limited to 'vendor/code.gitea.io')
51 files changed, 3844 insertions, 0 deletions
diff --git a/vendor/code.gitea.io/git/LICENSE b/vendor/code.gitea.io/git/LICENSE new file mode 100644 index 0000000000..176d8dfe01 --- /dev/null +++ b/vendor/code.gitea.io/git/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 All Gogs Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.
\ No newline at end of file diff --git a/vendor/code.gitea.io/git/README.md b/vendor/code.gitea.io/git/README.md new file mode 100644 index 0000000000..b9e34bcf02 --- /dev/null +++ b/vendor/code.gitea.io/git/README.md @@ -0,0 +1,13 @@ +# Git Shell [![Build # Status](https://travis-ci.org/go-gitea/git.svg?branch=master)](https://travis-ci.org/go-gitea/git) + +Package git is a Go module for Git access through shell commands. + +## Limitations + +- Go version must be at least **1.3**. +- Git version must be no less than **1.7.1**, and great than or equal to **1.8.0** is recommended. +- For Windows users, try use as higher version as possible. + +## License + +This project is under the MIT License. See the [LICENSE](LICENSE) file for the full license text. diff --git a/vendor/code.gitea.io/git/blob.go b/vendor/code.gitea.io/git/blob.go new file mode 100644 index 0000000000..478682e715 --- /dev/null +++ b/vendor/code.gitea.io/git/blob.go @@ -0,0 +1,30 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "bytes" + "io" +) + +// Blob represents a Git object. +type Blob struct { + repo *Repository + *TreeEntry +} + +// Data gets content of blob all at once and wrap it as io.Reader. +// This can be very slow and memory consuming for huge content. +func (b *Blob) Data() (io.Reader, error) { + stdout, err := NewCommand("show", b.ID.String()).RunInDirBytes(b.repo.Path) + if err != nil { + return nil, err + } + return bytes.NewBuffer(stdout), nil +} + +func (b *Blob) DataPipeline(stdout, stderr io.Writer) error { + return NewCommand("show", b.ID.String()).RunInDirPipeline(b.repo.Path, stdout, stderr) +} diff --git a/vendor/code.gitea.io/git/command.go b/vendor/code.gitea.io/git/command.go new file mode 100644 index 0000000000..f7fce67bee --- /dev/null +++ b/vendor/code.gitea.io/git/command.go @@ -0,0 +1,139 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "bytes" + "fmt" + "io" + "os/exec" + "strings" + "time" +) + +// Command represents a command with its subcommands or arguments. +type Command struct { + name string + args []string +} + +func (c *Command) String() string { + if len(c.args) == 0 { + return c.name + } + return fmt.Sprintf("%s %s", c.name, strings.Join(c.args, " ")) +} + +// NewCommand creates and returns a new Git Command based on given command and arguments. +func NewCommand(args ...string) *Command { + return &Command{ + name: "git", + args: args, + } +} + +// AddArguments adds new argument(s) to the command. +func (c *Command) AddArguments(args ...string) *Command { + c.args = append(c.args, args...) + 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 + } + + if len(dir) == 0 { + log(c.String()) + } else { + log("%s: %v", dir, c) + } + + cmd := exec.Command(c.name, c.args...) + cmd.Dir = dir + cmd.Stdout = stdout + cmd.Stderr = stderr + if err := cmd.Start(); err != nil { + return err + } + + done := make(chan error) + go func() { + done <- cmd.Wait() + }() + + var err error + select { + case <-time.After(timeout): + if cmd.Process != nil && cmd.ProcessState != nil && !cmd.ProcessState.Exited() { + if err := cmd.Process.Kill(); err != nil { + return fmt.Errorf("fail to kill process: %v", err) + } + } + + <-done + return ErrExecTimeout{timeout} + case err = <-done: + } + + return err +} + +// RunInDirTimeout executes the command in given directory with given timeout, +// and returns stdout in []byte and error (combined with stderr). +func (c *Command) RunInDirTimeout(timeout time.Duration, dir string) ([]byte, error) { + stdout := new(bytes.Buffer) + stderr := new(bytes.Buffer) + if err := c.RunInDirTimeoutPipeline(timeout, dir, stdout, stderr); err != nil { + return nil, concatenateError(err, stderr.String()) + } + + if stdout.Len() > 0 { + log("stdout:\n%s", stdout.Bytes()[:1024]) + } + return stdout.Bytes(), nil +} + +// RunInDirPipeline executes the command in given directory, +// it pipes stdout and stderr to given io.Writer. +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 +// and returns stdout in []byte and error (combined with stderr). +func (c *Command) RunInDirBytes(dir string) ([]byte, error) { + return c.RunInDirTimeout(-1, dir) +} + +// RunInDir executes the command in given directory +// and returns stdout in string and error (combined with stderr). +func (c *Command) RunInDir(dir string) (string, error) { + stdout, err := c.RunInDirTimeout(-1, dir) + if err != nil { + return "", err + } + return string(stdout), nil +} + +// RunTimeout executes the command in defualt working directory with given timeout, +// and returns stdout in string and error (combined with stderr). +func (c *Command) RunTimeout(timeout time.Duration) (string, error) { + stdout, err := c.RunInDirTimeout(timeout, "") + if err != nil { + return "", err + } + return string(stdout), nil +} + +// Run executes the command in defualt working directory +// and returns stdout in string and error (combined with stderr). +func (c *Command) Run() (string, error) { + return c.RunTimeout(-1) +} diff --git a/vendor/code.gitea.io/git/commit.go b/vendor/code.gitea.io/git/commit.go new file mode 100644 index 0000000000..e16246f982 --- /dev/null +++ b/vendor/code.gitea.io/git/commit.go @@ -0,0 +1,250 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "bufio" + "container/list" + "fmt" + "net/http" + "strconv" + "strings" + + "github.com/mcuadros/go-version" +) + +// Commit represents a git commit. +type Commit struct { + Tree + ID sha1 // The ID of this commit object + Author *Signature + Committer *Signature + CommitMessage string + + parents []sha1 // SHA1 strings + submoduleCache *objectCache +} + +// Message returns the commit message. Same as retrieving CommitMessage directly. +func (c *Commit) Message() string { + return c.CommitMessage +} + +// Summary returns first line of commit message. +func (c *Commit) Summary() string { + return strings.Split(c.CommitMessage, "\n")[0] +} + +// 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) { + if n >= len(c.parents) { + return sha1{}, ErrNotExist{"", ""} + } + return c.parents[n], nil +} + +// Parent returns n-th parent (0-based index) of the commit. +func (c *Commit) Parent(n int) (*Commit, error) { + id, err := c.ParentID(n) + if err != nil { + return nil, err + } + parent, err := c.repo.getCommit(id) + if err != nil { + return nil, err + } + return parent, nil +} + +// ParentCount returns number of parents of the commit. +// 0 if this is the root commit, otherwise 1,2, etc. +func (c *Commit) ParentCount() int { + return len(c.parents) +} + +func isImageFile(data []byte) (string, bool) { + contentType := http.DetectContentType(data) + if strings.Index(contentType, "image/") != -1 { + return contentType, true + } + return contentType, false +} + +func (c *Commit) IsImageFile(name string) bool { + blob, err := c.GetBlobByPath(name) + if err != nil { + return false + } + + dataRc, err := blob.Data() + if err != nil { + return false + } + buf := make([]byte, 1024) + n, _ := dataRc.Read(buf) + buf = buf[:n] + _, isImage := isImageFile(buf) + return isImage +} + +// GetCommitByPath return the commit of relative path object. +func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) { + return c.repo.getCommitByPathWithID(c.ID, relpath) +} + +// AddAllChanges marks local changes to be ready for commit. +func AddChanges(repoPath string, all bool, files ...string) error { + cmd := NewCommand("add") + if all { + cmd.AddArguments("--all") + } + _, err := cmd.AddArguments(files...).RunInDir(repoPath) + return err +} + +type CommitChangesOptions struct { + Committer *Signature + Author *Signature + Message string +} + +// CommitChanges commits local changes with given committer, author and message. +// If author is nil, it will be the same as committer. +func CommitChanges(repoPath string, opts CommitChangesOptions) error { + cmd := NewCommand() + if opts.Committer != nil { + cmd.AddArguments("-c", "user.name="+opts.Committer.Name, "-c", "user.email="+opts.Committer.Email) + } + cmd.AddArguments("commit") + + if opts.Author == nil { + opts.Author = opts.Committer + } + if opts.Author != nil { + cmd.AddArguments(fmt.Sprintf("--author='%s <%s>'", opts.Author.Name, opts.Author.Email)) + } + cmd.AddArguments("-m", opts.Message) + + _, err := cmd.RunInDir(repoPath) + // No stderr but exit status 1 means nothing to commit. + if err != nil && err.Error() == "exit status 1" { + return nil + } + return err +} + +func commitsCount(repoPath, revision, relpath string) (int64, error) { + var cmd *Command + isFallback := false + if version.Compare(gitVersion, "1.8.0", "<") { + isFallback = true + cmd = NewCommand("log", "--pretty=format:''") + } else { + cmd = NewCommand("rev-list", "--count") + } + cmd.AddArguments(revision) + if len(relpath) > 0 { + cmd.AddArguments("--", relpath) + } + + stdout, err := cmd.RunInDir(repoPath) + if err != nil { + return 0, err + } + + if isFallback { + return int64(strings.Count(stdout, "\n")) + 1, nil + } + return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64) +} + +// CommitsCount returns number of total commits of until given revision. +func CommitsCount(repoPath, revision string) (int64, error) { + return commitsCount(repoPath, revision, "") +} + +func (c *Commit) CommitsCount() (int64, error) { + return CommitsCount(c.repo.Path, c.ID.String()) +} + +func (c *Commit) CommitsByRange(page int) (*list.List, error) { + return c.repo.commitsByRange(c.ID, page) +} + +func (c *Commit) CommitsBefore() (*list.List, error) { + return c.repo.getCommitsBefore(c.ID) +} + +func (c *Commit) CommitsBeforeLimit(num int) (*list.List, error) { + return c.repo.getCommitsBeforeLimit(c.ID, num) +} + +func (c *Commit) CommitsBeforeUntil(commitID string) (*list.List, error) { + endCommit, err := c.repo.GetCommit(commitID) + if err != nil { + return nil, err + } + return c.repo.CommitsBetween(c, endCommit) +} + +func (c *Commit) SearchCommits(keyword string) (*list.List, error) { + return c.repo.searchCommits(c.ID, keyword) +} + +func (c *Commit) GetFilesChangedSinceCommit(pastCommit string) ([]string, error) { + return c.repo.getFilesChanged(pastCommit, c.ID.String()) +} + +func (c *Commit) GetSubModules() (*objectCache, error) { + if c.submoduleCache != nil { + return c.submoduleCache, nil + } + + entry, err := c.GetTreeEntryByPath(".gitmodules") + if err != nil { + return nil, err + } + rd, err := entry.Blob().Data() + if err != nil { + return nil, err + } + + scanner := bufio.NewScanner(rd) + c.submoduleCache = newObjectCache() + var ismodule bool + var path string + for scanner.Scan() { + if strings.HasPrefix(scanner.Text(), "[submodule") { + ismodule = true + continue + } + if ismodule { + fields := strings.Split(scanner.Text(), "=") + k := strings.TrimSpace(fields[0]) + if k == "path" { + path = strings.TrimSpace(fields[1]) + } else if k == "url" { + c.submoduleCache.Set(path, &SubModule{path, strings.TrimSpace(fields[1])}) + ismodule = false + } + } + } + + return c.submoduleCache, nil +} + +func (c *Commit) GetSubModule(entryname string) (*SubModule, error) { + modules, err := c.GetSubModules() + if err != nil { + return nil, err + } + + module, has := modules.Get(entryname) + if has { + return module.(*SubModule), nil + } + return nil, nil +} diff --git a/vendor/code.gitea.io/git/commit_archive.go b/vendor/code.gitea.io/git/commit_archive.go new file mode 100644 index 0000000000..1066ba69c4 --- /dev/null +++ b/vendor/code.gitea.io/git/commit_archive.go @@ -0,0 +1,33 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "fmt" + "path/filepath" + "strings" +) + +type ArchiveType int + +const ( + ZIP ArchiveType = iota + 1 + TARGZ +) + +func (c *Commit) CreateArchive(target string, archiveType ArchiveType) error { + var format string + switch archiveType { + case ZIP: + format = "zip" + case TARGZ: + format = "tar.gz" + default: + return fmt.Errorf("unknown format: %v", archiveType) + } + + _, err := NewCommand("archive", "--prefix="+filepath.Base(strings.TrimSuffix(c.repo.Path, ".git"))+"/", "--format="+format, "-o", target, c.ID.String()).RunInDir(c.repo.Path) + return err +} diff --git a/vendor/code.gitea.io/git/error.go b/vendor/code.gitea.io/git/error.go new file mode 100644 index 0000000000..848bfba127 --- /dev/null +++ b/vendor/code.gitea.io/git/error.go @@ -0,0 +1,50 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "fmt" + "time" +) + +type ErrExecTimeout struct { + Duration time.Duration +} + +func IsErrExecTimeout(err error) bool { + _, ok := err.(ErrExecTimeout) + return ok +} + +func (err ErrExecTimeout) Error() string { + return fmt.Sprintf("execution is timeout [duration: %v]", err.Duration) +} + +type ErrNotExist struct { + ID string + RelPath string +} + +func IsErrNotExist(err error) bool { + _, ok := err.(ErrNotExist) + return ok +} + +func (err ErrNotExist) Error() string { + return fmt.Sprintf("object does not exist [id: %s, rel_path: %s]", err.ID, err.RelPath) +} + +type ErrUnsupportedVersion struct { + Required string +} + +func IsErrUnsupportedVersion(err error) bool { + _, ok := err.(ErrUnsupportedVersion) + return ok +} + +func (err ErrUnsupportedVersion) Error() string { + return fmt.Sprintf("Operation requires higher version [required: %s]", err.Required) +} diff --git a/vendor/code.gitea.io/git/git.go b/vendor/code.gitea.io/git/git.go new file mode 100644 index 0000000000..71a9a37f42 --- /dev/null +++ b/vendor/code.gitea.io/git/git.go @@ -0,0 +1,80 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "fmt" + "strings" + "time" +) + +const _VERSION = "0.4.2" + +func Version() string { + return _VERSION +} + +var ( + // Debug enables verbose logging on everything. + // This should be false in case Gogs starts in SSH mode. + Debug = false + Prefix = "[git-module] " +) + +func log(format string, args ...interface{}) { + if !Debug { + return + } + + fmt.Print(Prefix) + if len(args) == 0 { + fmt.Println(format) + } else { + fmt.Printf(format+"\n", args...) + } +} + +var gitVersion string + +// Version returns current Git version from shell. +func BinVersion() (string, error) { + if len(gitVersion) > 0 { + return gitVersion, nil + } + + stdout, err := NewCommand("version").Run() + if err != nil { + return "", err + } + + fields := strings.Fields(stdout) + if len(fields) < 3 { + return "", fmt.Errorf("not enough output: %s", stdout) + } + + // Handle special case on Windows. + i := strings.Index(fields[2], "windows") + if i >= 1 { + gitVersion = fields[2][:i-1] + return gitVersion, nil + } + + gitVersion = fields[2] + return gitVersion, nil +} + +func init() { + BinVersion() +} + +// Fsck verifies the connectivity and validity of the objects in the database +func Fsck(repoPath string, timeout time.Duration, args ...string) error { + // Make sure timeout makes sense. + if timeout <= 0 { + timeout = -1 + } + _, err := NewCommand("fsck").AddArguments(args...).RunInDirTimeout(timeout, repoPath) + return err +} diff --git a/vendor/code.gitea.io/git/hook.go b/vendor/code.gitea.io/git/hook.go new file mode 100644 index 0000000000..086bf7126d --- /dev/null +++ b/vendor/code.gitea.io/git/hook.go @@ -0,0 +1,121 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "errors" + "io/ioutil" + "os" + "path" + "strings" + + "github.com/Unknwon/com" +) + +// hookNames is a list of Git server hooks' name that are supported. +var hookNames = []string{ + "pre-receive", + // "update", + "post-receive", +} + +var ( + ErrNotValidHook = errors.New("not a valid Git hook") +) + +// IsValidHookName returns true if given name is a valid Git hook. +func IsValidHookName(name string) bool { + for _, hn := range hookNames { + if hn == name { + return true + } + } + return false +} + +// Hook represents a Git hook. +type Hook struct { + name string + IsActive bool // Indicates whether repository has this hook. + Content string // Content of hook if it's active. + Sample string // Sample content from Git. + path string // Hook file path. +} + +// GetHook returns a Git hook by given name and repository. +func GetHook(repoPath, name string) (*Hook, error) { + if !IsValidHookName(name) { + return nil, ErrNotValidHook + } + h := &Hook{ + name: name, + path: path.Join(repoPath, "hooks", name), + } + if isFile(h.path) { + data, err := ioutil.ReadFile(h.path) + if err != nil { + return nil, err + } + h.IsActive = true + h.Content = string(data) + } else if isFile(h.path + ".sample") { + data, err := ioutil.ReadFile(h.path + ".sample") + if err != nil { + return nil, err + } + h.Sample = string(data) + } + return h, nil +} + +func (h *Hook) Name() string { + return h.name +} + +// Update updates hook settings. +func (h *Hook) Update() error { + if len(strings.TrimSpace(h.Content)) == 0 { + if isExist(h.path) { + return os.Remove(h.path) + } + return nil + } + return ioutil.WriteFile(h.path, []byte(strings.Replace(h.Content, "\r", "", -1)), os.ModePerm) +} + +// ListHooks returns a list of Git hooks of given repository. +func ListHooks(repoPath string) (_ []*Hook, err error) { + if !isDir(path.Join(repoPath, "hooks")) { + return nil, errors.New("hooks path does not exist") + } + + hooks := make([]*Hook, len(hookNames)) + for i, name := range hookNames { + hooks[i], err = GetHook(repoPath, name) + if err != nil { + return nil, err + } + } + return hooks, nil +} + +const ( + HookPathUpdate = "hooks/update" +) + +// SetUpdateHook writes given content to update hook of the reposiotry. +func SetUpdateHook(repoPath, content string) (err error) { + log("Setting update hook: %s", repoPath) + hookPath := path.Join(repoPath, HookPathUpdate) + if com.IsExist(hookPath) { + err = os.Remove(hookPath) + } else { + err = os.MkdirAll(path.Dir(hookPath), os.ModePerm) + } + if err != nil { + return err + } + return ioutil.WriteFile(hookPath, []byte(content), 0777) +} diff --git a/vendor/code.gitea.io/git/repo.go b/vendor/code.gitea.io/git/repo.go new file mode 100644 index 0000000000..bfc2cbe7c8 --- /dev/null +++ b/vendor/code.gitea.io/git/repo.go @@ -0,0 +1,193 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "bytes" + "container/list" + "errors" + "os" + "path" + "path/filepath" + "time" +) + +// Repository represents a Git repository. +type Repository struct { + Path string + + commitCache *objectCache + tagCache *objectCache +} + +const _PRETTY_LOG_FORMAT = `--pretty=format:%H` + +func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, error) { + l := list.New() + if len(logs) == 0 { + return l, nil + } + + parts := bytes.Split(logs, []byte{'\n'}) + + for _, commitId := range parts { + commit, err := repo.GetCommit(string(commitId)) + if err != nil { + return nil, err + } + l.PushBack(commit) + } + + return l, nil +} + +// IsRepoURLAccessible checks if given repository URL is accessible. +func IsRepoURLAccessible(url string) bool { + _, err := NewCommand("ls-remote", "-q", "-h", url, "HEAD").Run() + if err != nil { + return false + } + return true +} + +// InitRepository initializes a new Git repository. +func InitRepository(repoPath string, bare bool) error { + os.MkdirAll(repoPath, os.ModePerm) + + cmd := NewCommand("init") + if bare { + cmd.AddArguments("--bare") + } + _, err := cmd.RunInDir(repoPath) + return err +} + +// OpenRepository opens the repository at the given path. +func OpenRepository(repoPath string) (*Repository, error) { + repoPath, err := filepath.Abs(repoPath) + if err != nil { + return nil, err + } else if !isDir(repoPath) { + return nil, errors.New("no such file or directory") + } + + return &Repository{ + Path: repoPath, + commitCache: newObjectCache(), + tagCache: newObjectCache(), + }, nil +} + +type CloneRepoOptions struct { + Timeout time.Duration + Mirror bool + Bare bool + Quiet bool + Branch string +} + +// Clone clones original repository to target path. +func Clone(from, to string, opts CloneRepoOptions) (err error) { + toDir := path.Dir(to) + if err = os.MkdirAll(toDir, os.ModePerm); err != nil { + return err + } + + cmd := NewCommand("clone") + if opts.Mirror { + cmd.AddArguments("--mirror") + } + if opts.Bare { + cmd.AddArguments("--bare") + } + if opts.Quiet { + cmd.AddArguments("--quiet") + } + if len(opts.Branch) > 0 { + cmd.AddArguments("-b", opts.Branch) + } + cmd.AddArguments(from, to) + + if opts.Timeout <= 0 { + opts.Timeout = -1 + } + + _, err = cmd.RunTimeout(opts.Timeout) + return err +} + +type PullRemoteOptions struct { + Timeout time.Duration + All bool + Remote string + Branch string +} + +// Pull pulls changes from remotes. +func Pull(repoPath string, opts PullRemoteOptions) error { + cmd := NewCommand("pull") + if opts.All { + cmd.AddArguments("--all") + } else { + cmd.AddArguments(opts.Remote) + cmd.AddArguments(opts.Branch) + } + + if opts.Timeout <= 0 { + opts.Timeout = -1 + } + + _, err := cmd.RunInDirTimeout(opts.Timeout, repoPath) + return err +} + +// Push pushs local commits to given remote branch. +func Push(repoPath, remote, branch string) error { + _, err := NewCommand("push", remote, branch).RunInDir(repoPath) + return err +} + +type CheckoutOptions struct { + Timeout time.Duration + Branch string + OldBranch string +} + +// Checkout checkouts a branch +func Checkout(repoPath string, opts CheckoutOptions) error { + cmd := NewCommand("checkout") + if len(opts.OldBranch) > 0 { + cmd.AddArguments("-b") + } + + if opts.Timeout <= 0 { + opts.Timeout = -1 + } + + cmd.AddArguments(opts.Branch) + + if len(opts.OldBranch) > 0 { + cmd.AddArguments(opts.OldBranch) + } + + _, err := cmd.RunInDirTimeout(opts.Timeout, repoPath) + return err +} + +// ResetHEAD resets HEAD to given revision or head of branch. +func ResetHEAD(repoPath string, hard bool, revision string) error { + cmd := NewCommand("reset") + if hard { + cmd.AddArguments("--hard") + } + _, err := cmd.AddArguments(revision).RunInDir(repoPath) + return err +} + +// MoveFile moves a file to another file or directory. +func MoveFile(repoPath, oldTreeName, newTreeName string) error { + _, err := NewCommand("mv").AddArguments(oldTreeName, newTreeName).RunInDir(repoPath) + return err +} diff --git a/vendor/code.gitea.io/git/repo_branch.go b/vendor/code.gitea.io/git/repo_branch.go new file mode 100644 index 0000000000..f7252bb0e9 --- /dev/null +++ b/vendor/code.gitea.io/git/repo_branch.go @@ -0,0 +1,119 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "fmt" + "strings" + + "github.com/mcuadros/go-version" +) + +const BRANCH_PREFIX = "refs/heads/" + +// IsReferenceExist returns true if given reference exists in the repository. +func IsReferenceExist(repoPath, name string) bool { + _, err := NewCommand("show-ref", "--verify", name).RunInDir(repoPath) + return err == nil +} + +// IsBranchExist returns true if given branch exists in the repository. +func IsBranchExist(repoPath, name string) bool { + return IsReferenceExist(repoPath, BRANCH_PREFIX+name) +} + +func (repo *Repository) IsBranchExist(name string) bool { + return IsBranchExist(repo.Path, name) +} + +// Branch represents a Git branch. +type Branch struct { + Name string + Path string +} + +// GetHEADBranch returns corresponding branch of HEAD. +func (repo *Repository) GetHEADBranch() (*Branch, error) { + stdout, err := NewCommand("symbolic-ref", "HEAD").RunInDir(repo.Path) + if err != nil { + return nil, err + } + stdout = strings.TrimSpace(stdout) + + if !strings.HasPrefix(stdout, BRANCH_PREFIX) { + return nil, fmt.Errorf("invalid HEAD branch: %v", stdout) + } + + return &Branch{ + Name: stdout[len(BRANCH_PREFIX):], + Path: stdout, + }, nil +} + +// SetDefaultBranch sets default branch of repository. +func (repo *Repository) SetDefaultBranch(name string) error { + if version.Compare(gitVersion, "1.7.10", "<") { + return ErrUnsupportedVersion{"1.7.10"} + } + + _, err := NewCommand("symbolic-ref", "HEAD", BRANCH_PREFIX+name).RunInDir(repo.Path) + return err +} + +// GetBranches returns all branches of the repository. +func (repo *Repository) GetBranches() ([]string, error) { + stdout, err := NewCommand("show-ref", "--heads").RunInDir(repo.Path) + if err != nil { + return nil, err + } + + infos := strings.Split(stdout, "\n") + branches := make([]string, len(infos)-1) + for i, info := range infos[:len(infos)-1] { + fields := strings.Fields(info) + if len(fields) != 2 { + continue // NOTE: I should believe git will not give me wrong string. + } + branches[i] = strings.TrimPrefix(fields[1], BRANCH_PREFIX) + } + return branches, nil +} + +// Option(s) for delete branch +type DeleteBranchOptions struct { + Force bool +} + +// DeleteBranch delete a branch by name on repository. +func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) error { + cmd := NewCommand("branch", "-d") + + if opts.Force { + cmd.AddArguments("-f") + } + + cmd.AddArguments(name) + _, err := cmd.RunInDir(repo.Path) + + return err +} + +// AddRemote adds a new remote to repository. +func (repo *Repository) AddRemote(name, url string, fetch bool) error { + cmd := NewCommand("remote", "add") + if fetch { + cmd.AddArguments("-f") + } + cmd.AddArguments(name, url) + + _, err := cmd.RunInDir(repo.Path) + return err +} + +// RemoveRemote removes a remote from repository. +func (repo *Repository) RemoveRemote(name string) error { + _, err := NewCommand("remote", "remove", name).RunInDir(repo.Path) + return err +} diff --git a/vendor/code.gitea.io/git/repo_commit.go b/vendor/code.gitea.io/git/repo_commit.go new file mode 100644 index 0000000000..1e7e51a8f2 --- /dev/null +++ b/vendor/code.gitea.io/git/repo_commit.go @@ -0,0 +1,353 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "bytes" + "container/list" + "fmt" + "strconv" + "strings" + + "github.com/mcuadros/go-version" +) + +// getRefCommitID returns the last commit ID string of given reference (branch or tag). +func (repo *Repository) getRefCommitID(name string) (string, error) { + stdout, err := NewCommand("show-ref", "--verify", name).RunInDir(repo.Path) + if err != nil { + if strings.Contains(err.Error(), "not a valid ref") { + return "", ErrNotExist{name, ""} + } + return "", err + } + return strings.Split(stdout, " ")[0], nil +} + +// GetBranchCommitID returns last commit ID string of given branch. +func (repo *Repository) GetBranchCommitID(name string) (string, error) { + return repo.getRefCommitID(BRANCH_PREFIX + name) +} + +// GetTagCommitID returns last commit ID string of given tag. +func (repo *Repository) GetTagCommitID(name string) (string, error) { + return repo.getRefCommitID(TAG_PREFIX + name) +} + +// parseCommitData parses commit information from the (uncompressed) raw +// data from the commit object. +// \n\n separate headers from message +func parseCommitData(data []byte) (*Commit, error) { + commit := new(Commit) + commit.parents = make([]sha1, 0, 1) + // we now have the contents of the commit object. Let's investigate... + nextline := 0 +l: + for { + eol := bytes.IndexByte(data[nextline:], '\n') + switch { + case eol > 0: + line := data[nextline : nextline+eol] + spacepos := bytes.IndexByte(line, ' ') + reftype := line[:spacepos] + switch string(reftype) { + case "tree", "object": + id, err := NewIDFromString(string(line[spacepos+1:])) + if err != nil { + return nil, err + } + commit.Tree.ID = id + case "parent": + // A commit can have one or more parents + oid, err := NewIDFromString(string(line[spacepos+1:])) + if err != nil { + return nil, err + } + commit.parents = append(commit.parents, oid) + case "author", "tagger": + sig, err := newSignatureFromCommitline(line[spacepos+1:]) + if err != nil { + return nil, err + } + commit.Author = sig + case "committer": + sig, err := newSignatureFromCommitline(line[spacepos+1:]) + if err != nil { + return nil, err + } + commit.Committer = sig + } + nextline += eol + 1 + case eol == 0: + commit.CommitMessage = string(data[nextline+1:]) + break l + default: + break l + } + } + return commit, nil +} + +func (repo *Repository) getCommit(id sha1) (*Commit, error) { + c, ok := repo.commitCache.Get(id.String()) + if ok { + log("Hit cache: %s", id) + return c.(*Commit), nil + } + + data, err := NewCommand("cat-file", "-p", id.String()).RunInDirBytes(repo.Path) + if err != nil { + if strings.Contains(err.Error(), "fatal: Not a valid object name") { + return nil, ErrNotExist{id.String(), ""} + } + return nil, err + } + + commit, err := parseCommitData(data) + if err != nil { + return nil, err + } + commit.repo = repo + commit.ID = id + + repo.commitCache.Set(id.String(), commit) + return commit, nil +} + +// GetCommit returns commit object of by ID string. +func (repo *Repository) GetCommit(commitID string) (*Commit, error) { + if len(commitID) != 40 { + var err error + commitID, err = NewCommand("rev-parse", commitID).RunInDir(repo.Path) + if err != nil { + return nil, err + } + } + id, err := NewIDFromString(commitID) + if err != nil { + return nil, err + } + + return repo.getCommit(id) +} + +// GetBranchCommit returns the last commit of given branch. +func (repo *Repository) GetBranchCommit(name string) (*Commit, error) { + commitID, err := repo.GetBranchCommitID(name) + if err != nil { + return nil, err + } + return repo.GetCommit(commitID) +} + +func (repo *Repository) GetTagCommit(name string) (*Commit, error) { + commitID, err := repo.GetTagCommitID(name) + if err != nil { + return nil, err + } + return repo.GetCommit(commitID) +} + +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) + if err != nil { + return nil, err + } + + id, err = NewIDFromString(stdout) + if err != nil { + return nil, err + } + + return repo.getCommit(id) +} + +// 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) + if err != nil { + return nil, err + } + + commits, err := repo.parsePrettyFormatLogToList(stdout) + if err != nil { + return nil, err + } + return commits.Front().Value.(*Commit), nil +} + +var CommitsRangeSize = 50 + +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) + 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) + if err != nil { + return nil, err + } + return repo.parsePrettyFormatLogToList(stdout) +} + +func (repo *Repository) getFilesChanged(id1 string, id2 string) ([]string, error) { + stdout, err := NewCommand("diff", "--name-only", id1, id2).RunInDirBytes(repo.Path) + if err != nil { + return nil, err + } + return strings.Split(string(stdout), "\n"), nil +} + +func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) { + return commitsCount(repo.Path, revision, file) +} + +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) + if err != nil { + return nil, err + } + return repo.parsePrettyFormatLogToList(stdout) +} + +func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) { + stdout, err := NewCommand("diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path) + if err != nil { + return 0, err + } + return len(strings.Split(stdout, "\n")) - 1, nil +} + +// CommitsBetween returns a list that contains commits between [last, before). +func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List, error) { + if version.Compare(gitVersion, "1.8.0", ">=") { + stdout, err := NewCommand("rev-list", before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path) + if err != nil { + return nil, err + } + return repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout)) + } + + // Fallback to stupid solution, which iterates all commits of the repository + // if before is not an ancestor of last. + l := list.New() + if last == nil || last.ParentCount() == 0 { + return l, nil + } + + var err error + cur := last + for { + if cur.ID.Equal(before.ID) { + break + } + l.PushBack(cur) + if cur.ParentCount() == 0 { + break + } + cur, err = cur.Parent(0) + if err != nil { + return nil, err + } + } + return l, nil +} + +func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, error) { + lastCommit, err := repo.GetCommit(last) + if err != nil { + return nil, err + } + beforeCommit, err := repo.GetCommit(before) + if err != nil { + return nil, err + } + return repo.CommitsBetween(lastCommit, beforeCommit) +} + +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 { + // Reach the limit + if limit > 0 && current > limit { + return nil + } + + commit, err := repo.getCommit(id) + if err != nil { + return fmt.Errorf("getCommit: %v", err) + } + + var e *list.Element + if parent == nil { + e = l.PushBack(commit) + } else { + var in = parent + for { + if in == nil { + break + } else if in.Value.(*Commit).ID.Equal(commit.ID) { + return nil + } else if in.Next() == nil { + break + } + + if in.Value.(*Commit).Committer.When.Equal(commit.Committer.When) { + break + } + + if in.Value.(*Commit).Committer.When.After(commit.Committer.When) && + in.Next().Value.(*Commit).Committer.When.Before(commit.Committer.When) { + break + } + + in = in.Next() + } + + e = l.InsertAfter(commit, in) + } + + pr := parent + if commit.ParentCount() > 1 { + pr = e + } + + for i := 0; i < commit.ParentCount(); i++ { + id, err := commit.ParentID(i) + if err != nil { + return err + } + err = repo.commitsBefore(l, pr, id, current+1, limit) + if err != nil { + return err + } + } + + return nil +} + +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) { + l := list.New() + return l, repo.commitsBefore(l, nil, id, 1, num) +} diff --git a/vendor/code.gitea.io/git/repo_hook.go b/vendor/code.gitea.io/git/repo_hook.go new file mode 100644 index 0000000000..7b49647e3c --- /dev/null +++ b/vendor/code.gitea.io/git/repo_hook.go @@ -0,0 +1,13 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +func (repo *Repository) GetHook(name string) (*Hook, error) { + return GetHook(repo.Path, name) +} + +func (repo *Repository) Hooks() ([]*Hook, error) { + return ListHooks(repo.Path) +} diff --git a/vendor/code.gitea.io/git/repo_object.go b/vendor/code.gitea.io/git/repo_object.go new file mode 100644 index 0000000000..416ee4591a --- /dev/null +++ b/vendor/code.gitea.io/git/repo_object.go @@ -0,0 +1,14 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +type ObjectType string + +const ( + OBJECT_COMMIT ObjectType = "commit" + OBJECT_TREE ObjectType = "tree" + OBJECT_BLOB ObjectType = "blob" + OBJECT_TAG ObjectType = "tag" +) diff --git a/vendor/code.gitea.io/git/repo_pull.go b/vendor/code.gitea.io/git/repo_pull.go new file mode 100644 index 0000000000..1b0c1cf432 --- /dev/null +++ b/vendor/code.gitea.io/git/repo_pull.go @@ -0,0 +1,75 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "container/list" + "fmt" + "strconv" + "strings" + "time" +) + +// PullRequestInfo represents needed information for a pull request. +type PullRequestInfo struct { + MergeBase string + Commits *list.List + NumFiles int +} + +// GetMergeBase checks and returns merge base of two branches. +func (repo *Repository) GetMergeBase(base, head string) (string, error) { + stdout, err := NewCommand("merge-base", base, head).RunInDir(repo.Path) + return strings.TrimSpace(stdout), err +} + +// GetPullRequestInfo generates and returns pull request information +// between base and head branches of repositories. +func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch string) (_ *PullRequestInfo, err error) { + var remoteBranch string + + // We don't need a temporary remote for same repository. + if repo.Path != basePath { + // Add a temporary remote + tmpRemote := strconv.FormatInt(time.Now().UnixNano(), 10) + if err = repo.AddRemote(tmpRemote, basePath, true); err != nil { + return nil, fmt.Errorf("AddRemote: %v", err) + } + defer repo.RemoveRemote(tmpRemote) + + remoteBranch = "remotes/" + tmpRemote + "/" + baseBranch + } else { + remoteBranch = baseBranch + } + + prInfo := new(PullRequestInfo) + prInfo.MergeBase, err = repo.GetMergeBase(remoteBranch, headBranch) + if err != nil { + return nil, fmt.Errorf("GetMergeBase: %v", err) + } + + logs, err := NewCommand("log", prInfo.MergeBase+"..."+headBranch, _PRETTY_LOG_FORMAT).RunInDirBytes(repo.Path) + if err != nil { + return nil, err + } + prInfo.Commits, err = repo.parsePrettyFormatLogToList(logs) + if err != nil { + return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err) + } + + // Count number of changed files. + stdout, err := NewCommand("diff", "--name-only", remoteBranch+"..."+headBranch).RunInDir(repo.Path) + if err != nil { + return nil, err + } + prInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1 + + return prInfo, nil +} + +// GetPatch generates and returns patch data between given revisions. +func (repo *Repository) GetPatch(base, head string) ([]byte, error) { + return NewCommand("diff", "-p", "--binary", base, head).RunInDirBytes(repo.Path) +} diff --git a/vendor/code.gitea.io/git/repo_tag.go b/vendor/code.gitea.io/git/repo_tag.go new file mode 100644 index 0000000000..b69bbf8b37 --- /dev/null +++ b/vendor/code.gitea.io/git/repo_tag.go @@ -0,0 +1,120 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "strings" + + "github.com/mcuadros/go-version" +) + +const TAG_PREFIX = "refs/tags/" + +// IsTagExist returns true if given tag exists in the repository. +func IsTagExist(repoPath, name string) bool { + return IsReferenceExist(repoPath, TAG_PREFIX+name) +} + +func (repo *Repository) IsTagExist(name string) bool { + return IsTagExist(repo.Path, name) +} + +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) { + t, ok := repo.tagCache.Get(id.String()) + if ok { + log("Hit cache: %s", id) + return t.(*Tag), nil + } + + // Get tag type + tp, err := NewCommand("cat-file", "-t", id.String()).RunInDir(repo.Path) + if err != nil { + return nil, err + } + tp = strings.TrimSpace(tp) + + // Tag is a commit. + if ObjectType(tp) == OBJECT_COMMIT { + tag := &Tag{ + ID: id, + Object: id, + Type: string(OBJECT_COMMIT), + repo: repo, + } + + repo.tagCache.Set(id.String(), tag) + return tag, nil + } + + // Tag with message. + data, err := NewCommand("cat-file", "-p", id.String()).RunInDirBytes(repo.Path) + if err != nil { + return nil, err + } + + tag, err := parseTagData(data) + if err != nil { + return nil, err + } + + tag.ID = id + tag.repo = repo + + repo.tagCache.Set(id.String(), tag) + return tag, nil +} + +// GetTag returns a Git tag by given name. +func (repo *Repository) GetTag(name string) (*Tag, error) { + stdout, err := NewCommand("show-ref", "--tags", name).RunInDir(repo.Path) + if err != nil { + return nil, err + } + + id, err := NewIDFromString(strings.Split(stdout, " ")[0]) + if err != nil { + return nil, err + } + + tag, err := repo.getTag(id) + if err != nil { + return nil, err + } + tag.Name = name + return tag, nil +} + +// GetTags returns all tags of the repository. +func (repo *Repository) GetTags() ([]string, error) { + cmd := NewCommand("tag", "-l") + if version.Compare(gitVersion, "2.0.0", ">=") { + cmd.AddArguments("--sort=-v:refname") + } + + stdout, err := cmd.RunInDir(repo.Path) + if err != nil { + return nil, err + } + + tags := strings.Split(stdout, "\n") + tags = tags[:len(tags)-1] + + if version.Compare(gitVersion, "2.0.0", "<") { + version.Sort(tags) + + // Reverse order + for i := 0; i < len(tags) / 2; i++ { + j := len(tags) - i - 1 + tags[i], tags[j] = tags[j], tags[i] + } + } + + return tags, nil +} diff --git a/vendor/code.gitea.io/git/repo_tree.go b/vendor/code.gitea.io/git/repo_tree.go new file mode 100644 index 0000000000..baebb25101 --- /dev/null +++ b/vendor/code.gitea.io/git/repo_tree.go @@ -0,0 +1,26 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +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) + if err != nil { + return nil, ErrNotExist{id.String(), ""} + } + } + + return NewTree(repo, id), nil +} + +// Find the tree object in the repository. +func (repo *Repository) GetTree(idStr string) (*Tree, error) { + id, err := NewIDFromString(idStr) + if err != nil { + return nil, err + } + return repo.getTree(id) +} diff --git a/vendor/code.gitea.io/git/sha1.go b/vendor/code.gitea.io/git/sha1.go new file mode 100644 index 0000000000..7744275d85 --- /dev/null +++ b/vendor/code.gitea.io/git/sha1.go @@ -0,0 +1,93 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "encoding/hex" + "fmt" + "strings" +) + +const EMPTY_SHA = "0000000000000000000000000000000000000000" + +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 { + switch v := s2.(type) { + case string: + if len(v) != 40 { + return false + } + return v == id.String() + case []byte: + if len(v) != 20 { + return false + } + for i, v := range v { + if id[i] != v { + return false + } + } + case sha1: + for i, v := range v { + if id[i] != v { + return false + } + } + default: + return false + } + return true +} + +// String returns string (hex) representation of the Oid. +func (s 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]) + } + 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 + 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) { + if len(b) != 20 { + 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 { + 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 + s = strings.TrimSpace(s) + if len(s) != 40 { + return id, fmt.Errorf("Length must be 40: %s", s) + } + b, err := hex.DecodeString(s) + if err != nil { + return id, err + } + return NewID(b) +} diff --git a/vendor/code.gitea.io/git/signature.go b/vendor/code.gitea.io/git/signature.go new file mode 100644 index 0000000000..95eb1bbe07 --- /dev/null +++ b/vendor/code.gitea.io/git/signature.go @@ -0,0 +1,48 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "bytes" + "strconv" + "time" +) + +// Signature represents the Author or Committer information. +type Signature struct { + Email string + Name string + When time.Time +} + +// Helper to get a signature from the commit line, which looks like these: +// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200 +// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200 +// but without the "author " at the beginning (this method should) +// be used for author and committer. +// +// FIXME: include timezone for timestamp! +func newSignatureFromCommitline(line []byte) (_ *Signature, err error) { + sig := new(Signature) + emailStart := bytes.IndexByte(line, '<') + sig.Name = string(line[:emailStart-1]) + emailEnd := bytes.IndexByte(line, '>') + sig.Email = string(line[emailStart+1 : emailEnd]) + + // Check date format. + firstChar := line[emailEnd+2] + if firstChar >= 48 && firstChar <= 57 { + timestop := bytes.IndexByte(line[emailEnd+2:], ' ') + timestring := string(line[emailEnd+2 : emailEnd+2+timestop]) + seconds, _ := strconv.ParseInt(timestring, 10, 64) + sig.When = time.Unix(seconds, 0) + } else { + sig.When, err = time.Parse("Mon Jan _2 15:04:05 2006 -0700", string(line[emailEnd+2:])) + if err != nil { + return nil, err + } + } + return sig, nil +} diff --git a/vendor/code.gitea.io/git/submodule.go b/vendor/code.gitea.io/git/submodule.go new file mode 100644 index 0000000000..5777330058 --- /dev/null +++ b/vendor/code.gitea.io/git/submodule.go @@ -0,0 +1,78 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import "strings" + +type SubModule struct { + Name string + URL string +} + +// SubModuleFile represents a file with submodule type. +type SubModuleFile struct { + *Commit + + refURL string + refID string +} + +func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile { + return &SubModuleFile{ + Commit: c, + refURL: refURL, + refID: refID, + } +} + +// RefURL guesses and returns reference URL. +func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string { + if sf.refURL == "" { + return "" + } + + url := strings.TrimSuffix(sf.refURL, ".git") + + // git://xxx/user/repo + if strings.HasPrefix(url, "git://") { + return "http://" + strings.TrimPrefix(url, "git://") + } + + // http[s]://xxx/user/repo + if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") { + return url + } + + // Relative url prefix check (according to git submodule documentation) + if strings.HasPrefix(url, "./") || strings.HasPrefix(url, "../") { + // ...construct and return correct submodule url here... + idx := strings.Index(parentPath, "/src/") + if idx == -1 { + return url + } + return strings.TrimSuffix(urlPrefix, "/") + parentPath[:idx] + "/" + url + } + + // sysuser@xxx:user/repo + i := strings.Index(url, "@") + j := strings.LastIndex(url, ":") + + // Only process when i < j because git+ssh://git@git.forwardbias.in/npploader.git + if i > -1 && j > -1 && i < j { + // 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 url +} + +// RefID returns reference ID. +func (sf *SubModuleFile) RefID() string { + return sf.refID +} diff --git a/vendor/code.gitea.io/git/tag.go b/vendor/code.gitea.io/git/tag.go new file mode 100644 index 0000000000..f4bf77925f --- /dev/null +++ b/vendor/code.gitea.io/git/tag.go @@ -0,0 +1,65 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import "bytes" + +// Tag represents a Git tag. +type Tag struct { + Name string + ID sha1 + repo *Repository + Object sha1 // The id of this commit object + Type string + Tagger *Signature + Message string +} + +func (tag *Tag) Commit() (*Commit, error) { + return tag.repo.getCommit(tag.Object) +} + +// Parse commit information from the (uncompressed) raw +// data from the commit object. +// \n\n separate headers from message +func parseTagData(data []byte) (*Tag, error) { + tag := new(Tag) + // we now have the contents of the commit object. Let's investigate... + nextline := 0 +l: + for { + eol := bytes.IndexByte(data[nextline:], '\n') + switch { + case eol > 0: + line := data[nextline : nextline+eol] + spacepos := bytes.IndexByte(line, ' ') + reftype := line[:spacepos] + switch string(reftype) { + case "object": + id, err := NewIDFromString(string(line[spacepos+1:])) + if err != nil { + return nil, err + } + tag.Object = id + case "type": + // A commit can have one or more parents + tag.Type = string(line[spacepos+1:]) + case "tagger": + sig, err := newSignatureFromCommitline(line[spacepos+1:]) + if err != nil { + return nil, err + } + tag.Tagger = sig + } + nextline += eol + 1 + case eol == 0: + tag.Message = string(data[nextline+1:]) + break l + default: + break l + } + } + return tag, nil +} diff --git a/vendor/code.gitea.io/git/tree.go b/vendor/code.gitea.io/git/tree.go new file mode 100644 index 0000000000..8704282efd --- /dev/null +++ b/vendor/code.gitea.io/git/tree.go @@ -0,0 +1,151 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "bytes" + "fmt" + "strings" +) + +// Tree represents a flat directory listing. +type Tree struct { + ID sha1 + repo *Repository + + // parent tree + ptree *Tree + + entries Entries + entriesParsed bool +} + +func NewTree(repo *Repository, id sha1) *Tree { + return &Tree{ + ID: id, + repo: repo, + } +} + +var escapeChar = []byte("\\") + +// UnescapeChars reverses escaped characters. +func UnescapeChars(in []byte) []byte { + if bytes.Index(in, escapeChar) == -1 { + return in + } + + endIdx := len(in) - 1 + isEscape := false + out := make([]byte, 0, endIdx+1) + for i := range in { + if in[i] == '\\' && !isEscape { + isEscape = true + continue + } + isEscape = false + out = append(out, in[i]) + } + return out +} + +// parseTreeData parses tree information from the (uncompressed) raw +// data from the tree object. +func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) { + entries := make([]*TreeEntry, 0, 10) + l := len(data) + pos := 0 + for pos < l { + entry := new(TreeEntry) + entry.ptree = tree + step := 6 + switch string(data[pos : pos+step]) { + case "100644": + entry.mode = ENTRY_MODE_BLOB + entry.Type = OBJECT_BLOB + case "100755": + entry.mode = ENTRY_MODE_EXEC + entry.Type = OBJECT_BLOB + case "120000": + entry.mode = ENTRY_MODE_SYMLINK + entry.Type = OBJECT_BLOB + case "160000": + entry.mode = ENTRY_MODE_COMMIT + entry.Type = OBJECT_COMMIT + + step = 8 + case "040000": + entry.mode = ENTRY_MODE_TREE + entry.Type = OBJECT_TREE + default: + return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+step])) + } + pos += step + 6 // Skip string type of entry type. + + step = 40 + id, err := NewIDFromString(string(data[pos : pos+step])) + if err != nil { + return nil, err + } + entry.ID = id + pos += step + 1 // Skip half of sha1. + + step = bytes.IndexByte(data[pos:], '\n') + + // In case entry name is surrounded by double quotes(it happens only in git-shell). + if data[pos] == '"' { + entry.name = string(UnescapeChars(data[pos+1 : pos+step-1])) + } else { + entry.name = string(data[pos : pos+step]) + } + + pos += step + 1 + entries = append(entries, entry) + } + return entries, nil +} + +func (t *Tree) SubTree(rpath string) (*Tree, error) { + if len(rpath) == 0 { + return t, nil + } + + paths := strings.Split(rpath, "/") + var ( + err error + g = t + p = t + te *TreeEntry + ) + for _, name := range paths { + te, err = p.GetTreeEntryByPath(name) + if err != nil { + return nil, err + } + + g, err = t.repo.getTree(te.ID) + if err != nil { + return nil, err + } + g.ptree = p + p = g + } + return g, nil +} + +// ListEntries returns all entries of current tree. +func (t *Tree) ListEntries() (Entries, error) { + if t.entriesParsed { + return t.entries, nil + } + t.entriesParsed = true + + stdout, err := NewCommand("ls-tree", t.ID.String()).RunInDirBytes(t.repo.Path) + if err != nil { + return nil, err + } + t.entries, err = parseTreeData(t, stdout) + return t.entries, err +} diff --git a/vendor/code.gitea.io/git/tree_blob.go b/vendor/code.gitea.io/git/tree_blob.go new file mode 100644 index 0000000000..e2e701521f --- /dev/null +++ b/vendor/code.gitea.io/git/tree_blob.go @@ -0,0 +1,57 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "path" + "strings" +) + +func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) { + if len(relpath) == 0 { + return &TreeEntry{ + ID: t.ID, + Type: OBJECT_TREE, + mode: ENTRY_MODE_TREE, + }, nil + } + + relpath = path.Clean(relpath) + parts := strings.Split(relpath, "/") + var err error + tree := t + for i, name := range parts { + if i == len(parts)-1 { + entries, err := tree.ListEntries() + if err != nil { + return nil, err + } + for _, v := range entries { + if v.name == name { + return v, nil + } + } + } else { + tree, err = tree.SubTree(name) + if err != nil { + return nil, err + } + } + } + return nil, ErrNotExist{"", relpath} +} + +func (t *Tree) GetBlobByPath(relpath string) (*Blob, error) { + entry, err := t.GetTreeEntryByPath(relpath) + if err != nil { + return nil, err + } + + if !entry.IsDir() { + return entry.Blob(), nil + } + + return nil, ErrNotExist{"", relpath} +} diff --git a/vendor/code.gitea.io/git/tree_entry.go b/vendor/code.gitea.io/git/tree_entry.go new file mode 100644 index 0000000000..1c9e89d70c --- /dev/null +++ b/vendor/code.gitea.io/git/tree_entry.go @@ -0,0 +1,209 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "fmt" + "path" + "path/filepath" + "sort" + "strconv" + "strings" + "time" +) + +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 +) + +type TreeEntry struct { + ID sha1 + Type ObjectType + + mode EntryMode + name string + + ptree *Tree + + commited bool + + size int64 + sized bool +} + +func (te *TreeEntry) Name() string { + return te.name +} + +func (te *TreeEntry) Size() int64 { + if te.IsDir() { + return 0 + } else if te.sized { + return te.size + } + + stdout, err := NewCommand("cat-file", "-s", te.ID.String()).RunInDir(te.ptree.repo.Path) + if err != nil { + return 0 + } + + te.sized = true + te.size, _ = strconv.ParseInt(strings.TrimSpace(stdout), 10, 64) + return te.size +} + +func (te *TreeEntry) IsSubModule() bool { + return te.mode == ENTRY_MODE_COMMIT +} + +func (te *TreeEntry) IsDir() bool { + return te.mode == ENTRY_MODE_TREE +} + +func (te *TreeEntry) Blob() *Blob { + return &Blob{ + repo: te.ptree.repo, + TreeEntry: te, + } +} + +type Entries []*TreeEntry + +var sorter = []func(t1, t2 *TreeEntry) bool{ + func(t1, t2 *TreeEntry) bool { + return (t1.IsDir() || t1.IsSubModule()) && !t2.IsDir() && !t2.IsSubModule() + }, + func(t1, t2 *TreeEntry) bool { + return t1.name < t2.name + }, +} + +func (tes Entries) Len() int { return len(tes) } +func (tes Entries) Swap(i, j int) { tes[i], tes[j] = tes[j], tes[i] } +func (tes Entries) Less(i, j int) bool { + t1, t2 := tes[i], tes[j] + var k int + for k = 0; k < len(sorter)-1; k++ { + sort := sorter[k] + switch { + case sort(t1, t2): + return true + case sort(t2, t1): + return false + } + } + return sorter[k](t1, t2) +} + +func (tes Entries) Sort() { + sort.Sort(tes) +} + +type commitInfo struct { + entryName string + infos []interface{} + err error +} + +// GetCommitsInfo takes advantages of concurrey to speed up getting information +// of all commits that are corresponding to these entries. +// TODO: limit max goroutines number should be configurable +func (tes Entries) GetCommitsInfo(commit *Commit, treePath string) ([][]interface{}, error) { + if len(tes) == 0 { + return nil, nil + } + + // Length of taskChan determines how many goroutines (subprocesses) can run at the same time. + // The length of revChan should be same as taskChan so goroutines whoever finished job can + // exit as early as possible, only store data inside channel. + taskChan := make(chan bool, 10) + revChan := make(chan commitInfo, 10) + doneChan := make(chan error) + + // Receive loop will exit when it collects same number of data pieces as tree entries. + // It notifies doneChan before exits or notify early with possible error. + infoMap := make(map[string][]interface{}, len(tes)) + go func() { + i := 0 + for info := range revChan { + if info.err != nil { + doneChan <- info.err + return + } + + infoMap[info.entryName] = info.infos + i++ + if i == len(tes) { + break + } + } + doneChan <- nil + }() + + for i := range tes { + // When taskChan is idle (or has empty slots), put operation will not block. + // However when taskChan is full, code will block and wait any running goroutines to finish. + taskChan <- true + + if tes[i].Type != OBJECT_COMMIT { + go func(i int) { + time.Sleep(200 * time.Millisecond) + cinfo := commitInfo{entryName: tes[i].Name()} + c, err := commit.GetCommitByPath(filepath.Join(treePath, tes[i].Name())) + if err != nil { + cinfo.err = fmt.Errorf("GetCommitByPath (%s/%s): %v", treePath, tes[i].Name(), err) + } else { + cinfo.infos = []interface{}{tes[i], c} + } + revChan <- cinfo + <-taskChan // Clear one slot from taskChan to allow new goroutines to start. + }(i) + continue + } + + // Handle submodule + go func(i int) { + cinfo := commitInfo{entryName: tes[i].Name()} + sm, err := commit.GetSubModule(path.Join(treePath, tes[i].Name())) + if err != nil && !IsErrNotExist(err) { + cinfo.err = fmt.Errorf("GetSubModule (%s/%s): %v", treePath, tes[i].Name(), err) + revChan <- cinfo + return + } + + smURL := "" + if sm != nil { + smURL = sm.URL + } + + c, err := commit.GetCommitByPath(filepath.Join(treePath, tes[i].Name())) + if err != nil { + cinfo.err = fmt.Errorf("GetCommitByPath (%s/%s): %v", treePath, tes[i].Name(), err) + } else { + cinfo.infos = []interface{}{tes[i], NewSubModuleFile(c, smURL, tes[i].ID.String())} + } + revChan <- cinfo + <-taskChan + }(i) + } + + if err := <-doneChan; err != nil { + return nil, err + } + + commitsInfo := make([][]interface{}, len(tes)) + for i := 0; i < len(tes); i++ { + commitsInfo[i] = infoMap[tes[i].Name()] + } + return commitsInfo, nil +} diff --git a/vendor/code.gitea.io/git/utlis.go b/vendor/code.gitea.io/git/utlis.go new file mode 100644 index 0000000000..da8c58170e --- /dev/null +++ b/vendor/code.gitea.io/git/utlis.go @@ -0,0 +1,93 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package git + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "sync" +) + +// objectCache provides thread-safe cache opeations. +type objectCache struct { + lock sync.RWMutex + cache map[string]interface{} +} + +func newObjectCache() *objectCache { + return &objectCache{ + cache: make(map[string]interface{}, 10), + } +} + +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) { + oc.lock.RLock() + defer oc.lock.RUnlock() + + obj, has := oc.cache[id] + return obj, has +} + +// isDir returns true if given path is a directory, +// or returns false when it's a file or does not exist. +func isDir(dir string) bool { + f, e := os.Stat(dir) + if e != nil { + return false + } + return f.IsDir() +} + +// isFile returns true if given path is a file, +// or returns false when it's a directory or does not exist. +func isFile(filePath string) bool { + f, e := os.Stat(filePath) + if e != nil { + return false + } + return !f.IsDir() +} + +// isExist checks whether a file or directory exists. +// It returns false when the file or directory does not exist. +func isExist(path string) bool { + _, err := os.Stat(path) + return err == nil || os.IsExist(err) +} + +func concatenateError(err error, stderr string) error { + if len(stderr) == 0 { + return err + } + return fmt.Errorf("%v - %s", err, stderr) +} + +// If the object is stored in its own file (i.e not in a pack file), +// this function returns the full path to the object file. +// It does not test if the file exists. +func filepathFromSHA1(rootdir, sha1 string) string { + return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:]) +} + +func RefEndName(refStr string) string { + if strings.HasPrefix(refStr, BRANCH_PREFIX) { + return refStr[len(BRANCH_PREFIX):] + } + + if strings.HasPrefix(refStr, TAG_PREFIX) { + return refStr[len(TAG_PREFIX):] + } + + return refStr +} diff --git a/vendor/code.gitea.io/go-sdk/LICENSE b/vendor/code.gitea.io/go-sdk/LICENSE new file mode 100644 index 0000000000..10aeba46bc --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2016 The Gitea Authors +Copyright (c) 2014 The Gogs Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/code.gitea.io/go-sdk/gitea/admin_org.go b/vendor/code.gitea.io/go-sdk/gitea/admin_org.go new file mode 100644 index 0000000000..520fa12990 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/admin_org.go @@ -0,0 +1,21 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" +) + +func (c *Client) AdminCreateOrg(user string, opt CreateOrgOption) (*Organization, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + org := new(Organization) + return org, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/orgs", user), + jsonHeader, bytes.NewReader(body), org) +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/admin_repo.go b/vendor/code.gitea.io/go-sdk/gitea/admin_repo.go new file mode 100644 index 0000000000..06daa94597 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/admin_repo.go @@ -0,0 +1,21 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" +) + +func (c *Client) AdminCreateRepo(user string, opt CreateRepoOption) (*Repository, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + repo := new(Repository) + return repo, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/repos", user), + jsonHeader, bytes.NewReader(body), repo) +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/admin_user.go b/vendor/code.gitea.io/go-sdk/gitea/admin_user.go new file mode 100644 index 0000000000..186008b77b --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/admin_user.go @@ -0,0 +1,68 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" +) + +type CreateUserOption struct { + SourceID int64 `json:"source_id"` + LoginName string `json:"login_name"` + Username string `json:"username" binding:"Required;AlphaDashDot;MaxSize(35)"` + FullName string `json:"full_name" binding:"MaxSize(100)"` + Email string `json:"email" binding:"Required;Email;MaxSize(254)"` + Password string `json:"password" binding:"MaxSize(255)"` + SendNotify bool `json:"send_notify"` +} + +func (c *Client) AdminCreateUser(opt CreateUserOption) (*User, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + user := new(User) + return user, c.getParsedResponse("POST", "/admin/users", jsonHeader, bytes.NewReader(body), user) +} + +type EditUserOption struct { + SourceID int64 `json:"source_id"` + LoginName string `json:"login_name"` + FullName string `json:"full_name" binding:"MaxSize(100)"` + Email string `json:"email" binding:"Required;Email;MaxSize(254)"` + Password string `json:"password" binding:"MaxSize(255)"` + Website string `json:"website" binding:"MaxSize(50)"` + Location string `json:"location" binding:"MaxSize(50)"` + Active *bool `json:"active"` + Admin *bool `json:"admin"` + AllowGitHook *bool `json:"allow_git_hook"` + AllowImportLocal *bool `json:"allow_import_local"` + MaxRepoCreation *int `json:"max_repo_creation"` +} + +func (c *Client) AdminEditUser(user string, opt EditUserOption) error { + body, err := json.Marshal(&opt) + if err != nil { + return err + } + _, err = c.getResponse("PATCH", fmt.Sprintf("/admin/users/%s", user), jsonHeader, bytes.NewReader(body)) + return err +} + +func (c *Client) AdminDeleteUser(user string) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/admin/users/%s", user), nil, nil) + return err +} + +func (c *Client) AdminCreateUserPublicKey(user string, opt CreateKeyOption) (*PublicKey, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + key := new(PublicKey) + return key, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/keys", user), jsonHeader, bytes.NewReader(body), key) +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/gitea.go b/vendor/code.gitea.io/go-sdk/gitea/gitea.go new file mode 100644 index 0000000000..0a6bf4d749 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/gitea.go @@ -0,0 +1,90 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "encoding/json" + "errors" + "io" + "io/ioutil" + "net/http" + "strings" +) + +func Version() string { + return "0.12.3" +} + +// Client represents a Gogs API client. +type Client struct { + url string + accessToken string + client *http.Client +} + +// NewClient initializes and returns a API client. +func NewClient(url, token string) *Client { + return &Client{ + url: strings.TrimSuffix(url, "/"), + accessToken: token, + client: &http.Client{}, + } +} + +// SetHTTPClient replaces default http.Client with user given one. +func (c *Client) SetHTTPClient(client *http.Client) { + c.client = client +} + +func (c *Client) doRequest(method, path string, header http.Header, body io.Reader) (*http.Response, error) { + req, err := http.NewRequest(method, c.url+"/api/v1"+path, body) + if err != nil { + return nil, err + } + req.Header.Set("Authorization", "token "+c.accessToken) + for k, v := range header { + req.Header[k] = v + } + + return c.client.Do(req) +} + +func (c *Client) getResponse(method, path string, header http.Header, body io.Reader) ([]byte, error) { + resp, err := c.doRequest(method, path, header, body) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + switch resp.StatusCode { + case 403: + return nil, errors.New("403 Forbidden") + case 404: + return nil, errors.New("404 Not Found") + } + + if resp.StatusCode/100 != 2 { + errMap := make(map[string]interface{}) + if err = json.Unmarshal(data, &errMap); err != nil { + return nil, err + } + return nil, errors.New(errMap["message"].(string)) + } + + return data, nil +} + +func (c *Client) getParsedResponse(method, path string, header http.Header, body io.Reader, obj interface{}) error { + data, err := c.getResponse(method, path, header, body) + if err != nil { + return err + } + return json.Unmarshal(data, obj) +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/issue.go b/vendor/code.gitea.io/go-sdk/gitea/issue.go new file mode 100644 index 0000000000..4392e00004 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/issue.go @@ -0,0 +1,92 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" + "time" +) + +type StateType string + +const ( + STATE_OPEN StateType = "open" + STATE_CLOSED StateType = "closed" +) + +type PullRequestMeta struct { + HasMerged bool `json:"merged"` + Merged *time.Time `json:"merged_at"` +} + +type Issue struct { + ID int64 `json:"id"` + Index int64 `json:"number"` + Poster *User `json:"user"` + Title string `json:"title"` + Body string `json:"body"` + Labels []*Label `json:"labels"` + Milestone *Milestone `json:"milestone"` + Assignee *User `json:"assignee"` + State StateType `json:"state"` + Comments int `json:"comments"` + Created time.Time `json:"created_at"` + Updated time.Time `json:"updated_at"` + + PullRequest *PullRequestMeta `json:"pull_request"` +} + +type ListIssueOption struct { + Page int +} + +func (c *Client) ListRepoIssues(owner, repo string, opt ListIssueOption) ([]*Issue, error) { + issues := make([]*Issue, 0, 10) + return issues, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues?page=%d", owner, repo, opt.Page), nil, nil, &issues) +} + +func (c *Client) GetIssue(owner, repo string, index int64) (*Issue, error) { + issue := new(Issue) + return issue, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index), nil, nil, issue) +} + +type CreateIssueOption struct { + Title string `json:"title" binding:"Required"` + Body string `json:"body"` + Assignee string `json:"assignee"` + Milestone int64 `json:"milestone"` + Labels []int64 `json:"labels"` + Closed bool `json:"closed"` +} + +func (c *Client) CreateIssue(owner, repo string, opt CreateIssueOption) (*Issue, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + issue := new(Issue) + return issue, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues", owner, repo), + jsonHeader, bytes.NewReader(body), issue) +} + +type EditIssueOption struct { + Title string `json:"title"` + Body *string `json:"body"` + Assignee *string `json:"assignee"` + Milestone *int64 `json:"milestone"` + State *string `json:"state"` +} + +func (c *Client) EditIssue(owner, repo string, index int64, opt EditIssueOption) (*Issue, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + issue := new(Issue) + return issue, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index), + jsonHeader, bytes.NewReader(body), issue) +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/issue_comment.go b/vendor/code.gitea.io/go-sdk/gitea/issue_comment.go new file mode 100644 index 0000000000..59f064a8ad --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/issue_comment.go @@ -0,0 +1,57 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" + "time" +) + +// Comment represents a comment in commit and issue page. +type Comment struct { + ID int64 `json:"id"` + Poster *User `json:"user"` + Body string `json:"body"` + Created time.Time `json:"created_at"` + Updated time.Time `json:"updated_at"` +} + +// ListIssueComments list comments on an issue. +func (c *Client) ListIssueComments(owner, repo string, index int64) ([]*Comment, error) { + comments := make([]*Comment, 0, 10) + return comments, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/comments", owner, repo, index), nil, nil, &comments) +} + +// CreateIssueCommentOption is option when creating an issue comment. +type CreateIssueCommentOption struct { + Body string `json:"body" binding:"Required"` +} + +// CreateIssueComment create comment on an issue. +func (c *Client) CreateIssueComment(owner, repo string, index int64, opt CreateIssueCommentOption) (*Comment, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + comment := new(Comment) + return comment, c.getParsedResponse("POST", fmt.Sprintf("/repos/:%s/:%s/issues/%d/comments", owner, repo, index), jsonHeader, bytes.NewReader(body), comment) +} + +// EditIssueCommentOption is option when editing an issue comment. +type EditIssueCommentOption struct { + Body string `json:"body" binding:"Required"` +} + +// EditIssueComment edits an issue comment. +func (c *Client) EditIssueComment(owner, repo string, index, commentID int64, opt EditIssueCommentOption) (*Comment, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + comment := new(Comment) + return comment, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/:%s/:%s/issues/%d/comments/%d", owner, repo, index, commentID), jsonHeader, bytes.NewReader(body), comment) +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/issue_label.go b/vendor/code.gitea.io/go-sdk/gitea/issue_label.go new file mode 100644 index 0000000000..681e504c34 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/issue_label.go @@ -0,0 +1,98 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" +) + +type Label struct { + ID int64 `json:"id"` + Name string `json:"name"` + Color string `json:"color"` +} + +func (c *Client) ListRepoLabels(owner, repo string) ([]*Label, error) { + labels := make([]*Label, 0, 10) + return labels, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels", owner, repo), nil, nil, &labels) +} + +func (c *Client) GetRepoLabel(owner, repo string, id int64) (*Label, error) { + label := new(Label) + return label, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil, label) +} + +type CreateLabelOption struct { + Name string `json:"name" binding:"Required"` + Color string `json:"color" binding:"Required;Size(7)"` +} + +func (c *Client) CreateLabel(owner, repo string, opt CreateLabelOption) (*Label, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + label := new(Label) + return label, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/labels", owner, repo), + jsonHeader, bytes.NewReader(body), label) +} + +type EditLabelOption struct { + Name *string `json:"name"` + Color *string `json:"color"` +} + +func (c *Client) EditLabel(owner, repo string, id int64, opt EditLabelOption) (*Label, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + label := new(Label) + return label, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), label) +} + +func (c *Client) DeleteLabel(owner, repo string, id int64) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil) + return err +} + +type IssueLabelsOption struct { + Labels []int64 `json:"labels"` +} + +func (c *Client) GetIssueLabels(owner, repo string, index int64) ([]*Label, error) { + labels := make([]*Label, 0, 5) + return labels, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), nil, nil, &labels) +} + +func (c *Client) AddIssueLabels(owner, repo string, index int64, opt IssueLabelsOption) ([]*Label, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + labels := make([]*Label, 0) + return labels, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), jsonHeader, bytes.NewReader(body), &labels) +} + +func (c *Client) ReplaceIssueLabels(owner, repo string, index int64, opt IssueLabelsOption) ([]*Label, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + labels := make([]*Label, 0) + return labels, c.getParsedResponse("PUT", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), jsonHeader, bytes.NewReader(body), &labels) +} + +func (c *Client) DeleteIssueLabel(owner, repo string, index, label int64) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/labels/%d", owner, repo, index, label), nil, nil) + return err +} + +func (c *Client) ClearIssueLabels(owner, repo string, index int64) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), nil, nil) + return err +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/issue_milestone.go b/vendor/code.gitea.io/go-sdk/gitea/issue_milestone.go new file mode 100644 index 0000000000..58f17893a7 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/issue_milestone.go @@ -0,0 +1,69 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" + "time" +) + +type Milestone struct { + ID int64 `json:"id"` + Title string `json:"title"` + Description string `json:"description"` + State StateType `json:"state"` + OpenIssues int `json:"open_issues"` + ClosedIssues int `json:"closed_issues"` + Closed *time.Time `json:"closed_at"` + Deadline *time.Time `json:"due_on"` +} + +func (c *Client) ListRepoMilestones(owner, repo string) ([]*Milestone, error) { + milestones := make([]*Milestone, 0, 10) + return milestones, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/milestones", owner, repo), nil, nil, &milestones) +} + +func (c *Client) GetMilestone(owner, repo string, id int64) (*Milestone, error) { + milestone := new(Milestone) + return milestone, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), nil, nil, milestone) +} + +type CreateMilestoneOption struct { + Title string `json:"title"` + Description string `json:"description"` + Deadline *time.Time `json:"due_on"` +} + +func (c *Client) CreateMilestone(owner, repo string, opt CreateMilestoneOption) (*Milestone, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + milestone := new(Milestone) + return milestone, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/milestones", owner, repo), jsonHeader, bytes.NewReader(body), milestone) +} + +type EditMilestoneOption struct { + Title string `json:"title"` + Description *string `json:"description"` + State *string `json:"state"` + Deadline *time.Time `json:"due_on"` +} + +func (c *Client) EditMilestone(owner, repo string, id int64, opt EditMilestoneOption) (*Milestone, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + milestone := new(Milestone) + return milestone, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), milestone) +} + +func (c *Client) DeleteMilestone(owner, repo string, id int64) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), nil, nil) + return err +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/miscellaneous.go b/vendor/code.gitea.io/go-sdk/gitea/miscellaneous.go new file mode 100644 index 0000000000..d97940e13c --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/miscellaneous.go @@ -0,0 +1,11 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +type MarkdownOption struct { + Text string + Mode string + Context string +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/org.go b/vendor/code.gitea.io/go-sdk/gitea/org.go new file mode 100644 index 0000000000..70d872cf51 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/org.go @@ -0,0 +1,60 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" +) + +type Organization struct { + ID int64 `json:"id"` + UserName string `json:"username"` + FullName string `json:"full_name"` + AvatarUrl string `json:"avatar_url"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` +} + +func (c *Client) ListMyOrgs() ([]*Organization, error) { + orgs := make([]*Organization, 0, 5) + return orgs, c.getParsedResponse("GET", "/user/orgs", nil, nil, &orgs) +} + +func (c *Client) ListUserOrgs(user string) ([]*Organization, error) { + orgs := make([]*Organization, 0, 5) + return orgs, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/orgs", user), nil, nil, &orgs) +} + +func (c *Client) GetOrg(orgname string) (*Organization, error) { + org := new(Organization) + return org, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s", orgname), nil, nil, org) +} + +type CreateOrgOption struct { + UserName string `json:"username" binding:"Required"` + FullName string `json:"full_name"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` +} + +type EditOrgOption struct { + FullName string `json:"full_name"` + Description string `json:"description"` + Website string `json:"website"` + Location string `json:"location"` +} + +func (c *Client) EditOrg(orgname string, opt EditOrgOption) error { + body, err := json.Marshal(&opt) + if err != nil { + return err + } + _, err = c.getResponse("PATCH", fmt.Sprintf("/orgs/%s", orgname), jsonHeader, bytes.NewReader(body)) + return err +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/org_member.go b/vendor/code.gitea.io/go-sdk/gitea/org_member.go new file mode 100644 index 0000000000..46e839805d --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/org_member.go @@ -0,0 +1,24 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" +) + +type AddOrgMembershipOption struct { + Role string `json:"role" binding:"Required"` +} + +func (c *Client) AddOrgMembership(org, user string, opt AddOrgMembershipOption) error { + body, err := json.Marshal(&opt) + if err != nil { + return err + } + _, err = c.getResponse("PUT", fmt.Sprintf("/orgs/%s/membership/%s", org, user), jsonHeader, bytes.NewReader(body)) + return err +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/org_team.go b/vendor/code.gitea.io/go-sdk/gitea/org_team.go new file mode 100644 index 0000000000..38da20d997 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/org_team.go @@ -0,0 +1,18 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +type Team struct { + ID int64 `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Permission string `json:"permission"` +} + +type CreateTeamOption struct { + Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(30)"` + Description string `json:"description" binding:"MaxSize(255)"` + Permission string `json:"permission"` +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/pull.go b/vendor/code.gitea.io/go-sdk/gitea/pull.go new file mode 100644 index 0000000000..efc746388a --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/pull.go @@ -0,0 +1,37 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "time" +) + +// PullRequest represents a pull reqesut API object. +type PullRequest struct { + // Copied from issue.go + ID int64 `json:"id"` + Index int64 `json:"number"` + Poster *User `json:"user"` + Title string `json:"title"` + Body string `json:"body"` + Labels []*Label `json:"labels"` + Milestone *Milestone `json:"milestone"` + Assignee *User `json:"assignee"` + State StateType `json:"state"` + Comments int `json:"comments"` + + HeadBranch string `json:"head_branch"` + HeadRepo *Repository `json:"head_repo"` + BaseBranch string `json:"base_branch"` + BaseRepo *Repository `json:"base_repo"` + + HTMLURL string `json:"html_url"` + + Mergeable *bool `json:"mergeable"` + HasMerged bool `json:"merged"` + Merged *time.Time `json:"merged_at"` + MergedCommitID *string `json:"merge_commit_sha"` + MergedBy *User `json:"merged_by"` +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/repo.go b/vendor/code.gitea.io/go-sdk/gitea/repo.go new file mode 100644 index 0000000000..266c01cc92 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/repo.go @@ -0,0 +1,125 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" + "time" +) + +// Permission represents a API permission. +type Permission struct { + Admin bool `json:"admin"` + Push bool `json:"push"` + Pull bool `json:"pull"` +} + +// Repository represents a API repository. +type Repository struct { + ID int64 `json:"id"` + Owner *User `json:"owner"` + Name string `json:"name"` + FullName string `json:"full_name"` + Description string `json:"description"` + Private bool `json:"private"` + Fork bool `json:"fork"` + HTMLURL string `json:"html_url"` + SSHURL string `json:"ssh_url"` + CloneURL string `json:"clone_url"` + Website string `json:"website"` + Stars int `json:"stars_count"` + Forks int `json:"forks_count"` + Watchers int `json:"watchers_count"` + OpenIssues int `json:"open_issues_count"` + DefaultBranch string `json:"default_branch"` + Created time.Time `json:"created_at"` + Updated time.Time `json:"updated_at"` + Permissions *Permission `json:"permissions,omitempty"` +} + +// ListMyRepos lists all repositories for the authenticated user that has access to. +func (c *Client) ListMyRepos() ([]*Repository, error) { + repos := make([]*Repository, 0, 10) + return repos, c.getParsedResponse("GET", "/user/repos", nil, nil, &repos) +} + +func (c *Client) ListUserRepos(user string) ([]*Repository, error) { + repos := make([]*Repository, 0, 10) + return repos, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/repos", user), nil, nil, &repos) +} + +func (c *Client) ListOrgRepos(org string) ([]*Repository, error) { + repos := make([]*Repository, 0, 10) + return repos, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/repos", org), nil, nil, &repos) +} + +type CreateRepoOption struct { + Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(100)"` + Description string `json:"description" binding:"MaxSize(255)"` + Private bool `json:"private"` + AutoInit bool `json:"auto_init"` + Gitignores string `json:"gitignores"` + License string `json:"license"` + Readme string `json:"readme"` +} + +// CreateRepo creates a repository for authenticated user. +func (c *Client) CreateRepo(opt CreateRepoOption) (*Repository, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + repo := new(Repository) + return repo, c.getParsedResponse("POST", "/user/repos", jsonHeader, bytes.NewReader(body), repo) +} + +// CreateOrgRepo creates an organization repository for authenticated user. +func (c *Client) CreateOrgRepo(org string, opt CreateRepoOption) (*Repository, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + repo := new(Repository) + return repo, c.getParsedResponse("POST", fmt.Sprintf("/org/%s/repos", org), jsonHeader, bytes.NewReader(body), repo) +} + +// GetRepo returns information of a repository of given owner. +func (c *Client) GetRepo(owner, reponame string) (*Repository, error) { + repo := new(Repository) + return repo, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s", owner, reponame), nil, nil, repo) +} + +// DeleteRepo deletes a repository of user or organization. +func (c *Client) DeleteRepo(owner, repo string) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s", owner, repo), nil, nil) + return err +} + +type MigrateRepoOption struct { + CloneAddr string `json:"clone_addr" binding:"Required"` + AuthUsername string `json:"auth_username"` + AuthPassword string `json:"auth_password"` + UID int `json:"uid" binding:"Required"` + RepoName string `json:"repo_name" binding:"Required"` + Mirror bool `json:"mirror"` + Private bool `json:"private"` + Description string `json:"description"` +} + +// MigrateRepo migrates a repository from other Git hosting sources for the +// authenticated user. +// +// To migrate a repository for a organization, the authenticated user must be a +// owner of the specified organization. +func (c *Client) MigrateRepo(opt MigrateRepoOption) (*Repository, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + repo := new(Repository) + return repo, c.getParsedResponse("POST", "/repos/migrate", jsonHeader, bytes.NewReader(body), repo) +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/repo_branch.go b/vendor/code.gitea.io/go-sdk/gitea/repo_branch.go new file mode 100644 index 0000000000..c57df07c62 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/repo_branch.go @@ -0,0 +1,25 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "fmt" +) + +// Branch represents a repository branch. +type Branch struct { + Name string `json:"name"` + Commit *PayloadCommit `json:"commit"` +} + +func (c *Client) ListRepoBranches(user, repo string) ([]*Branch, error) { + branches := make([]*Branch, 0, 10) + return branches, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches", user, repo), nil, nil, &branches) +} + +func (c *Client) GetRepoBranch(user, repo, branch string) (*Branch, error) { + b := new(Branch) + return b, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches/%s", user, repo, branch), nil, nil, &b) +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/repo_collaborator.go b/vendor/code.gitea.io/go-sdk/gitea/repo_collaborator.go new file mode 100644 index 0000000000..1937de4c0e --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/repo_collaborator.go @@ -0,0 +1,24 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" +) + +type AddCollaboratorOption struct { + Permission *string `json:"permission"` +} + +func (c *Client) AddCollaborator(user, repo, collaborator string, opt AddCollaboratorOption) error { + body, err := json.Marshal(&opt) + if err != nil { + return err + } + _, err = c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, bytes.NewReader(body)) + return err +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/repo_file.go b/vendor/code.gitea.io/go-sdk/gitea/repo_file.go new file mode 100644 index 0000000000..e6c89f0c0f --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/repo_file.go @@ -0,0 +1,15 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "fmt" +) + +// GetFile downloads a file of repository, ref can be branch/tag/commit. +// e.g.: ref -> master, tree -> macaron.go(no leading slash) +func (c *Client) GetFile(user, repo, ref, tree string) ([]byte, error) { + return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/raw/%s/%s", user, repo, ref, tree), nil, nil) +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/repo_hook.go b/vendor/code.gitea.io/go-sdk/gitea/repo_hook.go new file mode 100644 index 0000000000..01cb254216 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/repo_hook.go @@ -0,0 +1,245 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "strings" + "time" +) + +var ( + ErrInvalidReceiveHook = errors.New("Invalid JSON payload received over webhook") +) + +type Hook struct { + ID int64 `json:"id"` + Type string `json:"type"` + URL string `json:"-"` + Config map[string]string `json:"config"` + Events []string `json:"events"` + Active bool `json:"active"` + Updated time.Time `json:"updated_at"` + Created time.Time `json:"created_at"` +} + +func (c *Client) ListRepoHooks(user, repo string) ([]*Hook, error) { + hooks := make([]*Hook, 0, 10) + return hooks, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks", user, repo), nil, nil, &hooks) +} + +type CreateHookOption struct { + Type string `json:"type" binding:"Required"` + Config map[string]string `json:"config" binding:"Required"` + Events []string `json:"events"` + Active bool `json:"active"` +} + +func (c *Client) CreateRepoHook(user, repo string, opt CreateHookOption) (*Hook, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + h := new(Hook) + return h, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/hooks", user, repo), jsonHeader, bytes.NewReader(body), h) +} + +type EditHookOption struct { + Config map[string]string `json:"config"` + Events []string `json:"events"` + Active *bool `json:"active"` +} + +func (c *Client) EditRepoHook(user, repo string, id int64, opt EditHookOption) error { + body, err := json.Marshal(&opt) + if err != nil { + return err + } + _, err = c.getResponse("PATCH", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), jsonHeader, bytes.NewReader(body)) + return err +} + +func (c *Client) DeleteRepoHook(user, repo string, id int64) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil) + return err +} + +type Payloader interface { + SetSecret(string) + JSONPayload() ([]byte, error) +} + +type PayloadUser struct { + Name string `json:"name"` + Email string `json:"email"` + UserName string `json:"username"` +} + +// FIXME: consider use same format as API when commits API are added. +type PayloadCommit struct { + ID string `json:"id"` + Message string `json:"message"` + URL string `json:"url"` + Author *PayloadUser `json:"author"` + Committer *PayloadUser `json:"committer"` + Timestamp time.Time `json:"timestamp"` +} + +var ( + _ Payloader = &CreatePayload{} + _ Payloader = &PushPayload{} + _ Payloader = &PullRequestPayload{} +) + +// _________ __ +// \_ ___ \_______ ____ _____ _/ |_ ____ +// / \ \/\_ __ \_/ __ \\__ \\ __\/ __ \ +// \ \____| | \/\ ___/ / __ \| | \ ___/ +// \______ /|__| \___ >____ /__| \___ > +// \/ \/ \/ \/ + +type CreatePayload struct { + Secret string `json:"secret"` + Ref string `json:"ref"` + RefType string `json:"ref_type"` + Repo *Repository `json:"repository"` + Sender *User `json:"sender"` +} + +func (p *CreatePayload) SetSecret(secret string) { + p.Secret = secret +} + +func (p *CreatePayload) JSONPayload() ([]byte, error) { + return json.MarshalIndent(p, "", " ") +} + +// ParseCreateHook parses create event hook content. +func ParseCreateHook(raw []byte) (*CreatePayload, error) { + hook := new(CreatePayload) + if err := json.Unmarshal(raw, hook); err != nil { + return nil, err + } + + // it is possible the JSON was parsed, however, + // was not from Gogs (maybe was from Bitbucket) + // So we'll check to be sure certain key fields + // were populated + switch { + case hook.Repo == nil: + return nil, ErrInvalidReceiveHook + case len(hook.Ref) == 0: + return nil, ErrInvalidReceiveHook + } + return hook, nil +} + +// __________ .__ +// \______ \__ __ _____| |__ +// | ___/ | \/ ___/ | \ +// | | | | /\___ \| Y \ +// |____| |____//____ >___| / +// \/ \/ + +// PushPayload represents a payload information of push event. +type PushPayload struct { + Secret string `json:"secret"` + Ref string `json:"ref"` + Before string `json:"before"` + After string `json:"after"` + CompareURL string `json:"compare_url"` + Commits []*PayloadCommit `json:"commits"` + Repo *Repository `json:"repository"` + Pusher *User `json:"pusher"` + Sender *User `json:"sender"` +} + +func (p *PushPayload) SetSecret(secret string) { + p.Secret = secret +} + +func (p *PushPayload) JSONPayload() ([]byte, error) { + return json.MarshalIndent(p, "", " ") +} + +// ParsePushHook parses push event hook content. +func ParsePushHook(raw []byte) (*PushPayload, error) { + hook := new(PushPayload) + if err := json.Unmarshal(raw, hook); err != nil { + return nil, err + } + + switch { + case hook.Repo == nil: + return nil, ErrInvalidReceiveHook + case len(hook.Ref) == 0: + return nil, ErrInvalidReceiveHook + } + return hook, nil +} + +// Branch returns branch name from a payload +func (p *PushPayload) Branch() string { + return strings.Replace(p.Ref, "refs/heads/", "", -1) +} + +// .___ +// | | ______ ________ __ ____ +// | |/ ___// ___/ | \_/ __ \ +// | |\___ \ \___ \| | /\ ___/ +// |___/____ >____ >____/ \___ > +// \/ \/ \/ + +type HookIssueAction string + +const ( + HookIssueOpened HookIssueAction = "opened" + HookIssueClosed HookIssueAction = "closed" + HookIssueReopened HookIssueAction = "reopened" + HookIssueEdited HookIssueAction = "edited" + HookIssueAssigned HookIssueAction = "assigned" + HookIssueUnassigned HookIssueAction = "unassigned" + HookIssueLabelUpdated HookIssueAction = "label_updated" + HookIssueLabelCleared HookIssueAction = "label_cleared" + HookIssueSynchronized HookIssueAction = "synchronized" +) + +type ChangesFromPayload struct { + From string `json:"from"` +} + +type ChangesPayload struct { + Title *ChangesFromPayload `json:"title,omitempty"` + Body *ChangesFromPayload `json:"body,omitempty"` +} + +// __________ .__ .__ __________ __ +// \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_ +// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\ +// | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | | +// |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__| +// \/ \/ |__| \/ \/ + +// PullRequestPayload represents a payload information of pull request event. +type PullRequestPayload struct { + Secret string `json:"secret"` + Action HookIssueAction `json:"action"` + Index int64 `json:"number"` + Changes *ChangesPayload `json:"changes,omitempty"` + PullRequest *PullRequest `json:"pull_request"` + Repository *Repository `json:"repository"` + Sender *User `json:"sender"` +} + +func (p *PullRequestPayload) SetSecret(secret string) { + p.Secret = secret +} + +func (p *PullRequestPayload) JSONPayload() ([]byte, error) { + return json.MarshalIndent(p, "", " ") +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/repo_key.go b/vendor/code.gitea.io/go-sdk/gitea/repo_key.go new file mode 100644 index 0000000000..acae30aa54 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/repo_key.go @@ -0,0 +1,50 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" + "time" +) + +type DeployKey struct { + ID int64 `json:"id"` + Key string `json:"key"` + URL string `json:"url"` + Title string `json:"title"` + Created time.Time `json:"created_at"` + ReadOnly bool `json:"read_only"` +} + +func (c *Client) ListDeployKeys(user, repo string) ([]*DeployKey, error) { + keys := make([]*DeployKey, 0, 10) + return keys, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/keys", user, repo), nil, nil, &keys) +} + +func (c *Client) GetDeployKey(user, repo string, keyID int64) (*DeployKey, error) { + key := new(DeployKey) + return key, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/keys/%d", user, repo, keyID), nil, nil, &key) +} + +type CreateKeyOption struct { + Title string `json:"title" binding:"Required"` + Key string `json:"key" binding:"Required"` +} + +func (c *Client) CreateDeployKey(user, repo string, opt CreateKeyOption) (*DeployKey, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + key := new(DeployKey) + return key, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/keys", user, repo), jsonHeader, bytes.NewReader(body), key) +} + +func (c *Client) DeleteDeployKey(owner, repo string, keyID int64) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/keys/%d", owner, repo, keyID), nil, nil) + return err +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/user.go b/vendor/code.gitea.io/go-sdk/gitea/user.go new file mode 100644 index 0000000000..8b78bea941 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/user.go @@ -0,0 +1,24 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "fmt" +) + +// User represents a API user. +type User struct { + ID int64 `json:"id"` + UserName string `json:"username"` + FullName string `json:"full_name"` + Email string `json:"email"` + AvatarUrl string `json:"avatar_url"` +} + +func (c *Client) GetUserInfo(user string) (*User, error) { + u := new(User) + err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s", user), nil, nil, u) + return u, err +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/user_app.go b/vendor/code.gitea.io/go-sdk/gitea/user_app.go new file mode 100644 index 0000000000..187053bc94 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/user_app.go @@ -0,0 +1,46 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + "net/http" +) + +func BasicAuthEncode(user, pass string) string { + return base64.StdEncoding.EncodeToString([]byte(user + ":" + pass)) +} + +// AccessToken represents a API access token. +type AccessToken struct { + Name string `json:"name"` + Sha1 string `json:"sha1"` +} + +func (c *Client) ListAccessTokens(user, pass string) ([]*AccessToken, error) { + tokens := make([]*AccessToken, 0, 10) + return tokens, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/tokens", user), + http.Header{"Authorization": []string{"Basic " + BasicAuthEncode(user, pass)}}, nil, &tokens) +} + +type CreateAccessTokenOption struct { + Name string `json:"name" binding:"Required"` +} + +func (c *Client) CreateAccessToken(user, pass string, opt CreateAccessTokenOption) (*AccessToken, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + t := new(AccessToken) + return t, c.getParsedResponse("POST", fmt.Sprintf("/users/%s/tokens", user), + http.Header{ + "content-type": []string{"application/json"}, + "Authorization": []string{"Basic " + BasicAuthEncode(user, pass)}}, + bytes.NewReader(body), t) +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/user_email.go b/vendor/code.gitea.io/go-sdk/gitea/user_email.go new file mode 100644 index 0000000000..e9805ecb69 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/user_email.go @@ -0,0 +1,43 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" +) + +type Email struct { + Email string `json:"email"` + Verified bool `json:"verified"` + Primary bool `json:"primary"` +} + +func (c *Client) ListEmails() ([]*Email, error) { + emails := make([]*Email, 0, 3) + return emails, c.getParsedResponse("GET", "/user/emails", nil, nil, &emails) +} + +type CreateEmailOption struct { + Emails []string `json:"emails"` +} + +func (c *Client) AddEmail(opt CreateEmailOption) ([]*Email, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + emails := make([]*Email, 0, 3) + return emails, c.getParsedResponse("POST", "/user/emails", jsonHeader, bytes.NewReader(body), emails) +} + +func (c *Client) DeleteEmail(opt CreateEmailOption) error { + body, err := json.Marshal(&opt) + if err != nil { + return err + } + _, err = c.getResponse("DELETE", "/user/emails", jsonHeader, bytes.NewReader(body)) + return err +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/user_follow.go b/vendor/code.gitea.io/go-sdk/gitea/user_follow.go new file mode 100644 index 0000000000..cbb2c7b3f3 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/user_follow.go @@ -0,0 +1,47 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import "fmt" + +func (c *Client) ListMyFollowers(page int) ([]*User, error) { + users := make([]*User, 0, 10) + return users, c.getParsedResponse("GET", fmt.Sprintf("/user/followers?page=%d", page), nil, nil, &users) +} + +func (c *Client) ListFollowers(user string, page int) ([]*User, error) { + users := make([]*User, 0, 10) + return users, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/followers?page=%d", user, page), nil, nil, &users) +} + +func (c *Client) ListMyFollowing(page int) ([]*User, error) { + users := make([]*User, 0, 10) + return users, c.getParsedResponse("GET", fmt.Sprintf("/user/following?page=%d", page), nil, nil, &users) +} + +func (c *Client) ListFollowing(user string, page int) ([]*User, error) { + users := make([]*User, 0, 10) + return users, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/following?page=%d", user, page), nil, nil, &users) +} + +func (c *Client) IsFollowing(target string) bool { + _, err := c.getResponse("GET", fmt.Sprintf("/user/following/%s", target), nil, nil) + return err == nil +} + +func (c *Client) IsUserFollowing(user, target string) bool { + _, err := c.getResponse("GET", fmt.Sprintf("/users/%s/following/%s", user, target), nil, nil) + return err == nil +} + +func (c *Client) Follow(target string) error { + _, err := c.getResponse("PUT", fmt.Sprintf("/user/following/%s", target), nil, nil) + return err +} + +func (c *Client) Unfollow(target string) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/user/following/%s", target), nil, nil) + return err +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/user_key.go b/vendor/code.gitea.io/go-sdk/gitea/user_key.go new file mode 100644 index 0000000000..8af5ed7c42 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/user_key.go @@ -0,0 +1,49 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "bytes" + "encoding/json" + "fmt" + "time" +) + +type PublicKey struct { + ID int64 `json:"id"` + Key string `json:"key"` + URL string `json:"url,omitempty"` + Title string `json:"title,omitempty"` + Created time.Time `json:"created_at,omitempty"` +} + +func (c *Client) ListPublicKeys(user string) ([]*PublicKey, error) { + keys := make([]*PublicKey, 0, 10) + return keys, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/keys", user), nil, nil, &keys) +} + +func (c *Client) ListMyPublicKeys() ([]*PublicKey, error) { + keys := make([]*PublicKey, 0, 10) + return keys, c.getParsedResponse("GET", "/user/keys", nil, nil, &keys) +} + +func (c *Client) GetPublicKey(keyID int64) (*PublicKey, error) { + key := new(PublicKey) + return key, c.getParsedResponse("GET", fmt.Sprintf("/user/keys/%d", keyID), nil, nil, &key) +} + +func (c *Client) CreatePublicKey(opt CreateKeyOption) (*PublicKey, error) { + body, err := json.Marshal(&opt) + if err != nil { + return nil, err + } + key := new(PublicKey) + return key, c.getParsedResponse("POST", "/user/keys", jsonHeader, bytes.NewReader(body), key) +} + +func (c *Client) DeletePublicKey(keyID int64) error { + _, err := c.getResponse("DELETE", fmt.Sprintf("/user/keys/%d", keyID), nil, nil) + return err +} diff --git a/vendor/code.gitea.io/go-sdk/gitea/utils.go b/vendor/code.gitea.io/go-sdk/gitea/utils.go new file mode 100644 index 0000000000..8d962ba288 --- /dev/null +++ b/vendor/code.gitea.io/go-sdk/gitea/utils.go @@ -0,0 +1,23 @@ +// Copyright 2015 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package gitea + +import ( + "net/http" +) + +var jsonHeader = http.Header{"content-type": []string{"application/json"}} + +func Bool(v bool) *bool { + return &v +} + +func String(v string) *string { + return &v +} + +func Int64(v int64) *int64 { + return &v +} |