From b4970e54d4872d57244f63f35cc4cd00d63bfcfa Mon Sep 17 00:00:00 2001 From: Mark Old Date: Fri, 8 Jun 2018 13:17:37 -0700 Subject: [PATCH 01/58] Add rudimentary gitlab support --- Gopkg.lock | 8 +- Gopkg.toml | 4 + gitlab/display.go | 75 ++ gitlab/gitlab_repo.go | 113 ++ gitlab/widget.go | 162 +++ vendor/github.com/xanzy/go-gitlab/.gitignore | 24 + vendor/github.com/xanzy/go-gitlab/.travis.yml | 27 + .../github.com/xanzy/go-gitlab/CHANGELOG.md | 27 + vendor/github.com/xanzy/go-gitlab/LICENSE | 202 ++++ vendor/github.com/xanzy/go-gitlab/README.md | 171 +++ .../xanzy/go-gitlab/award_emojis.go | 460 ++++++++ vendor/github.com/xanzy/go-gitlab/boards.go | 261 +++++ vendor/github.com/xanzy/go-gitlab/branches.go | 238 +++++ .../xanzy/go-gitlab/broadcast_messages.go | 172 +++ .../xanzy/go-gitlab/build_variables.go | 173 +++ vendor/github.com/xanzy/go-gitlab/commits.go | 448 ++++++++ .../github.com/xanzy/go-gitlab/deploy_keys.go | 201 ++++ .../github.com/xanzy/go-gitlab/deployments.go | 121 +++ .../xanzy/go-gitlab/environments.go | 166 +++ .../github.com/xanzy/go-gitlab/event_types.go | 649 ++++++++++++ vendor/github.com/xanzy/go-gitlab/events.go | 147 +++ .../xanzy/go-gitlab/feature_flags.go | 79 ++ .../xanzy/go-gitlab/gitignore_templates.go | 84 ++ vendor/github.com/xanzy/go-gitlab/gitlab.go | 854 +++++++++++++++ .../xanzy/go-gitlab/group_members.go | 195 ++++ .../xanzy/go-gitlab/group_milestones.go | 250 +++++ vendor/github.com/xanzy/go-gitlab/groups.go | 307 ++++++ .../github.com/xanzy/go-gitlab/issue_links.go | 128 +++ vendor/github.com/xanzy/go-gitlab/issues.go | 403 +++++++ vendor/github.com/xanzy/go-gitlab/jobs.go | 350 ++++++ vendor/github.com/xanzy/go-gitlab/labels.go | 228 ++++ .../go-gitlab/merge_request_approvals.go | 125 +++ .../xanzy/go-gitlab/merge_requests.go | 743 +++++++++++++ .../github.com/xanzy/go-gitlab/milestones.go | 267 +++++ .../github.com/xanzy/go-gitlab/namespaces.go | 122 +++ vendor/github.com/xanzy/go-gitlab/notes.go | 490 +++++++++ .../xanzy/go-gitlab/notifications.go | 214 ++++ .../xanzy/go-gitlab/pages_domains.go | 175 +++ .../xanzy/go-gitlab/pipeline_schedules.go | 341 ++++++ .../xanzy/go-gitlab/pipeline_triggers.go | 232 ++++ .../github.com/xanzy/go-gitlab/pipelines.go | 220 ++++ .../xanzy/go-gitlab/project_members.go | 179 ++++ .../xanzy/go-gitlab/project_snippets.go | 207 ++++ vendor/github.com/xanzy/go-gitlab/projects.go | 997 ++++++++++++++++++ .../xanzy/go-gitlab/protected_branches.go | 165 +++ .../xanzy/go-gitlab/repositories.go | 260 +++++ .../xanzy/go-gitlab/repository_files.go | 235 +++++ vendor/github.com/xanzy/go-gitlab/runners.go | 326 ++++++ vendor/github.com/xanzy/go-gitlab/search.go | 326 ++++++ vendor/github.com/xanzy/go-gitlab/services.go | 515 +++++++++ vendor/github.com/xanzy/go-gitlab/session.go | 78 ++ vendor/github.com/xanzy/go-gitlab/settings.go | 265 +++++ .../xanzy/go-gitlab/sidekiq_metrics.go | 154 +++ vendor/github.com/xanzy/go-gitlab/snippets.go | 230 ++++ vendor/github.com/xanzy/go-gitlab/strings.go | 94 ++ .../xanzy/go-gitlab/system_hooks.go | 143 +++ vendor/github.com/xanzy/go-gitlab/tags.go | 232 ++++ .../github.com/xanzy/go-gitlab/time_stats.go | 163 +++ vendor/github.com/xanzy/go-gitlab/todos.go | 175 +++ vendor/github.com/xanzy/go-gitlab/users.go | 767 ++++++++++++++ vendor/github.com/xanzy/go-gitlab/validate.go | 40 + vendor/github.com/xanzy/go-gitlab/version.go | 56 + vendor/github.com/xanzy/go-gitlab/wikis.go | 204 ++++ wtf.go | 4 + 64 files changed, 15470 insertions(+), 1 deletion(-) create mode 100644 gitlab/display.go create mode 100644 gitlab/gitlab_repo.go create mode 100644 gitlab/widget.go create mode 100644 vendor/github.com/xanzy/go-gitlab/.gitignore create mode 100644 vendor/github.com/xanzy/go-gitlab/.travis.yml create mode 100644 vendor/github.com/xanzy/go-gitlab/CHANGELOG.md create mode 100644 vendor/github.com/xanzy/go-gitlab/LICENSE create mode 100644 vendor/github.com/xanzy/go-gitlab/README.md create mode 100644 vendor/github.com/xanzy/go-gitlab/award_emojis.go create mode 100644 vendor/github.com/xanzy/go-gitlab/boards.go create mode 100644 vendor/github.com/xanzy/go-gitlab/branches.go create mode 100644 vendor/github.com/xanzy/go-gitlab/broadcast_messages.go create mode 100644 vendor/github.com/xanzy/go-gitlab/build_variables.go create mode 100644 vendor/github.com/xanzy/go-gitlab/commits.go create mode 100644 vendor/github.com/xanzy/go-gitlab/deploy_keys.go create mode 100644 vendor/github.com/xanzy/go-gitlab/deployments.go create mode 100644 vendor/github.com/xanzy/go-gitlab/environments.go create mode 100644 vendor/github.com/xanzy/go-gitlab/event_types.go create mode 100644 vendor/github.com/xanzy/go-gitlab/events.go create mode 100644 vendor/github.com/xanzy/go-gitlab/feature_flags.go create mode 100644 vendor/github.com/xanzy/go-gitlab/gitignore_templates.go create mode 100644 vendor/github.com/xanzy/go-gitlab/gitlab.go create mode 100644 vendor/github.com/xanzy/go-gitlab/group_members.go create mode 100644 vendor/github.com/xanzy/go-gitlab/group_milestones.go create mode 100644 vendor/github.com/xanzy/go-gitlab/groups.go create mode 100644 vendor/github.com/xanzy/go-gitlab/issue_links.go create mode 100644 vendor/github.com/xanzy/go-gitlab/issues.go create mode 100644 vendor/github.com/xanzy/go-gitlab/jobs.go create mode 100644 vendor/github.com/xanzy/go-gitlab/labels.go create mode 100644 vendor/github.com/xanzy/go-gitlab/merge_request_approvals.go create mode 100644 vendor/github.com/xanzy/go-gitlab/merge_requests.go create mode 100644 vendor/github.com/xanzy/go-gitlab/milestones.go create mode 100644 vendor/github.com/xanzy/go-gitlab/namespaces.go create mode 100644 vendor/github.com/xanzy/go-gitlab/notes.go create mode 100644 vendor/github.com/xanzy/go-gitlab/notifications.go create mode 100644 vendor/github.com/xanzy/go-gitlab/pages_domains.go create mode 100644 vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go create mode 100644 vendor/github.com/xanzy/go-gitlab/pipeline_triggers.go create mode 100644 vendor/github.com/xanzy/go-gitlab/pipelines.go create mode 100644 vendor/github.com/xanzy/go-gitlab/project_members.go create mode 100644 vendor/github.com/xanzy/go-gitlab/project_snippets.go create mode 100644 vendor/github.com/xanzy/go-gitlab/projects.go create mode 100644 vendor/github.com/xanzy/go-gitlab/protected_branches.go create mode 100644 vendor/github.com/xanzy/go-gitlab/repositories.go create mode 100644 vendor/github.com/xanzy/go-gitlab/repository_files.go create mode 100644 vendor/github.com/xanzy/go-gitlab/runners.go create mode 100644 vendor/github.com/xanzy/go-gitlab/search.go create mode 100644 vendor/github.com/xanzy/go-gitlab/services.go create mode 100644 vendor/github.com/xanzy/go-gitlab/session.go create mode 100644 vendor/github.com/xanzy/go-gitlab/settings.go create mode 100644 vendor/github.com/xanzy/go-gitlab/sidekiq_metrics.go create mode 100644 vendor/github.com/xanzy/go-gitlab/snippets.go create mode 100644 vendor/github.com/xanzy/go-gitlab/strings.go create mode 100644 vendor/github.com/xanzy/go-gitlab/system_hooks.go create mode 100644 vendor/github.com/xanzy/go-gitlab/tags.go create mode 100644 vendor/github.com/xanzy/go-gitlab/time_stats.go create mode 100644 vendor/github.com/xanzy/go-gitlab/todos.go create mode 100644 vendor/github.com/xanzy/go-gitlab/users.go create mode 100644 vendor/github.com/xanzy/go-gitlab/validate.go create mode 100644 vendor/github.com/xanzy/go-gitlab/version.go create mode 100644 vendor/github.com/xanzy/go-gitlab/wikis.go diff --git a/Gopkg.lock b/Gopkg.lock index ef289b39..d59fa66b 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -88,6 +88,12 @@ packages = ["."] revision = "71ecf1f4299c6d72b16d20da72405b7e85ac8720" +[[projects]] + branch = "master" + name = "github.com/xanzy/go-gitlab" + packages = ["."] + revision = "73e9df58a3194b1256edae4d2e819603f06d428c" + [[projects]] branch = "master" name = "github.com/yfronto/newrelic" @@ -164,6 +170,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "b0e632406212933c5f4d7652db7aa06e63f4ed94d38ceb823e5c51b865c20be0" + inputs-digest = "fd122eb7175ffd7db7cb197de13e0b850231ec9269a63a8ca9d117a8aa50d7e5" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index c18c9146..e64c4c7b 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -41,6 +41,10 @@ name = "github.com/google/go-github" branch = "master" +[[constraint]] + name = "github.com/xanzy/go-gitlab" + branch = "master" + [[constraint]] name = "github.com/jessevdk/go-flags" version = "1.4.0" diff --git a/gitlab/display.go b/gitlab/display.go new file mode 100644 index 00000000..8968701b --- /dev/null +++ b/gitlab/display.go @@ -0,0 +1,75 @@ +package gitlab + +import ( + "fmt" + + "github.com/senorprogrammer/wtf/wtf" +) + +func (widget *Widget) display() { + + project := widget.currentGitlabProject() + if project == nil { + fmt.Fprintf(widget.View, "%s", " Gitlab project data is unavailable (1)") + return + } + + widget.View.SetTitle(fmt.Sprintf("%s- %s", widget.Name, widget.title(project))) + + str := wtf.SigilStr(len(widget.GitlabProjects), widget.Idx, widget.View) + "\n" + str = str + " [red]Stats[white]\n" + str = str + widget.displayStats(project) + str = str + "\n" + str = str + " [red]Open Approval Requests[white]\n" + str = str + widget.displayMyApprovalRequests(project, Config.UString("wtf.mods.gitlab.username")) + str = str + "\n" + str = str + " [red]My Merge Requests[white]\n" + str = str + widget.displayMyMergeRequests(project, Config.UString("wtf.mods.gitlab.username")) + + widget.View.SetText(str) +} + +func (widget *Widget) displayMyMergeRequests(project *GitlabProject, username string) string { + mrs := project.myMergeRequests(username) + + if len(mrs) == 0 { + return " [grey]none[white]\n" + } + + str := "" + for _, mr := range mrs { + str = str + fmt.Sprintf(" [green]%4d[white] %s\n", mr.IID, mr.Title) + } + + return str +} + +func (widget *Widget) displayMyApprovalRequests(project *GitlabProject, username string) string { + mrs := project.myApprovalRequests(username) + + if len(mrs) == 0 { + return " [grey]none[white]\n" + } + + str := "" + for _, mr := range mrs { + str = str + fmt.Sprintf(" [green]%4d[white] %s\n", mr.IID, mr.Title) + } + + return str +} + +func (widget *Widget) displayStats(project *GitlabProject) string { + str := fmt.Sprintf( + " MRs: %d Issues: %d Stars: %d\n", + project.MergeRequestCount(), + project.IssueCount(), + project.StarCount(), + ) + + return str +} + +func (widget *Widget) title(project *GitlabProject) string { + return fmt.Sprintf("[green]%s [white]", project.Path) +} diff --git a/gitlab/gitlab_repo.go b/gitlab/gitlab_repo.go new file mode 100644 index 00000000..1af7e00c --- /dev/null +++ b/gitlab/gitlab_repo.go @@ -0,0 +1,113 @@ +package gitlab + +import ( + glb "github.com/xanzy/go-gitlab" +) + +type GitlabProject struct { + gitlab *glb.Client + Path string + + MergeRequests []*glb.MergeRequest + RemoteProject *glb.Project +} + +func NewGitlabProject(name string, namespace string, gitlab *glb.Client) *GitlabProject { + path := namespace + "/" + name + project := GitlabProject{ + gitlab: gitlab, + Path: path, + } + + return &project +} + +// Refresh reloads the gitlab data via the Gitlab API +func (project *GitlabProject) Refresh() { + project.MergeRequests, _ = project.loadMergeRequests() + project.RemoteProject, _ = project.loadRemoteProject() +} + +/* -------------------- Counts -------------------- */ + +func (project *GitlabProject) IssueCount() int { + if project.RemoteProject == nil { + return 0 + } + + return project.RemoteProject.OpenIssuesCount +} + +func (project *GitlabProject) MergeRequestCount() int { + return len(project.MergeRequests) +} + +func (project *GitlabProject) StarCount() int { + if project.RemoteProject == nil { + return 0 + } + + return project.RemoteProject.StarCount +} + +/* -------------------- Unexported Functions -------------------- */ + +// myMergeRequests returns a list of merge requests created by username on this project +func (project *GitlabProject) myMergeRequests(username string) []*glb.MergeRequest { + mrs := []*glb.MergeRequest{} + + for _, mr := range project.MergeRequests { + user := mr.Author + + if user.Username == username { + mrs = append(mrs, mr) + } + } + + return mrs +} + +// myApprovalRequests returns a list of merge requests for which username has been +// requested to approve +func (project *GitlabProject) myApprovalRequests(username string) []*glb.MergeRequest { + mrs := []*glb.MergeRequest{} + + for _, mr := range project.MergeRequests { + approvers, _, err := project.gitlab.MergeRequests.GetMergeRequestApprovals(project.Path, mr.IID) + if err != nil { + continue + } + for _, approver := range approvers.Approvers { + if approver.User.Username == username { + mrs = append(mrs, mr) + } + } + } + + return mrs +} + +func (project *GitlabProject) loadMergeRequests() ([]*glb.MergeRequest, error) { + state := "opened" + opts := glb.ListProjectMergeRequestsOptions{ + State: &state, + } + + mrs, _, err := project.gitlab.MergeRequests.ListProjectMergeRequests(project.Path, &opts) + + if err != nil { + return nil, err + } + + return mrs, nil +} + +func (project *GitlabProject) loadRemoteProject() (*glb.Project, error) { + projectsitory, _, err := project.gitlab.Projects.GetProject(project.Path) + + if err != nil { + return nil, err + } + + return projectsitory, nil +} diff --git a/gitlab/widget.go b/gitlab/widget.go new file mode 100644 index 00000000..9dd19ba9 --- /dev/null +++ b/gitlab/widget.go @@ -0,0 +1,162 @@ +package gitlab + +import ( + "os" + + "github.com/gdamore/tcell" + "github.com/olebedev/config" + "github.com/rivo/tview" + "github.com/senorprogrammer/wtf/wtf" + glb "github.com/xanzy/go-gitlab" +) + +// Config is a pointer to the global config object +var Config *config.Config + +const HelpText = ` + Keyboard commands for Gitlab: + + /: Show/hide this help window + h: Previous project + l: Next project + r: Refresh the data + + arrow left: Previous project + arrow right: Next project +` + +type Widget struct { + wtf.TextWidget + + app *tview.Application + pages *tview.Pages + + gitlab *glb.Client + + GitlabProjects []*GitlabProject + Idx int +} + +func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { + apiKey := os.Getenv("WTF_GITLAB_TOKEN") + baseURL := Config.UString("wtf.mods.gitlab.domain") + gitlab := glb.NewClient(nil, apiKey) + if baseURL != "" { + gitlab.SetBaseURL(baseURL) + } + + widget := Widget{ + TextWidget: wtf.NewTextWidget(" Gitlab ", "gitlab", true), + + app: app, + pages: pages, + + gitlab: gitlab, + + Idx: 0, + } + + widget.GitlabProjects = widget.buildProjectCollection(Config.UMap("wtf.mods.gitlab.projects")) + + widget.View.SetInputCapture(widget.keyboardIntercept) + + return &widget +} + +/* -------------------- Exported Functions -------------------- */ + +func (widget *Widget) Refresh() { + if widget.Disabled() { + return + } + + for _, project := range widget.GitlabProjects { + project.Refresh() + } + + widget.UpdateRefreshedAt() + widget.display() +} + +func (widget *Widget) Next() { + widget.Idx = widget.Idx + 1 + if widget.Idx == len(widget.GitlabProjects) { + widget.Idx = 0 + } + + widget.display() +} + +func (widget *Widget) Prev() { + widget.Idx = widget.Idx - 1 + if widget.Idx < 0 { + widget.Idx = len(widget.GitlabProjects) - 1 + } + + widget.display() +} + +/* -------------------- Unexported Functions -------------------- */ + +func (widget *Widget) buildProjectCollection(projectData map[string]interface{}) []*GitlabProject { + gitlabProjects := []*GitlabProject{} + + for name, namespace := range projectData { + project := NewGitlabProject(name, namespace.(string), widget.gitlab) + gitlabProjects = append(gitlabProjects, project) + } + + return gitlabProjects +} + +func (widget *Widget) currentGitlabProject() *GitlabProject { + if len(widget.GitlabProjects) == 0 { + return nil + } + + if widget.Idx < 0 || widget.Idx >= len(widget.GitlabProjects) { + return nil + } + + return widget.GitlabProjects[widget.Idx] +} + +func (widget *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey { + switch string(event.Rune()) { + case "/": + widget.showHelp() + return nil + case "h": + widget.Prev() + return nil + case "l": + widget.Next() + return nil + case "r": + widget.Refresh() + return nil + } + + switch event.Key() { + case tcell.KeyLeft: + widget.Prev() + return nil + case tcell.KeyRight: + widget.Next() + return nil + default: + return event + } +} + +func (widget *Widget) showHelp() { + closeFunc := func() { + widget.pages.RemovePage("help") + widget.app.SetFocus(widget.View) + } + + modal := wtf.NewBillboardModal(HelpText, closeFunc) + + widget.pages.AddPage("help", modal, false, true) + widget.app.SetFocus(modal) +} diff --git a/vendor/github.com/xanzy/go-gitlab/.gitignore b/vendor/github.com/xanzy/go-gitlab/.gitignore new file mode 100644 index 00000000..daf913b1 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/xanzy/go-gitlab/.travis.yml b/vendor/github.com/xanzy/go-gitlab/.travis.yml new file mode 100644 index 00000000..26203291 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/.travis.yml @@ -0,0 +1,27 @@ +language: go + +go: + - 1.8.x + - 1.9.x + - 1.10.x + - master + +stages: + - lint + - test + +jobs: + include: + - stage: lint + script: + - go get github.com/golang/lint/golint + - golint -set_exit_status + - go vet -v + - stage: test + script: + - go test -v + +matrix: + allow_failures: + - go: master + fast_finish: true diff --git a/vendor/github.com/xanzy/go-gitlab/CHANGELOG.md b/vendor/github.com/xanzy/go-gitlab/CHANGELOG.md new file mode 100644 index 00000000..29e93fff --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/CHANGELOG.md @@ -0,0 +1,27 @@ +go-github CHANGELOG +=================== + +0.6.0 +----- +- Add support for the V4 Gitlab API. This means the older V3 API is no longer fully supported + with this version. If you still need that version, please use the `f-api-v3` branch. + +0.4.0 +----- +- Add support to use [`sudo`](https://docs.gitlab.com/ce/api/README.html#sudo) for all API calls. +- Add support for the Notification Settings API. +- Add support for the Time Tracking API. +- Make sure that the error response correctly outputs any returned errors. +- And a reasonable number of smaller enhanchements and bugfixes. + +0.3.0 +----- +- Moved the tags related API calls to their own service, following the Gitlab API structure. + +0.2.0 +----- +- Convert all Option structs to use pointers for their fields. + +0.1.0 +----- +- Initial release. diff --git a/vendor/github.com/xanzy/go-gitlab/LICENSE b/vendor/github.com/xanzy/go-gitlab/LICENSE new file mode 100644 index 00000000..e06d2081 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/LICENSE @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/github.com/xanzy/go-gitlab/README.md b/vendor/github.com/xanzy/go-gitlab/README.md new file mode 100644 index 00000000..dc793162 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/README.md @@ -0,0 +1,171 @@ +# go-gitlab + +A GitLab API client enabling Go programs to interact with GitLab in a simple and uniform way + +[![Build Status](https://travis-ci.org/xanzy/go-gitlab.svg?branch=master)](https://travis-ci.org/xanzy/go-gitlab) +[![GitHub license](https://img.shields.io/github/license/xanzy/go-gitlab.svg)](https://github.com/xanzy/go-gitlab/blob/master/LICENSE) +[![Sourcegraph](https://sourcegraph.com/github.com/xanzy/go-gitlab/-/badge.svg)](https://sourcegraph.com/github.com/xanzy/go-gitlab?badge) +[![GoDoc](https://godoc.org/github.com/xanzy/go-gitlab?status.svg)](https://godoc.org/github.com/xanzy/go-gitlab) +[![Go Report Card](https://goreportcard.com/badge/github.com/xanzy/go-gitlab)](https://goreportcard.com/report/github.com/xanzy/go-gitlab) +[![GitHub issues](https://img.shields.io/github/issues/xanzy/go-gitlab.svg)](https://github.com/xanzy/go-gitlab/issues) + +## NOTE + +Release v0.6.0 (released on 25-08-2017) no longer supports the older V3 Gitlab API. If +you need V3 support, please use the `f-api-v3` branch. This release contains some backwards +incompatible changes that were needed to fully support the V4 Gitlab API. + +## Coverage + +This API client package covers most of the existing Gitlab API calls and is updated regularly +to add new and/or missing endpoints. Currently the following services are supported: + +- [x] Award Emojis +- [x] Branches +- [x] Broadcast Messages +- [ ] Project-level Variables +- [ ] Group-level Variables +- [x] Commits +- [ ] Custom Attributes +- [x] Deployments +- [x] Deploy Keys +- [x] Environments +- [ ] Epics +- [ ] Epic Issues +- [x] Events +- [x] Feature flags +- [ ] Geo Nodes +- [x] Gitignores templates +- [ ] GitLab CI Config templates +- [x] Groups +- [ ] Group Access Requests +- [x] Group Members +- [x] Issues +- [x] Issue Boards +- [x] Jobs +- [ ] Keys +- [x] Labels +- [ ] License +- [x] Merge Requests +- [x] Merge Request Approvals +- [x] Project Milestones +- [ ] Group Milestones +- [x] Namespaces +- [x] Notes (comments) +- [ ] Discussions (threaded comments) +- [x] Notification settings +- [ ] Open source license templates +- [x] Pages Domains +- [x] Pipelines +- [x] Pipeline Triggers +- [x] Pipeline Schedules +- [x] Projects (including setting Webhooks) +- [ ] Project Access Requests +- [ ] Project badges +- [ ] Project import/export +- [x] Project Members +- [x] Project Snippets +- [x] Protected Branches +- [x] Repositories +- [x] Repository Files +- [x] Runners +- [ ] Search +- [x] Services +- [x] Settings +- [x] Sidekiq metrics +- [x] Session +- [x] System Hooks +- [x] Tags +- [x] Todos +- [x] Users +- [x] Validate CI configuration +- [x] Version +- [x] Wikis + +## Usage + +```go +import "github.com/xanzy/go-gitlab" +``` + +Construct a new GitLab client, then use the various services on the client to +access different parts of the GitLab API. For example, to list all +users: + +```go +git := gitlab.NewClient(nil, "yourtokengoeshere") +//git.SetBaseURL("https://git.mydomain.com/api/v3") +users, _, err := git.Users.ListUsers() +``` + +Some API methods have optional parameters that can be passed. For example, +to list all projects for user "svanharmelen": + +```go +git := gitlab.NewClient(nil) +opt := &ListProjectsOptions{Search: gitlab.String("svanharmelen")} +projects, _, err := git.Projects.ListProjects(opt) +``` + +### Examples + +The [examples](https://github.com/xanzy/go-gitlab/tree/master/examples) directory +contains a couple for clear examples, of which one is partially listed here as well: + +```go +package main + +import ( + "log" + + "github.com/xanzy/go-gitlab" +) + +func main() { + git := gitlab.NewClient(nil, "yourtokengoeshere") + + // Create new project + p := &gitlab.CreateProjectOptions{ + Name: gitlab.String("My Project"), + Description: gitlab.String("Just a test project to play with"), + MergeRequestsEnabled: gitlab.Bool(true), + SnippetsEnabled: gitlab.Bool(true), + Visibility: gitlab.Visibility(gitlab.PublicVisibility), + } + project, _, err := git.Projects.CreateProject(p) + if err != nil { + log.Fatal(err) + } + + // Add a new snippet + s := &gitlab.CreateProjectSnippetOptions{ + Title: gitlab.String("Dummy Snippet"), + FileName: gitlab.String("snippet.go"), + Code: gitlab.String("package main...."), + Visibility: gitlab.Visibility(gitlab.PublicVisibility), + } + _, _, err = git.ProjectSnippets.CreateSnippet(project.ID, s) + if err != nil { + log.Fatal(err) + } +} + +``` + +For complete usage of go-gitlab, see the full [package docs](https://godoc.org/github.com/xanzy/go-gitlab). + +## ToDo + +- The biggest thing this package still needs is tests :disappointed: + +## Issues + +- If you have an issue: report it on the [issue tracker](https://github.com/xanzy/go-gitlab/issues) + +## Author + +Sander van Harmelen () + +## License + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at diff --git a/vendor/github.com/xanzy/go-gitlab/award_emojis.go b/vendor/github.com/xanzy/go-gitlab/award_emojis.go new file mode 100644 index 00000000..b12a662f --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/award_emojis.go @@ -0,0 +1,460 @@ +// +// Copyright 2017, Arkbriar +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// AwardEmojiService handles communication with the emoji awards related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/award_emoji.html +type AwardEmojiService struct { + client *Client +} + +// AwardEmoji represents a GitLab Award Emoji. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/award_emoji.html +type AwardEmoji struct { + ID int `json:"id"` + Name string `json:"name"` + User struct { + Name string `json:"name"` + Username string `json:"username"` + ID int `json:"id"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + } `json:"user"` + CreatedAt *time.Time `json:"created_at"` + UpdatedAt *time.Time `json:"updated_at"` + AwardableID int `json:"awardable_id"` + AwardableType string `json:"awardable_type"` +} + +const ( + awardMergeRequest = "merge_requests" + awardIssue = "issues" + awardSnippets = "snippets" +) + +// ListEmojiAwardsOptions represents the available options for listing emoji +// for each resources +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html +type ListEmojiAwardsOptions ListOptions + +// ListMergeRequestAwardEmoji gets a list of all award emoji on the merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji +func (s *AwardEmojiService) ListMergeRequestAwardEmoji(pid interface{}, mergeRequestIID int, opt *ListEmojiAwardsOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { + return s.listAwardEmoji(pid, awardMergeRequest, mergeRequestIID, opt, options...) +} + +// ListIssueAwardEmoji gets a list of all award emoji on the issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji +func (s *AwardEmojiService) ListIssueAwardEmoji(pid interface{}, issueIID int, opt *ListEmojiAwardsOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { + return s.listAwardEmoji(pid, awardIssue, issueIID, opt, options...) +} + +// ListSnippetAwardEmoji gets a list of all award emoji on the snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji +func (s *AwardEmojiService) ListSnippetAwardEmoji(pid interface{}, snippetID int, opt *ListEmojiAwardsOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { + return s.listAwardEmoji(pid, awardSnippets, snippetID, opt, options...) +} + +func (s *AwardEmojiService) listAwardEmoji(pid interface{}, resource string, resourceID int, opt *ListEmojiAwardsOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/award_emoji", + url.QueryEscape(project), + resource, + resourceID, + ) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var as []*AwardEmoji + resp, err := s.client.Do(req, &as) + if err != nil { + return nil, resp, err + } + + return as, resp, err +} + +// GetMergeRequestAwardEmoji get an award emoji from merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji +func (s *AwardEmojiService) GetMergeRequestAwardEmoji(pid interface{}, mergeRequestIID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.getAwardEmoji(pid, awardMergeRequest, mergeRequestIID, awardID, options...) +} + +// GetIssueAwardEmoji get an award emoji from issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji +func (s *AwardEmojiService) GetIssueAwardEmoji(pid interface{}, issueIID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.getAwardEmoji(pid, awardIssue, issueIID, awardID, options...) +} + +// GetSnippetAwardEmoji get an award emoji from snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#list-an-awardable-39-s-award-emoji +func (s *AwardEmojiService) GetSnippetAwardEmoji(pid interface{}, snippetID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.getAwardEmoji(pid, awardSnippets, snippetID, awardID, options...) +} + +func (s *AwardEmojiService) getAwardEmoji(pid interface{}, resource string, resourceID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/award_emoji/%d", + url.QueryEscape(project), + resource, + resourceID, + awardID, + ) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + a := new(AwardEmoji) + resp, err := s.client.Do(req, &a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// CreateMergeRequestAwardEmoji get an award emoji from merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji +func (s *AwardEmojiService) CreateMergeRequestAwardEmoji(pid interface{}, mergeRequestIID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.createAwardEmoji(pid, awardMergeRequest, mergeRequestIID, awardID, options...) +} + +// CreateIssueAwardEmoji get an award emoji from issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji +func (s *AwardEmojiService) CreateIssueAwardEmoji(pid interface{}, issueIID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.createAwardEmoji(pid, awardIssue, issueIID, awardID, options...) +} + +// CreateSnippetAwardEmoji get an award emoji from snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji +func (s *AwardEmojiService) CreateSnippetAwardEmoji(pid interface{}, snippetID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.createAwardEmoji(pid, awardSnippets, snippetID, awardID, options...) +} + +func (s *AwardEmojiService) createAwardEmoji(pid interface{}, resource string, resourceID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/award_emoji/%d", + url.QueryEscape(project), + resource, + resourceID, + awardID, + ) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + a := new(AwardEmoji) + resp, err := s.client.Do(req, &a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// DeleteIssueAwardEmoji delete award emoji on an issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note +func (s *AwardEmojiService) DeleteIssueAwardEmoji(pid interface{}, issueIID, awardID int, options ...OptionFunc) (*Response, error) { + return s.deleteAwardEmoji(pid, awardMergeRequest, issueIID, awardID, options...) +} + +// DeleteMergeRequestAwardEmoji delete award emoji on a merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note +func (s *AwardEmojiService) DeleteMergeRequestAwardEmoji(pid interface{}, mergeRequestIID, awardID int, options ...OptionFunc) (*Response, error) { + return s.deleteAwardEmoji(pid, awardMergeRequest, mergeRequestIID, awardID, options...) +} + +// DeleteSnippetAwardEmoji delete award emoji on a snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note +func (s *AwardEmojiService) DeleteSnippetAwardEmoji(pid interface{}, snippetID, awardID int, options ...OptionFunc) (*Response, error) { + return s.deleteAwardEmoji(pid, awardMergeRequest, snippetID, awardID, options...) +} + +// DeleteAwardEmoji Delete an award emoji on the specified resource. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#delete-an-award-emoji +func (s *AwardEmojiService) deleteAwardEmoji(pid interface{}, resource string, resourceID, awardID int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/award_emoji/%d", url.QueryEscape(project), resource, + resourceID, awardID) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + return s.client.Do(req, nil) +} + +// ListIssuesAwardEmojiOnNote gets a list of all award emoji on a note from the +// issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) ListIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID int, opt *ListEmojiAwardsOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { + return s.listAwardEmojiOnNote(pid, awardIssue, issueID, noteID, opt, options...) +} + +// ListMergeRequestAwardEmojiOnNote gets a list of all award emoji on a note +// from the merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) ListMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID int, opt *ListEmojiAwardsOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { + return s.listAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, opt, options...) +} + +// ListSnippetAwardEmojiOnNote gets a list of all award emoji on a note from the +// snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) ListSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID int, opt *ListEmojiAwardsOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { + return s.listAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, opt, options...) +} + +func (s *AwardEmojiService) listAwardEmojiOnNote(pid interface{}, resources string, ressourceID, noteID int, opt *ListEmojiAwardsOptions, options ...OptionFunc) ([]*AwardEmoji, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji", url.QueryEscape(project), resources, + ressourceID, noteID) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var as []*AwardEmoji + resp, err := s.client.Do(req, &as) + if err != nil { + return nil, resp, err + } + + return as, resp, err +} + +// GetIssuesAwardEmojiOnNote gets an award emoji on a note from an issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) GetIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.getSingleNoteAwardEmoji(pid, awardIssue, issueID, noteID, awardID, options...) +} + +// GetMergeRequestAwardEmojiOnNote gets an award emoji on a note from a +// merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) GetMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.getSingleNoteAwardEmoji(pid, awardMergeRequest, mergeRequestIID, noteID, awardID, + options...) +} + +// GetSnippetAwardEmojiOnNote gets an award emoji on a note from a snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) GetSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.getSingleNoteAwardEmoji(pid, awardSnippets, snippetIID, noteID, awardID, options...) +} + +func (s *AwardEmojiService) getSingleNoteAwardEmoji(pid interface{}, ressource string, resourceID, noteID, awardID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji/%d", + url.QueryEscape(project), + ressource, + resourceID, + noteID, + awardID, + ) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + a := new(AwardEmoji) + resp, err := s.client.Do(req, &a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// CreateIssuesAwardEmojiOnNote gets an award emoji on a note from an issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) CreateIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.createAwardEmojiOnNote(pid, awardIssue, issueID, noteID, options...) +} + +// CreateMergeRequestAwardEmojiOnNote gets an award emoji on a note from a +// merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) CreateMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.createAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, options...) +} + +// CreateSnippetAwardEmojiOnNote gets an award emoji on a note from a snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) CreateSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + return s.createAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, options...) +} + +// CreateAwardEmojiOnNote award emoji on a note. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-a-new-emoji-on-a-note +func (s *AwardEmojiService) createAwardEmojiOnNote(pid interface{}, resource string, resourceID, noteID int, options ...OptionFunc) (*AwardEmoji, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji", + url.QueryEscape(project), + resource, + resourceID, + noteID, + ) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + a := new(AwardEmoji) + resp, err := s.client.Do(req, &a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// DeleteIssuesAwardEmojiOnNote deletes an award emoji on a note from an issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) DeleteIssuesAwardEmojiOnNote(pid interface{}, issueID, noteID, awardID int, options ...OptionFunc) (*Response, error) { + return s.deleteAwardEmojiOnNote(pid, awardIssue, issueID, noteID, awardID, options...) +} + +// DeleteMergeRequestAwardEmojiOnNote deletes an award emoji on a note from a +// merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) DeleteMergeRequestAwardEmojiOnNote(pid interface{}, mergeRequestIID, noteID, awardID int, options ...OptionFunc) (*Response, error) { + return s.deleteAwardEmojiOnNote(pid, awardMergeRequest, mergeRequestIID, noteID, awardID, + options...) +} + +// DeleteSnippetAwardEmojiOnNote deletes an award emoji on a note from a snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/award_emoji.html#award-emoji-on-notes +func (s *AwardEmojiService) DeleteSnippetAwardEmojiOnNote(pid interface{}, snippetIID, noteID, awardID int, options ...OptionFunc) (*Response, error) { + return s.deleteAwardEmojiOnNote(pid, awardSnippets, snippetIID, noteID, awardID, options...) +} + +func (s *AwardEmojiService) deleteAwardEmojiOnNote(pid interface{}, resource string, resourceID, noteID, awardID int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/notes/%d/award_emoji/%d", + url.QueryEscape(project), + resource, + resourceID, + noteID, + awardID, + ) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/boards.go b/vendor/github.com/xanzy/go-gitlab/boards.go new file mode 100644 index 00000000..7579a5bd --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/boards.go @@ -0,0 +1,261 @@ +// +// Copyright 2015, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// IssueBoardsService handles communication with the issue board related +// methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html +type IssueBoardsService struct { + client *Client +} + +// IssueBoard represents a GitLab issue board. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html +type IssueBoard struct { + ID int `json:"id"` + Name string `json:"name"` + Project *Project `json:"project"` + Milestone *Milestone `json:"milestone"` + Lists []*BoardList `json:"lists"` +} + +func (b IssueBoard) String() string { + return Stringify(b) +} + +// BoardList represents a GitLab board list. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html +type BoardList struct { + ID int `json:"id"` + Labels []*Label `json:"labels"` + Position int `json:"position"` +} + +func (b BoardList) String() string { + return Stringify(b) +} + +// ListIssueBoardsOptions represents the available ListIssueBoards() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#project-board +type ListIssueBoardsOptions ListOptions + +// ListIssueBoards gets a list of all issue boards in a project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#project-board +func (s *IssueBoardsService) ListIssueBoards(pid interface{}, opt *ListIssueBoardsOptions, options ...OptionFunc) ([]*IssueBoard, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/boards", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var is []*IssueBoard + resp, err := s.client.Do(req, &is) + if err != nil { + return nil, resp, err + } + + return is, resp, err +} + +// GetIssueBoard gets a single issue board of a project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#single-board +func (s *IssueBoardsService) GetIssueBoard(pid interface{}, board int, options ...OptionFunc) (*IssueBoard, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/boards/%d", url.QueryEscape(project), board) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + ib := new(IssueBoard) + resp, err := s.client.Do(req, ib) + if err != nil { + return nil, resp, err + } + + return ib, resp, err +} + +// GetIssueBoardListsOptions represents the available GetIssueBoardLists() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#list-board-lists +type GetIssueBoardListsOptions ListOptions + +// GetIssueBoardLists gets a list of the issue board's lists. Does not include +// backlog and closed lists. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#list-board-lists +func (s *IssueBoardsService) GetIssueBoardLists(pid interface{}, board int, opt *GetIssueBoardListsOptions, options ...OptionFunc) ([]*BoardList, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/boards/%d/lists", url.QueryEscape(project), board) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var bl []*BoardList + resp, err := s.client.Do(req, &bl) + if err != nil { + return nil, resp, err + } + + return bl, resp, err +} + +// GetIssueBoardList gets a single issue board list. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#single-board-list +func (s *IssueBoardsService) GetIssueBoardList(pid interface{}, board, list int, options ...OptionFunc) (*BoardList, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/boards/%d/lists/%d", + url.QueryEscape(project), + board, + list, + ) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + bl := new(BoardList) + resp, err := s.client.Do(req, bl) + if err != nil { + return nil, resp, err + } + + return bl, resp, err +} + +// CreateIssueBoardListOptions represents the available CreateIssueBoardList() +// options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#new-board-list +type CreateIssueBoardListOptions struct { + LabelID *int `url:"label_id" json:"label_id"` +} + +// CreateIssueBoardList creates a new issue board list. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#new-board-list +func (s *IssueBoardsService) CreateIssueBoardList(pid interface{}, board int, opt *CreateIssueBoardListOptions, options ...OptionFunc) (*BoardList, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/boards/%d/lists", url.QueryEscape(project), board) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + bl := new(BoardList) + resp, err := s.client.Do(req, bl) + if err != nil { + return nil, resp, err + } + + return bl, resp, err +} + +// UpdateIssueBoardListOptions represents the available UpdateIssueBoardList() +// options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#edit-board-list +type UpdateIssueBoardListOptions struct { + Position *int `url:"position" json:"position"` +} + +// UpdateIssueBoardList updates the position of an existing issue board list. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/boards.html#edit-board-list +func (s *IssueBoardsService) UpdateIssueBoardList(pid interface{}, board, list int, opt *UpdateIssueBoardListOptions, options ...OptionFunc) (*BoardList, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/boards/%d/lists/%d", + url.QueryEscape(project), + board, + list, + ) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + bl := new(BoardList) + resp, err := s.client.Do(req, bl) + if err != nil { + return nil, resp, err + } + + return bl, resp, err +} + +// DeleteIssueBoardList soft deletes an issue board list. Only for admins and +// project owners. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/boards.html#delete-a-board-list +func (s *IssueBoardsService) DeleteIssueBoardList(pid interface{}, board, list int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/boards/%d/lists/%d", + url.QueryEscape(project), + board, + list, + ) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/branches.go b/vendor/github.com/xanzy/go-gitlab/branches.go new file mode 100644 index 00000000..3f7bd0cd --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/branches.go @@ -0,0 +1,238 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// BranchesService handles communication with the branch related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/branches.html +type BranchesService struct { + client *Client +} + +// Branch represents a GitLab branch. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/branches.html +type Branch struct { + Commit *Commit `json:"commit"` + Name string `json:"name"` + Protected bool `json:"protected"` + Merged bool `json:"merged"` + DevelopersCanPush bool `json:"developers_can_push"` + DevelopersCanMerge bool `json:"developers_can_merge"` +} + +func (b Branch) String() string { + return Stringify(b) +} + +// ListBranchesOptions represents the available ListBranches() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/branches.html#list-repository-branches +type ListBranchesOptions ListOptions + +// ListBranches gets a list of repository branches from a project, sorted by +// name alphabetically. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/branches.html#list-repository-branches +func (s *BranchesService) ListBranches(pid interface{}, opts *ListBranchesOptions, options ...OptionFunc) ([]*Branch, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/branches", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opts, options) + if err != nil { + return nil, nil, err + } + + var b []*Branch + resp, err := s.client.Do(req, &b) + if err != nil { + return nil, resp, err + } + + return b, resp, err +} + +// GetBranch gets a single project repository branch. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/branches.html#get-single-repository-branch +func (s *BranchesService) GetBranch(pid interface{}, branch string, options ...OptionFunc) (*Branch, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/branches/%s", url.QueryEscape(project), url.QueryEscape(branch)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + b := new(Branch) + resp, err := s.client.Do(req, b) + if err != nil { + return nil, resp, err + } + + return b, resp, err +} + +// ProtectBranchOptions represents the available ProtectBranch() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch +type ProtectBranchOptions struct { + DevelopersCanPush *bool `url:"developers_can_push,omitempty" json:"developers_can_push,omitempty"` + DevelopersCanMerge *bool `url:"developers_can_merge,omitempty" json:"developers_can_merge,omitempty"` +} + +// ProtectBranch protects a single project repository branch. This is an +// idempotent function, protecting an already protected repository branch +// still returns a 200 OK status code. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/branches.html#protect-repository-branch +func (s *BranchesService) ProtectBranch(pid interface{}, branch string, opts *ProtectBranchOptions, options ...OptionFunc) (*Branch, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/branches/%s/protect", url.QueryEscape(project), url.QueryEscape(branch)) + + req, err := s.client.NewRequest("PUT", u, opts, options) + if err != nil { + return nil, nil, err + } + + b := new(Branch) + resp, err := s.client.Do(req, b) + if err != nil { + return nil, resp, err + } + + return b, resp, err +} + +// UnprotectBranch unprotects a single project repository branch. This is an +// idempotent function, unprotecting an already unprotected repository branch +// still returns a 200 OK status code. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/branches.html#unprotect-repository-branch +func (s *BranchesService) UnprotectBranch(pid interface{}, branch string, options ...OptionFunc) (*Branch, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/branches/%s/unprotect", url.QueryEscape(project), url.QueryEscape(branch)) + + req, err := s.client.NewRequest("PUT", u, nil, options) + if err != nil { + return nil, nil, err + } + + b := new(Branch) + resp, err := s.client.Do(req, b) + if err != nil { + return nil, resp, err + } + + return b, resp, err +} + +// CreateBranchOptions represents the available CreateBranch() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/branches.html#create-repository-branch +type CreateBranchOptions struct { + Branch *string `url:"branch,omitempty" json:"branch,omitempty"` + Ref *string `url:"ref,omitempty" json:"ref,omitempty"` +} + +// CreateBranch creates branch from commit SHA or existing branch. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/branches.html#create-repository-branch +func (s *BranchesService) CreateBranch(pid interface{}, opt *CreateBranchOptions, options ...OptionFunc) (*Branch, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/branches", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + b := new(Branch) + resp, err := s.client.Do(req, b) + if err != nil { + return nil, resp, err + } + + return b, resp, err +} + +// DeleteBranch deletes an existing branch. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/branches.html#delete-repository-branch +func (s *BranchesService) DeleteBranch(pid interface{}, branch string, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/repository/branches/%s", url.QueryEscape(project), url.QueryEscape(branch)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteMergedBranches deletes all branches that are merged into the project's default branch. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/branches.html#delete-merged-branches +func (s *BranchesService) DeleteMergedBranches(pid interface{}, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/repository/merged_branches", url.QueryEscape(project)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/broadcast_messages.go b/vendor/github.com/xanzy/go-gitlab/broadcast_messages.go new file mode 100644 index 00000000..aee852d4 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/broadcast_messages.go @@ -0,0 +1,172 @@ +// +// Copyright 2018, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "time" +) + +// BroadcastMessagesService handles communication with the broadcast +// messages methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/broadcast_messages.html +type BroadcastMessagesService struct { + client *Client +} + +// BroadcastMessage represents a GitLab issue board. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages +type BroadcastMessage struct { + Message string `json:"message"` + StartsAt *time.Time `json:"starts_at"` + EndsAt *time.Time `json:"ends_at"` + Color string `json:"color"` + Font string `json:"font"` + ID int `json:"id"` + Active bool `json:"active"` +} + +// ListBroadcastMessagesOptions represents the available ListBroadcastMessages() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages +type ListBroadcastMessagesOptions ListOptions + +// ListBroadcastMessages gets a list of all broadcasted messages. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-all-broadcast-messages +func (s *BroadcastMessagesService) ListBroadcastMessages(opt *ListBroadcastMessagesOptions, options ...OptionFunc) ([]*BroadcastMessage, *Response, error) { + req, err := s.client.NewRequest("GET", "broadcast_messages", opt, options) + if err != nil { + return nil, nil, err + } + + var bs []*BroadcastMessage + resp, err := s.client.Do(req, &bs) + if err != nil { + return nil, resp, err + } + + return bs, resp, err +} + +// GetBroadcastMessage gets a single broadcast message. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/broadcast_messages.html#get-a-specific-broadcast-message +func (s *BroadcastMessagesService) GetBroadcastMessage(broadcast int, options ...OptionFunc) (*BroadcastMessage, *Response, error) { + u := fmt.Sprintf("broadcast_messages/%d", broadcast) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + b := new(BroadcastMessage) + resp, err := s.client.Do(req, &b) + if err != nil { + return nil, resp, err + } + + return b, resp, err +} + +// CreateBroadcastMessageOptions represents the available CreateBroadcastMessage() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/broadcast_messages.html#create-a-broadcast-message +type CreateBroadcastMessageOptions struct { + Message *string `url:"message" json:"message"` + StartsAt *time.Time `url:"starts_at,omitempty" json:"starts_at,omitempty"` + EndsAt *time.Time `url:"ends_at,omitempty" json:"ends_at,omitempty"` + Color *string `url:"color,omitempty" json:"color,omitempty"` + Font *string `url:"font,omitempty" json:"font,omitempty"` +} + +// CreateBroadcastMessage creates a message to broadcast. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/broadcast_messages.html#create-a-broadcast-message +func (s *BroadcastMessagesService) CreateBroadcastMessage(opt *CreateBroadcastMessageOptions, options ...OptionFunc) (*BroadcastMessage, *Response, error) { + req, err := s.client.NewRequest("POST", "broadcast_messages", opt, options) + if err != nil { + return nil, nil, err + } + + b := new(BroadcastMessage) + resp, err := s.client.Do(req, &b) + if err != nil { + return nil, resp, err + } + + return b, resp, err +} + +// UpdateBroadcastMessageOptions represents the available CreateBroadcastMessage() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/broadcast_messages.html#update-a-broadcast-message +type UpdateBroadcastMessageOptions struct { + Message *string `url:"message,omitempty" json:"message,omitempty"` + StartsAt *time.Time `url:"starts_at,omitempty" json:"starts_at,omitempty"` + EndsAt *time.Time `url:"ends_at,omitempty" json:"ends_at,omitempty"` + Color *string `url:"color,omitempty" json:"color,omitempty"` + Font *string `url:"font,omitempty" json:"font,omitempty"` +} + +// UpdateBroadcastMessage update a broadcasted message. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/broadcast_messages.html#update-a-broadcast-message +func (s *BroadcastMessagesService) UpdateBroadcastMessage(broadcast int, opt *UpdateBroadcastMessageOptions, options ...OptionFunc) (*BroadcastMessage, *Response, error) { + u := fmt.Sprintf("broadcast_messages/%d", broadcast) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + b := new(BroadcastMessage) + resp, err := s.client.Do(req, &b) + if err != nil { + return nil, resp, err + } + + return b, resp, err +} + +// DeleteBroadcastMessage deletes a broadcasted message. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/broadcast_messages.html#delete-a-broadcast-message +func (s *BroadcastMessagesService) DeleteBroadcastMessage(broadcast int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("broadcast_messages/%d", broadcast) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/build_variables.go b/vendor/github.com/xanzy/go-gitlab/build_variables.go new file mode 100644 index 00000000..8a6c8cdd --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/build_variables.go @@ -0,0 +1,173 @@ +package gitlab + +import ( + "fmt" + "net/url" +) + +// BuildVariablesService handles communication with the project variables related methods +// of the Gitlab API +// +// Gitlab API Docs : https://docs.gitlab.com/ce/api/build_variables.html +type BuildVariablesService struct { + client *Client +} + +// BuildVariable represents a variable available for each build of the given project +// +// Gitlab API Docs : https://docs.gitlab.com/ce/api/build_variables.html +type BuildVariable struct { + Key string `json:"key"` + Value string `json:"value"` + Protected bool `json:"protected"` +} + +func (v BuildVariable) String() string { + return Stringify(v) +} + +// ListBuildVariablesOptions are the parameters to ListBuildVariables() +// +// Gitlab API Docs: +// https://docs.gitlab.com/ce/api/build_variables.html#list-project-variables +type ListBuildVariablesOptions ListOptions + +// ListBuildVariables gets the a list of project variables in a project +// +// Gitlab API Docs: +// https://docs.gitlab.com/ce/api/build_variables.html#list-project-variables +func (s *BuildVariablesService) ListBuildVariables(pid interface{}, opts *ListBuildVariablesOptions, options ...OptionFunc) ([]*BuildVariable, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/variables", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opts, options) + if err != nil { + return nil, nil, err + } + + var v []*BuildVariable + resp, err := s.client.Do(req, &v) + if err != nil { + return nil, resp, err + } + + return v, resp, err +} + +// GetBuildVariable gets a single project variable of a project +// +// Gitlab API Docs: +// https://docs.gitlab.com/ce/api/build_variables.html#show-variable-details +func (s *BuildVariablesService) GetBuildVariable(pid interface{}, key string, options ...OptionFunc) (*BuildVariable, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/variables/%s", url.QueryEscape(project), key) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + v := new(BuildVariable) + resp, err := s.client.Do(req, v) + if err != nil { + return nil, resp, err + } + + return v, resp, err +} + +// CreateBuildVariableOptions are the parameters to CreateBuildVariable() +// +// Gitlab API Docs: +// https://docs.gitlab.com/ce/api/build_variables.html#create-variable +type CreateBuildVariableOptions struct { + Key *string `url:"key" json:"key"` + Value *string `url:"value" json:"value"` + Protected *bool `url:"protected,omitempty" json:"protected,omitempty"` +} + +// CreateBuildVariable creates a variable for a given project +// +// Gitlab API Docs: +// https://docs.gitlab.com/ce/api/build_variables.html#create-variable +func (s *BuildVariablesService) CreateBuildVariable(pid interface{}, opt *CreateBuildVariableOptions, options ...OptionFunc) (*BuildVariable, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/variables", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + v := new(BuildVariable) + resp, err := s.client.Do(req, v) + if err != nil { + return nil, resp, err + } + + return v, resp, err +} + +// UpdateBuildVariableOptions are the parameters to UpdateBuildVariable() +// +// Gitlab API Docs: +// https://docs.gitlab.com/ce/api/build_variables.html#update-variable +type UpdateBuildVariableOptions struct { + Key *string `url:"key" json:"key"` + Value *string `url:"value" json:"value"` + Protected *bool `url:"protected,omitempty" json:"protected,omitempty"` +} + +// UpdateBuildVariable updates an existing project variable +// The variable key must exist +// +// Gitlab API Docs: +// https://docs.gitlab.com/ce/api/build_variables.html#update-variable +func (s *BuildVariablesService) UpdateBuildVariable(pid interface{}, key string, opt *UpdateBuildVariableOptions, options ...OptionFunc) (*BuildVariable, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/variables/%s", url.QueryEscape(project), key) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + v := new(BuildVariable) + resp, err := s.client.Do(req, v) + if err != nil { + return nil, resp, err + } + + return v, resp, err +} + +// RemoveBuildVariable removes a project variable of a given project identified by its key +// +// Gitlab API Docs: +// https://docs.gitlab.com/ce/api/build_variables.html#remove-variable +func (s *BuildVariablesService) RemoveBuildVariable(pid interface{}, key string, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/variables/%s", url.QueryEscape(project), key) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/commits.go b/vendor/github.com/xanzy/go-gitlab/commits.go new file mode 100644 index 00000000..5b5dc2a7 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/commits.go @@ -0,0 +1,448 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// CommitsService handles communication with the commit related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html +type CommitsService struct { + client *Client +} + +// Commit represents a GitLab commit. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html +type Commit struct { + ID string `json:"id"` + ShortID string `json:"short_id"` + Title string `json:"title"` + AuthorName string `json:"author_name"` + AuthorEmail string `json:"author_email"` + AuthoredDate *time.Time `json:"authored_date"` + CommitterName string `json:"committer_name"` + CommitterEmail string `json:"committer_email"` + CommittedDate *time.Time `json:"committed_date"` + CreatedAt *time.Time `json:"created_at"` + Message string `json:"message"` + ParentIDs []string `json:"parent_ids"` + Stats *CommitStats `json:"stats"` + Status *BuildStateValue `json:"status"` +} + +// CommitStats represents the number of added and deleted files in a commit. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html +type CommitStats struct { + Additions int `json:"additions"` + Deletions int `json:"deletions"` + Total int `json:"total"` +} + +func (c Commit) String() string { + return Stringify(c) +} + +// ListCommitsOptions represents the available ListCommits() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#list-repository-commits +type ListCommitsOptions struct { + ListOptions + RefName *string `url:"ref_name,omitempty" json:"ref_name,omitempty"` + Since *time.Time `url:"since,omitempty" json:"since,omitempty"` + Until *time.Time `url:"until,omitempty" json:"until,omitempty"` + Path *string `url:"path,omitempty" json:"path,omitempty"` + All *bool `url:"all,omitempty" json:"all,omitempty"` +} + +// ListCommits gets a list of repository commits in a project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#list-commits +func (s *CommitsService) ListCommits(pid interface{}, opt *ListCommitsOptions, options ...OptionFunc) ([]*Commit, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/commits", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var c []*Commit + resp, err := s.client.Do(req, &c) + if err != nil { + return nil, resp, err + } + + return c, resp, err +} + +// FileAction represents the available actions that can be performed on a file. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions +type FileAction string + +// The available file actions. +const ( + FileCreate FileAction = "create" + FileDelete FileAction = "delete" + FileMove FileAction = "move" + FileUpdate FileAction = "update" +) + +// CommitAction represents a single file action within a commit. +type CommitAction struct { + Action FileAction `url:"action" json:"action"` + FilePath string `url:"file_path" json:"file_path"` + PreviousPath string `url:"previous_path,omitempty" json:"previous_path,omitempty"` + Content string `url:"content,omitempty" json:"content,omitempty"` + Encoding string `url:"encoding,omitempty" json:"encoding,omitempty"` +} + +// GetCommit gets a specific commit identified by the commit hash or name of a +// branch or tag. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-a-single-commit +func (s *CommitsService) GetCommit(pid interface{}, sha string, options ...OptionFunc) (*Commit, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/commits/%s", url.QueryEscape(project), sha) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + c := new(Commit) + resp, err := s.client.Do(req, c) + if err != nil { + return nil, resp, err + } + + return c, resp, err +} + +// CreateCommitOptions represents the available options for a new commit. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions +type CreateCommitOptions struct { + Branch *string `url:"branch" json:"branch"` + CommitMessage *string `url:"commit_message" json:"commit_message"` + StartBranch *string `url:"start_branch,omitempty" json:"start_branch,omitempty"` + Actions []*CommitAction `url:"actions" json:"actions"` + AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` + AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` +} + +// CreateCommit creates a commit with multiple files and actions. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions +func (s *CommitsService) CreateCommit(pid interface{}, opt *CreateCommitOptions, options ...OptionFunc) (*Commit, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/commits", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + var c *Commit + resp, err := s.client.Do(req, &c) + if err != nil { + return nil, resp, err + } + + return c, resp, err +} + +// Diff represents a GitLab diff. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html +type Diff struct { + Diff string `json:"diff"` + NewPath string `json:"new_path"` + OldPath string `json:"old_path"` + AMode string `json:"a_mode"` + BMode string `json:"b_mode"` + NewFile bool `json:"new_file"` + RenamedFile bool `json:"renamed_file"` + DeletedFile bool `json:"deleted_file"` +} + +func (d Diff) String() string { + return Stringify(d) +} + +// GetCommitDiffOptions represents the available GetCommitDiff() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/commits.html#get-the-diff-of-a-commit +type GetCommitDiffOptions ListOptions + +// GetCommitDiff gets the diff of a commit in a project.. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/commits.html#get-the-diff-of-a-commit +func (s *CommitsService) GetCommitDiff(pid interface{}, sha string, opt *GetCommitDiffOptions, options ...OptionFunc) ([]*Diff, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/commits/%s/diff", url.QueryEscape(project), sha) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var d []*Diff + resp, err := s.client.Do(req, &d) + if err != nil { + return nil, resp, err + } + + return d, resp, err +} + +// CommitComment represents a GitLab commit comment. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html +type CommitComment struct { + Note string `json:"note"` + Path string `json:"path"` + Line int `json:"line"` + LineType string `json:"line_type"` + Author Author `json:"author"` +} + +// Author represents a GitLab commit author +type Author struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` + Name string `json:"name"` + State string `json:"state"` + Blocked bool `json:"blocked"` + CreatedAt *time.Time `json:"created_at"` +} + +func (c CommitComment) String() string { + return Stringify(c) +} + +// GetCommitCommentsOptions represents the available GetCommitComments() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/commits.html#get-the-comments-of-a-commit +type GetCommitCommentsOptions ListOptions + +// GetCommitComments gets the comments of a commit in a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/commits.html#get-the-comments-of-a-commit +func (s *CommitsService) GetCommitComments(pid interface{}, sha string, opt *GetCommitCommentsOptions, options ...OptionFunc) ([]*CommitComment, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", url.QueryEscape(project), sha) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var c []*CommitComment + resp, err := s.client.Do(req, &c) + if err != nil { + return nil, resp, err + } + + return c, resp, err +} + +// PostCommitCommentOptions represents the available PostCommitComment() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit +type PostCommitCommentOptions struct { + Note *string `url:"note,omitempty" json:"note,omitempty"` + Path *string `url:"path" json:"path"` + Line *int `url:"line" json:"line"` + LineType *string `url:"line_type" json:"line_type"` +} + +// PostCommitComment adds a comment to a commit. Optionally you can post +// comments on a specific line of a commit. Therefor both path, line_new and +// line_old are required. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit +func (s *CommitsService) PostCommitComment(pid interface{}, sha string, opt *PostCommitCommentOptions, options ...OptionFunc) (*CommitComment, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/commits/%s/comments", url.QueryEscape(project), sha) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + c := new(CommitComment) + resp, err := s.client.Do(req, c) + if err != nil { + return nil, resp, err + } + + return c, resp, err +} + +// GetCommitStatusesOptions represents the available GetCommitStatuses() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit +type GetCommitStatusesOptions struct { + ListOptions + Ref *string `url:"ref,omitempty" json:"ref,omitempty"` + Stage *string `url:"stage,omitempty" json:"stage,omitempty"` + Name *string `url:"name,omitempty" json:"name,omitempty"` + All *bool `url:"all,omitempty" json:"all,omitempty"` +} + +// CommitStatus represents a GitLab commit status. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit +type CommitStatus struct { + ID int `json:"id"` + SHA string `json:"sha"` + Ref string `json:"ref"` + Status string `json:"status"` + Name string `json:"name"` + TargetURL string `json:"target_url"` + Description string `json:"description"` + CreatedAt *time.Time `json:"created_at"` + StartedAt *time.Time `json:"started_at"` + FinishedAt *time.Time `json:"finished_at"` + Author Author `json:"author"` +} + +// GetCommitStatuses gets the statuses of a commit in a project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#get-the-status-of-a-commit +func (s *CommitsService) GetCommitStatuses(pid interface{}, sha string, opt *GetCommitStatusesOptions, options ...OptionFunc) ([]*CommitStatus, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/commits/%s/statuses", url.QueryEscape(project), sha) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var cs []*CommitStatus + resp, err := s.client.Do(req, &cs) + if err != nil { + return nil, resp, err + } + + return cs, resp, err +} + +// SetCommitStatusOptions represents the available SetCommitStatus() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#post-the-status-to-commit +type SetCommitStatusOptions struct { + State BuildStateValue `url:"state" json:"state"` + Ref *string `url:"ref,omitempty" json:"ref,omitempty"` + Name *string `url:"name,omitempty" json:"name,omitempty"` + Context *string `url:"context,omitempty" json:"context,omitempty"` + TargetURL *string `url:"target_url,omitempty" json:"target_url,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` +} + +// SetCommitStatus sets the status of a commit in a project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#post-the-status-to-commit +func (s *CommitsService) SetCommitStatus(pid interface{}, sha string, opt *SetCommitStatusOptions, options ...OptionFunc) (*CommitStatus, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/statuses/%s", url.QueryEscape(project), sha) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + var cs *CommitStatus + resp, err := s.client.Do(req, &cs) + if err != nil { + return nil, resp, err + } + + return cs, resp, err +} + +// CherryPickCommitOptions represents the available options for cherry-picking a commit. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#cherry-pick-a-commit +type CherryPickCommitOptions struct { + TargetBranch *string `url:"branch" json:"branch,omitempty"` +} + +// CherryPickCommit sherry picks a commit to a given branch. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/commits.html#cherry-pick-a-commit +func (s *CommitsService) CherryPickCommit(pid interface{}, sha string, opt *CherryPickCommitOptions, options ...OptionFunc) (*Commit, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/commits/%s/cherry_pick", + url.QueryEscape(project), url.QueryEscape(sha)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + var c *Commit + resp, err := s.client.Do(req, &c) + if err != nil { + return nil, resp, err + } + + return c, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/deploy_keys.go b/vendor/github.com/xanzy/go-gitlab/deploy_keys.go new file mode 100644 index 00000000..76444592 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/deploy_keys.go @@ -0,0 +1,201 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// DeployKeysService handles communication with the keys related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/deploy_keys.html +type DeployKeysService struct { + client *Client +} + +// DeployKey represents a GitLab deploy key. +type DeployKey struct { + ID int `json:"id"` + Title string `json:"title"` + Key string `json:"key"` + CanPush *bool `json:"can_push"` + CreatedAt *time.Time `json:"created_at"` +} + +func (k DeployKey) String() string { + return Stringify(k) +} + +// ListAllDeployKeys gets a list of all deploy keys +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/deploy_keys.html#list-all-deploy-keys +func (s *DeployKeysService) ListAllDeployKeys(options ...OptionFunc) ([]*DeployKey, *Response, error) { + req, err := s.client.NewRequest("GET", "deploy_keys", nil, options) + if err != nil { + return nil, nil, err + } + + var ks []*DeployKey + resp, err := s.client.Do(req, &ks) + if err != nil { + return nil, resp, err + } + + return ks, resp, err +} + +// ListProjectDeployKeysOptions represents the available ListProjectDeployKeys() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/deploy_keys.html#list-project-deploy-keys +type ListProjectDeployKeysOptions ListOptions + +// ListProjectDeployKeys gets a list of a project's deploy keys +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/deploy_keys.html#list-project-deploy-keys +func (s *DeployKeysService) ListProjectDeployKeys(pid interface{}, opt *ListProjectDeployKeysOptions, options ...OptionFunc) ([]*DeployKey, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/deploy_keys", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var ks []*DeployKey + resp, err := s.client.Do(req, &ks) + if err != nil { + return nil, resp, err + } + + return ks, resp, err +} + +// GetDeployKey gets a single deploy key. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/deploy_keys.html#single-deploy-key +func (s *DeployKeysService) GetDeployKey(pid interface{}, deployKey int, options ...OptionFunc) (*DeployKey, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/deploy_keys/%d", url.QueryEscape(project), deployKey) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + k := new(DeployKey) + resp, err := s.client.Do(req, k) + if err != nil { + return nil, resp, err + } + + return k, resp, err +} + +// AddDeployKeyOptions represents the available ADDDeployKey() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key +type AddDeployKeyOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + Key *string `url:"key,omitempty" json:"key,omitempty"` + CanPush *bool `url:"can_push,omitempty" json:"can_push,omitempty"` +} + +// AddDeployKey creates a new deploy key for a project. If deploy key already +// exists in another project - it will be joined to project but only if +// original one was is accessible by same user. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/deploy_keys.html#add-deploy-key +func (s *DeployKeysService) AddDeployKey(pid interface{}, opt *AddDeployKeyOptions, options ...OptionFunc) (*DeployKey, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/deploy_keys", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + k := new(DeployKey) + resp, err := s.client.Do(req, k) + if err != nil { + return nil, resp, err + } + + return k, resp, err +} + +// DeleteDeployKey deletes a deploy key from a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/deploy_keys.html#delete-deploy-key +func (s *DeployKeysService) DeleteDeployKey(pid interface{}, deployKey int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/deploy_keys/%d", url.QueryEscape(project), deployKey) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// EnableDeployKey enables a deploy key. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/deploy_keys.html#enable-deploy-key +func (s *DeployKeysService) EnableDeployKey(pid interface{}, deployKey int, options ...OptionFunc) (*DeployKey, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/deploy_keys/%d/enable", url.QueryEscape(project), deployKey) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + k := new(DeployKey) + resp, err := s.client.Do(req, k) + if err != nil { + return nil, resp, err + } + + return k, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/deployments.go b/vendor/github.com/xanzy/go-gitlab/deployments.go new file mode 100644 index 00000000..a648605e --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/deployments.go @@ -0,0 +1,121 @@ +// +// Copyright 2018, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// DeploymentsService handles communication with the deployment related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html +type DeploymentsService struct { + client *Client +} + +// Deployment represents the Gitlab deployment +type Deployment struct { + ID int `json:"id"` + IID int `json:"iid"` + Ref string `json:"ref"` + Sha string `json:"sha"` + CreatedAt *time.Time `json:"created_at"` + User *ProjectUser `json:"user"` + Environment *Environment `json:"environment"` + Deployable struct { + ID int `json:"id"` + Status string `json:"status"` + Stage string `json:"stage"` + Name string `json:"name"` + Ref string `json:"ref"` + Tag bool `json:"tag"` + Coverage float64 `json:"coverage"` + CreatedAt *time.Time `json:"created_at"` + StartedAt *time.Time `json:"started_at"` + FinishedAt *time.Time `json:"finished_at"` + Duration float64 `json:"duration"` + User *User `json:"user"` + Commit *Commit `json:"commit"` + Pipeline struct { + ID int `json:"id"` + Sha string `json:"sha"` + Ref string `json:"ref"` + Status string `json:"status"` + } `json:"pipeline"` + Runner *Runner `json:"runner"` + } `json:"deployable"` +} + +// ListProjectDeploymentsOptions represents the available ListProjectDeployments() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/deployments.html#list-project-deployments +type ListProjectDeploymentsOptions struct { + ListOptions + OrderBy *OrderByValue `url:"order_by,omitempty" json:"order_by,omitempty"` + Sort *string `url:"sort,omitempty" json:"sort,omitempty"` +} + +// ListProjectDeployments gets a list of deployments in a project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html#list-project-deployments +func (s *DeploymentsService) ListProjectDeployments(pid interface{}, opts *ListProjectDeploymentsOptions, options ...OptionFunc) ([]*Deployment, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/deployments", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opts, options) + if err != nil { + return nil, nil, err + } + + var ds []*Deployment + resp, err := s.client.Do(req, &ds) + if err != nil { + return nil, resp, err + } + + return ds, resp, err +} + +// GetProjectDeployment get a deployment for a project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/deployments.html#get-a-specific-deployment +func (s *DeploymentsService) GetProjectDeployment(pid interface{}, deployment int, options ...OptionFunc) (*Deployment, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/deployments/%d", url.QueryEscape(project), deployment) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + d := new(Deployment) + resp, err := s.client.Do(req, d) + if err != nil { + return nil, resp, err + } + + return d, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/environments.go b/vendor/github.com/xanzy/go-gitlab/environments.go new file mode 100644 index 00000000..c2305ee9 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/environments.go @@ -0,0 +1,166 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// EnvironmentsService handles communication with the environment related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/environments.html +type EnvironmentsService struct { + client *Client +} + +// Environment represents a GitLab environment. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/environments.html +type Environment struct { + ID int `json:"id"` + Name string `json:"name"` + Slug string `json:"slug"` + ExternalURL string `json:"external_url"` +} + +func (env Environment) String() string { + return Stringify(env) +} + +// ListEnvironmentsOptions represents the available ListEnvironments() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/environments.html#list-environments +type ListEnvironmentsOptions ListOptions + +// ListEnvironments gets a list of environments from a project, sorted by name +// alphabetically. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/environments.html#list-environments +func (s *EnvironmentsService) ListEnvironments(pid interface{}, opts *ListEnvironmentsOptions, options ...OptionFunc) ([]*Environment, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/environments", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opts, options) + if err != nil { + return nil, nil, err + } + + var envs []*Environment + resp, err := s.client.Do(req, &envs) + if err != nil { + return nil, resp, err + } + + return envs, resp, err +} + +// CreateEnvironmentOptions represents the available CreateEnvironment() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/environments.html#create-a-new-environment +type CreateEnvironmentOptions struct { + Name *string `url:"name,omitempty" json:"name,omitempty"` + ExternalURL *string `url:"external_url,omitempty" json:"external_url,omitempty"` +} + +// CreateEnvironment adds a environment to a project. This is an idempotent +// method and can be called multiple times with the same parameters. Createing +// an environment that is already a environment does not affect the +// existing environmentship. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/environments.html#create-a-new-environment +func (s *EnvironmentsService) CreateEnvironment(pid interface{}, opt *CreateEnvironmentOptions, options ...OptionFunc) (*Environment, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/environments", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + env := new(Environment) + resp, err := s.client.Do(req, env) + if err != nil { + return nil, resp, err + } + + return env, resp, err +} + +// EditEnvironmentOptions represents the available EditEnvironment() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/environments.html#edit-an-existing-environment +type EditEnvironmentOptions struct { + Name *string `url:"name,omitempty" json:"name,omitempty"` + ExternalURL *string `url:"external_url,omitempty" json:"external_url,omitempty"` +} + +// EditEnvironment updates a project team environment to a specified access level.. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/environments.html#edit-an-existing-environment +func (s *EnvironmentsService) EditEnvironment(pid interface{}, environment int, opt *EditEnvironmentOptions, options ...OptionFunc) (*Environment, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/environments/%d", url.QueryEscape(project), environment) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + env := new(Environment) + resp, err := s.client.Do(req, env) + if err != nil { + return nil, resp, err + } + + return env, resp, err +} + +// DeleteEnvironment removes a environment from a project team. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/environments.html#remove-a-environment-from-a-group-or-project +func (s *EnvironmentsService) DeleteEnvironment(pid interface{}, environment int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/environments/%d", url.QueryEscape(project), environment) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/event_types.go b/vendor/github.com/xanzy/go-gitlab/event_types.go new file mode 100644 index 00000000..f051726e --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/event_types.go @@ -0,0 +1,649 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "time" +) + +// PushEvent represents a push event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#push-events +type PushEvent struct { + ObjectKind string `json:"object_kind"` + Before string `json:"before"` + After string `json:"after"` + Ref string `json:"ref"` + CheckoutSha string `json:"checkout_sha"` + UserID int `json:"user_id"` + UserName string `json:"user_name"` + UserEmail string `json:"user_email"` + UserAvatar string `json:"user_avatar"` + ProjectID int `json:"project_id"` + Project struct { + Name string `json:"name"` + Description string `json:"description"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` + WebURL string `json:"web_url"` + Visibility VisibilityValue `json:"visibility"` + } `json:"project"` + Repository *Repository `json:"repository"` + Commits []*struct { + ID string `json:"id"` + Message string `json:"message"` + Timestamp *time.Time `json:"timestamp"` + URL string `json:"url"` + Author struct { + Name string `json:"name"` + Email string `json:"email"` + } `json:"author"` + Added []string `json:"added"` + Modified []string `json:"modified"` + Removed []string `json:"removed"` + } `json:"commits"` + TotalCommitsCount int `json:"total_commits_count"` +} + +// TagEvent represents a tag event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#tag-events +type TagEvent struct { + ObjectKind string `json:"object_kind"` + Before string `json:"before"` + After string `json:"after"` + Ref string `json:"ref"` + CheckoutSha string `json:"checkout_sha"` + UserID int `json:"user_id"` + UserName string `json:"user_name"` + UserAvatar string `json:"user_avatar"` + ProjectID int `json:"project_id"` + Project struct { + Name string `json:"name"` + Description string `json:"description"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` + WebURL string `json:"web_url"` + Visibility VisibilityValue `json:"visibility"` + } `json:"project"` + Repository *Repository `json:"repository"` + Commits []*struct { + ID string `json:"id"` + Message string `json:"message"` + Timestamp *time.Time `json:"timestamp"` + URL string `json:"url"` + Author struct { + Name string `json:"name"` + Email string `json:"email"` + } `json:"author"` + Added []string `json:"added"` + Modified []string `json:"modified"` + Removed []string `json:"removed"` + } `json:"commits"` + TotalCommitsCount int `json:"total_commits_count"` +} + +// IssueEvent represents a issue event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#issues-events +type IssueEvent struct { + ObjectKind string `json:"object_kind"` + User *User `json:"user"` + Project struct { + Name string `json:"name"` + Description string `json:"description"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` + WebURL string `json:"web_url"` + Visibility VisibilityValue `json:"visibility"` + } `json:"project"` + Repository *Repository `json:"repository"` + ObjectAttributes struct { + ID int `json:"id"` + Title string `json:"title"` + AssigneeID int `json:"assignee_id"` + AuthorID int `json:"author_id"` + ProjectID int `json:"project_id"` + CreatedAt string `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468) + UpdatedAt string `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468) + Position int `json:"position"` + BranchName string `json:"branch_name"` + Description string `json:"description"` + MilestoneID int `json:"milestone_id"` + State string `json:"state"` + IID int `json:"iid"` + URL string `json:"url"` + Action string `json:"action"` + } `json:"object_attributes"` + Assignee struct { + Name string `json:"name"` + Username string `json:"username"` + AvatarURL string `json:"avatar_url"` + } `json:"assignee"` +} + +// CommitCommentEvent represents a comment on a commit event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#comment-on-commit +type CommitCommentEvent struct { + ObjectKind string `json:"object_kind"` + User *User `json:"user"` + ProjectID int `json:"project_id"` + Project struct { + Name string `json:"name"` + Description string `json:"description"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` + WebURL string `json:"web_url"` + Visibility VisibilityValue `json:"visibility"` + } `json:"project"` + Repository *Repository `json:"repository"` + ObjectAttributes struct { + ID int `json:"id"` + Note string `json:"note"` + NoteableType string `json:"noteable_type"` + AuthorID int `json:"author_id"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + ProjectID int `json:"project_id"` + Attachment string `json:"attachment"` + LineCode string `json:"line_code"` + CommitID string `json:"commit_id"` + NoteableID int `json:"noteable_id"` + System bool `json:"system"` + StDiff struct { + Diff string `json:"diff"` + NewPath string `json:"new_path"` + OldPath string `json:"old_path"` + AMode string `json:"a_mode"` + BMode string `json:"b_mode"` + NewFile bool `json:"new_file"` + RenamedFile bool `json:"renamed_file"` + DeletedFile bool `json:"deleted_file"` + } `json:"st_diff"` + } `json:"object_attributes"` + Commit *struct { + ID string `json:"id"` + Message string `json:"message"` + Timestamp *time.Time `json:"timestamp"` + URL string `json:"url"` + Author struct { + Name string `json:"name"` + Email string `json:"email"` + } `json:"author"` + } `json:"commit"` +} + +// MergeCommentEvent represents a comment on a merge event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#comment-on-merge-request +type MergeCommentEvent struct { + ObjectKind string `json:"object_kind"` + User *User `json:"user"` + ProjectID int `json:"project_id"` + Project struct { + Name string `json:"name"` + Description string `json:"description"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` + WebURL string `json:"web_url"` + Visibility VisibilityValue `json:"visibility"` + } `json:"project"` + ObjectAttributes struct { + ID int `json:"id"` + Note string `json:"note"` + NoteableType string `json:"noteable_type"` + AuthorID int `json:"author_id"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + ProjectID int `json:"project_id"` + Attachment string `json:"attachment"` + LineCode string `json:"line_code"` + CommitID string `json:"commit_id"` + NoteableID int `json:"noteable_id"` + System bool `json:"system"` + StDiff *Diff `json:"st_diff"` + URL string `json:"url"` + } `json:"object_attributes"` + Repository *Repository `json:"repository"` + MergeRequest struct { + ID int `json:"id"` + TargetBranch string `json:"target_branch"` + SourceBranch string `json:"source_branch"` + SourceProjectID int `json:"source_project_id"` + AuthorID int `json:"author_id"` + AssigneeID int `json:"assignee_id"` + Title string `json:"title"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + MilestoneID int `json:"milestone_id"` + State string `json:"state"` + MergeStatus string `json:"merge_status"` + TargetProjectID int `json:"target_project_id"` + IID int `json:"iid"` + Description string `json:"description"` + Position int `json:"position"` + LockedAt string `json:"locked_at"` + UpdatedByID int `json:"updated_by_id"` + MergeError string `json:"merge_error"` + MergeParams struct { + ForceRemoveSourceBranch string `json:"force_remove_source_branch"` + } `json:"merge_params"` + MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` + MergeUserID int `json:"merge_user_id"` + MergeCommitSha string `json:"merge_commit_sha"` + DeletedAt string `json:"deleted_at"` + InProgressMergeCommitSha string `json:"in_progress_merge_commit_sha"` + LockVersion int `json:"lock_version"` + ApprovalsBeforeMerge string `json:"approvals_before_merge"` + RebaseCommitSha string `json:"rebase_commit_sha"` + TimeEstimate int `json:"time_estimate"` + Squash bool `json:"squash"` + LastEditedAt string `json:"last_edited_at"` + LastEditedByID int `json:"last_edited_by_id"` + Source *Repository `json:"source"` + Target *Repository `json:"target"` + LastCommit struct { + ID string `json:"id"` + Message string `json:"message"` + Timestamp *time.Time `json:"timestamp"` + URL string `json:"url"` + Author struct { + Name string `json:"name"` + Email string `json:"email"` + } `json:"author"` + } `json:"last_commit"` + WorkInProgress bool `json:"work_in_progress"` + TotalTimeSpent int `json:"total_time_spent"` + } `json:"merge_request"` +} + +// IssueCommentEvent represents a comment on an issue event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#comment-on-issue +type IssueCommentEvent struct { + ObjectKind string `json:"object_kind"` + User *User `json:"user"` + ProjectID int `json:"project_id"` + Project struct { + Name string `json:"name"` + Description string `json:"description"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` + WebURL string `json:"web_url"` + Visibility VisibilityValue `json:"visibility"` + } `json:"project"` + Repository *Repository `json:"repository"` + ObjectAttributes struct { + ID int `json:"id"` + Note string `json:"note"` + NoteableType string `json:"noteable_type"` + AuthorID int `json:"author_id"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + ProjectID int `json:"project_id"` + Attachment string `json:"attachment"` + LineCode string `json:"line_code"` + CommitID string `json:"commit_id"` + NoteableID int `json:"noteable_id"` + System bool `json:"system"` + StDiff []*Diff `json:"st_diff"` + URL string `json:"url"` + } `json:"object_attributes"` + Issue *Issue `json:"issue"` +} + +// SnippetCommentEvent represents a comment on a snippet event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#comment-on-code-snippet +type SnippetCommentEvent struct { + ObjectKind string `json:"object_kind"` + User *User `json:"user"` + ProjectID int `json:"project_id"` + Project struct { + Name string `json:"name"` + Description string `json:"description"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` + WebURL string `json:"web_url"` + Visibility VisibilityValue `json:"visibility"` + } `json:"project"` + Repository *Repository `json:"repository"` + ObjectAttributes struct { + ID int `json:"id"` + Note string `json:"note"` + NoteableType string `json:"noteable_type"` + AuthorID int `json:"author_id"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + ProjectID int `json:"project_id"` + Attachment string `json:"attachment"` + LineCode string `json:"line_code"` + CommitID string `json:"commit_id"` + NoteableID int `json:"noteable_id"` + System bool `json:"system"` + StDiff *Diff `json:"st_diff"` + URL string `json:"url"` + } `json:"object_attributes"` + Snippet *Snippet `json:"snippet"` +} + +// MergeEvent represents a merge event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#merge-request-events +type MergeEvent struct { + ObjectKind string `json:"object_kind"` + User *User `json:"user"` + Project struct { + Name string `json:"name"` + Description string `json:"description"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` + WebURL string `json:"web_url"` + Visibility VisibilityValue `json:"visibility"` + } `json:"project"` + ObjectAttributes struct { + ID int `json:"id"` + TargetBranch string `json:"target_branch"` + SourceBranch string `json:"source_branch"` + SourceProjectID int `json:"source_project_id"` + AuthorID int `json:"author_id"` + AssigneeID int `json:"assignee_id"` + Title string `json:"title"` + CreatedAt string `json:"created_at"` // Should be *time.Time (see Gitlab issue #21468) + UpdatedAt string `json:"updated_at"` // Should be *time.Time (see Gitlab issue #21468) + StCommits []*Commit `json:"st_commits"` + StDiffs []*Diff `json:"st_diffs"` + MilestoneID int `json:"milestone_id"` + State string `json:"state"` + MergeStatus string `json:"merge_status"` + TargetProjectID int `json:"target_project_id"` + IID int `json:"iid"` + Description string `json:"description"` + Position int `json:"position"` + LockedAt string `json:"locked_at"` + UpdatedByID int `json:"updated_by_id"` + MergeError string `json:"merge_error"` + MergeParams struct { + ForceRemoveSourceBranch string `json:"force_remove_source_branch"` + } `json:"merge_params"` + MergeWhenBuildSucceeds bool `json:"merge_when_build_succeeds"` + MergeUserID int `json:"merge_user_id"` + MergeCommitSha string `json:"merge_commit_sha"` + DeletedAt string `json:"deleted_at"` + ApprovalsBeforeMerge string `json:"approvals_before_merge"` + RebaseCommitSha string `json:"rebase_commit_sha"` + InProgressMergeCommitSha string `json:"in_progress_merge_commit_sha"` + LockVersion int `json:"lock_version"` + TimeEstimate int `json:"time_estimate"` + Source *Repository `json:"source"` + Target *Repository `json:"target"` + LastCommit struct { + ID string `json:"id"` + Message string `json:"message"` + Timestamp *time.Time `json:"timestamp"` + URL string `json:"url"` + Author struct { + Name string `json:"name"` + Email string `json:"email"` + } `json:"author"` + } `json:"last_commit"` + WorkInProgress bool `json:"work_in_progress"` + URL string `json:"url"` + Action string `json:"action"` + Assignee struct { + Name string `json:"name"` + Username string `json:"username"` + AvatarURL string `json:"avatar_url"` + } `json:"assignee"` + } `json:"object_attributes"` + Repository *Repository `json:"repository"` + Assignee struct { + Name string `json:"name"` + Username string `json:"username"` + AvatarURL string `json:"avatar_url"` + } `json:"assignee"` +} + +// WikiPageEvent represents a wiki page event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#wiki-page-events +type WikiPageEvent struct { + ObjectKind string `json:"object_kind"` + User *User `json:"user"` + Project struct { + Name string `json:"name"` + Description string `json:"description"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` + WebURL string `json:"web_url"` + Visibility VisibilityValue `json:"visibility"` + } `json:"project"` + Wiki struct { + WebURL string `json:"web_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + } `json:"wiki"` + ObjectAttributes struct { + Title string `json:"title"` + Content string `json:"content"` + Format string `json:"format"` + Message string `json:"message"` + Slug string `json:"slug"` + URL string `json:"url"` + Action string `json:"action"` + } `json:"object_attributes"` +} + +// PipelineEvent represents a pipeline event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#pipeline-events +type PipelineEvent struct { + ObjectKind string `json:"object_kind"` + ObjectAttributes struct { + ID int `json:"id"` + Ref string `json:"ref"` + Tag bool `json:"tag"` + Sha string `json:"sha"` + BeforeSha string `json:"before_sha"` + Status string `json:"status"` + Stages []string `json:"stages"` + CreatedAt string `json:"created_at"` + FinishedAt string `json:"finished_at"` + Duration int `json:"duration"` + } `json:"object_attributes"` + User struct { + Name string `json:"name"` + Username string `json:"username"` + AvatarURL string `json:"avatar_url"` + } `json:"user"` + Project struct { + Name string `json:"name"` + Description string `json:"description"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` + WebURL string `json:"web_url"` + Visibility VisibilityValue `json:"visibility"` + } `json:"project"` + Commit struct { + ID string `json:"id"` + Message string `json:"message"` + Timestamp *time.Time `json:"timestamp"` + URL string `json:"url"` + Author struct { + Name string `json:"name"` + Email string `json:"email"` + } `json:"author"` + } `json:"commit"` + Builds []struct { + ID int `json:"id"` + Stage string `json:"stage"` + Name string `json:"name"` + Status string `json:"status"` + CreatedAt string `json:"created_at"` + StartedAt string `json:"started_at"` + FinishedAt string `json:"finished_at"` + When string `json:"when"` + Manual bool `json:"manual"` + User struct { + Name string `json:"name"` + Username string `json:"username"` + AvatarURL string `json:"avatar_url"` + } `json:"user"` + Runner struct { + ID int `json:"id"` + Description string `json:"description"` + Active bool `json:"active"` + IsShared bool `json:"is_shared"` + } `json:"runner"` + ArtifactsFile struct { + Filename string `json:"filename"` + Size int `json:"size"` + } `json:"artifacts_file"` + } `json:"builds"` +} + +//BuildEvent represents a build event +// +// GitLab API docs: +// https://docs.gitlab.com/ce/web_hooks/web_hooks.html#build-events +type BuildEvent struct { + ObjectKind string `json:"object_kind"` + Ref string `json:"ref"` + Tag bool `json:"tag"` + BeforeSha string `json:"before_sha"` + Sha string `json:"sha"` + BuildID int `json:"build_id"` + BuildName string `json:"build_name"` + BuildStage string `json:"build_stage"` + BuildStatus string `json:"build_status"` + BuildStartedAt string `json:"build_started_at"` + BuildFinishedAt string `json:"build_finished_at"` + BuildDuration float64 `json:"build_duration"` + BuildAllowFailure bool `json:"build_allow_failure"` + ProjectID int `json:"project_id"` + ProjectName string `json:"project_name"` + User struct { + ID int `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + } `json:"user"` + Commit struct { + ID int `json:"id"` + Sha string `json:"sha"` + Message string `json:"message"` + AuthorName string `json:"author_name"` + AuthorEmail string `json:"author_email"` + Status string `json:"status"` + Duration int `json:"duration"` + StartedAt string `json:"started_at"` + FinishedAt string `json:"finished_at"` + } `json:"commit"` + Repository *Repository `json:"repository"` +} diff --git a/vendor/github.com/xanzy/go-gitlab/events.go b/vendor/github.com/xanzy/go-gitlab/events.go new file mode 100644 index 00000000..4740e4ab --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/events.go @@ -0,0 +1,147 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// EventsService handles communication with the event related methods of +// the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/events.html +type EventsService struct { + client *Client +} + +// ContributionEvent represents a user's contribution +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events +type ContributionEvent struct { + Title string `json:"title"` + ProjectID int `json:"project_id"` + ActionName string `json:"action_name"` + TargetID int `json:"target_id"` + TargetIID int `json:"target_iid"` + TargetType string `json:"target_type"` + AuthorID int `json:"author_id"` + TargetTitle string `json:"target_title"` + CreatedAt *time.Time `json:"created_at"` + PushData struct { + CommitCount int `json:"commit_count"` + Action string `json:"action"` + RefType string `json:"ref_type"` + CommitFrom string `json:"commit_from"` + CommitTo string `json:"commit_to"` + Ref string `json:"ref"` + CommitTitle string `json:"commit_title"` + } `json:"push_data"` + Note *Note `json:"note"` + Author struct { + Name string `json:"name"` + Username string `json:"username"` + ID int `json:"id"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + } `json:"author"` + AuthorUsername string `json:"author_username"` +} + +// ListContributionEventsOptions represents the options for GetUserContributionEvents +// +// GitLap API docs: +// https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events +type ListContributionEventsOptions struct { + ListOptions + Action *EventTypeValue `json:"action,omitempty"` + TargetType *EventTargetTypeValue `json:"target_type,omitempty"` + Before *ISOTime `json:"before,omitempty"` + After *ISOTime `json:"after,omitempty"` + Sort *string `json:"sort,omitempty"` +} + +// ListUserContributionEvents retrieves user contribution events +// for the specified user, sorted from newest to oldest. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/events.html#get-user-contribution-events +func (s *UsersService) ListUserContributionEvents(uid interface{}, opt *ListContributionEventsOptions, options ...OptionFunc) ([]*ContributionEvent, *Response, error) { + user, err := parseID(uid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("users/%s/events", user) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var cs []*ContributionEvent + resp, err := s.client.Do(req, &cs) + if err != nil { + return nil, resp, err + } + + return cs, resp, err +} + +// ListCurrentUserContributionEvents gets a list currently authenticated user's events +// +// GitLab API docs: https://docs.gitlab.com/ce/api/events.html#list-currently-authenticated-user-39-s-events +func (s *EventsService) ListCurrentUserContributionEvents(opt *ListContributionEventsOptions, options ...OptionFunc) ([]*ContributionEvent, *Response, error) { + req, err := s.client.NewRequest("GET", "events", opt, options) + if err != nil { + return nil, nil, err + } + + var cs []*ContributionEvent + resp, err := s.client.Do(req, &cs) + if err != nil { + return nil, resp, err + } + + return cs, resp, err +} + +// ListProjectContributionEvents gets a list currently authenticated user's events +// +// GitLab API docs: https://docs.gitlab.com/ce/api/events.html#list-a-project-39-s-visible-events +func (s *EventsService) ListProjectContributionEvents(pid interface{}, opt *ListContributionEventsOptions, options ...OptionFunc) ([]*ContributionEvent, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("%s/events", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var cs []*ContributionEvent + resp, err := s.client.Do(req, &cs) + if err != nil { + return nil, resp, err + } + + return cs, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/feature_flags.go b/vendor/github.com/xanzy/go-gitlab/feature_flags.go new file mode 100644 index 00000000..b6380ab0 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/feature_flags.go @@ -0,0 +1,79 @@ +package gitlab + +import ( + "fmt" + "net/url" +) + +// FeaturesService handles the communication with the application FeaturesService +// related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/features.html +type FeaturesService struct { + client *Client +} + +// Feature represents a GitLab feature flag. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/features.html +type Feature struct { + Name string `json:"name"` + State string `json:"state"` + Gates []Gate +} + +// Gate represents a gate of a GitLab feature flag. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/features.html +type Gate struct { + Key string `json:"key"` + Value interface{} `json:"value"` +} + +func (f Feature) String() string { + return Stringify(f) +} + +// ListFeatures gets a list of feature flags +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/features.html#list-all-features +func (s *FeaturesService) ListFeatures(options ...OptionFunc) ([]*Feature, *Response, error) { + req, err := s.client.NewRequest("GET", "features", nil, options) + if err != nil { + return nil, nil, err + } + + var f []*Feature + resp, err := s.client.Do(req, &f) + if err != nil { + return nil, resp, err + } + return f, resp, err +} + +// SetFeatureFlag sets or creates a feature flag gate +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/features.html#set-or-create-a-feature +func (s *FeaturesService) SetFeatureFlag(name string, value interface{}, options ...OptionFunc) (*Feature, *Response, error) { + u := fmt.Sprintf("features/%s", url.QueryEscape(name)) + + opt := struct { + Value interface{} `url:"value" json:"value"` + }{ + value, + } + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + f := &Feature{} + resp, err := s.client.Do(req, f) + if err != nil { + return nil, resp, err + } + return f, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/gitignore_templates.go b/vendor/github.com/xanzy/go-gitlab/gitignore_templates.go new file mode 100644 index 00000000..5c911f45 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/gitignore_templates.go @@ -0,0 +1,84 @@ +// +// Copyright 2018, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// GitIgnoreTemplatesService handles communication with the gitignore +// templates related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/templates/gitignores.html +type GitIgnoreTemplatesService struct { + client *Client +} + +// GitIgnoreTemplate represents a GitLab gitignore template. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/templates/gitignores.html +type GitIgnoreTemplate struct { + Name string `json:"name"` + Content string `json:"content"` +} + +// ListTemplatesOptions represents the available ListAllTemplates() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates +type ListTemplatesOptions ListOptions + +// ListTemplates get a list of available git ignore templates +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/templates/gitignores.html#list-gitignore-templates +func (s *GitIgnoreTemplatesService) ListTemplates(opt *ListTemplatesOptions, options ...OptionFunc) ([]*GitIgnoreTemplate, *Response, error) { + req, err := s.client.NewRequest("GET", "templates/gitignores", opt, options) + if err != nil { + return nil, nil, err + } + + var gs []*GitIgnoreTemplate + resp, err := s.client.Do(req, &gs) + if err != nil { + return nil, resp, err + } + + return gs, resp, err +} + +// GetTemplate get a git ignore template +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/templates/gitignores.html#single-gitignore-template +func (s *GitIgnoreTemplatesService) GetTemplate(key string, options ...OptionFunc) (*GitIgnoreTemplate, *Response, error) { + u := fmt.Sprintf("templates/gitignores/%s", url.QueryEscape(key)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + g := new(GitIgnoreTemplate) + resp, err := s.client.Do(req, g) + if err != nil { + return nil, resp, err + } + + return g, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/gitlab.go b/vendor/github.com/xanzy/go-gitlab/gitlab.go new file mode 100644 index 00000000..7d6df8ff --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/gitlab.go @@ -0,0 +1,854 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "sort" + "strconv" + "strings" + "time" + + "github.com/google/go-querystring/query" + "golang.org/x/oauth2" +) + +const ( + defaultBaseURL = "https://gitlab.com/" + apiVersionPath = "api/v4/" + userAgent = "go-gitlab" +) + +// authType represents an authentication type within GitLab. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/ +type authType int + +// List of available authentication types. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/ +const ( + basicAuth authType = iota + oAuthToken + privateToken +) + +// AccessLevelValue represents a permission level within GitLab. +// +// GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html +type AccessLevelValue int + +// List of available access levels +// +// GitLab API docs: https://docs.gitlab.com/ce/permissions/permissions.html +const ( + NoPermissions AccessLevelValue = 0 + GuestPermissions AccessLevelValue = 10 + ReporterPermissions AccessLevelValue = 20 + DeveloperPermissions AccessLevelValue = 30 + MasterPermissions AccessLevelValue = 40 + OwnerPermission AccessLevelValue = 50 +) + +// BuildStateValue represents a GitLab build state. +type BuildStateValue string + +// These constants represent all valid build states. +const ( + Pending BuildStateValue = "pending" + Running BuildStateValue = "running" + Success BuildStateValue = "success" + Failed BuildStateValue = "failed" + Canceled BuildStateValue = "canceled" + Skipped BuildStateValue = "skipped" +) + +// ISOTime represents an ISO 8601 formatted date +type ISOTime time.Time + +// ISO 8601 date format +const iso8601 = "2006-01-02" + +// MarshalJSON implements the json.Marshaler interface +func (t ISOTime) MarshalJSON() ([]byte, error) { + if y := time.Time(t).Year(); y < 0 || y >= 10000 { + // ISO 8901 uses 4 digits for the years + return nil, errors.New("ISOTime.MarshalJSON: year outside of range [0,9999]") + } + + b := make([]byte, 0, len(iso8601)+2) + b = append(b, '"') + b = time.Time(t).AppendFormat(b, iso8601) + b = append(b, '"') + + return b, nil +} + +// UnmarshalJSON implements the json.Unmarshaler interface +func (t *ISOTime) UnmarshalJSON(data []byte) error { + // Ignore null, like in the main JSON package + if string(data) == "null" { + return nil + } + + isotime, err := time.Parse(`"`+iso8601+`"`, string(data)) + *t = ISOTime(isotime) + + return err +} + +// String implements the Stringer interface +func (t ISOTime) String() string { + return time.Time(t).Format(iso8601) +} + +// NotificationLevelValue represents a notification level. +type NotificationLevelValue int + +// String implements the fmt.Stringer interface. +func (l NotificationLevelValue) String() string { + return notificationLevelNames[l] +} + +// MarshalJSON implements the json.Marshaler interface. +func (l NotificationLevelValue) MarshalJSON() ([]byte, error) { + return json.Marshal(l.String()) +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (l *NotificationLevelValue) UnmarshalJSON(data []byte) error { + var raw interface{} + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + switch raw := raw.(type) { + case float64: + *l = NotificationLevelValue(raw) + case string: + *l = notificationLevelTypes[raw] + case nil: + // No action needed. + default: + return fmt.Errorf("json: cannot unmarshal %T into Go value of type %T", raw, *l) + } + + return nil +} + +// List of valid notification levels. +const ( + DisabledNotificationLevel NotificationLevelValue = iota + ParticipatingNotificationLevel + WatchNotificationLevel + GlobalNotificationLevel + MentionNotificationLevel + CustomNotificationLevel +) + +var notificationLevelNames = [...]string{ + "disabled", + "participating", + "watch", + "global", + "mention", + "custom", +} + +var notificationLevelTypes = map[string]NotificationLevelValue{ + "disabled": DisabledNotificationLevel, + "participating": ParticipatingNotificationLevel, + "watch": WatchNotificationLevel, + "global": GlobalNotificationLevel, + "mention": MentionNotificationLevel, + "custom": CustomNotificationLevel, +} + +// OrderByValue represent in which order to sort the item +type OrderByValue string + +// These constants represent all valid order by values. +const ( + OrderByCreatedAt OrderByValue = "created_at" + OrderByID OrderByValue = "id" + OrderByIID OrderByValue = "iid" + OrderByRef OrderByValue = "ref" + OrderByStatus OrderByValue = "status" + OrderByUserID OrderByValue = "user_id" +) + +// VisibilityValue represents a visibility level within GitLab. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/ +type VisibilityValue string + +// List of available visibility levels +// +// GitLab API docs: https://docs.gitlab.com/ce/api/ +const ( + PrivateVisibility VisibilityValue = "private" + InternalVisibility VisibilityValue = "internal" + PublicVisibility VisibilityValue = "public" +) + +// MergeMethodValue represents a project merge type within GitLab. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#project-merge-method +type MergeMethodValue string + +// List of available merge type +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#project-merge-method +const ( + NoFastForwardMerge MergeMethodValue = "merge" + FastForwardMerge MergeMethodValue = "ff" + RebaseMerge MergeMethodValue = "rebase_merge" +) + +// EventTypeValue represents actions type for contribution events +type EventTypeValue string + +// List of available action type +// +// GitLab API docs: https://docs.gitlab.com/ce/api/events.html#action-types +const ( + CreatedEventType EventTypeValue = "created" + UpdatedEventType EventTypeValue = "updated" + ClosedEventType EventTypeValue = "closed" + ReopenedEventType EventTypeValue = "reopened" + PushedEventType EventTypeValue = "pushed" + CommentedEventType EventTypeValue = "commented" + MergedEventType EventTypeValue = "merged" + JoinedEventType EventTypeValue = "joined" + LeftEventType EventTypeValue = "left" + DestroyedEventType EventTypeValue = "destroyed" + ExpiredEventType EventTypeValue = "expired" +) + +// EventTargetTypeValue represents actions type value for contribution events +type EventTargetTypeValue string + +// List of available action type +// +// GitLab API docs: https://docs.gitlab.com/ce/api/events.html#target-types +const ( + IssueEventTargetType EventTargetTypeValue = "issue" + MilestoneEventTargetType EventTargetTypeValue = "milestone" + MergeRequestEventTargetType EventTargetTypeValue = "merge_request" + NoteEventTargetType EventTargetTypeValue = "note" + ProjectEventTargetType EventTargetTypeValue = "project" + SnippetEventTargetType EventTargetTypeValue = "snippet" + UserEventTargetType EventTargetTypeValue = "user" +) + +// A Client manages communication with the GitLab API. +type Client struct { + // HTTP client used to communicate with the API. + client *http.Client + + // Base URL for API requests. Defaults to the public GitLab API, but can be + // set to a domain endpoint to use with a self hosted GitLab server. baseURL + // should always be specified with a trailing slash. + baseURL *url.URL + + // Token type used to make authenticated API calls. + authType authType + + // Username and password used for basix authentication. + username, password string + + // Token used to make authenticated API calls. + token string + + // User agent used when communicating with the GitLab API. + UserAgent string + + // Services used for talking to different parts of the GitLab API. + AwardEmoji *AwardEmojiService + Branches *BranchesService + BuildVariables *BuildVariablesService + BroadcastMessage *BroadcastMessagesService + Commits *CommitsService + DeployKeys *DeployKeysService + Deployments *DeploymentsService + Environments *EnvironmentsService + Events *EventsService + Features *FeaturesService + GitIgnoreTemplates *GitIgnoreTemplatesService + Groups *GroupsService + GroupMembers *GroupMembersService + GroupMilestones *GroupMilestonesService + Issues *IssuesService + IssueLinks *IssueLinksService + Jobs *JobsService + Boards *IssueBoardsService + Labels *LabelsService + MergeRequests *MergeRequestsService + MergeRequestApprovals *MergeRequestApprovalsService + Milestones *MilestonesService + Namespaces *NamespacesService + Notes *NotesService + NotificationSettings *NotificationSettingsService + PagesDomains *PagesDomainsService + Pipelines *PipelinesService + PipelineSchedules *PipelineSchedulesService + PipelineTriggers *PipelineTriggersService + Projects *ProjectsService + ProjectMembers *ProjectMembersService + ProjectSnippets *ProjectSnippetsService + ProtectedBranches *ProtectedBranchesService + Repositories *RepositoriesService + RepositoryFiles *RepositoryFilesService + Runners *RunnersService + Search *SearchService + Services *ServicesService + Session *SessionService + Settings *SettingsService + Sidekiq *SidekiqService + Snippets *SnippetsService + SystemHooks *SystemHooksService + Tags *TagsService + Todos *TodosService + Users *UsersService + Validate *ValidateService + Version *VersionService + Wikis *WikisService +} + +// ListOptions specifies the optional parameters to various List methods that +// support pagination. +type ListOptions struct { + // For paginated result sets, page of results to retrieve. + Page int `url:"page,omitempty" json:"page,omitempty"` + + // For paginated result sets, the number of results to include per page. + PerPage int `url:"per_page,omitempty" json:"per_page,omitempty"` +} + +// NewClient returns a new GitLab API client. If a nil httpClient is +// provided, http.DefaultClient will be used. To use API methods which require +// authentication, provide a valid private or personal token. +func NewClient(httpClient *http.Client, token string) *Client { + client := newClient(httpClient) + client.authType = privateToken + client.token = token + return client +} + +// NewBasicAuthClient returns a new GitLab API client. If a nil httpClient is +// provided, http.DefaultClient will be used. To use API methods which require +// authentication, provide a valid username and password. +func NewBasicAuthClient(httpClient *http.Client, endpoint, username, password string) (*Client, error) { + client := newClient(httpClient) + client.authType = basicAuth + client.username = username + client.password = password + client.SetBaseURL(endpoint) + + err := client.requestOAuthToken(context.TODO()) + if err != nil { + return nil, err + } + + return client, nil +} + +func (c *Client) requestOAuthToken(ctx context.Context) error { + config := &oauth2.Config{ + Endpoint: oauth2.Endpoint{ + AuthURL: fmt.Sprintf("%s://%s/oauth/authorize", c.BaseURL().Scheme, c.BaseURL().Host), + TokenURL: fmt.Sprintf("%s://%s/oauth/token", c.BaseURL().Scheme, c.BaseURL().Host), + }, + } + ctx = context.WithValue(ctx, oauth2.HTTPClient, c.client) + t, err := config.PasswordCredentialsToken(ctx, c.username, c.password) + if err != nil { + return err + } + c.token = t.AccessToken + return nil +} + +// NewOAuthClient returns a new GitLab API client. If a nil httpClient is +// provided, http.DefaultClient will be used. To use API methods which require +// authentication, provide a valid oauth token. +func NewOAuthClient(httpClient *http.Client, token string) *Client { + client := newClient(httpClient) + client.authType = oAuthToken + client.token = token + return client +} + +func newClient(httpClient *http.Client) *Client { + if httpClient == nil { + httpClient = http.DefaultClient + } + + c := &Client{client: httpClient, UserAgent: userAgent} + if err := c.SetBaseURL(defaultBaseURL); err != nil { + // Should never happen since defaultBaseURL is our constant. + panic(err) + } + + // Create the internal timeStats service. + timeStats := &timeStatsService{client: c} + + // Create all the public services. + c.AwardEmoji = &AwardEmojiService{client: c} + c.Branches = &BranchesService{client: c} + c.BuildVariables = &BuildVariablesService{client: c} + c.BroadcastMessage = &BroadcastMessagesService{client: c} + c.Commits = &CommitsService{client: c} + c.DeployKeys = &DeployKeysService{client: c} + c.Deployments = &DeploymentsService{client: c} + c.Environments = &EnvironmentsService{client: c} + c.Events = &EventsService{client: c} + c.Features = &FeaturesService{client: c} + c.GitIgnoreTemplates = &GitIgnoreTemplatesService{client: c} + c.Groups = &GroupsService{client: c} + c.GroupMembers = &GroupMembersService{client: c} + c.GroupMilestones = &GroupMilestonesService{client: c} + c.Issues = &IssuesService{client: c, timeStats: timeStats} + c.IssueLinks = &IssueLinksService{client: c} + c.Jobs = &JobsService{client: c} + c.Boards = &IssueBoardsService{client: c} + c.Labels = &LabelsService{client: c} + c.MergeRequests = &MergeRequestsService{client: c, timeStats: timeStats} + c.MergeRequestApprovals = &MergeRequestApprovalsService{client: c} + c.Milestones = &MilestonesService{client: c} + c.Namespaces = &NamespacesService{client: c} + c.Notes = &NotesService{client: c} + c.NotificationSettings = &NotificationSettingsService{client: c} + c.PagesDomains = &PagesDomainsService{client: c} + c.Pipelines = &PipelinesService{client: c} + c.PipelineSchedules = &PipelineSchedulesService{client: c} + c.PipelineTriggers = &PipelineTriggersService{client: c} + c.Projects = &ProjectsService{client: c} + c.ProjectMembers = &ProjectMembersService{client: c} + c.ProjectSnippets = &ProjectSnippetsService{client: c} + c.ProtectedBranches = &ProtectedBranchesService{client: c} + c.Repositories = &RepositoriesService{client: c} + c.RepositoryFiles = &RepositoryFilesService{client: c} + c.Runners = &RunnersService{client: c} + c.Services = &ServicesService{client: c} + c.Search = &SearchService{client: c} + c.Session = &SessionService{client: c} + c.Settings = &SettingsService{client: c} + c.Sidekiq = &SidekiqService{client: c} + c.Snippets = &SnippetsService{client: c} + c.SystemHooks = &SystemHooksService{client: c} + c.Tags = &TagsService{client: c} + c.Todos = &TodosService{client: c} + c.Users = &UsersService{client: c} + c.Validate = &ValidateService{client: c} + c.Version = &VersionService{client: c} + c.Wikis = &WikisService{client: c} + + return c +} + +// BaseURL return a copy of the baseURL. +func (c *Client) BaseURL() *url.URL { + u := *c.baseURL + return &u +} + +// SetBaseURL sets the base URL for API requests to a custom endpoint. urlStr +// should always be specified with a trailing slash. +func (c *Client) SetBaseURL(urlStr string) error { + // Make sure the given URL end with a slash + if !strings.HasSuffix(urlStr, "/") { + urlStr += "/" + } + + baseURL, err := url.Parse(urlStr) + if err != nil { + return err + } + + if !strings.HasSuffix(baseURL.Path, apiVersionPath) { + baseURL.Path += apiVersionPath + } + + // Update the base URL of the client. + c.baseURL = baseURL + + return nil +} + +// NewRequest creates an API request. A relative URL path can be provided in +// urlStr, in which case it is resolved relative to the base URL of the Client. +// Relative URL paths should always be specified without a preceding slash. If +// specified, the value pointed to by body is JSON encoded and included as the +// request body. +func (c *Client) NewRequest(method, path string, opt interface{}, options []OptionFunc) (*http.Request, error) { + u := *c.baseURL + // Set the encoded opaque data + u.Opaque = c.baseURL.Path + path + + if opt != nil { + q, err := query.Values(opt) + if err != nil { + return nil, err + } + u.RawQuery = q.Encode() + } + + req := &http.Request{ + Method: method, + URL: &u, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Header: make(http.Header), + Host: u.Host, + } + + for _, fn := range options { + if fn == nil { + continue + } + + if err := fn(req); err != nil { + return nil, err + } + } + + if method == "POST" || method == "PUT" { + bodyBytes, err := json.Marshal(opt) + if err != nil { + return nil, err + } + bodyReader := bytes.NewReader(bodyBytes) + + u.RawQuery = "" + req.Body = ioutil.NopCloser(bodyReader) + req.ContentLength = int64(bodyReader.Len()) + req.Header.Set("Content-Type", "application/json") + } + + req.Header.Set("Accept", "application/json") + + switch c.authType { + case basicAuth, oAuthToken: + req.Header.Set("Authorization", "Bearer "+c.token) + case privateToken: + req.Header.Set("PRIVATE-TOKEN", c.token) + } + + if c.UserAgent != "" { + req.Header.Set("User-Agent", c.UserAgent) + } + + return req, nil +} + +// Response is a GitLab API response. This wraps the standard http.Response +// returned from GitLab and provides convenient access to things like +// pagination links. +type Response struct { + *http.Response + + // These fields provide the page values for paginating through a set of + // results. Any or all of these may be set to the zero value for + // responses that are not part of a paginated set, or for which there + // are no additional pages. + TotalItems int + TotalPages int + ItemsPerPage int + CurrentPage int + NextPage int + PreviousPage int +} + +// newResponse creates a new Response for the provided http.Response. +func newResponse(r *http.Response) *Response { + response := &Response{Response: r} + response.populatePageValues() + return response +} + +const ( + xTotal = "X-Total" + xTotalPages = "X-Total-Pages" + xPerPage = "X-Per-Page" + xPage = "X-Page" + xNextPage = "X-Next-Page" + xPrevPage = "X-Prev-Page" +) + +// populatePageValues parses the HTTP Link response headers and populates the +// various pagination link values in the Response. +func (r *Response) populatePageValues() { + if totalItems := r.Response.Header.Get(xTotal); totalItems != "" { + r.TotalItems, _ = strconv.Atoi(totalItems) + } + if totalPages := r.Response.Header.Get(xTotalPages); totalPages != "" { + r.TotalPages, _ = strconv.Atoi(totalPages) + } + if itemsPerPage := r.Response.Header.Get(xPerPage); itemsPerPage != "" { + r.ItemsPerPage, _ = strconv.Atoi(itemsPerPage) + } + if currentPage := r.Response.Header.Get(xPage); currentPage != "" { + r.CurrentPage, _ = strconv.Atoi(currentPage) + } + if nextPage := r.Response.Header.Get(xNextPage); nextPage != "" { + r.NextPage, _ = strconv.Atoi(nextPage) + } + if previousPage := r.Response.Header.Get(xPrevPage); previousPage != "" { + r.PreviousPage, _ = strconv.Atoi(previousPage) + } +} + +// Do sends an API request and returns the API response. The API response is +// JSON decoded and stored in the value pointed to by v, or returned as an +// error if an API error has occurred. If v implements the io.Writer +// interface, the raw response body will be written to v, without attempting to +// first decode it. +func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) { + resp, err := c.client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusUnauthorized && c.authType == basicAuth { + err = c.requestOAuthToken(req.Context()) + if err != nil { + return nil, err + } + return c.Do(req, v) + } + + response := newResponse(resp) + + err = CheckResponse(resp) + if err != nil { + // even though there was an error, we still return the response + // in case the caller wants to inspect it further + return response, err + } + + if v != nil { + if w, ok := v.(io.Writer); ok { + _, err = io.Copy(w, resp.Body) + } else { + err = json.NewDecoder(resp.Body).Decode(v) + } + } + + return response, err +} + +// Helper function to accept and format both the project ID or name as project +// identifier for all API calls. +func parseID(id interface{}) (string, error) { + switch v := id.(type) { + case int: + return strconv.Itoa(v), nil + case string: + return v, nil + default: + return "", fmt.Errorf("invalid ID type %#v, the ID must be an int or a string", id) + } +} + +// An ErrorResponse reports one or more errors caused by an API request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/README.html#data-validation-and-error-reporting +type ErrorResponse struct { + Response *http.Response + Message string +} + +func (e *ErrorResponse) Error() string { + path, _ := url.QueryUnescape(e.Response.Request.URL.Opaque) + u := fmt.Sprintf("%s://%s%s", e.Response.Request.URL.Scheme, e.Response.Request.URL.Host, path) + return fmt.Sprintf("%s %s: %d %s", e.Response.Request.Method, u, e.Response.StatusCode, e.Message) +} + +// CheckResponse checks the API response for errors, and returns them if present. +func CheckResponse(r *http.Response) error { + switch r.StatusCode { + case 200, 201, 202, 204, 304: + return nil + } + + errorResponse := &ErrorResponse{Response: r} + data, err := ioutil.ReadAll(r.Body) + if err == nil && data != nil { + var raw interface{} + if err := json.Unmarshal(data, &raw); err != nil { + errorResponse.Message = "failed to parse unknown error format" + } + + errorResponse.Message = parseError(raw) + } + + return errorResponse +} + +// Format: +// { +// "message": { +// "": [ +// "", +// "", +// ... +// ], +// "": { +// "": [ +// "", +// "", +// ... +// ], +// } +// }, +// "error": "" +// } +func parseError(raw interface{}) string { + switch raw := raw.(type) { + case string: + return raw + + case []interface{}: + var errs []string + for _, v := range raw { + errs = append(errs, parseError(v)) + } + return fmt.Sprintf("[%s]", strings.Join(errs, ", ")) + + case map[string]interface{}: + var errs []string + for k, v := range raw { + errs = append(errs, fmt.Sprintf("{%s: %s}", k, parseError(v))) + } + sort.Strings(errs) + return strings.Join(errs, ", ") + + default: + return fmt.Sprintf("failed to parse unexpected error type: %T", raw) + } +} + +// OptionFunc can be passed to all API requests to make the API call as if you were +// another user, provided your private token is from an administrator account. +// +// GitLab docs: https://docs.gitlab.com/ce/api/README.html#sudo +type OptionFunc func(*http.Request) error + +// WithSudo takes either a username or user ID and sets the SUDO request header +func WithSudo(uid interface{}) OptionFunc { + return func(req *http.Request) error { + user, err := parseID(uid) + if err != nil { + return err + } + req.Header.Set("SUDO", user) + return nil + } +} + +// WithContext runs the request with the provided context +func WithContext(ctx context.Context) OptionFunc { + return func(req *http.Request) error { + *req = *req.WithContext(ctx) + return nil + } +} + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { + p := new(bool) + *p = v + return p +} + +// Int is a helper routine that allocates a new int32 value +// to store v and returns a pointer to it, but unlike Int32 +// its argument value is an int. +func Int(v int) *int { + p := new(int) + *p = v + return p +} + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { + p := new(string) + *p = v + return p +} + +// AccessLevel is a helper routine that allocates a new AccessLevelValue +// to store v and returns a pointer to it. +func AccessLevel(v AccessLevelValue) *AccessLevelValue { + p := new(AccessLevelValue) + *p = v + return p +} + +// BuildState is a helper routine that allocates a new BuildStateValue +// to store v and returns a pointer to it. +func BuildState(v BuildStateValue) *BuildStateValue { + p := new(BuildStateValue) + *p = v + return p +} + +// NotificationLevel is a helper routine that allocates a new NotificationLevelValue +// to store v and returns a pointer to it. +func NotificationLevel(v NotificationLevelValue) *NotificationLevelValue { + p := new(NotificationLevelValue) + *p = v + return p +} + +// OrderBy is a helper routine that allocates a new OrderByValue +// to store v and returns a pointer to it. +func OrderBy(v OrderByValue) *OrderByValue { + p := new(OrderByValue) + *p = v + return p +} + +// Visibility is a helper routine that allocates a new VisibilityValue +// to store v and returns a pointer to it. +func Visibility(v VisibilityValue) *VisibilityValue { + p := new(VisibilityValue) + *p = v + return p +} + +// MergeMethod is a helper routine that allocates a new MergeMethod +// to sotre v and returns a pointer to it. +func MergeMethod(v MergeMethodValue) *MergeMethodValue { + p := new(MergeMethodValue) + *p = v + return p +} diff --git a/vendor/github.com/xanzy/go-gitlab/group_members.go b/vendor/github.com/xanzy/go-gitlab/group_members.go new file mode 100644 index 00000000..9423ff68 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/group_members.go @@ -0,0 +1,195 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// GroupMembersService handles communication with the group members +// related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/members.html +type GroupMembersService struct { + client *Client +} + +// GroupMember represents a GitLab group member. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/members.html +type GroupMember struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + AccessLevel AccessLevelValue `json:"access_level"` + ExpiresAt *ISOTime `json:"expires_at"` +} + +// ListGroupMembersOptions represents the available ListGroupMembers() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project +type ListGroupMembersOptions struct { + ListOptions + Query *string `url:"query,omitempty" json:"query,omitempty"` +} + +// ListGroupMembers get a list of group members viewable by the authenticated +// user. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project +func (s *GroupsService) ListGroupMembers(gid interface{}, opt *ListGroupMembersOptions, options ...OptionFunc) ([]*GroupMember, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/members", url.QueryEscape(group)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var gm []*GroupMember + resp, err := s.client.Do(req, &gm) + if err != nil { + return nil, resp, err + } + + return gm, resp, err +} + +// AddGroupMemberOptions represents the available AddGroupMember() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project +type AddGroupMemberOptions struct { + UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"` + AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` + ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"` +} + +// GetGroupMember gets a member of a group. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project +func (s *GroupMembersService) GetGroupMember(gid interface{}, user int, options ...OptionFunc) (*GroupMember, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/members/%d", url.QueryEscape(group), user) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + gm := new(GroupMember) + resp, err := s.client.Do(req, gm) + if err != nil { + return nil, resp, err + } + + return gm, resp, err +} + +// AddGroupMember adds a user to the list of group members. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project +func (s *GroupMembersService) AddGroupMember(gid interface{}, opt *AddGroupMemberOptions, options ...OptionFunc) (*GroupMember, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/members", url.QueryEscape(group)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + gm := new(GroupMember) + resp, err := s.client.Do(req, gm) + if err != nil { + return nil, resp, err + } + + return gm, resp, err +} + +// EditGroupMemberOptions represents the available EditGroupMember() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project +type EditGroupMemberOptions struct { + AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` + ExpiresAt *string `url:"expires_at,omitempty" json:"expires_at"` +} + +// EditGroupMember updates a member of a group. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project +func (s *GroupMembersService) EditGroupMember(gid interface{}, user int, opt *EditGroupMemberOptions, options ...OptionFunc) (*GroupMember, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/members/%d", url.QueryEscape(group), user) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + gm := new(GroupMember) + resp, err := s.client.Do(req, gm) + if err != nil { + return nil, resp, err + } + + return gm, resp, err +} + +// RemoveGroupMember removes user from user team. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#remove-a-member-from-a-group-or-project +func (s *GroupMembersService) RemoveGroupMember(gid interface{}, user int, options ...OptionFunc) (*Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("groups/%s/members/%d", url.QueryEscape(group), user) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/group_milestones.go b/vendor/github.com/xanzy/go-gitlab/group_milestones.go new file mode 100644 index 00000000..8335a47b --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/group_milestones.go @@ -0,0 +1,250 @@ +// +// Copyright 2018, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// GroupMilestonesService handles communication with the milestone related +// methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/group_milestones.html +type GroupMilestonesService struct { + client *Client +} + +// GroupMilestone represents a GitLab milestone. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/group_milestones.html +type GroupMilestone struct { + ID int `json:"id"` + IID int `json:"iid"` + GroupID int `json:"group_id"` + Title string `json:"title"` + Description string `json:"description"` + StartDate *ISOTime `json:"start_date"` + DueDate *ISOTime `json:"due_date"` + State string `json:"state"` + UpdatedAt *time.Time `json:"updated_at"` + CreatedAt *time.Time `json:"created_at"` +} + +func (m GroupMilestone) String() string { + return Stringify(m) +} + +// ListGroupMilestonesOptions represents the available +// ListGroupMilestones() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#list-group-milestones +type ListGroupMilestonesOptions struct { + ListOptions + IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` + State string `url:"state,omitempty" json:"state,omitempty"` + Search string `url:"search,omitempty" json:"search,omitempty"` +} + +// ListGroupMilestones returns a list of group milestones. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#list-group-milestones +func (s *GroupMilestonesService) ListGroupMilestones(gid interface{}, opt *ListGroupMilestonesOptions, options ...OptionFunc) ([]*GroupMilestone, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/milestones", url.QueryEscape(group)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var m []*GroupMilestone + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// GetGroupMilestone gets a single group milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#get-single-milestone +func (s *GroupMilestonesService) GetGroupMilestone(gid interface{}, milestone int, options ...OptionFunc) (*GroupMilestone, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/milestones/%d", url.QueryEscape(group), milestone) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + m := new(GroupMilestone) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// CreateGroupMilestoneOptions represents the available CreateGroupMilestone() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#create-new-milestone +type CreateGroupMilestoneOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` + DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` +} + +// CreateGroupMilestone creates a new group milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#create-new-milestone +func (s *GroupMilestonesService) CreateGroupMilestone(gid interface{}, opt *CreateGroupMilestoneOptions, options ...OptionFunc) (*GroupMilestone, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/milestones", url.QueryEscape(group)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + m := new(GroupMilestone) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// UpdateGroupMilestoneOptions represents the available UpdateGroupMilestone() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#edit-milestone +type UpdateGroupMilestoneOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` + DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` + StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` +} + +// UpdateGroupMilestone updates an existing group milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#edit-milestone +func (s *GroupMilestonesService) UpdateGroupMilestone(gid interface{}, milestone int, opt *UpdateGroupMilestoneOptions, options ...OptionFunc) (*GroupMilestone, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/milestones/%d", url.QueryEscape(group), milestone) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + m := new(GroupMilestone) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// GetGroupMilestoneIssuesOptions represents the available GetGroupMilestoneIssues() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-issues-assigned-to-a-single-milestone +type GetGroupMilestoneIssuesOptions ListOptions + +// GetGroupMilestoneIssues gets all issues assigned to a single group milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-issues-assigned-to-a-single-milestone +func (s *GroupMilestonesService) GetGroupMilestoneIssues(gid interface{}, milestone int, opt *GetGroupMilestoneIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/milestones/%d/issues", url.QueryEscape(group), milestone) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var i []*Issue + resp, err := s.client.Do(req, &i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} + +// GetGroupMilestoneMergeRequestsOptions represents the available +// GetGroupMilestoneMergeRequests() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-merge-requests-assigned-to-a-single-milestone +type GetGroupMilestoneMergeRequestsOptions ListOptions + +// GetGroupMilestoneMergeRequests gets all merge requests assigned to a +// single group milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/group_milestones.html#get-all-merge-requests-assigned-to-a-single-milestone +func (s *GroupMilestonesService) GetGroupMilestoneMergeRequests(gid interface{}, milestone int, opt *GetGroupMilestoneMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/milestones/%d/merge_requests", url.QueryEscape(group), milestone) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var mr []*MergeRequest + resp, err := s.client.Do(req, &mr) + if err != nil { + return nil, resp, err + } + + return mr, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/groups.go b/vendor/github.com/xanzy/go-gitlab/groups.go new file mode 100644 index 00000000..d379915c --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/groups.go @@ -0,0 +1,307 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// GroupsService handles communication with the group related methods of +// the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html +type GroupsService struct { + client *Client +} + +// Group represents a GitLab group. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html +type Group struct { + ID int `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Description string `json:"description"` + Visibility *VisibilityValue `json:"visibility"` + LFSEnabled bool `json:"lfs_enabled"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + RequestAccessEnabled bool `json:"request_access_enabled"` + FullName string `json:"full_name"` + FullPath string `json:"full_path"` + ParentID int `json:"parent_id"` + Projects []*Project `json:"projects"` + Statistics *StorageStatistics `json:"statistics"` +} + +// ListGroupsOptions represents the available ListGroups() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-project-groups +type ListGroupsOptions struct { + ListOptions + AllAvailable *bool `url:"all_available,omitempty" json:"all_available,omitempty"` + OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` + Owned *bool `url:"owned,omitempty" json:"owned,omitempty"` + Search *string `url:"search,omitempty" json:"search,omitempty"` + Sort *string `url:"sort,omitempty" json:"sort,omitempty"` + Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"` +} + +// ListGroups gets a list of groups (as user: my groups, as admin: all groups). +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/groups.html#list-project-groups +func (s *GroupsService) ListGroups(opt *ListGroupsOptions, options ...OptionFunc) ([]*Group, *Response, error) { + req, err := s.client.NewRequest("GET", "groups", opt, options) + if err != nil { + return nil, nil, err + } + + var g []*Group + resp, err := s.client.Do(req, &g) + if err != nil { + return nil, resp, err + } + + return g, resp, err +} + +// GetGroup gets all details of a group. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#details-of-a-group +func (s *GroupsService) GetGroup(gid interface{}, options ...OptionFunc) (*Group, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s", url.QueryEscape(group)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + g := new(Group) + resp, err := s.client.Do(req, g) + if err != nil { + return nil, resp, err + } + + return g, resp, err +} + +// CreateGroupOptions represents the available CreateGroup() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group +type CreateGroupOptions struct { + Name *string `url:"name,omitempty" json:"name,omitempty"` + Path *string `url:"path,omitempty" json:"path,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` + LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` + RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` + ParentID *int `url:"parent_id,omitempty" json:"parent_id,omitempty"` +} + +// CreateGroup creates a new project group. Available only for users who can +// create groups. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#new-group +func (s *GroupsService) CreateGroup(opt *CreateGroupOptions, options ...OptionFunc) (*Group, *Response, error) { + req, err := s.client.NewRequest("POST", "groups", opt, options) + if err != nil { + return nil, nil, err + } + + g := new(Group) + resp, err := s.client.Do(req, g) + if err != nil { + return nil, resp, err + } + + return g, resp, err +} + +// TransferGroup transfers a project to the Group namespace. Available only +// for admin. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/groups.html#transfer-project-to-group +func (s *GroupsService) TransferGroup(gid interface{}, pid interface{}, options ...OptionFunc) (*Group, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + + u := fmt.Sprintf("groups/%s/projects/%s", url.QueryEscape(group), + url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + g := new(Group) + resp, err := s.client.Do(req, g) + if err != nil { + return nil, resp, err + } + + return g, resp, err +} + +// UpdateGroupOptions represents the set of available options to update a Group; +// as of today these are exactly the same available when creating a new Group. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#update-group +type UpdateGroupOptions CreateGroupOptions + +// UpdateGroup updates an existing group; only available to group owners and +// administrators. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#update-group +func (s *GroupsService) UpdateGroup(gid interface{}, opt *UpdateGroupOptions, options ...OptionFunc) (*Group, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s", url.QueryEscape(group)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + g := new(Group) + resp, err := s.client.Do(req, g) + if err != nil { + return nil, resp, err + } + + return g, resp, err +} + +// DeleteGroup removes group with all projects inside. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#remove-group +func (s *GroupsService) DeleteGroup(gid interface{}, options ...OptionFunc) (*Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("groups/%s", url.QueryEscape(group)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// SearchGroup get all groups that match your string in their name or path. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#search-for-group +func (s *GroupsService) SearchGroup(query string, options ...OptionFunc) ([]*Group, *Response, error) { + var q struct { + Search string `url:"search,omitempty" json:"search,omitempty"` + } + q.Search = query + + req, err := s.client.NewRequest("GET", "groups", &q, options) + if err != nil { + return nil, nil, err + } + + var g []*Group + resp, err := s.client.Do(req, &g) + if err != nil { + return nil, resp, err + } + + return g, resp, err +} + +// ListGroupProjectsOptions represents the available ListGroupProjects() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/groups.html#list-a-group-39-s-projects +type ListGroupProjectsOptions ListProjectsOptions + +// ListGroupProjects get a list of group projects +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/groups.html#list-a-group-39-s-projects +func (s *GroupsService) ListGroupProjects(gid interface{}, opt *ListGroupProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/projects", url.QueryEscape(group)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var p []*Project + resp, err := s.client.Do(req, &p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// ListSubgroupsOptions represents the available ListSubgroupsOptions() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/groups.html#list-a-groups-s-subgroups +type ListSubgroupsOptions ListGroupsOptions + +// ListSubgroups gets a list of subgroups for a given project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/groups.html#list-a-groups-s-subgroups +func (s *GroupsService) ListSubgroups(gid interface{}, opt *ListSubgroupsOptions, options ...OptionFunc) ([]*Group, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/subgroups", url.QueryEscape(group)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var g []*Group + resp, err := s.client.Do(req, &g) + if err != nil { + return nil, resp, err + } + + return g, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/issue_links.go b/vendor/github.com/xanzy/go-gitlab/issue_links.go new file mode 100644 index 00000000..5dfd76aa --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/issue_links.go @@ -0,0 +1,128 @@ +// +// Copyright 2017, Arkbriar +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// IssueLinksService handles communication with the issue relations related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ee/api/issue_links.html +type IssueLinksService struct { + client *Client +} + +// IssueLink represents a two-way relation between two issues. +// +// GitLab API docs: https://docs.gitlab.com/ee/api/issue_links.html +type IssueLink struct { + SourceIssue *Issue `json:"source_issue"` + TargetIssue *Issue `json:"target_issue"` +} + +// ListIssueRelations gets a list of related issues of a given issue, +// sorted by the relationship creation datetime (ascending). +// +// Issues will be filtered according to the user authorizations. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/issue_links.html#list-issue-relations +func (s *IssueLinksService) ListIssueRelations(pid interface{}, issueIID int, options ...OptionFunc) ([]*Issue, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d/links", url.QueryEscape(project), issueIID) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var is []*Issue + resp, err := s.client.Do(req, &is) + if err != nil { + return nil, resp, err + } + + return is, resp, err +} + +// CreateIssueLinkOptions represents the available CreateIssueLink() options. +// +// GitLab API docs: https://docs.gitlab.com/ee/api/issue_links.html +type CreateIssueLinkOptions struct { + TargetProjectID *string `json:"target_project_id"` + TargetIssueIID *string `json:"target_issue_iid"` +} + +// CreateIssueLink creates a two-way relation between two issues. +// User must be allowed to update both issues in order to succeed. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/issue_links.html#create-an-issue-link +func (s *IssueLinksService) CreateIssueLink(pid interface{}, issueIID int, opt *CreateIssueLinkOptions, options ...OptionFunc) (*IssueLink, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d/links", url.QueryEscape(project), issueIID) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + i := new(IssueLink) + resp, err := s.client.Do(req, &i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} + +// DeleteIssueLink deletes an issue link, thus removes the two-way relationship. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/issue_links.html#delete-an-issue-link +func (s *IssueLinksService) DeleteIssueLink(pid interface{}, issueIID, issueLinkID int, options ...OptionFunc) (*IssueLink, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d/links/%d", + url.QueryEscape(project), + issueIID, + issueLinkID) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, nil, err + } + + i := new(IssueLink) + resp, err := s.client.Do(req, &i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/issues.go b/vendor/github.com/xanzy/go-gitlab/issues.go new file mode 100644 index 00000000..51c3a19a --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/issues.go @@ -0,0 +1,403 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "encoding/json" + "fmt" + "net/url" + "strings" + "time" +) + +// IssuesService handles communication with the issue related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html +type IssuesService struct { + client *Client + timeStats *timeStatsService +} + +// Issue represents a GitLab issue. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html +type Issue struct { + ID int `json:"id"` + IID int `json:"iid"` + ProjectID int `json:"project_id"` + Milestone *Milestone `json:"milestone"` + Author struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + } `json:"author"` + Description string `json:"description"` + State string `json:"state"` + Assignees []struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + } `json:"assignees"` + Assignee struct { + ID int `json:"id"` + Name string `json:"name"` + Username string `json:"username"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + } `json:"assignee"` + Upvotes int `json:"upvotes"` + Downvotes int `json:"downvotes"` + Labels []string `json:"labels"` + Title string `json:"title"` + UpdatedAt *time.Time `json:"updated_at"` + CreatedAt *time.Time `json:"created_at"` + ClosedAt *time.Time `json:"closed_at"` + Subscribed bool `json:"subscribed"` + UserNotesCount int `json:"user_notes_count"` + DueDate *ISOTime `json:"due_date"` + WebURL string `json:"web_url"` + TimeStats *TimeStats `json:"time_stats"` + Confidential bool `json:"confidential"` + Weight int `json:"weight"` + DiscussionLocked bool `json:"discussion_locked"` + Links struct { + Self string `json:"self"` + Notes string `json:"notes"` + AwardEmoji string `json:"award_emoji"` + Project string `json:"project"` + } `json:"_links"` + IssueLinkID int `json:"issue_link_id"` +} + +func (i Issue) String() string { + return Stringify(i) +} + +// Labels is a custom type with specific marshaling characteristics. +type Labels []string + +// MarshalJSON implements the json.Marshaler interface. +func (l *Labels) MarshalJSON() ([]byte, error) { + return json.Marshal(strings.Join(*l, ",")) +} + +// ListIssuesOptions represents the available ListIssues() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues +type ListIssuesOptions struct { + ListOptions + State *string `url:"state,omitempty" json:"state,omitempty"` + Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` + Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` + IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` + OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` + Sort *string `url:"sort,omitempty" json:"sort,omitempty"` + Search *string `url:"search,omitempty" json:"search,omitempty"` + CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` + CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` + UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` + UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` +} + +// ListIssues gets all issues created by authenticated user. This function +// takes pagination parameters page and per_page to restrict the list of issues. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-issues +func (s *IssuesService) ListIssues(opt *ListIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) { + req, err := s.client.NewRequest("GET", "issues", opt, options) + if err != nil { + return nil, nil, err + } + + var i []*Issue + resp, err := s.client.Do(req, &i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} + +// ListGroupIssuesOptions represents the available ListGroupIssues() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-group-issues +type ListGroupIssuesOptions struct { + ListOptions + State *string `url:"state,omitempty" json:"state,omitempty"` + Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` + IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` + Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` + OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` + Sort *string `url:"sort,omitempty" json:"sort,omitempty"` + Search *string `url:"search,omitempty" json:"search,omitempty"` + CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` + CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` + UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` + UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` +} + +// ListGroupIssues gets a list of group issues. This function accepts +// pagination parameters page and per_page to return the list of group issues. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-group-issues +func (s *IssuesService) ListGroupIssues(pid interface{}, opt *ListGroupIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) { + group, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/issues", url.QueryEscape(group)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var i []*Issue + resp, err := s.client.Do(req, &i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} + +// ListProjectIssuesOptions represents the available ListProjectIssues() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-project-issues +type ListProjectIssuesOptions struct { + ListOptions + IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` + State *string `url:"state,omitempty" json:"state,omitempty"` + Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` + Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` + OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` + Sort *string `url:"sort,omitempty" json:"sort,omitempty"` + Search *string `url:"search,omitempty" json:"search,omitempty"` + CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` + CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` + UpdatedAfter *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"` + UpdatedBefore *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"` +} + +// ListProjectIssues gets a list of project issues. This function accepts +// pagination parameters page and per_page to return the list of project issues. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#list-project-issues +func (s *IssuesService) ListProjectIssues(pid interface{}, opt *ListProjectIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var i []*Issue + resp, err := s.client.Do(req, &i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} + +// GetIssue gets a single project issue. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#single-issues +func (s *IssuesService) GetIssue(pid interface{}, issue int, options ...OptionFunc) (*Issue, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d", url.QueryEscape(project), issue) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + i := new(Issue) + resp, err := s.client.Do(req, i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} + +// CreateIssueOptions represents the available CreateIssue() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#new-issues +type CreateIssueOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` + AssigneeIDs []int `url:"assignee_ids,omitempty" json:"assignee_ids,omitempty"` + MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` + Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` + CreatedAt *time.Time `url:"created_at,omitempty" json:"created_at,omitempty"` + DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` + MergeRequestToResolveDiscussionsOf *int `url:"merge_request_to_resolve_discussions_of,omitempty" json:"merge_request_to_resolve_discussions_of,omitempty"` + DiscussionToResolve *string `url:"discussion_to_resolve,omitempty" json:"discussion_to_resolve,omitempty"` + Weight *int `url:"weight,omitempty" json:"weight,omitempty"` +} + +// CreateIssue creates a new project issue. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#new-issues +func (s *IssuesService) CreateIssue(pid interface{}, opt *CreateIssueOptions, options ...OptionFunc) (*Issue, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + i := new(Issue) + resp, err := s.client.Do(req, i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} + +// UpdateIssueOptions represents the available UpdateIssue() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#edit-issues +type UpdateIssueOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + Confidential *bool `url:"confidential,omitempty" json:"confidential,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` + Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` + StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` + UpdatedAt *time.Time `url:"updated_at,omitempty" json:"updated_at,omitempty"` + DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` + DiscussionLocked *bool `url:"discussion_locked,omitempty" json:"discussion_locked,omitempty"` +} + +// UpdateIssue updates an existing project issue. This function is also used +// to mark an issue as closed. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#edit-issues +func (s *IssuesService) UpdateIssue(pid interface{}, issue int, opt *UpdateIssueOptions, options ...OptionFunc) (*Issue, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d", url.QueryEscape(project), issue) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + i := new(Issue) + resp, err := s.client.Do(req, i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} + +// DeleteIssue deletes a single project issue. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/issues.html#delete-an-issue +func (s *IssuesService) DeleteIssue(pid interface{}, issue int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d", url.QueryEscape(project), issue) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// SetTimeEstimate sets the time estimate for a single project issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/issues.html#set-a-time-estimate-for-an-issue +func (s *IssuesService) SetTimeEstimate(pid interface{}, issue int, opt *SetTimeEstimateOptions, options ...OptionFunc) (*TimeStats, *Response, error) { + return s.timeStats.setTimeEstimate(pid, "issues", issue, opt, options...) +} + +// ResetTimeEstimate resets the time estimate for a single project issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/issues.html#reset-the-time-estimate-for-an-issue +func (s *IssuesService) ResetTimeEstimate(pid interface{}, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { + return s.timeStats.resetTimeEstimate(pid, "issues", issue, options...) +} + +// AddSpentTime adds spent time for a single project issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/issues.html#add-spent-time-for-an-issue +func (s *IssuesService) AddSpentTime(pid interface{}, issue int, opt *AddSpentTimeOptions, options ...OptionFunc) (*TimeStats, *Response, error) { + return s.timeStats.addSpentTime(pid, "issues", issue, opt, options...) +} + +// ResetSpentTime resets the spent time for a single project issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/issues.html#reset-spent-time-for-an-issue +func (s *IssuesService) ResetSpentTime(pid interface{}, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { + return s.timeStats.resetSpentTime(pid, "issues", issue, options...) +} + +// GetTimeSpent gets the spent time for a single project issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/issues.html#get-time-tracking-stats +func (s *IssuesService) GetTimeSpent(pid interface{}, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { + return s.timeStats.getTimeSpent(pid, "issues", issue, options...) +} diff --git a/vendor/github.com/xanzy/go-gitlab/jobs.go b/vendor/github.com/xanzy/go-gitlab/jobs.go new file mode 100644 index 00000000..669f96dd --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/jobs.go @@ -0,0 +1,350 @@ +// +// Copyright 2017, Arkbriar +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "bytes" + "fmt" + "io" + "net/url" + "time" +) + +// JobsService handles communication with the ci builds related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html +type JobsService struct { + client *Client +} + +// Job represents a ci build. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html +type Job struct { + Commit *Commit `json:"commit"` + CreatedAt *time.Time `json:"created_at"` + Coverage float64 `json:"coverage"` + ArtifactsFile struct { + Filename string `json:"filename"` + Size int `json:"size"` + } `json:"artifacts_file"` + FinishedAt *time.Time `json:"finished_at"` + ID int `json:"id"` + Name string `json:"name"` + Ref string `json:"ref"` + Runner struct { + ID int `json:"id"` + Description string `json:"description"` + Active bool `json:"active"` + IsShared bool `json:"is_shared"` + Name string `json:"name"` + } `json:"runner"` + Stage string `json:"stage"` + StartedAt *time.Time `json:"started_at"` + Status string `json:"status"` + Tag bool `json:"tag"` + User *User `json:"user"` +} + +// ListJobsOptions are options for two list apis +type ListJobsOptions struct { + ListOptions + Scope []BuildStateValue `url:"scope,omitempty" json:"scope,omitempty"` +} + +// ListProjectJobs gets a list of jobs in a project. +// +// The scope of jobs to show, one or array of: created, pending, running, +// failed, success, canceled, skipped; showing all jobs if none provided +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#list-project-jobs +func (s *JobsService) ListProjectJobs(pid interface{}, opts *ListJobsOptions, options ...OptionFunc) ([]Job, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/jobs", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opts, options) + if err != nil { + return nil, nil, err + } + + var jobs []Job + resp, err := s.client.Do(req, &jobs) + if err != nil { + return nil, resp, err + } + + return jobs, resp, err +} + +// ListPipelineJobs gets a list of jobs for specific pipeline in a +// project. If the pipeline ID is not found, it will respond with 404. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#list-pipeline-jobs +func (s *JobsService) ListPipelineJobs(pid interface{}, pipelineID int, opts *ListJobsOptions, options ...OptionFunc) ([]*Job, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipelines/%d/jobs", url.QueryEscape(project), pipelineID) + + req, err := s.client.NewRequest("GET", u, opts, options) + if err != nil { + return nil, nil, err + } + + var jobs []*Job + resp, err := s.client.Do(req, &jobs) + if err != nil { + return nil, resp, err + } + + return jobs, resp, err +} + +// GetJob gets a single job of a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#get-a-single-job +func (s *JobsService) GetJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/jobs/%d", url.QueryEscape(project), jobID) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + job := new(Job) + resp, err := s.client.Do(req, job) + if err != nil { + return nil, resp, err + } + + return job, resp, err +} + +// GetJobArtifacts get jobs artifacts of a project +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#get-job-artifacts +func (s *JobsService) GetJobArtifacts(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/jobs/%d/artifacts", url.QueryEscape(project), jobID) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + artifactsBuf := new(bytes.Buffer) + resp, err := s.client.Do(req, artifactsBuf) + if err != nil { + return nil, resp, err + } + + return artifactsBuf, resp, err +} + +// DownloadArtifactsFile download the artifacts file from the given +// reference name and job provided the job finished successfully. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file +func (s *JobsService) DownloadArtifactsFile(pid interface{}, refName string, job string, options ...OptionFunc) (io.Reader, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/jobs/artifacts/%s/download?job=%s", url.QueryEscape(project), refName, job) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + artifactsBuf := new(bytes.Buffer) + resp, err := s.client.Do(req, artifactsBuf) + if err != nil { + return nil, resp, err + } + + return artifactsBuf, resp, err +} + +// GetTraceFile gets a trace of a specific job of a project +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#get-a-trace-file +func (s *JobsService) GetTraceFile(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/jobs/%d/trace", url.QueryEscape(project), jobID) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + traceBuf := new(bytes.Buffer) + resp, err := s.client.Do(req, traceBuf) + if err != nil { + return nil, resp, err + } + + return traceBuf, resp, err +} + +// CancelJob cancels a single job of a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#cancel-a-job +func (s *JobsService) CancelJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/jobs/%d/cancel", url.QueryEscape(project), jobID) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + job := new(Job) + resp, err := s.client.Do(req, job) + if err != nil { + return nil, resp, err + } + + return job, resp, err +} + +// RetryJob retries a single job of a project +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#retry-a-job +func (s *JobsService) RetryJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/jobs/%d/retry", url.QueryEscape(project), jobID) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + job := new(Job) + resp, err := s.client.Do(req, job) + if err != nil { + return nil, resp, err + } + + return job, resp, err +} + +// EraseJob erases a single job of a project, removes a job +// artifacts and a job trace. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#erase-a-job +func (s *JobsService) EraseJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/jobs/%d/erase", url.QueryEscape(project), jobID) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + job := new(Job) + resp, err := s.client.Do(req, job) + if err != nil { + return nil, resp, err + } + + return job, resp, err +} + +// KeepArtifacts prevents artifacts from being deleted when +// expiration is set. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#keep-artifacts +func (s *JobsService) KeepArtifacts(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/jobs/%d/artifacts/keep", url.QueryEscape(project), jobID) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + job := new(Job) + resp, err := s.client.Do(req, job) + if err != nil { + return nil, resp, err + } + + return job, resp, err +} + +// PlayJob triggers a manual action to start a job. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/jobs.html#play-a-job +func (s *JobsService) PlayJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/jobs/%d/play", url.QueryEscape(project), jobID) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + job := new(Job) + resp, err := s.client.Do(req, job) + if err != nil { + return nil, resp, err + } + + return job, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/labels.go b/vendor/github.com/xanzy/go-gitlab/labels.go new file mode 100644 index 00000000..2f8307d2 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/labels.go @@ -0,0 +1,228 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// LabelsService handles communication with the label related methods of the +// GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html +type LabelsService struct { + client *Client +} + +// Label represents a GitLab label. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html +type Label struct { + ID int `json:"id"` + Name string `json:"name"` + Color string `json:"color"` + Description string `json:"description"` + OpenIssuesCount int `json:"open_issues_count"` + ClosedIssuesCount int `json:"closed_issues_count"` + OpenMergeRequestsCount int `json:"open_merge_requests_count"` + Subscribed bool `json:"subscribed"` + Priority int `json:"priority"` +} + +func (l Label) String() string { + return Stringify(l) +} + +// ListLabelsOptions represents the available ListLabels() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels +type ListLabelsOptions ListOptions + +// ListLabels gets all labels for given project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#list-labels +func (s *LabelsService) ListLabels(pid interface{}, opt *ListLabelsOptions, options ...OptionFunc) ([]*Label, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var l []*Label + resp, err := s.client.Do(req, &l) + if err != nil { + return nil, resp, err + } + + return l, resp, err +} + +// CreateLabelOptions represents the available CreateLabel() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label +type CreateLabelOptions struct { + Name *string `url:"name,omitempty" json:"name,omitempty"` + Color *string `url:"color,omitempty" json:"color,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` +} + +// CreateLabel creates a new label for given repository with given name and +// color. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#create-a-new-label +func (s *LabelsService) CreateLabel(pid interface{}, opt *CreateLabelOptions, options ...OptionFunc) (*Label, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + l := new(Label) + resp, err := s.client.Do(req, l) + if err != nil { + return nil, resp, err + } + + return l, resp, err +} + +// DeleteLabelOptions represents the available DeleteLabel() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label +type DeleteLabelOptions struct { + Name *string `url:"name,omitempty" json:"name,omitempty"` +} + +// DeleteLabel deletes a label given by its name. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label +func (s *LabelsService) DeleteLabel(pid interface{}, opt *DeleteLabelOptions, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project)) + + req, err := s.client.NewRequest("DELETE", u, opt, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// UpdateLabelOptions represents the available UpdateLabel() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#delete-a-label +type UpdateLabelOptions struct { + Name *string `url:"name,omitempty" json:"name,omitempty"` + NewName *string `url:"new_name,omitempty" json:"new_name,omitempty"` + Color *string `url:"color,omitempty" json:"color,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` +} + +// UpdateLabel updates an existing label with new name or now color. At least +// one parameter is required, to update the label. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/labels.html#edit-an-existing-label +func (s *LabelsService) UpdateLabel(pid interface{}, opt *UpdateLabelOptions, options ...OptionFunc) (*Label, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/labels", url.QueryEscape(project)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + l := new(Label) + resp, err := s.client.Do(req, l) + if err != nil { + return nil, resp, err + } + + return l, resp, err +} + +// SubscribeToLabel subscribes the authenticated user to a label to receive +// notifications. If the user is already subscribed to the label, the status +// code 304 is returned. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/labels.html#subscribe-to-a-label +func (s *LabelsService) SubscribeToLabel(pid interface{}, labelID interface{}, options ...OptionFunc) (*Label, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + label, err := parseID(labelID) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/labels/%s/subscribe", url.QueryEscape(project), label) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + l := new(Label) + resp, err := s.client.Do(req, l) + if err != nil { + return nil, resp, err + } + + return l, resp, err +} + +// UnsubscribeFromLabel unsubscribes the authenticated user from a label to not +// receive notifications from it. If the user is not subscribed to the label, the +// status code 304 is returned. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/labels.html#unsubscribe-from-a-label +func (s *LabelsService) UnsubscribeFromLabel(pid interface{}, labelID interface{}, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + label, err := parseID(labelID) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/labels/%s/unsubscribe", url.QueryEscape(project), label) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/merge_request_approvals.go b/vendor/github.com/xanzy/go-gitlab/merge_request_approvals.go new file mode 100644 index 00000000..e03cb618 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/merge_request_approvals.go @@ -0,0 +1,125 @@ +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// MergeRequestApprovalsService handles communication with the merge request +// approvals related methods of the GitLab API. This includes reading/updating +// approval settings and approve/unapproving merge requests +// +// GitLab API docs: https://docs.gitlab.com/ee/api/merge_request_approvals.html +type MergeRequestApprovalsService struct { + client *Client +} + +// MergeRequestApprovals represents GitLab merge request approvals. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals +type MergeRequestApprovals struct { + ID int `json:"id"` + ProjectID int `json:"project_id"` + Title string `json:"title"` + Description string `json:"description"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + UpdatedAt *time.Time `json:"updated_at"` + MergeStatus string `json:"merge_status"` + ApprovalsRequired int `json:"approvals_required"` + ApprovalsLeft int `json:"approvals_left"` + ApprovedBy []struct { + User struct { + ID int `json:"id"` + Name string `json:"name"` + Username string `json:"username"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + } `json:"user"` + } `json:"approved_by"` + Approvers []struct { + User struct { + ID int `json:"id"` + Name string `json:"name"` + Username string `json:"username"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + } `json:"user"` + } `json:"approvers"` + ApproverGroups []struct { + Group struct { + ID int `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Description string `json:"description"` + Visibility string `json:"visibility"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + FullName string `json:"full_name"` + FullPath string `json:"full_path"` + LFSEnabled bool `json:"lfs_enabled"` + RequestAccessEnabled bool `json:"request_access_enabled"` + } `json:"group"` + } `json:"approver_group"` +} + +func (m MergeRequestApprovals) String() string { + return Stringify(m) +} + +// ApproveMergeRequestOptions represents the available ApproveMergeRequest() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/merge_request_approvals.html#approve-merge-request +type ApproveMergeRequestOptions struct { + Sha *string `url:"sha,omitempty" json:"sha,omitempty"` +} + +// ApproveMergeRequest approves a merge request on GitLab. If a non-empty sha +// is provided then it must match the sha at the HEAD of the MR. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/merge_request_approvals.html#approve-merge-request +func (s *MergeRequestApprovalsService) ApproveMergeRequest(pid interface{}, mr int, opt *ApproveMergeRequestOptions, options ...OptionFunc) (*MergeRequestApprovals, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/approve", url.QueryEscape(project), mr) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + m := new(MergeRequestApprovals) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// UnapproveMergeRequest unapproves a previously approved merge request on GitLab. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/merge_request_approvals.html#unapprove-merge-request +func (s *MergeRequestApprovalsService) UnapproveMergeRequest(pid interface{}, mr int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/unapprove", url.QueryEscape(project), mr) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/merge_requests.go b/vendor/github.com/xanzy/go-gitlab/merge_requests.go new file mode 100644 index 00000000..269ef0a1 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/merge_requests.go @@ -0,0 +1,743 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// MergeRequestsService handles communication with the merge requests related +// methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html +type MergeRequestsService struct { + client *Client + timeStats *timeStatsService +} + +// MergeRequest represents a GitLab merge request. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/merge_requests.html +type MergeRequest struct { + ID int `json:"id"` + IID int `json:"iid"` + TargetBranch string `json:"target_branch"` + SourceBranch string `json:"source_branch"` + ProjectID int `json:"project_id"` + Title string `json:"title"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + UpdatedAt *time.Time `json:"updated_at"` + Upvotes int `json:"upvotes"` + Downvotes int `json:"downvotes"` + Author struct { + ID int `json:"id"` + Username string `json:"username"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + } `json:"author"` + Assignee struct { + ID int `json:"id"` + Username string `json:"username"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + } `json:"assignee"` + SourceProjectID int `json:"source_project_id"` + TargetProjectID int `json:"target_project_id"` + Labels []string `json:"labels"` + Description string `json:"description"` + WorkInProgress bool `json:"work_in_progress"` + Milestone *Milestone `json:"milestone"` + MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` + MergeStatus string `json:"merge_status"` + MergedBy struct { + ID int `json:"id"` + Username string `json:"username"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + } `json:"merged_by"` + MergedAt *time.Time `json:"merged_at"` + ClosedBy struct { + ID int `json:"id"` + Username string `json:"username"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + } `json:"closed_by"` + ClosedAt *time.Time `json:"closed_at"` + Subscribed bool `json:"subscribed"` + SHA string `json:"sha"` + MergeCommitSHA string `json:"merge_commit_sha"` + UserNotesCount int `json:"user_notes_count"` + ChangesCount string `json:"changes_count"` + ShouldRemoveSourceBranch bool `json:"should_remove_source_branch"` + ForceRemoveSourceBranch bool `json:"force_remove_source_branch"` + WebURL string `json:"web_url"` + DiscussionLocked bool `json:"discussion_locked"` + Changes []struct { + OldPath string `json:"old_path"` + NewPath string `json:"new_path"` + AMode string `json:"a_mode"` + BMode string `json:"b_mode"` + Diff string `json:"diff"` + NewFile bool `json:"new_file"` + RenamedFile bool `json:"renamed_file"` + DeletedFile bool `json:"deleted_file"` + } `json:"changes"` + TimeStats *TimeStats `json:"time_stats"` + Squash bool `json:"squash"` + Pipeline struct { + ID int `json:"id"` + Ref string `json:"ref"` + SHA string `json:"sha"` + Status string `json:"status"` + } `json:"pipeline"` +} + +func (m MergeRequest) String() string { + return Stringify(m) +} + +// MergeRequestDiffVersion represents Gitlab merge request version. +// +// Gitlab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#get-a-single-mr-diff-version +type MergeRequestDiffVersion struct { + ID int `json:"id"` + HeadCommitSHA string `json:"head_commit_sha,omitempty"` + BaseCommitSHA string `json:"base_commit_sha,omitempty"` + StartCommitSHA string `json:"start_commit_sha,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + MergeRequestID int `json:"merge_request_id,omitempty"` + State string `json:"state,omitempty"` + RealSize string `json:"real_size,omitempty"` + Commits []*Commit `json:"commits,omitempty"` + Diffs []*Diff `json:"diffs,omitempty"` +} + +func (m MergeRequestDiffVersion) String() string { + return Stringify(m) +} + +// ListMergeRequestsOptions represents the available ListMergeRequests() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests +type ListMergeRequestsOptions struct { + ListOptions + State *string `url:"state,omitempty" json:"state,omitempty"` + OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` + Sort *string `url:"sort,omitempty" json:"sort,omitempty"` + Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` + View *string `url:"view,omitempty" json:"view,omitempty"` + Labels Labels `url:"labels,omitempty" json:"labels,omitempty"` + CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` + CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` +} + +// ListMergeRequests gets all merge requests. The state parameter can be used +// to get only merge requests with a given state (opened, closed, or merged) +// or all of them (all). The pagination parameters page and per_page can be +// used to restrict the list of merge requests. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests +func (s *MergeRequestsService) ListMergeRequests(opt *ListMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { + req, err := s.client.NewRequest("GET", "merge_requests", opt, options) + if err != nil { + return nil, nil, err + } + + var m []*MergeRequest + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// ListProjectMergeRequestsOptions represents the available ListMergeRequests() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#list-project-merge-requests +type ListProjectMergeRequestsOptions struct { + ListOptions + IIDs []int `url:"iids[],omitempty" json:"iids,omitempty"` + State *string `url:"state,omitempty" json:"state,omitempty"` + OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` + Sort *string `url:"sort,omitempty" json:"sort,omitempty"` + Milestone *string `url:"milestone,omitempty" json:"milestone,omitempty"` + View *string `url:"view,omitempty" json:"view,omitempty"` + Labels Labels `url:"labels,omitempty" json:"labels,omitempty"` + CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` + CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + MyReactionEmoji *string `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"` +} + +// ListProjectMergeRequests gets all merge requests for this project. The state +// parameter can be used to get only merge requests with a given state (opened, +// closed, or merged) or all of them (all). The pagination parameters page and +// per_page can be used to restrict the list of merge requests. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#list-merge-requests +func (s *MergeRequestsService) ListProjectMergeRequests(pid interface{}, opt *ListProjectMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var m []*MergeRequest + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// GetMergeRequest shows information about a single merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr +func (s *MergeRequestsService) GetMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + m := new(MergeRequest) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// GetMergeRequestApprovals gets information about a merge requests approvals +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals +func (s *MergeRequestsService) GetMergeRequestApprovals(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequestApprovals, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/approvals", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + a := new(MergeRequestApprovals) + resp, err := s.client.Do(req, a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// GetMergeRequestCommitsOptions represents the available GetMergeRequestCommits() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-commits +type GetMergeRequestCommitsOptions ListOptions + +// GetMergeRequestCommits gets a list of merge request commits. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-commits +func (s *MergeRequestsService) GetMergeRequestCommits(pid interface{}, mergeRequest int, opt *GetMergeRequestCommitsOptions, options ...OptionFunc) ([]*Commit, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/commits", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var c []*Commit + resp, err := s.client.Do(req, &c) + if err != nil { + return nil, resp, err + } + + return c, resp, err +} + +// GetMergeRequestChanges shows information about the merge request including +// its files and changes. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr-changes +func (s *MergeRequestsService) GetMergeRequestChanges(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/changes", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + m := new(MergeRequest) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// ListMergeRequestPipelines gets all pipelines for the provided merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#list-mr-pipelines +func (s *MergeRequestsService) ListMergeRequestPipelines(pid interface{}, mergeRequest int, options ...OptionFunc) (PipelineList, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%v/pipelines", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var p PipelineList + resp, err := s.client.Do(req, &p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// GetIssuesClosedOnMergeOptions represents the available GetIssuesClosedOnMerge() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#list-issues-that-will-close-on-merge +type GetIssuesClosedOnMergeOptions ListOptions + +// GetIssuesClosedOnMerge gets all the issues that would be closed by merging the +// provided merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#list-issues-that-will-close-on-merge +func (s *MergeRequestsService) GetIssuesClosedOnMerge(pid interface{}, mergeRequest int, opt *GetIssuesClosedOnMergeOptions, options ...OptionFunc) ([]*Issue, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("/projects/%s/merge_requests/%v/closes_issues", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var i []*Issue + resp, err := s.client.Do(req, &i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} + +// CreateMergeRequestOptions represents the available CreateMergeRequest() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr +type CreateMergeRequestOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + SourceBranch *string `url:"source_branch,omitempty" json:"source_branch,omitempty"` + TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + TargetProjectID *int `url:"target_project_id,omitempty" json:"target_project_id,omitempty"` +} + +// CreateMergeRequest creates a new merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#create-mr +func (s *MergeRequestsService) CreateMergeRequest(pid interface{}, opt *CreateMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + m := new(MergeRequest) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// UpdateMergeRequestOptions represents the available UpdateMergeRequest() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr +type UpdateMergeRequestOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + TargetBranch *string `url:"target_branch,omitempty" json:"target_branch,omitempty"` + AssigneeID *int `url:"assignee_id,omitempty" json:"assignee_id,omitempty"` + Labels Labels `url:"labels,comma,omitempty" json:"labels,omitempty"` + MilestoneID *int `url:"milestone_id,omitempty" json:"milestone_id,omitempty"` + StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` +} + +// UpdateMergeRequest updates an existing project milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#update-mr +func (s *MergeRequestsService) UpdateMergeRequest(pid interface{}, mergeRequest int, opt *UpdateMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + m := new(MergeRequest) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// DeleteMergeRequest deletes a merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#delete-a-merge-request +func (s *MergeRequestsService) DeleteMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// AcceptMergeRequestOptions represents the available AcceptMergeRequest() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr +type AcceptMergeRequestOptions struct { + MergeCommitMessage *string `url:"merge_commit_message,omitempty" json:"merge_commit_message,omitempty"` + ShouldRemoveSourceBranch *bool `url:"should_remove_source_branch,omitempty" json:"should_remove_source_branch,omitempty"` + MergeWhenPipelineSucceeds *bool `url:"merge_when_pipeline_succeeds,omitempty" json:"merge_when_pipeline_succeeds,omitempty"` + Sha *string `url:"sha,omitempty" json:"sha,omitempty"` +} + +// AcceptMergeRequest merges changes submitted with MR using this API. If merge +// success you get 200 OK. If it has some conflicts and can not be merged - you +// get 405 and error message 'Branch cannot be merged'. If merge request is +// already merged or closed - you get 405 and error message 'Method Not Allowed' +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#accept-mr +func (s *MergeRequestsService) AcceptMergeRequest(pid interface{}, mergeRequest int, opt *AcceptMergeRequestOptions, options ...OptionFunc) (*MergeRequest, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/merge", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + m := new(MergeRequest) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// CancelMergeWhenPipelineSucceeds cancels a merge when pipeline succeeds. If +// you don't have permissions to accept this merge request - you'll get a 401. +// If the merge request is already merged or closed - you get 405 and error +// message 'Method Not Allowed'. In case the merge request is not set to be +// merged when the pipeline succeeds, you'll also get a 406 error. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#cancel-merge-when-pipeline-succeeds +func (s *MergeRequestsService) CancelMergeWhenPipelineSucceeds(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/cancel_merge_when_pipeline_succeeds", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("PUT", u, nil, options) + if err != nil { + return nil, nil, err + } + + m := new(MergeRequest) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// GetMergeRequestDiffVersionsOptions represents the available +// GetMergeRequestDiffVersions() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#get-mr-diff-versions +type GetMergeRequestDiffVersionsOptions ListOptions + +// GetMergeRequestDiffVersions get a list of merge request diff versions. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#get-mr-diff-versions +func (s *MergeRequestsService) GetMergeRequestDiffVersions(pid interface{}, mergeRequest int, opt *GetMergeRequestDiffVersionsOptions, options ...OptionFunc) ([]*MergeRequestDiffVersion, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/versions", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var v []*MergeRequestDiffVersion + resp, err := s.client.Do(req, &v) + if err != nil { + return nil, resp, err + } + + return v, resp, err +} + +// GetSingleMergeRequestDiffVersion get a single MR diff version +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#get-a-single-mr-diff-version +func (s *MergeRequestsService) GetSingleMergeRequestDiffVersion(pid interface{}, mergeRequest, version int, options ...OptionFunc) (*MergeRequestDiffVersion, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/versions/%d", url.QueryEscape(project), mergeRequest, version) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var v = new(MergeRequestDiffVersion) + resp, err := s.client.Do(req, v) + if err != nil { + return nil, resp, err + } + + return v, resp, err +} + +// SubscribeToMergeRequest subscribes the authenticated user to the given merge request +// to receive notifications. If the user is already subscribed to the +// merge request, the status code 304 is returned. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#subscribe-to-a-merge-request +func (s *MergeRequestsService) SubscribeToMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/subscribe", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + m := new(MergeRequest) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// UnsubscribeFromMergeRequest unsubscribes the authenticated user from the given merge request +// to not receive notifications from that merge request. If the user is +// not subscribed to the merge request, status code 304 is returned. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#unsubscribe-from-a-merge-request +func (s *MergeRequestsService) UnsubscribeFromMergeRequest(pid interface{}, mergeRequest int, options ...OptionFunc) (*MergeRequest, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/unsubscribe", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + m := new(MergeRequest) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// CreateTodo manually creates a todo for the current user on a merge request. +// If there already exists a todo for the user on that merge request, +// status code 304 is returned. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#create-a-todo +func (s *MergeRequestsService) CreateTodo(pid interface{}, mergeRequest int, options ...OptionFunc) (*Todo, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/todo", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + t := new(Todo) + resp, err := s.client.Do(req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// SetTimeEstimate sets the time estimate for a single project merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#set-a-time-estimate-for-a-merge-request +func (s *MergeRequestsService) SetTimeEstimate(pid interface{}, mergeRequest int, opt *SetTimeEstimateOptions, options ...OptionFunc) (*TimeStats, *Response, error) { + return s.timeStats.setTimeEstimate(pid, "merge_requests", mergeRequest, opt, options...) +} + +// ResetTimeEstimate resets the time estimate for a single project merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#reset-the-time-estimate-for-a-merge-request +func (s *MergeRequestsService) ResetTimeEstimate(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) { + return s.timeStats.resetTimeEstimate(pid, "merge_requests", mergeRequest, options...) +} + +// AddSpentTime adds spent time for a single project merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#add-spent-time-for-a-merge-request +func (s *MergeRequestsService) AddSpentTime(pid interface{}, mergeRequest int, opt *AddSpentTimeOptions, options ...OptionFunc) (*TimeStats, *Response, error) { + return s.timeStats.addSpentTime(pid, "merge_requests", mergeRequest, opt, options...) +} + +// ResetSpentTime resets the spent time for a single project merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#reset-spent-time-for-a-merge-request +func (s *MergeRequestsService) ResetSpentTime(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) { + return s.timeStats.resetSpentTime(pid, "merge_requests", mergeRequest, options...) +} + +// GetTimeSpent gets the spent time for a single project merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/merge_requests.html#get-time-tracking-stats +func (s *MergeRequestsService) GetTimeSpent(pid interface{}, mergeRequest int, options ...OptionFunc) (*TimeStats, *Response, error) { + return s.timeStats.getTimeSpent(pid, "merge_requests", mergeRequest, options...) +} diff --git a/vendor/github.com/xanzy/go-gitlab/milestones.go b/vendor/github.com/xanzy/go-gitlab/milestones.go new file mode 100644 index 00000000..c1a69f93 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/milestones.go @@ -0,0 +1,267 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// MilestonesService handles communication with the milestone related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/milestones.html +type MilestonesService struct { + client *Client +} + +// Milestone represents a GitLab milestone. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/milestones.html +type Milestone struct { + ID int `json:"id"` + IID int `json:"iid"` + ProjectID int `json:"project_id"` + Title string `json:"title"` + Description string `json:"description"` + StartDate *ISOTime `json:"start_date"` + DueDate *ISOTime `json:"due_date"` + State string `json:"state"` + UpdatedAt *time.Time `json:"updated_at"` + CreatedAt *time.Time `json:"created_at"` +} + +func (m Milestone) String() string { + return Stringify(m) +} + +// ListMilestonesOptions represents the available ListMilestones() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#list-project-milestones +type ListMilestonesOptions struct { + ListOptions + IIDs []int `url:"iids,omitempty" json:"iids,omitempty"` + State string `url:"state,omitempty" json:"state,omitempty"` + Search string `url:"search,omitempty" json:"search,omitempty"` +} + +// ListMilestones returns a list of project milestones. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#list-project-milestones +func (s *MilestonesService) ListMilestones(pid interface{}, opt *ListMilestonesOptions, options ...OptionFunc) ([]*Milestone, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/milestones", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var m []*Milestone + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// GetMilestone gets a single project milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#get-single-milestone +func (s *MilestonesService) GetMilestone(pid interface{}, milestone int, options ...OptionFunc) (*Milestone, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/milestones/%d", url.QueryEscape(project), milestone) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + m := new(Milestone) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// CreateMilestoneOptions represents the available CreateMilestone() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#create-new-milestone +type CreateMilestoneOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` + DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` +} + +// CreateMilestone creates a new project milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#create-new-milestone +func (s *MilestonesService) CreateMilestone(pid interface{}, opt *CreateMilestoneOptions, options ...OptionFunc) (*Milestone, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/milestones", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + m := new(Milestone) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// UpdateMilestoneOptions represents the available UpdateMilestone() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#edit-milestone +type UpdateMilestoneOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + StartDate *ISOTime `url:"start_date,omitempty" json:"start_date,omitempty"` + DueDate *ISOTime `url:"due_date,omitempty" json:"due_date,omitempty"` + StateEvent *string `url:"state_event,omitempty" json:"state_event,omitempty"` +} + +// UpdateMilestone updates an existing project milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#edit-milestone +func (s *MilestonesService) UpdateMilestone(pid interface{}, milestone int, opt *UpdateMilestoneOptions, options ...OptionFunc) (*Milestone, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/milestones/%d", url.QueryEscape(project), milestone) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + m := new(Milestone) + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, err +} + +// DeleteMilestone deletes a specified project milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#delete-project-milestone +func (s *MilestonesService) DeleteMilestone(pid interface{}, milestone int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/milestones/%d", url.QueryEscape(project), milestone) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + return s.client.Do(req, nil) +} + +// GetMilestoneIssuesOptions represents the available GetMilestoneIssues() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#get-all-issues-assigned-to-a-single-milestone +type GetMilestoneIssuesOptions ListOptions + +// GetMilestoneIssues gets all issues assigned to a single project milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#get-all-issues-assigned-to-a-single-milestone +func (s *MilestonesService) GetMilestoneIssues(pid interface{}, milestone int, opt *GetMilestoneIssuesOptions, options ...OptionFunc) ([]*Issue, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/milestones/%d/issues", url.QueryEscape(project), milestone) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var i []*Issue + resp, err := s.client.Do(req, &i) + if err != nil { + return nil, resp, err + } + + return i, resp, err +} + +// GetMilestoneMergeRequestsOptions represents the available +// GetMilestoneMergeRequests() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#get-all-merge-requests-assigned-to-a-single-milestone +type GetMilestoneMergeRequestsOptions ListOptions + +// GetMilestoneMergeRequests gets all merge requests assigned to a single +// project milestone. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/milestones.html#get-all-merge-requests-assigned-to-a-single-milestone +func (s *MilestonesService) GetMilestoneMergeRequests(pid interface{}, milestone int, opt *GetMilestoneMergeRequestsOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/milestones/%d/merge_requests", url.QueryEscape(project), milestone) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var mr []*MergeRequest + resp, err := s.client.Do(req, &mr) + if err != nil { + return nil, resp, err + } + + return mr, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/namespaces.go b/vendor/github.com/xanzy/go-gitlab/namespaces.go new file mode 100644 index 00000000..9add6449 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/namespaces.go @@ -0,0 +1,122 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" +) + +// NamespacesService handles communication with the namespace related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html +type NamespacesService struct { + client *Client +} + +// Namespace represents a GitLab namespace. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html +type Namespace struct { + ID int `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Kind string `json:"kind"` + FullPath string `json:"full_path"` + ParentID int `json:"parent_id"` + MembersCountWithDescendants int `json:"members_count_with_descendants"` +} + +func (n Namespace) String() string { + return Stringify(n) +} + +// ListNamespacesOptions represents the available ListNamespaces() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces +type ListNamespacesOptions struct { + ListOptions + Search *string `url:"search,omitempty" json:"search,omitempty"` +} + +// ListNamespaces gets a list of projects accessible by the authenticated user. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/namespaces.html#list-namespaces +func (s *NamespacesService) ListNamespaces(opt *ListNamespacesOptions, options ...OptionFunc) ([]*Namespace, *Response, error) { + req, err := s.client.NewRequest("GET", "namespaces", opt, options) + if err != nil { + return nil, nil, err + } + + var n []*Namespace + resp, err := s.client.Do(req, &n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// SearchNamespace gets all namespaces that match your string in their name +// or path. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/namespaces.html#search-for-namespace +func (s *NamespacesService) SearchNamespace(query string, options ...OptionFunc) ([]*Namespace, *Response, error) { + var q struct { + Search string `url:"search,omitempty" json:"search,omitempty"` + } + q.Search = query + + req, err := s.client.NewRequest("GET", "namespaces", &q, options) + if err != nil { + return nil, nil, err + } + + var n []*Namespace + resp, err := s.client.Do(req, &n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// GetNamespace gets a namespace by id. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/namespaces.html#get-namespace-by-id +func (s *NamespacesService) GetNamespace(id interface{}, options ...OptionFunc) (*Namespace, *Response, error) { + namespace, err := parseID(id) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("namespaces/%s", namespace) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + n := new(Namespace) + resp, err := s.client.Do(req, n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/notes.go b/vendor/github.com/xanzy/go-gitlab/notes.go new file mode 100644 index 00000000..2ad7f9d4 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/notes.go @@ -0,0 +1,490 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// NotesService handles communication with the notes related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/notes.html +type NotesService struct { + client *Client +} + +// Note represents a GitLab note. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/notes.html +type Note struct { + ID int `json:"id"` + Body string `json:"body"` + Attachment string `json:"attachment"` + Title string `json:"title"` + FileName string `json:"file_name"` + Author struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + } `json:"author"` + System bool `json:"system"` + ExpiresAt *time.Time `json:"expires_at"` + UpdatedAt *time.Time `json:"updated_at"` + CreatedAt *time.Time `json:"created_at"` + NoteableID int `json:"noteable_id"` + NoteableType string `json:"noteable_type"` + NoteableIID int `json:"noteable_iid"` +} + +func (n Note) String() string { + return Stringify(n) +} + +// ListIssueNotesOptions represents the available ListIssueNotes() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes +type ListIssueNotesOptions ListOptions + +// ListIssueNotes gets a list of all notes for a single issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#list-project-issue-notes +func (s *NotesService) ListIssueNotes(pid interface{}, issue int, opt *ListIssueNotesOptions, options ...OptionFunc) ([]*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d/notes", url.QueryEscape(project), issue) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var n []*Note + resp, err := s.client.Do(req, &n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// GetIssueNote returns a single note for a specific project issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#get-single-issue-note +func (s *NotesService) GetIssueNote(pid interface{}, issue, note int, options ...OptionFunc) (*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", url.QueryEscape(project), issue, note) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + n := new(Note) + resp, err := s.client.Do(req, n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// CreateIssueNoteOptions represents the available CreateIssueNote() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#create-new-issue-note +type CreateIssueNoteOptions struct { + Body *string `url:"body,omitempty" json:"body,omitempty"` +} + +// CreateIssueNote creates a new note to a single project issue. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#create-new-issue-note +func (s *NotesService) CreateIssueNote(pid interface{}, issue int, opt *CreateIssueNoteOptions, options ...OptionFunc) (*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d/notes", url.QueryEscape(project), issue) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + n := new(Note) + resp, err := s.client.Do(req, n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// UpdateIssueNoteOptions represents the available UpdateIssueNote() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note +type UpdateIssueNoteOptions struct { + Body *string `url:"body,omitempty" json:"body,omitempty"` +} + +// UpdateIssueNote modifies existing note of an issue. +// +// https://docs.gitlab.com/ce/api/notes.html#modify-existing-issue-note +func (s *NotesService) UpdateIssueNote(pid interface{}, issue, note int, opt *UpdateIssueNoteOptions, options ...OptionFunc) (*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", url.QueryEscape(project), issue, note) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + n := new(Note) + resp, err := s.client.Do(req, n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// DeleteIssueNote deletes an existing note of an issue. +// +// https://docs.gitlab.com/ce/api/notes.html#delete-an-issue-note +func (s *NotesService) DeleteIssueNote(pid interface{}, issue, note int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/issues/%d/notes/%d", url.QueryEscape(project), issue, note) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// ListSnippetNotesOptions represents the available ListSnippetNotes() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#list-all-snippet-notes +type ListSnippetNotesOptions ListOptions + +// ListSnippetNotes gets a list of all notes for a single snippet. Snippet +// notes are comments users can post to a snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#list-all-snippet-notes +func (s *NotesService) ListSnippetNotes(pid interface{}, snippet int, opt *ListSnippetNotesOptions, options ...OptionFunc) ([]*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/snippets/%d/notes", url.QueryEscape(project), snippet) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var n []*Note + resp, err := s.client.Do(req, &n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// GetSnippetNote returns a single note for a given snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#get-single-snippet-note +func (s *NotesService) GetSnippetNote(pid interface{}, snippet, note int, options ...OptionFunc) (*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", url.QueryEscape(project), snippet, note) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + n := new(Note) + resp, err := s.client.Do(req, n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// CreateSnippetNoteOptions represents the available CreateSnippetNote() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#create-new-snippet-note +type CreateSnippetNoteOptions struct { + Body *string `url:"body,omitempty" json:"body,omitempty"` +} + +// CreateSnippetNote creates a new note for a single snippet. Snippet notes are +// comments users can post to a snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#create-new-snippet-note +func (s *NotesService) CreateSnippetNote(pid interface{}, snippet int, opt *CreateSnippetNoteOptions, options ...OptionFunc) (*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/snippets/%d/notes", url.QueryEscape(project), snippet) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + n := new(Note) + resp, err := s.client.Do(req, n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// UpdateSnippetNoteOptions represents the available UpdateSnippetNote() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note +type UpdateSnippetNoteOptions struct { + Body *string `url:"body,omitempty" json:"body,omitempty"` +} + +// UpdateSnippetNote modifies existing note of a snippet. +// +// https://docs.gitlab.com/ce/api/notes.html#modify-existing-snippet-note +func (s *NotesService) UpdateSnippetNote(pid interface{}, snippet, note int, opt *UpdateSnippetNoteOptions, options ...OptionFunc) (*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", url.QueryEscape(project), snippet, note) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + n := new(Note) + resp, err := s.client.Do(req, n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// DeleteSnippetNote deletes an existing note of a snippet. +// +// https://docs.gitlab.com/ce/api/notes.html#delete-a-snippet-note +func (s *NotesService) DeleteSnippetNote(pid interface{}, snippet, note int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/snippets/%d/notes/%d", url.QueryEscape(project), snippet, note) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// ListMergeRequestNotesOptions represents the available ListMergeRequestNotes() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#list-all-merge-request-notes +type ListMergeRequestNotesOptions ListOptions + +// ListMergeRequestNotes gets a list of all notes for a single merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#list-all-merge-request-notes +func (s *NotesService) ListMergeRequestNotes(pid interface{}, mergeRequest int, opt *ListMergeRequestNotesOptions, options ...OptionFunc) ([]*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/notes", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var n []*Note + resp, err := s.client.Do(req, &n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// GetMergeRequestNote returns a single note for a given merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#get-single-merge-request-note +func (s *NotesService) GetMergeRequestNote(pid interface{}, mergeRequest, note int, options ...OptionFunc) (*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/notes/%d", url.QueryEscape(project), mergeRequest, note) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + n := new(Note) + resp, err := s.client.Do(req, n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// CreateMergeRequestNoteOptions represents the available +// CreateMergeRequestNote() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#create-new-merge-request-note +type CreateMergeRequestNoteOptions struct { + Body *string `url:"body,omitempty" json:"body,omitempty"` +} + +// CreateMergeRequestNote creates a new note for a single merge request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#create-new-merge-request-note +func (s *NotesService) CreateMergeRequestNote(pid interface{}, mergeRequest int, opt *CreateMergeRequestNoteOptions, options ...OptionFunc) (*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/merge_requests/%d/notes", url.QueryEscape(project), mergeRequest) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + n := new(Note) + resp, err := s.client.Do(req, n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// UpdateMergeRequestNoteOptions represents the available +// UpdateMergeRequestNote() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note +type UpdateMergeRequestNoteOptions struct { + Body *string `url:"body,omitempty" json:"body,omitempty"` +} + +// UpdateMergeRequestNote modifies existing note of a merge request. +// +// https://docs.gitlab.com/ce/api/notes.html#modify-existing-merge-request-note +func (s *NotesService) UpdateMergeRequestNote(pid interface{}, mergeRequest, note int, opt *UpdateMergeRequestNoteOptions, options ...OptionFunc) (*Note, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf( + "projects/%s/merge_requests/%d/notes/%d", url.QueryEscape(project), mergeRequest, note) + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + n := new(Note) + resp, err := s.client.Do(req, n) + if err != nil { + return nil, resp, err + } + + return n, resp, err +} + +// DeleteMergeRequestNote deletes an existing note of a merge request. +// +// https://docs.gitlab.com/ce/api/notes.html#delete-a-merge-request-note +func (s *NotesService) DeleteMergeRequestNote(pid interface{}, mergeRequest, note int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf( + "projects/%s/merge_requests/%d/notes/%d", url.QueryEscape(project), mergeRequest, note) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/notifications.go b/vendor/github.com/xanzy/go-gitlab/notifications.go new file mode 100644 index 00000000..a5501dd7 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/notifications.go @@ -0,0 +1,214 @@ +package gitlab + +import ( + "errors" + "fmt" + "net/url" +) + +// NotificationSettingsService handles communication with the notification settings +// related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/notification_settings.html +type NotificationSettingsService struct { + client *Client +} + +// NotificationSettings represents the Gitlab notification setting. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notification_settings.html#notification-settings +type NotificationSettings struct { + Level NotificationLevelValue `json:"level"` + NotificationEmail string `json:"notification_email"` + Events *NotificationEvents `json:"events"` +} + +// NotificationEvents represents the available notification setting events. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notification_settings.html#notification-settings +type NotificationEvents struct { + CloseIssue bool `json:"close_issue"` + CloseMergeRequest bool `json:"close_merge_request"` + FailedPipeline bool `json:"failed_pipeline"` + MergeMergeRequest bool `json:"merge_merge_request"` + NewIssue bool `json:"new_issue"` + NewMergeRequest bool `json:"new_merge_request"` + NewNote bool `json:"new_note"` + ReassignIssue bool `json:"reassign_issue"` + ReassignMergeRequest bool `json:"reassign_merge_request"` + ReopenIssue bool `json:"reopen_issue"` + ReopenMergeRequest bool `json:"reopen_merge_request"` + SuccessPipeline bool `json:"success_pipeline"` +} + +func (ns NotificationSettings) String() string { + return Stringify(ns) +} + +// GetGlobalSettings returns current notification settings and email address. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notification_settings.html#global-notification-settings +func (s *NotificationSettingsService) GetGlobalSettings(options ...OptionFunc) (*NotificationSettings, *Response, error) { + u := "notification_settings" + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + ns := new(NotificationSettings) + resp, err := s.client.Do(req, ns) + if err != nil { + return nil, resp, err + } + + return ns, resp, err +} + +// NotificationSettingsOptions represents the available options that can be passed +// to the API when updating the notification settings. +type NotificationSettingsOptions struct { + Level *NotificationLevelValue `url:"level,omitempty" json:"level,omitempty"` + NotificationEmail *string `url:"notification_email,omitempty" json:"notification_email,omitempty"` + CloseIssue *bool `url:"close_issue,omitempty" json:"close_issue,omitempty"` + CloseMergeRequest *bool `url:"close_merge_request,omitempty" json:"close_merge_request,omitempty"` + FailedPipeline *bool `url:"failed_pipeline,omitempty" json:"failed_pipeline,omitempty"` + MergeMergeRequest *bool `url:"merge_merge_request,omitempty" json:"merge_merge_request,omitempty"` + NewIssue *bool `url:"new_issue,omitempty" json:"new_issue,omitempty"` + NewMergeRequest *bool `url:"new_merge_request,omitempty" json:"new_merge_request,omitempty"` + NewNote *bool `url:"new_note,omitempty" json:"new_note,omitempty"` + ReassignIssue *bool `url:"reassign_issue,omitempty" json:"reassign_issue,omitempty"` + ReassignMergeRequest *bool `url:"reassign_merge_request,omitempty" json:"reassign_merge_request,omitempty"` + ReopenIssue *bool `url:"reopen_issue,omitempty" json:"reopen_issue,omitempty"` + ReopenMergeRequest *bool `url:"reopen_merge_request,omitempty" json:"reopen_merge_request,omitempty"` + SuccessPipeline *bool `url:"success_pipeline,omitempty" json:"success_pipeline,omitempty"` +} + +// UpdateGlobalSettings updates current notification settings and email address. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notification_settings.html#update-global-notification-settings +func (s *NotificationSettingsService) UpdateGlobalSettings(opt *NotificationSettingsOptions, options ...OptionFunc) (*NotificationSettings, *Response, error) { + if opt.Level != nil && *opt.Level == GlobalNotificationLevel { + return nil, nil, errors.New( + "notification level 'global' is not valid for global notification settings") + } + + u := "notification_settings" + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + ns := new(NotificationSettings) + resp, err := s.client.Do(req, ns) + if err != nil { + return nil, resp, err + } + + return ns, resp, err +} + +// GetSettingsForGroup returns current group notification settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notification_settings.html#group-project-level-notification-settings +func (s *NotificationSettingsService) GetSettingsForGroup(gid interface{}, options ...OptionFunc) (*NotificationSettings, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/notification_settings", url.QueryEscape(group)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + ns := new(NotificationSettings) + resp, err := s.client.Do(req, ns) + if err != nil { + return nil, resp, err + } + + return ns, resp, err +} + +// GetSettingsForProject returns current project notification settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notification_settings.html#group-project-level-notification-settings +func (s *NotificationSettingsService) GetSettingsForProject(pid interface{}, options ...OptionFunc) (*NotificationSettings, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/notification_settings", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + ns := new(NotificationSettings) + resp, err := s.client.Do(req, ns) + if err != nil { + return nil, resp, err + } + + return ns, resp, err +} + +// UpdateSettingsForGroup updates current group notification settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notification_settings.html#update-group-project-level-notification-settings +func (s *NotificationSettingsService) UpdateSettingsForGroup(gid interface{}, opt *NotificationSettingsOptions, options ...OptionFunc) (*NotificationSettings, *Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("groups/%s/notification_settings", url.QueryEscape(group)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + ns := new(NotificationSettings) + resp, err := s.client.Do(req, ns) + if err != nil { + return nil, resp, err + } + + return ns, resp, err +} + +// UpdateSettingsForProject updates current project notification settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/notification_settings.html#update-group-project-level-notification-settings +func (s *NotificationSettingsService) UpdateSettingsForProject(pid interface{}, opt *NotificationSettingsOptions, options ...OptionFunc) (*NotificationSettings, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/notification_settings", url.QueryEscape(project)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + ns := new(NotificationSettings) + resp, err := s.client.Do(req, ns) + if err != nil { + return nil, resp, err + } + + return ns, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/pages_domains.go b/vendor/github.com/xanzy/go-gitlab/pages_domains.go new file mode 100644 index 00000000..3cd72e21 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/pages_domains.go @@ -0,0 +1,175 @@ +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// PagesDomainsService handles communication with the pages domains +// related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pages_domains.html +type PagesDomainsService struct { + client *Client +} + +// PagesDomain represents a pages domain. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pages_domains.html +type PagesDomain struct { + Domain string `json:"domain"` + URL string `json:"url"` + ProjectID int `json:"project_id"` + Verified bool `json:"verified"` + VerificationCode string `json:"verification_code"` + EnabledUntil *time.Time `json:"enabled_until"` + Certificate struct { + Expired bool `json:"expired"` + Expiration *time.Time `json:"expiration"` + } `json:"certificate"` +} + +// ListPagesDomainsOptions represents the available ListPagesDomains() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pages_domains.html#list-pages-domains +type ListPagesDomainsOptions ListOptions + +// ListPagesDomains gets a list of project pages domains. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pages_domains.html#list-pages-domains +func (s *PagesDomainsService) ListPagesDomains(pid interface{}, opt *ListPagesDomainsOptions, options ...OptionFunc) ([]*PagesDomain, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pages/domains", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var pd []*PagesDomain + resp, err := s.client.Do(req, &pd) + if err != nil { + return nil, resp, err + } + + return pd, resp, err +} + +// GetPagesDomain get a specific pages domain for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pages_domains.html#single-pages-domain +func (s *PagesDomainsService) GetPagesDomain(pid interface{}, domain string, options ...OptionFunc) (*PagesDomain, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pages/domains/%s", url.QueryEscape(project), domain) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + pd := new(PagesDomain) + resp, err := s.client.Do(req, pd) + if err != nil { + return nil, resp, err + } + + return pd, resp, err +} + +// CreatePagesDomainOptions represents the available CreatePagesDomain() options. +// +// GitLab API docs: +// // https://docs.gitlab.com/ce/api/pages_domains.html#create-new-pages-domain +type CreatePagesDomainOptions struct { + Domain *string `url:"domain,omitempty" json:"domain,omitempty"` + Certificate *string `url:"certifiate,omitempty" json:"certifiate,omitempty"` + Key *string `url:"key,omitempty" json:"key,omitempty"` +} + +// CreatePagesDomain creates a new project pages domain. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pages_domains.html#create-new-pages-domain +func (s *PagesDomainsService) CreatePagesDomain(pid interface{}, opt *CreatePagesDomainOptions, options ...OptionFunc) (*PagesDomain, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pages/domains", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + pd := new(PagesDomain) + resp, err := s.client.Do(req, pd) + if err != nil { + return nil, resp, err + } + + return pd, resp, err +} + +// UpdatePagesDomainOptions represents the available UpdatePagesDomain() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pages_domains.html#update-pages-domain +type UpdatePagesDomainOptions struct { + Cerificate *string `url:"certifiate" json:"certifiate"` + Key *string `url:"key" json:"key"` +} + +// UpdatePagesDomain updates an existing project pages domain. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pages_domains.html#update-pages-domain +func (s *PagesDomainsService) UpdatePagesDomain(pid interface{}, domain string, opt *UpdatePagesDomainOptions, options ...OptionFunc) (*PagesDomain, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pages/domains/%s", url.QueryEscape(project), domain) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + pd := new(PagesDomain) + resp, err := s.client.Do(req, pd) + if err != nil { + return nil, resp, err + } + + return pd, resp, err +} + +// DeletePagesDomain deletes an existing prject pages domain. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pages_domains.html#delete-pages-domain +func (s *PagesDomainsService) DeletePagesDomain(pid interface{}, domain string, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/pages/domains/%s", url.QueryEscape(project), domain) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go b/vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go new file mode 100644 index 00000000..bb935835 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/pipeline_schedules.go @@ -0,0 +1,341 @@ +// +// Copyright 2018, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// PipelineSchedulesService handles communication with the pipeline +// schedules related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pipeline_schedules.html +type PipelineSchedulesService struct { + client *Client +} + +// PipelineVariable represents a pipeline schedule variable. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#pipeline-schedule-variable +type PipelineVariable struct { + Key string `json:"key"` + Value string `json:"value"` +} + +// PipelineSchedule represents a pipeline schedule. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html +type PipelineSchedule struct { + ID int `json:"id"` + Description string `json:"description"` + Ref string `json:"ref"` + Cron string `json:"cron"` + CronTimezone string `json:"cron_timezone"` + NextRunAt *time.Time `json:"next_run_at"` + Active bool `json:"active"` + CreatedAt *time.Time `json:"created_at"` + UpdatedAt *time.Time `json:"updated_at"` + Owner *User `json:"owner"` + LastPipeline struct { + ID int `json:"id"` + Sha string `json:"sha"` + Ref string `json:"ref"` + Status string `json:"status"` + } `json:"last_pipeline"` + Variables []*PipelineVariable `json:"variables"` +} + +// ListPipelineSchedulesOptions represents the available ListPipelineTriggers() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers +type ListPipelineSchedulesOptions ListOptions + +// ListPipelineSchedules gets a list of project triggers. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html +func (s *PipelineSchedulesService) ListPipelineSchedules(pid interface{}, opt *ListPipelineSchedulesOptions, options ...OptionFunc) ([]*PipelineSchedule, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipeline_schedules", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var ps []*PipelineSchedule + resp, err := s.client.Do(req, &ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} + +// GetPipelineSchedule gets a pipeline schedule. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html +func (s *PipelineSchedulesService) GetPipelineSchedule(pid interface{}, schedule int, options ...OptionFunc) (*PipelineSchedule, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipeline_schedules/%d", url.QueryEscape(project), schedule) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(PipelineSchedule) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// CreatePipelineScheduleOptions represents the available +// CreatePipelineSchedule() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule +type CreatePipelineScheduleOptions struct { + Description *string `url:"description" json:"description"` + Ref *string `url:"ref" json:"ref"` + Cron *string `url:"cron" json:"cron"` + CronTimezone *string `url:"cron_timezone,omitempty" json:"cron_timezone,omitempty"` + Active *bool `url:"active,omitempty" json:"active,omitempty"` +} + +// CreatePipelineSchedule creates a pipeline schedule. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule +func (s *PipelineSchedulesService) CreatePipelineSchedule(pid interface{}, opt *CreatePipelineScheduleOptions, options ...OptionFunc) (*PipelineSchedule, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipeline_schedules", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + p := new(PipelineSchedule) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// EditPipelineScheduleOptions represents the available +// EditPipelineSchedule() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule +type EditPipelineScheduleOptions struct { + Description *string `url:"description,omitempty" json:"description,omitempty"` + Ref *string `url:"ref,omitempty" json:"ref,omitempty"` + Cron *string `url:"cron,omitempty" json:"cron,omitempty"` + CronTimezone *string `url:"cron_timezone,omitempty" json:"cron_timezone,omitempty"` + Active *bool `url:"active,omitempty" json:"active,omitempty"` +} + +// EditPipelineSchedule edits a pipeline schedule. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#edit-a-pipeline-schedule +func (s *PipelineSchedulesService) EditPipelineSchedule(pid interface{}, schedule int, opt *EditPipelineScheduleOptions, options ...OptionFunc) (*PipelineSchedule, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipeline_schedules/%d", url.QueryEscape(project), schedule) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + p := new(PipelineSchedule) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// TakeOwnershipOfPipelineSchedule sets the owner of the specified +// pipeline schedule to the user issuing the request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#take-ownership-of-a-pipeline-schedule +func (s *PipelineSchedulesService) TakeOwnershipOfPipelineSchedule(pid interface{}, schedule int, options ...OptionFunc) (*PipelineSchedule, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/take_ownership", url.QueryEscape(project), schedule) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(PipelineSchedule) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// DeletePipelineSchedule deletes a pipeline schedule. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#delete-a-pipeline-schedule +func (s *PipelineSchedulesService) DeletePipelineSchedule(pid interface{}, schedule int, options ...OptionFunc) (*PipelineSchedule, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipeline_schedules/%d", url.QueryEscape(project), schedule) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(PipelineSchedule) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// CreatePipelineScheduleVariableOptions represents the available +// CreatePipelineScheduleVariable() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule +type CreatePipelineScheduleVariableOptions struct { + Key *string `url:"key" json:"key"` + Value *string `url:"value" json:"value"` +} + +// CreatePipelineScheduleVariable creates a pipeline schedule variable. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#create-a-new-pipeline-schedule +func (s *PipelineSchedulesService) CreatePipelineScheduleVariable(pid interface{}, schedule int, opt *CreatePipelineScheduleVariableOptions, options ...OptionFunc) (*PipelineVariable, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/variables", url.QueryEscape(project), schedule) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + p := new(PipelineVariable) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// EditPipelineScheduleVariableOptions represents the available +// EditPipelineScheduleVariable() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#edit-a-pipeline-schedule-variable +type EditPipelineScheduleVariableOptions struct { + Value *string `url:"value" json:"value"` +} + +// EditPipelineScheduleVariable creates a pipeline schedule variable. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#edit-a-pipeline-schedule-variable +func (s *PipelineSchedulesService) EditPipelineScheduleVariable(pid interface{}, schedule int, key string, opt *EditPipelineScheduleVariableOptions, options ...OptionFunc) (*PipelineVariable, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/variables/%s", url.QueryEscape(project), schedule, key) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + p := new(PipelineVariable) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// DeletePipelineScheduleVariable creates a pipeline schedule variable. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_schedules.html#delete-a-pipeline-schedule-variable +func (s *PipelineSchedulesService) DeletePipelineScheduleVariable(pid interface{}, schedule int, key string, options ...OptionFunc) (*PipelineVariable, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipeline_schedules/%d/variables/%s", url.QueryEscape(project), schedule, key) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(PipelineVariable) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/pipeline_triggers.go b/vendor/github.com/xanzy/go-gitlab/pipeline_triggers.go new file mode 100644 index 00000000..6e8dfb8a --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/pipeline_triggers.go @@ -0,0 +1,232 @@ +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// PipelineTriggersService handles Project pipeline triggers. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html +type PipelineTriggersService struct { + client *Client +} + +// PipelineTrigger represents a project pipeline trigger. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#pipeline-triggers +type PipelineTrigger struct { + ID int `json:"id"` + Description string `json:"description"` + CreatedAt *time.Time `json:"created_at"` + DeletedAt *time.Time `json:"deleted_at"` + LastUsed *time.Time `json:"last_used"` + Token string `json:"token"` + UpdatedAt *time.Time `json:"updated_at"` + Owner *User `json:"owner"` +} + +// ListPipelineTriggersOptions represents the available ListPipelineTriggers() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers +type ListPipelineTriggersOptions ListOptions + +// ListPipelineTriggers gets a list of project triggers. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#list-project-triggers +func (s *PipelineTriggersService) ListPipelineTriggers(pid interface{}, opt *ListPipelineTriggersOptions, options ...OptionFunc) ([]*PipelineTrigger, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/triggers", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var pt []*PipelineTrigger + resp, err := s.client.Do(req, &pt) + if err != nil { + return nil, resp, err + } + + return pt, resp, err +} + +// GetPipelineTrigger gets a specific pipeline trigger for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#get-trigger-details +func (s *PipelineTriggersService) GetPipelineTrigger(pid interface{}, trigger int, options ...OptionFunc) (*PipelineTrigger, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/triggers/%d", url.QueryEscape(project), trigger) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + pt := new(PipelineTrigger) + resp, err := s.client.Do(req, pt) + if err != nil { + return nil, resp, err + } + + return pt, resp, err +} + +// AddPipelineTriggerOptions represents the available AddPipelineTrigger() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#create-a-project-trigger +type AddPipelineTriggerOptions struct { + Description *string `url:"description,omitempty" json:"description,omitempty"` +} + +// AddPipelineTrigger adds a pipeline trigger to a specified project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#create-a-project-trigger +func (s *PipelineTriggersService) AddPipelineTrigger(pid interface{}, opt *AddPipelineTriggerOptions, options ...OptionFunc) (*PipelineTrigger, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/triggers", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + pt := new(PipelineTrigger) + resp, err := s.client.Do(req, pt) + if err != nil { + return nil, resp, err + } + + return pt, resp, err +} + +// EditPipelineTriggerOptions represents the available EditPipelineTrigger() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#update-a-project-trigger +type EditPipelineTriggerOptions struct { + Description *string `url:"description,omitempty" json:"description,omitempty"` +} + +// EditPipelineTrigger edits a trigger for a specified project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#update-a-project-trigger +func (s *PipelineTriggersService) EditPipelineTrigger(pid interface{}, trigger int, opt *EditPipelineTriggerOptions, options ...OptionFunc) (*PipelineTrigger, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/triggers/%d", url.QueryEscape(project), trigger) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + pt := new(PipelineTrigger) + resp, err := s.client.Do(req, pt) + if err != nil { + return nil, resp, err + } + + return pt, resp, err +} + +// TakeOwnershipOfPipelineTrigger sets the owner of the specified +// pipeline trigger to the user issuing the request. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#take-ownership-of-a-project-trigger +func (s *PipelineTriggersService) TakeOwnershipOfPipelineTrigger(pid interface{}, trigger int, options ...OptionFunc) (*PipelineTrigger, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/triggers/%d/take_ownership", url.QueryEscape(project), trigger) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + pt := new(PipelineTrigger) + resp, err := s.client.Do(req, pt) + if err != nil { + return nil, resp, err + } + + return pt, resp, err +} + +// DeletePipelineTrigger removes a trigger from a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipeline_triggers.html#remove-a-project-trigger +func (s *PipelineTriggersService) DeletePipelineTrigger(pid interface{}, trigger int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/triggers/%d", url.QueryEscape(project), trigger) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// RunPipelineTriggerOptions represents the available RunPipelineTrigger() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/ci/triggers/README.html#triggering-a-pipeline +type RunPipelineTriggerOptions struct { + Ref *string `url:"ref" json:"ref"` + Token *string `url:"token" json:"token"` + Variables map[string]string `url:"variables,omitempty" json:"variables,omitempty"` +} + +// RunPipelineTrigger starts a trigger from a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/ci/triggers/README.html#triggering-a-pipeline +func (s *PipelineTriggersService) RunPipelineTrigger(pid interface{}, opt *RunPipelineTriggerOptions, options ...OptionFunc) (*Pipeline, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/trigger/pipeline", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + pt := new(Pipeline) + resp, err := s.client.Do(req, pt) + if err != nil { + return nil, resp, err + } + + return pt, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/pipelines.go b/vendor/github.com/xanzy/go-gitlab/pipelines.go new file mode 100644 index 00000000..0c736dd2 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/pipelines.go @@ -0,0 +1,220 @@ +// +// Copyright 2017, Igor Varavko +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// PipelinesService handles communication with the repositories related +// methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html +type PipelinesService struct { + client *Client +} + +// Pipeline represents a GitLab pipeline. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html +type Pipeline struct { + ID int `json:"id"` + Status string `json:"status"` + Ref string `json:"ref"` + Sha string `json:"sha"` + BeforeSha string `json:"before_sha"` + Tag bool `json:"tag"` + YamlErrors string `json:"yaml_errors"` + User struct { + Name string `json:"name"` + Username string `json:"username"` + ID int `json:"id"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + } + UpdatedAt *time.Time `json:"updated_at"` + CreatedAt *time.Time `json:"created_at"` + StartedAt *time.Time `json:"started_at"` + FinishedAt *time.Time `json:"finished_at"` + CommittedAt *time.Time `json:"committed_at"` + Duration int `json:"duration"` + Coverage string `json:"coverage"` +} + +func (i Pipeline) String() string { + return Stringify(i) +} + +// PipelineList represents a GitLab list project pipelines +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#list-project-pipelines +type PipelineList []struct { + ID int `json:"id"` + Status string `json:"status"` + Ref string `json:"ref"` + Sha string `json:"sha"` +} + +func (i PipelineList) String() string { + return Stringify(i) +} + +// ListProjectPipelinesOptions represents the available ListProjectPipelines() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#list-project-pipelines +type ListProjectPipelinesOptions struct { + ListOptions + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` + Status *BuildStateValue `url:"status,omitempty" json:"status,omitempty"` + Ref *string `url:"ref,omitempty" json:"ref,omitempty"` + YamlErrors *bool `url:"yaml_errors,omitempty" json:"yaml_errors,omitempty"` + Name *string `url:"name,omitempty" json:"name,omitempty"` + Username *string `url:"username,omitempty" json:"username,omitempty"` + OrderBy *OrderByValue `url:"order_by,omitempty" json:"order_by,omitempty"` + Sort *string `url:"sort,omitempty" json:"sort,omitempty"` +} + +// ListProjectPipelines gets a list of project piplines. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#list-project-pipelines +func (s *PipelinesService) ListProjectPipelines(pid interface{}, opt *ListProjectPipelinesOptions, options ...OptionFunc) (PipelineList, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipelines", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var p PipelineList + resp, err := s.client.Do(req, &p) + if err != nil { + return nil, resp, err + } + return p, resp, err +} + +// GetPipeline gets a single project pipeline. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#get-a-single-pipeline +func (s *PipelinesService) GetPipeline(pid interface{}, pipeline int, options ...OptionFunc) (*Pipeline, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipelines/%d", url.QueryEscape(project), pipeline) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(Pipeline) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// CreatePipelineOptions represents the available CreatePipeline() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#create-a-new-pipeline +type CreatePipelineOptions struct { + Ref *string `url:"ref,omitempty" json:"ref"` +} + +// CreatePipeline creates a new project pipeline. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/pipelines.html#create-a-new-pipeline +func (s *PipelinesService) CreatePipeline(pid interface{}, opt *CreatePipelineOptions, options ...OptionFunc) (*Pipeline, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipeline", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + p := new(Pipeline) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// RetryPipelineBuild retries failed builds in a pipeline +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/pipelines.html#retry-failed-builds-in-a-pipeline +func (s *PipelinesService) RetryPipelineBuild(pid interface{}, pipelineID int, options ...OptionFunc) (*Pipeline, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipelines/%d/retry", project, pipelineID) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(Pipeline) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// CancelPipelineBuild cancels a pipeline builds +// +// GitLab API docs: +//https://docs.gitlab.com/ce/api/pipelines.html#cancel-a-pipelines-builds +func (s *PipelinesService) CancelPipelineBuild(pid interface{}, pipelineID int, options ...OptionFunc) (*Pipeline, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/pipelines/%d/cancel", project, pipelineID) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(Pipeline) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/project_members.go b/vendor/github.com/xanzy/go-gitlab/project_members.go new file mode 100644 index 00000000..70beb72d --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/project_members.go @@ -0,0 +1,179 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// ProjectMembersService handles communication with the project members +// related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/members.html +type ProjectMembersService struct { + client *Client +} + +// ListProjectMembersOptions represents the available ListProjectMembers() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project +type ListProjectMembersOptions struct { + ListOptions + Query *string `url:"query,omitempty" json:"query,omitempty"` +} + +// ListProjectMembers gets a list of a project's team members. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#list-all-members-of-a-group-or-project +func (s *ProjectMembersService) ListProjectMembers(pid interface{}, opt *ListProjectMembersOptions, options ...OptionFunc) ([]*ProjectMember, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/members", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var pm []*ProjectMember + resp, err := s.client.Do(req, &pm) + if err != nil { + return nil, resp, err + } + + return pm, resp, err +} + +// GetProjectMember gets a project team member. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#get-a-member-of-a-group-or-project +func (s *ProjectMembersService) GetProjectMember(pid interface{}, user int, options ...OptionFunc) (*ProjectMember, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/members/%d", url.QueryEscape(project), user) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + pm := new(ProjectMember) + resp, err := s.client.Do(req, pm) + if err != nil { + return nil, resp, err + } + + return pm, resp, err +} + +// AddProjectMemberOptions represents the available AddProjectMember() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project +type AddProjectMemberOptions struct { + UserID *int `url:"user_id,omitempty" json:"user_id,omitempty"` + AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` +} + +// AddProjectMember adds a user to a project team. This is an idempotent +// method and can be called multiple times with the same parameters. Adding +// team membership to a user that is already a member does not affect the +// existing membership. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#add-a-member-to-a-group-or-project +func (s *ProjectMembersService) AddProjectMember(pid interface{}, opt *AddProjectMemberOptions, options ...OptionFunc) (*ProjectMember, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/members", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + pm := new(ProjectMember) + resp, err := s.client.Do(req, pm) + if err != nil { + return nil, resp, err + } + + return pm, resp, err +} + +// EditProjectMemberOptions represents the available EditProjectMember() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project +type EditProjectMemberOptions struct { + AccessLevel *AccessLevelValue `url:"access_level,omitempty" json:"access_level,omitempty"` +} + +// EditProjectMember updates a project team member to a specified access level.. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#edit-a-member-of-a-group-or-project +func (s *ProjectMembersService) EditProjectMember(pid interface{}, user int, opt *EditProjectMemberOptions, options ...OptionFunc) (*ProjectMember, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/members/%d", url.QueryEscape(project), user) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + pm := new(ProjectMember) + resp, err := s.client.Do(req, pm) + if err != nil { + return nil, resp, err + } + + return pm, resp, err +} + +// DeleteProjectMember removes a user from a project team. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/members.html#remove-a-member-from-a-group-or-project +func (s *ProjectMembersService) DeleteProjectMember(pid interface{}, user int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/members/%d", url.QueryEscape(project), user) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/project_snippets.go b/vendor/github.com/xanzy/go-gitlab/project_snippets.go new file mode 100644 index 00000000..00428196 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/project_snippets.go @@ -0,0 +1,207 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "bytes" + "fmt" + "net/url" +) + +// ProjectSnippetsService handles communication with the project snippets +// related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html +type ProjectSnippetsService struct { + client *Client +} + +// ListProjectSnippetsOptions represents the available ListSnippets() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html#list-snippets +type ListProjectSnippetsOptions ListOptions + +// ListSnippets gets a list of project snippets. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/project_snippets.html#list-snippets +func (s *ProjectSnippetsService) ListSnippets(pid interface{}, opt *ListProjectSnippetsOptions, options ...OptionFunc) ([]*Snippet, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/snippets", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var ps []*Snippet + resp, err := s.client.Do(req, &ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} + +// GetSnippet gets a single project snippet +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/project_snippets.html#single-snippet +func (s *ProjectSnippetsService) GetSnippet(pid interface{}, snippet int, options ...OptionFunc) (*Snippet, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/snippets/%d", url.QueryEscape(project), snippet) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + ps := new(Snippet) + resp, err := s.client.Do(req, ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} + +// CreateProjectSnippetOptions represents the available CreateSnippet() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/project_snippets.html#create-new-snippet +type CreateProjectSnippetOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + Code *string `url:"code,omitempty" json:"code,omitempty"` + Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` +} + +// CreateSnippet creates a new project snippet. The user must have permission +// to create new snippets. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/project_snippets.html#create-new-snippet +func (s *ProjectSnippetsService) CreateSnippet(pid interface{}, opt *CreateProjectSnippetOptions, options ...OptionFunc) (*Snippet, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/snippets", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + ps := new(Snippet) + resp, err := s.client.Do(req, ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} + +// UpdateProjectSnippetOptions represents the available UpdateSnippet() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/project_snippets.html#update-snippet +type UpdateProjectSnippetOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + Code *string `url:"code,omitempty" json:"code,omitempty"` + Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` +} + +// UpdateSnippet updates an existing project snippet. The user must have +// permission to change an existing snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/project_snippets.html#update-snippet +func (s *ProjectSnippetsService) UpdateSnippet(pid interface{}, snippet int, opt *UpdateProjectSnippetOptions, options ...OptionFunc) (*Snippet, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/snippets/%d", url.QueryEscape(project), snippet) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + ps := new(Snippet) + resp, err := s.client.Do(req, ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} + +// DeleteSnippet deletes an existing project snippet. This is an idempotent +// function and deleting a non-existent snippet still returns a 200 OK status +// code. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/project_snippets.html#delete-snippet +func (s *ProjectSnippetsService) DeleteSnippet(pid interface{}, snippet int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/snippets/%d", url.QueryEscape(project), snippet) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// SnippetContent returns the raw project snippet as plain text. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/project_snippets.html#snippet-content +func (s *ProjectSnippetsService) SnippetContent(pid interface{}, snippet int, options ...OptionFunc) ([]byte, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/snippets/%d/raw", url.QueryEscape(project), snippet) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var b bytes.Buffer + resp, err := s.client.Do(req, &b) + if err != nil { + return nil, resp, err + } + + return b.Bytes(), resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/projects.go b/vendor/github.com/xanzy/go-gitlab/projects.go new file mode 100644 index 00000000..4a252a99 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/projects.go @@ -0,0 +1,997 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "mime/multipart" + "net/url" + "os" + "time" +) + +// ProjectsService handles communication with the repositories related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html +type ProjectsService struct { + client *Client +} + +// Project represents a GitLab project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html +type Project struct { + ID int `json:"id"` + Description string `json:"description"` + DefaultBranch string `json:"default_branch"` + Public bool `json:"public"` + Visibility VisibilityValue `json:"visibility"` + SSHURLToRepo string `json:"ssh_url_to_repo"` + HTTPURLToRepo string `json:"http_url_to_repo"` + WebURL string `json:"web_url"` + TagList []string `json:"tag_list"` + Owner *User `json:"owner"` + Name string `json:"name"` + NameWithNamespace string `json:"name_with_namespace"` + Path string `json:"path"` + PathWithNamespace string `json:"path_with_namespace"` + IssuesEnabled bool `json:"issues_enabled"` + OpenIssuesCount int `json:"open_issues_count"` + MergeRequestsEnabled bool `json:"merge_requests_enabled"` + ApprovalsBeforeMerge int `json:"approvals_before_merge"` + JobsEnabled bool `json:"jobs_enabled"` + WikiEnabled bool `json:"wiki_enabled"` + SnippetsEnabled bool `json:"snippets_enabled"` + ContainerRegistryEnabled bool `json:"container_registry_enabled"` + CreatedAt *time.Time `json:"created_at,omitempty"` + LastActivityAt *time.Time `json:"last_activity_at,omitempty"` + CreatorID int `json:"creator_id"` + Namespace *ProjectNamespace `json:"namespace"` + ImportStatus string `json:"import_status"` + ImportError string `json:"import_error"` + Permissions *Permissions `json:"permissions"` + Archived bool `json:"archived"` + AvatarURL string `json:"avatar_url"` + SharedRunnersEnabled bool `json:"shared_runners_enabled"` + ForksCount int `json:"forks_count"` + StarCount int `json:"star_count"` + RunnersToken string `json:"runners_token"` + PublicJobs bool `json:"public_jobs"` + OnlyAllowMergeIfPipelineSucceeds bool `json:"only_allow_merge_if_pipeline_succeeds"` + OnlyAllowMergeIfAllDiscussionsAreResolved bool `json:"only_allow_merge_if_all_discussions_are_resolved"` + LFSEnabled bool `json:"lfs_enabled"` + RequestAccessEnabled bool `json:"request_access_enabled"` + MergeMethod string `json:"merge_method"` + ForkedFromProject *ForkParent `json:"forked_from_project"` + SharedWithGroups []struct { + GroupID int `json:"group_id"` + GroupName string `json:"group_name"` + GroupAccessLevel int `json:"group_access_level"` + } `json:"shared_with_groups"` + Statistics *ProjectStatistics `json:"statistics"` + Links *Links `json:"_links,omitempty"` + CIConfigPath *string `json:"ci_config_path"` +} + +// Repository represents a repository. +type Repository struct { + Name string `json:"name"` + Description string `json:"description"` + WebURL string `json:"web_url"` + AvatarURL string `json:"avatar_url"` + GitSSHURL string `json:"git_ssh_url"` + GitHTTPURL string `json:"git_http_url"` + Namespace string `json:"namespace"` + Visibility VisibilityValue `json:"visibility"` + PathWithNamespace string `json:"path_with_namespace"` + DefaultBranch string `json:"default_branch"` + Homepage string `json:"homepage"` + URL string `json:"url"` + SSHURL string `json:"ssh_url"` + HTTPURL string `json:"http_url"` +} + +// ProjectNamespace represents a project namespace. +type ProjectNamespace struct { + ID int `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Kind string `json:"kind"` + FullPath string `json:"full_path"` +} + +// StorageStatistics represents a statistics record for a group or project. +type StorageStatistics struct { + StorageSize int64 `json:"storage_size"` + RepositorySize int64 `json:"repository_size"` + LfsObjectsSize int64 `json:"lfs_objects_size"` + JobArtifactsSize int64 `json:"job_artifacts_size"` +} + +// ProjectStatistics represents a statistics record for a project. +type ProjectStatistics struct { + StorageStatistics + CommitCount int `json:"commit_count"` +} + +// Permissions represents permissions. +type Permissions struct { + ProjectAccess *ProjectAccess `json:"project_access"` + GroupAccess *GroupAccess `json:"group_access"` +} + +// ProjectAccess represents project access. +type ProjectAccess struct { + AccessLevel AccessLevelValue `json:"access_level"` + NotificationLevel NotificationLevelValue `json:"notification_level"` +} + +// GroupAccess represents group access. +type GroupAccess struct { + AccessLevel AccessLevelValue `json:"access_level"` + NotificationLevel NotificationLevelValue `json:"notification_level"` +} + +// ForkParent represents the parent project when this is a fork. +type ForkParent struct { + HTTPURLToRepo string `json:"http_url_to_repo"` + ID int `json:"id"` + Name string `json:"name"` + NameWithNamespace string `json:"name_with_namespace"` + Path string `json:"path"` + PathWithNamespace string `json:"path_with_namespace"` + WebURL string `json:"web_url"` +} + +// Links represents a project web links for self, issues, merge_requests, +// repo_branches, labels, events, members. +type Links struct { + Self string `json:"self"` + Issues string `json:"issues"` + MergeRequests string `json:"merge_requests"` + RepoBranches string `json:"repo_branches"` + Labels string `json:"labels"` + Events string `json:"events"` + Members string `json:"members"` +} + +func (s Project) String() string { + return Stringify(s) +} + +// ListProjectsOptions represents the available ListProjects() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects +type ListProjectsOptions struct { + ListOptions + Archived *bool `url:"archived,omitempty" json:"archived,omitempty"` + OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` + Sort *string `url:"sort,omitempty" json:"sort,omitempty"` + Search *string `url:"search,omitempty" json:"search,omitempty"` + Simple *bool `url:"simple,omitempty" json:"simple,omitempty"` + Owned *bool `url:"owned,omitempty" json:"owned,omitempty"` + Membership *bool `url:"membership,omitempty" json:"membership,omitempty"` + Starred *bool `url:"starred,omitempty" json:"starred,omitempty"` + Statistics *bool `url:"statistics,omitempty" json:"statistics,omitempty"` + Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` + WithIssuesEnabled *bool `url:"with_issues_enabled,omitempty" json:"with_issues_enabled,omitempty"` + WithMergeRequestsEnabled *bool `url:"with_merge_requests_enabled,omitempty" json:"with_merge_requests_enabled,omitempty"` +} + +// ListProjects gets a list of projects accessible by the authenticated user. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-projects +func (s *ProjectsService) ListProjects(opt *ListProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) { + req, err := s.client.NewRequest("GET", "projects", opt, options) + if err != nil { + return nil, nil, err + } + + var p []*Project + resp, err := s.client.Do(req, &p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// ListUserProjects gets a list of projects for the given user. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#list-user-projects +func (s *ProjectsService) ListUserProjects(uid interface{}, opt *ListProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) { + user, err := parseID(uid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("users/%s/projects", user) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var p []*Project + resp, err := s.client.Do(req, &p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// ProjectUser represents a GitLab project user. +type ProjectUser struct { + ID int `json:"id"` + Name string `json:"name"` + Username string `json:"username"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` +} + +// ListProjectUserOptions represents the available ListProjectsUsers() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#get-project-users +type ListProjectUserOptions struct { + ListOptions + Search *string `url:"search,omitempty" json:"search,omitempty"` +} + +// ListProjectsUsers gets a list of users for the given project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#get-project-users +func (s *ProjectsService) ListProjectsUsers(pid interface{}, opt *ListProjectUserOptions, options ...OptionFunc) ([]*ProjectUser, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/users", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var p []*ProjectUser + resp, err := s.client.Do(req, &p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// GetProject gets a specific project, identified by project ID or +// NAMESPACE/PROJECT_NAME, which is owned by the authenticated user. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#get-single-project +func (s *ProjectsService) GetProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(Project) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// ProjectEvent represents a GitLab project event. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#get-project-events +type ProjectEvent struct { + Title interface{} `json:"title"` + ProjectID int `json:"project_id"` + ActionName string `json:"action_name"` + TargetID interface{} `json:"target_id"` + TargetType interface{} `json:"target_type"` + AuthorID int `json:"author_id"` + AuthorUsername string `json:"author_username"` + Data struct { + Before string `json:"before"` + After string `json:"after"` + Ref string `json:"ref"` + UserID int `json:"user_id"` + UserName string `json:"user_name"` + Repository *Repository `json:"repository"` + Commits []*Commit `json:"commits"` + TotalCommitsCount int `json:"total_commits_count"` + } `json:"data"` + TargetTitle interface{} `json:"target_title"` +} + +func (s ProjectEvent) String() string { + return Stringify(s) +} + +// GetProjectEventsOptions represents the available GetProjectEvents() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#get-project-events +type GetProjectEventsOptions ListOptions + +// GetProjectEvents gets the events for the specified project. Sorted from +// newest to latest. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#get-project-events +func (s *ProjectsService) GetProjectEvents(pid interface{}, opt *GetProjectEventsOptions, options ...OptionFunc) ([]*ProjectEvent, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/events", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var p []*ProjectEvent + resp, err := s.client.Do(req, &p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// CreateProjectOptions represents the available CreateProjects() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#create-project +type CreateProjectOptions struct { + Name *string `url:"name,omitempty" json:"name,omitempty"` + Path *string `url:"path,omitempty" json:"path,omitempty"` + DefaultBranch *string `url:"default_branch,omitempty" json:"default_branch,omitempty"` + NamespaceID *int `url:"namespace_id,omitempty" json:"namespace_id,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + IssuesEnabled *bool `url:"issues_enabled,omitempty" json:"issues_enabled,omitempty"` + MergeRequestsEnabled *bool `url:"merge_requests_enabled,omitempty" json:"merge_requests_enabled,omitempty"` + JobsEnabled *bool `url:"jobs_enabled,omitempty" json:"jobs_enabled,omitempty"` + WikiEnabled *bool `url:"wiki_enabled,omitempty" json:"wiki_enabled,omitempty"` + SnippetsEnabled *bool `url:"snippets_enabled,omitempty" json:"snippets_enabled,omitempty"` + ResolveOutdatedDiffDiscussions *bool `url:"resolve_outdated_diff_discussions,omitempty" json:"resolve_outdated_diff_discussions,omitempty"` + ContainerRegistryEnabled *bool `url:"container_registry_enabled,omitempty" json:"container_registry_enabled,omitempty"` + SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` + Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` + ImportURL *string `url:"import_url,omitempty" json:"import_url,omitempty"` + PublicJobs *bool `url:"public_jobs,omitempty" json:"public_jobs,omitempty"` + OnlyAllowMergeIfPipelineSucceeds *bool `url:"only_allow_merge_if_pipeline_succeeds,omitempty" json:"only_allow_merge_if_pipeline_succeeds,omitempty"` + OnlyAllowMergeIfAllDiscussionsAreResolved *bool `url:"only_allow_merge_if_all_discussions_are_resolved,omitempty" json:"only_allow_merge_if_all_discussions_are_resolved,omitempty"` + MergeMethod *MergeMethodValue `url:"merge_method,omitempty" json:"merge_method,omitempty"` + LFSEnabled *bool `url:"lfs_enabled,omitempty" json:"lfs_enabled,omitempty"` + RequestAccessEnabled *bool `url:"request_access_enabled,omitempty" json:"request_access_enabled,omitempty"` + TagList *[]string `url:"tag_list,omitempty" json:"tag_list,omitempty"` + PrintingMergeRequestLinkEnabled *bool `url:"printing_merge_request_link_enabled,omitempty" json:"printing_merge_request_link_enabled,omitempty"` + CIConfigPath *string `url:"ci_config_path,omitempty" json:"ci_config_path,omitempty"` +} + +// CreateProject creates a new project owned by the authenticated user. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#create-project +func (s *ProjectsService) CreateProject(opt *CreateProjectOptions, options ...OptionFunc) (*Project, *Response, error) { + req, err := s.client.NewRequest("POST", "projects", opt, options) + if err != nil { + return nil, nil, err + } + + p := new(Project) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// CreateProjectForUserOptions represents the available CreateProjectForUser() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#create-project-for-user +type CreateProjectForUserOptions CreateProjectOptions + +// CreateProjectForUser creates a new project owned by the specified user. +// Available only for admins. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#create-project-for-user +func (s *ProjectsService) CreateProjectForUser(user int, opt *CreateProjectForUserOptions, options ...OptionFunc) (*Project, *Response, error) { + u := fmt.Sprintf("projects/user/%d", user) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + p := new(Project) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// EditProjectOptions represents the available EditProject() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project +type EditProjectOptions CreateProjectOptions + +// EditProject updates an existing project. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#edit-project +func (s *ProjectsService) EditProject(pid interface{}, opt *EditProjectOptions, options ...OptionFunc) (*Project, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s", url.QueryEscape(project)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + p := new(Project) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// ForkProject forks a project into the user namespace of the authenticated +// user. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#fork-project +func (s *ProjectsService) ForkProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/fork", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(Project) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// StarProject stars a given the project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#star-a-project +func (s *ProjectsService) StarProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/star", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(Project) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// UnstarProject unstars a given project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#unstar-a-project +func (s *ProjectsService) UnstarProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/unstar", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(Project) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// ArchiveProject archives the project if the user is either admin or the +// project owner of this project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#archive-a-project +func (s *ProjectsService) ArchiveProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/archive", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(Project) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// UnarchiveProject unarchives the project if the user is either admin or +// the project owner of this project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#unarchive-a-project +func (s *ProjectsService) UnarchiveProject(pid interface{}, options ...OptionFunc) (*Project, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/unarchive", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(Project) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// DeleteProject removes a project including all associated resources +// (issues, merge requests etc.) +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#remove-project +func (s *ProjectsService) DeleteProject(pid interface{}, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s", url.QueryEscape(project)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// ShareWithGroupOptions represents options to share project with groups +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#share-project-with-group +type ShareWithGroupOptions struct { + GroupID *int `url:"group_id" json:"group_id"` + GroupAccess *AccessLevelValue `url:"group_access" json:"group_access"` + ExpiresAt *string `url:"expires_at" json:"expires_at"` +} + +// ShareProjectWithGroup allows to share a project with a group. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#share-project-with-group +func (s *ProjectsService) ShareProjectWithGroup(pid interface{}, opt *ShareWithGroupOptions, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/share", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteSharedProjectFromGroup allows to unshare a project from a group. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#delete-a-shared-project-link-within-a-group +func (s *ProjectsService) DeleteSharedProjectFromGroup(pid interface{}, groupID int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/share/%d", url.QueryEscape(project), groupID) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// ProjectMember represents a project member. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#list-project-team-members +type ProjectMember struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + AccessLevel AccessLevelValue `json:"access_level"` +} + +// ProjectHook represents a project hook. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#list-project-hooks +type ProjectHook struct { + ID int `json:"id"` + URL string `json:"url"` + ProjectID int `json:"project_id"` + PushEvents bool `json:"push_events"` + IssuesEvents bool `json:"issues_events"` + ConfidentialIssuesEvents bool `json:"confidential_issues_events"` + MergeRequestsEvents bool `json:"merge_requests_events"` + TagPushEvents bool `json:"tag_push_events"` + NoteEvents bool `json:"note_events"` + JobEvents bool `json:"job_events"` + PipelineEvents bool `json:"pipeline_events"` + WikiPageEvents bool `json:"wiki_page_events"` + EnableSSLVerification bool `json:"enable_ssl_verification"` + CreatedAt *time.Time `json:"created_at"` +} + +// ListProjectHooksOptions represents the available ListProjectHooks() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#list-project-hooks +type ListProjectHooksOptions ListOptions + +// ListProjectHooks gets a list of project hooks. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#list-project-hooks +func (s *ProjectsService) ListProjectHooks(pid interface{}, opt *ListProjectHooksOptions, options ...OptionFunc) ([]*ProjectHook, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/hooks", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var ph []*ProjectHook + resp, err := s.client.Do(req, &ph) + if err != nil { + return nil, resp, err + } + + return ph, resp, err +} + +// GetProjectHook gets a specific hook for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#get-project-hook +func (s *ProjectsService) GetProjectHook(pid interface{}, hook int, options ...OptionFunc) (*ProjectHook, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/hooks/%d", url.QueryEscape(project), hook) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + ph := new(ProjectHook) + resp, err := s.client.Do(req, ph) + if err != nil { + return nil, resp, err + } + + return ph, resp, err +} + +// AddProjectHookOptions represents the available AddProjectHook() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#add-project-hook +type AddProjectHookOptions struct { + URL *string `url:"url,omitempty" json:"url,omitempty"` + PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` + IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` + ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` + MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` + TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` + NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` + JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"` + PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` + WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` + EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` + Token *string `url:"token,omitempty" json:"token,omitempty"` +} + +// AddProjectHook adds a hook to a specified project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#add-project-hook +func (s *ProjectsService) AddProjectHook(pid interface{}, opt *AddProjectHookOptions, options ...OptionFunc) (*ProjectHook, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/hooks", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + ph := new(ProjectHook) + resp, err := s.client.Do(req, ph) + if err != nil { + return nil, resp, err + } + + return ph, resp, err +} + +// EditProjectHookOptions represents the available EditProjectHook() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#edit-project-hook +type EditProjectHookOptions struct { + URL *string `url:"url,omitempty" json:"url,omitempty"` + PushEvents *bool `url:"push_events,omitempty" json:"push_events,omitempty"` + IssuesEvents *bool `url:"issues_events,omitempty" json:"issues_events,omitempty"` + ConfidentialIssuesEvents *bool `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"` + MergeRequestsEvents *bool `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"` + TagPushEvents *bool `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"` + NoteEvents *bool `url:"note_events,omitempty" json:"note_events,omitempty"` + JobEvents *bool `url:"job_events,omitempty" json:"job_events,omitempty"` + PipelineEvents *bool `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"` + WikiPageEvents *bool `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"` + EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` + Token *string `url:"token,omitempty" json:"token,omitempty"` +} + +// EditProjectHook edits a hook for a specified project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#edit-project-hook +func (s *ProjectsService) EditProjectHook(pid interface{}, hook int, opt *EditProjectHookOptions, options ...OptionFunc) (*ProjectHook, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/hooks/%d", url.QueryEscape(project), hook) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + ph := new(ProjectHook) + resp, err := s.client.Do(req, ph) + if err != nil { + return nil, resp, err + } + + return ph, resp, err +} + +// DeleteProjectHook removes a hook from a project. This is an idempotent +// method and can be called multiple times. Either the hook is available or not. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#delete-project-hook +func (s *ProjectsService) DeleteProjectHook(pid interface{}, hook int, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/hooks/%d", url.QueryEscape(project), hook) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// ProjectForkRelation represents a project fork relationship. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#admin-fork-relation +type ProjectForkRelation struct { + ID int `json:"id"` + ForkedToProjectID int `json:"forked_to_project_id"` + ForkedFromProjectID int `json:"forked_from_project_id"` + CreatedAt *time.Time `json:"created_at"` + UpdatedAt *time.Time `json:"updated_at"` +} + +// CreateProjectForkRelation creates a forked from/to relation between +// existing projects. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#create-a-forked-fromto-relation-between-existing-projects. +func (s *ProjectsService) CreateProjectForkRelation(pid int, fork int, options ...OptionFunc) (*ProjectForkRelation, *Response, error) { + u := fmt.Sprintf("projects/%d/fork/%d", pid, fork) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + pfr := new(ProjectForkRelation) + resp, err := s.client.Do(req, pfr) + if err != nil { + return nil, resp, err + } + + return pfr, resp, err +} + +// DeleteProjectForkRelation deletes an existing forked from relationship. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#delete-an-existing-forked-from-relationship +func (s *ProjectsService) DeleteProjectForkRelation(pid int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("projects/%d/fork", pid) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// ProjectFile represents an uploaded project file +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#upload-a-file +type ProjectFile struct { + Alt string `json:"alt"` + URL string `json:"url"` + Markdown string `json:"markdown"` +} + +// UploadFile upload a file from disk +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#upload-a-file +func (s *ProjectsService) UploadFile(pid interface{}, file string, options ...OptionFunc) (*ProjectFile, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/uploads", url.QueryEscape(project)) + + f, err := os.Open(file) + if err != nil { + return nil, nil, err + } + defer f.Close() + + b := &bytes.Buffer{} + w := multipart.NewWriter(b) + + fw, err := w.CreateFormFile("file", file) + if err != nil { + return nil, nil, err + } + + _, err = io.Copy(fw, f) + if err != nil { + return nil, nil, err + } + w.Close() + + req, err := s.client.NewRequest("", u, nil, options) + if err != nil { + return nil, nil, err + } + + req.Body = ioutil.NopCloser(b) + req.ContentLength = int64(b.Len()) + req.Header.Set("Content-Type", w.FormDataContentType()) + req.Method = "POST" + + uf := &ProjectFile{} + resp, err := s.client.Do(req, uf) + if err != nil { + return nil, resp, err + } + + return uf, resp, nil +} + +// ListProjectForks gets a list of project forks. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/projects.html#list-forks-of-a-project +func (s *ProjectsService) ListProjectForks(pid interface{}, opt *ListProjectsOptions, options ...OptionFunc) ([]*Project, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/forks", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var forks []*Project + resp, err := s.client.Do(req, &forks) + if err != nil { + return nil, resp, err + } + + return forks, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/protected_branches.go b/vendor/github.com/xanzy/go-gitlab/protected_branches.go new file mode 100644 index 00000000..0a56241e --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/protected_branches.go @@ -0,0 +1,165 @@ +// +// Copyright 2017, Sander van Harmelen, Michael Lihs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// ProtectedBranchesService handles communication with the protected branch +// related methods of the GitLab API. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/protected_branches.html#protected-branches-api +type ProtectedBranchesService struct { + client *Client +} + +// BranchAccessDescription represents the access description for a protected +// branch. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/protected_branches.html#protected-branches-api +type BranchAccessDescription struct { + AccessLevel AccessLevelValue `json:"access_level"` + AccessLevelDescription string `json:"access_level_description"` +} + +// ProtectedBranch represents a protected branch. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/protected_branches.html#list-protected-branches +type ProtectedBranch struct { + Name string `json:"name"` + PushAccessLevels []*BranchAccessDescription `json:"push_access_levels"` + MergeAccessLevels []*BranchAccessDescription `json:"merge_access_levels"` +} + +// ListProtectedBranchesOptions represents the available ListProtectedBranches() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/protected_branches.html#list-protected-branches +type ListProtectedBranchesOptions ListOptions + +// ListProtectedBranches gets a list of protected branches from a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/protected_branches.html#list-protected-branches +func (s *ProtectedBranchesService) ListProtectedBranches(pid interface{}, opt *ListProtectedBranchesOptions, options ...OptionFunc) ([]*ProtectedBranch, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/protected_branches", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var p []*ProtectedBranch + resp, err := s.client.Do(req, &p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// GetProtectedBranch gets a single protected branch or wildcard protected branch. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/protected_branches.html#get-a-single-protected-branch-or-wildcard-protected-branch +func (s *ProtectedBranchesService) GetProtectedBranch(pid interface{}, branch string, options ...OptionFunc) (*ProtectedBranch, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/protected_branches/%s", url.QueryEscape(project), branch) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + p := new(ProtectedBranch) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// ProtectRepositoryBranchesOptions represents the available +// ProtectRepositoryBranches() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/protected_branches.html#protect-repository-branches +type ProtectRepositoryBranchesOptions struct { + Name *string `url:"name,omitempty" json:"name,omitempty"` + PushAccessLevel *AccessLevelValue `url:"push_access_level,omitempty" json:"push_access_level,omitempty"` + MergeAccessLevel *AccessLevelValue `url:"merge_access_level,omitempty" json:"merge_access_level,omitempty"` +} + +// ProtectRepositoryBranches protects a single repository branch or several +// project repository branches using a wildcard protected branch. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/protected_branches.html#protect-repository-branches +func (s *ProtectedBranchesService) ProtectRepositoryBranches(pid interface{}, opt *ProtectRepositoryBranchesOptions, options ...OptionFunc) (*ProtectedBranch, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/protected_branches", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + p := new(ProtectedBranch) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// UnprotectRepositoryBranches unprotects the given protected branch or wildcard +// protected branch. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/protected_branches.html#unprotect-repository-branches +func (s *ProtectedBranchesService) UnprotectRepositoryBranches(pid interface{}, branch string, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/protected_branches/%s", url.QueryEscape(project), branch) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/repositories.go b/vendor/github.com/xanzy/go-gitlab/repositories.go new file mode 100644 index 00000000..7d109974 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/repositories.go @@ -0,0 +1,260 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "bytes" + "fmt" + "net/url" +) + +// RepositoriesService handles communication with the repositories related +// methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html +type RepositoriesService struct { + client *Client +} + +// TreeNode represents a GitLab repository file or directory. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html +type TreeNode struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Path string `json:"path"` + Mode string `json:"mode"` +} + +func (t TreeNode) String() string { + return Stringify(t) +} + +// ListTreeOptions represents the available ListTree() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repositories.html#list-repository-tree +type ListTreeOptions struct { + ListOptions + Path *string `url:"path,omitempty" json:"path,omitempty"` + Ref *string `url:"ref,omitempty" json:"ref,omitempty"` + Recursive *bool `url:"recursive,omitempty" json:"recursive,omitempty"` +} + +// ListTree gets a list of repository files and directories in a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repositories.html#list-repository-tree +func (s *RepositoriesService) ListTree(pid interface{}, opt *ListTreeOptions, options ...OptionFunc) ([]*TreeNode, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/tree", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var t []*TreeNode + resp, err := s.client.Do(req, &t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// RawFileContent gets the raw file contents for a file by commit SHA and path +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repositories.html#raw-file-content +func (s *RepositoriesService) RawFileContent(pid interface{}, sha string, options ...OptionFunc) ([]byte, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/blobs/%s", url.QueryEscape(project), sha) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var b bytes.Buffer + resp, err := s.client.Do(req, &b) + if err != nil { + return nil, resp, err + } + + return b.Bytes(), resp, err +} + +// RawBlobContent gets the raw file contents for a blob by blob SHA. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repositories.html#raw-blob-content +func (s *RepositoriesService) RawBlobContent(pid interface{}, sha string, options ...OptionFunc) ([]byte, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/blobs/%s/raw", url.QueryEscape(project), sha) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var b bytes.Buffer + resp, err := s.client.Do(req, &b) + if err != nil { + return nil, resp, err + } + + return b.Bytes(), resp, err +} + +// ArchiveOptions represents the available Archive() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repositories.html#get-file-archive +type ArchiveOptions struct { + SHA *string `url:"sha,omitempty" json:"sha,omitempty"` +} + +// Archive gets an archive of the repository. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repositories.html#get-file-archive +func (s *RepositoriesService) Archive(pid interface{}, opt *ArchiveOptions, options ...OptionFunc) ([]byte, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/archive", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var b bytes.Buffer + resp, err := s.client.Do(req, &b) + if err != nil { + return nil, resp, err + } + + return b.Bytes(), resp, err +} + +// Compare represents the result of a comparison of branches, tags or commits. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits +type Compare struct { + Commit *Commit `json:"commit"` + Commits []*Commit `json:"commits"` + Diffs []*Diff `json:"diffs"` + CompareTimeout bool `json:"compare_timeout"` + CompareSameRef bool `json:"compare_same_ref"` +} + +func (c Compare) String() string { + return Stringify(c) +} + +// CompareOptions represents the available Compare() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits +type CompareOptions struct { + From *string `url:"from,omitempty" json:"from,omitempty"` + To *string `url:"to,omitempty" json:"to,omitempty"` +} + +// Compare compares branches, tags or commits. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repositories.html#compare-branches-tags-or-commits +func (s *RepositoriesService) Compare(pid interface{}, opt *CompareOptions, options ...OptionFunc) (*Compare, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/compare", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + c := new(Compare) + resp, err := s.client.Do(req, c) + if err != nil { + return nil, resp, err + } + + return c, resp, err +} + +// Contributor represents a GitLap contributor. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors +type Contributor struct { + Name string `json:"name,omitempty"` + Email string `json:"email,omitempty"` + Commits int `json:"commits,omitempty"` + Additions int `json:"additions,omitempty"` + Deletions int `json:"deletions,omitempty"` +} + +func (c Contributor) String() string { + return Stringify(c) +} + +// ListContributorsOptions represents the available ListContributorsOptions() +// options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors +type ListContributorsOptions ListOptions + +// Contributors gets the repository contributors list. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/repositories.html#contributors +func (s *RepositoriesService) Contributors(pid interface{}, opt *ListContributorsOptions, options ...OptionFunc) ([]*Contributor, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/contributors", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var c []*Contributor + resp, err := s.client.Do(req, &c) + if err != nil { + return nil, resp, err + } + + return c, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/repository_files.go b/vendor/github.com/xanzy/go-gitlab/repository_files.go new file mode 100644 index 00000000..473128a3 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/repository_files.go @@ -0,0 +1,235 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "bytes" + "fmt" + "net/url" +) + +// RepositoryFilesService handles communication with the repository files +// related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html +type RepositoryFilesService struct { + client *Client +} + +// File represents a GitLab repository file. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html +type File struct { + FileName string `json:"file_name"` + FilePath string `json:"file_path"` + Size int `json:"size"` + Encoding string `json:"encoding"` + Content string `json:"content"` + Ref string `json:"ref"` + BlobID string `json:"blob_id"` + CommitID string `json:"commit_id"` +} + +func (r File) String() string { + return Stringify(r) +} + +// GetFileOptions represents the available GetFile() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository +type GetFileOptions struct { + Ref *string `url:"ref,omitempty" json:"ref,omitempty"` +} + +// GetFile allows you to receive information about a file in repository like +// name, size, content. Note that file content is Base64 encoded. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#get-file-from-repository +func (s *RepositoryFilesService) GetFile(pid interface{}, fileName string, opt *GetFileOptions, options ...OptionFunc) (*File, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.QueryEscape(fileName)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + f := new(File) + resp, err := s.client.Do(req, f) + if err != nil { + return nil, resp, err + } + + return f, resp, err +} + +// GetRawFileOptions represents the available GetRawFile() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#get-raw-file-from-repository +type GetRawFileOptions struct { + Ref *string `url:"ref,omitempty" json:"ref,omitempty"` +} + +// GetRawFile allows you to receive the raw file in repository. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#get-raw-file-from-repository +func (s *RepositoryFilesService) GetRawFile(pid interface{}, fileName string, opt *GetRawFileOptions, options ...OptionFunc) ([]byte, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/files/%s/raw", url.QueryEscape(project), url.QueryEscape(fileName)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var f bytes.Buffer + resp, err := s.client.Do(req, &f) + if err != nil { + return nil, resp, err + } + + return f.Bytes(), resp, err +} + +// FileInfo represents file details of a GitLab repository file. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/repository_files.html +type FileInfo struct { + FilePath string `json:"file_path"` + Branch string `json:"branch"` +} + +func (r FileInfo) String() string { + return Stringify(r) +} + +// CreateFileOptions represents the available CreateFile() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository +type CreateFileOptions struct { + Branch *string `url:"branch,omitempty" json:"branch,omitempty"` + Encoding *string `url:"encoding,omitempty" json:"encoding,omitempty"` + AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` + AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` + Content *string `url:"content,omitempty" json:"content,omitempty"` + CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"` +} + +// CreateFile creates a new file in a repository. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#create-new-file-in-repository +func (s *RepositoryFilesService) CreateFile(pid interface{}, fileName string, opt *CreateFileOptions, options ...OptionFunc) (*FileInfo, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.QueryEscape(fileName)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + f := new(FileInfo) + resp, err := s.client.Do(req, f) + if err != nil { + return nil, resp, err + } + + return f, resp, err +} + +// UpdateFileOptions represents the available UpdateFile() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository +type UpdateFileOptions struct { + Branch *string `url:"branch,omitempty" json:"branch,omitempty"` + Encoding *string `url:"encoding,omitempty" json:"encoding,omitempty"` + AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` + AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` + Content *string `url:"content,omitempty" json:"content,omitempty"` + CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"` + LastCommitID *string `url:"last_commit_id,omitempty" json:"last_commit_id,omitempty"` +} + +// UpdateFile updates an existing file in a repository +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#update-existing-file-in-repository +func (s *RepositoryFilesService) UpdateFile(pid interface{}, fileName string, opt *UpdateFileOptions, options ...OptionFunc) (*FileInfo, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.QueryEscape(fileName)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + f := new(FileInfo) + resp, err := s.client.Do(req, f) + if err != nil { + return nil, resp, err + } + + return f, resp, err +} + +// DeleteFileOptions represents the available DeleteFile() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#delete-existing-file-in-repository +type DeleteFileOptions struct { + Branch *string `url:"branch,omitempty" json:"branch,omitempty"` + AuthorEmail *string `url:"author_email,omitempty" json:"author_email,omitempty"` + AuthorName *string `url:"author_name,omitempty" json:"author_name,omitempty"` + CommitMessage *string `url:"commit_message,omitempty" json:"commit_message,omitempty"` +} + +// DeleteFile deletes an existing file in a repository +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/repository_files.html#delete-existing-file-in-repository +func (s *RepositoryFilesService) DeleteFile(pid interface{}, fileName string, opt *DeleteFileOptions, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/repository/files/%s", url.QueryEscape(project), url.QueryEscape(fileName)) + + req, err := s.client.NewRequest("DELETE", u, opt, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/runners.go b/vendor/github.com/xanzy/go-gitlab/runners.go new file mode 100644 index 00000000..4ffef038 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/runners.go @@ -0,0 +1,326 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// RunnersService handles communication with the runner related methods of the +// GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/runners.html +type RunnersService struct { + client *Client +} + +// Runner represents a GitLab CI Runner. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/runners.html +type Runner struct { + ID int `json:"id"` + Description string `json:"description"` + Active bool `json:"active"` + IsShared bool `json:"is_shared"` + Name string `json:"name"` + Online bool `json:"online"` + Status string `json:"status"` +} + +// RunnerDetails represents the GitLab CI runner details. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/runners.html +type RunnerDetails struct { + Active bool `json:"active"` + Architecture string `json:"architecture"` + Description string `json:"description"` + ID int `json:"id"` + IsShared bool `json:"is_shared"` + ContactedAt *time.Time `json:"contacted_at,omitempty"` + Name string `json:"name"` + Online bool `json:"online"` + Status string `json:"status"` + Platform string `json:"platform,omitempty"` + Projects []struct { + ID int `json:"id"` + Name string `json:"name"` + NameWithNamespace string `json:"name_with_namespace"` + Path string `json:"path"` + PathWithNamespace string `json:"path_with_namespace"` + } `json:"projects"` + Token string `json:"Token"` + Revision string `json:"revision,omitempty"` + TagList []string `json:"tag_list"` + Version string `json:"version,omitempty"` + AccessLevel string `json:"access_level"` +} + +// ListRunnersOptions represents the available ListRunners() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#list-owned-runners +type ListRunnersOptions struct { + ListOptions + Scope *string `url:"scope,omitempty" json:"scope,omitempty"` +} + +// ListRunners gets a list of runners accessible by the authenticated user. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#list-owned-runners +func (s *RunnersService) ListRunners(opt *ListRunnersOptions, options ...OptionFunc) ([]*Runner, *Response, error) { + req, err := s.client.NewRequest("GET", "runners", opt, options) + if err != nil { + return nil, nil, err + } + + var rs []*Runner + resp, err := s.client.Do(req, &rs) + if err != nil { + return nil, resp, err + } + + return rs, resp, err +} + +// ListAllRunners gets a list of all runners in the GitLab instance. Access is +// restricted to users with admin privileges. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#list-all-runners +func (s *RunnersService) ListAllRunners(opt *ListRunnersOptions, options ...OptionFunc) ([]*Runner, *Response, error) { + req, err := s.client.NewRequest("GET", "runners/all", opt, options) + if err != nil { + return nil, nil, err + } + + var rs []*Runner + resp, err := s.client.Do(req, &rs) + if err != nil { + return nil, resp, err + } + + return rs, resp, err +} + +// GetRunnerDetails returns details for given runner. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#get-runner-39-s-details +func (s *RunnersService) GetRunnerDetails(rid interface{}, options ...OptionFunc) (*RunnerDetails, *Response, error) { + runner, err := parseID(rid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("runners/%s", runner) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var rs *RunnerDetails + resp, err := s.client.Do(req, &rs) + if err != nil { + return nil, resp, err + } + + return rs, resp, err +} + +// UpdateRunnerDetailsOptions represents the available UpdateRunnerDetails() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#update-runner-39-s-details +type UpdateRunnerDetailsOptions struct { + Description *string `url:"description,omitempty" json:"description,omitempty"` + Active *bool `url:"active,omitempty" json:"active,omitempty"` + TagList []string `url:"tag_list[],omitempty" json:"tag_list,omitempty"` + RunUntagged *bool `url:"run_untagged,omitempty" json:"run_untagged,omitempty"` + Locked *bool `url:"locked,omitempty" json:"locked,omitempty"` + AccessLevel *string `url:"access_level,omitempty" json:"access_level,omitempty"` +} + +// UpdateRunnerDetails updates details for a given runner. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#update-runner-39-s-details +func (s *RunnersService) UpdateRunnerDetails(rid interface{}, opt *UpdateRunnerDetailsOptions, options ...OptionFunc) (*RunnerDetails, *Response, error) { + runner, err := parseID(rid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("runners/%s", runner) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + var rs *RunnerDetails + resp, err := s.client.Do(req, &rs) + if err != nil { + return nil, resp, err + } + + return rs, resp, err +} + +// RemoveRunner removes a runner. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#remove-a-runner +func (s *RunnersService) RemoveRunner(rid interface{}, options ...OptionFunc) (*Response, error) { + runner, err := parseID(rid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("runners/%s", runner) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// ListRunnerJobsOptions represents the available ListRunnerJobs() +// options. Status can be one of: running, success, failed, canceled. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#list-runner-39-s-jobs +type ListRunnerJobsOptions struct { + ListOptions + Status *string `url:"status,omitempty" json:"status,omitempty"` +} + +// ListRunnerJobs gets a list of jobs that are being processed or were processed by specified Runner. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#list-runner-39-s-jobs +func (s *RunnersService) ListRunnerJobs(rid interface{}, opt *ListRunnerJobsOptions, options ...OptionFunc) ([]*Job, *Response, error) { + runner, err := parseID(rid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("runners/%s/jobs", runner) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var rs []*Job + resp, err := s.client.Do(req, &rs) + if err != nil { + return nil, resp, err + } + + return rs, resp, err +} + +// ListProjectRunnersOptions represents the available ListProjectRunners() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#list-project-s-runners +type ListProjectRunnersOptions ListRunnersOptions + +// ListProjectRunners gets a list of runners accessible by the authenticated user. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#list-project-s-runners +func (s *RunnersService) ListProjectRunners(pid interface{}, opt *ListProjectRunnersOptions, options ...OptionFunc) ([]*Runner, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/runners", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var rs []*Runner + resp, err := s.client.Do(req, &rs) + if err != nil { + return nil, resp, err + } + + return rs, resp, err +} + +// EnableProjectRunnerOptions represents the available EnableProjectRunner() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#enable-a-runner-in-project +type EnableProjectRunnerOptions struct { + RunnerID int `json:"runner_id"` +} + +// EnableProjectRunner enables an available specific runner in the project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#enable-a-runner-in-project +func (s *RunnersService) EnableProjectRunner(pid interface{}, opt *EnableProjectRunnerOptions, options ...OptionFunc) (*Runner, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/runners", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + var r *Runner + resp, err := s.client.Do(req, &r) + if err != nil { + return nil, resp, err + } + + return r, resp, err +} + +// DisableProjectRunner disables a specific runner from project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/runners.html#disable-a-runner-from-project +func (s *RunnersService) DisableProjectRunner(pid interface{}, rid interface{}, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + runner, err := parseID(rid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/runners/%s", url.QueryEscape(project), url.QueryEscape(runner)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/search.go b/vendor/github.com/xanzy/go-gitlab/search.go new file mode 100644 index 00000000..99c2f020 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/search.go @@ -0,0 +1,326 @@ +// +// Copyright 2018, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// SearchService handles communication with the search related methods of the +// GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html +type SearchService struct { + client *Client +} + +// SearchOptions represents the available options for all search methods. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html +type SearchOptions ListOptions + +type searchOptions struct { + SearchOptions + Scope string `url:"scope" json:"scope"` + Search string `url:"search" json:"search"` +} + +// Projects searches the expression within projects +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-projects +func (s *SearchService) Projects(query string, opt *SearchOptions, options ...OptionFunc) ([]*Project, *Response, error) { + var ps []*Project + resp, err := s.search("projects", query, &ps, opt, options...) + return ps, resp, err +} + +// ProjectsByGroup searches the expression within projects for +// the specified group +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#group-search-api +func (s *SearchService) ProjectsByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Project, *Response, error) { + var ps []*Project + resp, err := s.searchByGroup(gid, "projects", query, &ps, opt, options...) + return ps, resp, err +} + +// Issues searches the expression within issues +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-issues +func (s *SearchService) Issues(query string, opt *SearchOptions, options ...OptionFunc) ([]*Issue, *Response, error) { + var is []*Issue + resp, err := s.search("issues", query, &is, opt, options...) + return is, resp, err +} + +// IssuesByGroup searches the expression within issues for +// the specified group +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-issues +func (s *SearchService) IssuesByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Issue, *Response, error) { + var is []*Issue + resp, err := s.searchByGroup(gid, "issues", query, &is, opt, options...) + return is, resp, err +} + +// IssuesByProject searches the expression within issues for +// the specified project +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-issues +func (s *SearchService) IssuesByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Issue, *Response, error) { + var is []*Issue + resp, err := s.searchByProject(pid, "issues", query, &is, opt, options...) + return is, resp, err +} + +// MergeRequests searches the expression within merge requests +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/search.html#scope-merge_requests +func (s *SearchService) MergeRequests(query string, opt *SearchOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { + var ms []*MergeRequest + resp, err := s.search("merge_requests", query, &ms, opt, options...) + return ms, resp, err +} + +// MergeRequestsByGroup searches the expression within merge requests for +// the specified group +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/search.html#scope-merge_requests +func (s *SearchService) MergeRequestsByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { + var ms []*MergeRequest + resp, err := s.searchByGroup(gid, "merge_requests", query, &ms, opt, options...) + return ms, resp, err +} + +// MergeRequestsByProject searches the expression within merge requests for +// the specified project +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/search.html#scope-merge_requests +func (s *SearchService) MergeRequestsByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*MergeRequest, *Response, error) { + var ms []*MergeRequest + resp, err := s.searchByProject(pid, "merge_requests", query, &ms, opt, options...) + return ms, resp, err +} + +// Milestones searches the expression within milestones +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-milestones +func (s *SearchService) Milestones(query string, opt *SearchOptions, options ...OptionFunc) ([]*Milestone, *Response, error) { + var ms []*Milestone + resp, err := s.search("milestones", query, &ms, opt, options...) + return ms, resp, err +} + +// MilestonesByGroup searches the expression within milestones for +// the specified group +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-milestones +func (s *SearchService) MilestonesByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Milestone, *Response, error) { + var ms []*Milestone + resp, err := s.searchByGroup(gid, "milestones", query, &ms, opt, options...) + return ms, resp, err +} + +// MilestonesByProject searches the expression within milestones for +// the specified project +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-milestones +func (s *SearchService) MilestonesByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Milestone, *Response, error) { + var ms []*Milestone + resp, err := s.searchByProject(pid, "milestones", query, &ms, opt, options...) + return ms, resp, err +} + +// SnippetTitles searches the expression within snippet titles +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/search.html#scope-snippet_titles +func (s *SearchService) SnippetTitles(query string, opt *SearchOptions, options ...OptionFunc) ([]*Snippet, *Response, error) { + var ss []*Snippet + resp, err := s.search("snippet_titles", query, &ss, opt, options...) + return ss, resp, err +} + +// SnippetBlobs searches the expression within snippet blobs +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/search.html#scope-snippet_blobs +func (s *SearchService) SnippetBlobs(query string, opt *SearchOptions, options ...OptionFunc) ([]*Snippet, *Response, error) { + var ss []*Snippet + resp, err := s.search("snippet_blobs", query, &ss, opt, options...) + return ss, resp, err +} + +// NotesByProject searches the expression within notes for the specified +// project +// +// GitLab API docs: // https://docs.gitlab.com/ce/api/search.html#scope-notes +func (s *SearchService) NotesByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Note, *Response, error) { + var ns []*Note + resp, err := s.searchByProject(pid, "notes", query, &ns, opt, options...) + return ns, resp, err +} + +// WikiBlobs searches the expression within all wiki blobs +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/search.html#scope-wiki_blobs +func (s *SearchService) WikiBlobs(query string, opt *SearchOptions, options ...OptionFunc) ([]*Wiki, *Response, error) { + var ws []*Wiki + resp, err := s.search("wiki_blobs", query, &ws, opt, options...) + return ws, resp, err +} + +// WikiBlobsByGroup searches the expression within wiki blobs for +// specified group +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/search.html#scope-wiki_blobs +func (s *SearchService) WikiBlobsByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Wiki, *Response, error) { + var ws []*Wiki + resp, err := s.searchByGroup(gid, "wiki_blobs", query, &ws, opt, options...) + return ws, resp, err +} + +// WikiBlobsByProject searches the expression within wiki blobs for +// the specified project +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/search.html#scope-wiki_blobs +func (s *SearchService) WikiBlobsByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Wiki, *Response, error) { + var ws []*Wiki + resp, err := s.searchByProject(pid, "wiki_blobs", query, &ws, opt, options...) + return ws, resp, err +} + +// Commits searches the expression within all commits +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-commits +func (s *SearchService) Commits(query string, opt *SearchOptions, options ...OptionFunc) ([]*Commit, *Response, error) { + var cs []*Commit + resp, err := s.search("commits", query, &cs, opt, options...) + return cs, resp, err +} + +// CommitsByGroup searches the expression within commits for the specified +// group +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-commits +func (s *SearchService) CommitsByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Commit, *Response, error) { + var cs []*Commit + resp, err := s.searchByGroup(gid, "commits", query, &cs, opt, options...) + return cs, resp, err +} + +// CommitsByProject searches the expression within commits for the +// specified project +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-commits +func (s *SearchService) CommitsByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Commit, *Response, error) { + var cs []*Commit + resp, err := s.searchByProject(pid, "commits", query, &cs, opt, options...) + return cs, resp, err +} + +// Blob represents a single blob. +type Blob struct { + Basename string `json:"basename"` + Data string `json:"data"` + Filename string `json:"filename"` + ID int `json:"id"` + Ref string `json:"ref"` + Startline int `json:"startline"` + ProjectID int `json:"project_id"` +} + +// Blobs searches the expression within all blobs +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-blobs +func (s *SearchService) Blobs(query string, opt *SearchOptions, options ...OptionFunc) ([]*Blob, *Response, error) { + var bs []*Blob + resp, err := s.search("blobs", query, &bs, opt, options...) + return bs, resp, err +} + +// BlobsByGroup searches the expression within blobs for the specified +// group +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-blobs +func (s *SearchService) BlobsByGroup(gid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Blob, *Response, error) { + var bs []*Blob + resp, err := s.searchByGroup(gid, "blobs", query, &bs, opt, options...) + return bs, resp, err +} + +// BlobsByProject searches the expression within blobs for the specified +// project +// +// GitLab API docs: https://docs.gitlab.com/ce/api/search.html#scope-blobs +func (s *SearchService) BlobsByProject(pid interface{}, query string, opt *SearchOptions, options ...OptionFunc) ([]*Blob, *Response, error) { + var bs []*Blob + resp, err := s.searchByProject(pid, "blobs", query, &bs, opt, options...) + return bs, resp, err +} + +func (s *SearchService) search(scope, query string, result interface{}, opt *SearchOptions, options ...OptionFunc) (*Response, error) { + opts := &searchOptions{SearchOptions: *opt, Scope: scope, Search: query} + + req, err := s.client.NewRequest("GET", "search", opts, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, result) +} + +func (s *SearchService) searchByGroup(gid interface{}, scope, query string, result interface{}, opt *SearchOptions, options ...OptionFunc) (*Response, error) { + group, err := parseID(gid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("groups/%s/-/search", url.QueryEscape(group)) + + opts := &searchOptions{SearchOptions: *opt, Scope: scope, Search: query} + + req, err := s.client.NewRequest("GET", u, opts, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, result) +} + +func (s *SearchService) searchByProject(pid interface{}, scope, query string, result interface{}, opt *SearchOptions, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/-/search", url.QueryEscape(project)) + + opts := &searchOptions{SearchOptions: *opt, Scope: scope, Search: query} + + req, err := s.client.NewRequest("GET", u, opts, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, result) +} diff --git a/vendor/github.com/xanzy/go-gitlab/services.go b/vendor/github.com/xanzy/go-gitlab/services.go new file mode 100644 index 00000000..e93ae600 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/services.go @@ -0,0 +1,515 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" + "time" +) + +// ServicesService handles communication with the services related methods of +// the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/services.html +type ServicesService struct { + client *Client +} + +// Service represents a GitLab service. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/services.html +type Service struct { + ID int `json:"id"` + Title string `json:"title"` + CreatedAt *time.Time `json:"created_at"` + UpdatedAt *time.Time `json:"updated_at"` + Active bool `json:"active"` + PushEvents bool `json:"push_events"` + IssuesEvents bool `json:"issues_events"` + ConfidentialIssuesEvents bool `json:"confidential_issues_events"` + MergeRequestsEvents bool `json:"merge_requests_events"` + TagPushEvents bool `json:"tag_push_events"` + NoteEvents bool `json:"note_events"` + PipelineEvents bool `json:"pipeline_events"` + JobEvents bool `json:"job_events"` +} + +// SetGitLabCIServiceOptions represents the available SetGitLabCIService() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#edit-gitlab-ci-service +type SetGitLabCIServiceOptions struct { + Token *string `url:"token,omitempty" json:"token,omitempty"` + ProjectURL *string `url:"project_url,omitempty" json:"project_url,omitempty"` +} + +// SetGitLabCIService sets GitLab CI service for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#edit-gitlab-ci-service +func (s *ServicesService) SetGitLabCIService(pid interface{}, opt *SetGitLabCIServiceOptions, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/gitlab-ci", url.QueryEscape(project)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteGitLabCIService deletes GitLab CI service settings for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#delete-gitlab-ci-service +func (s *ServicesService) DeleteGitLabCIService(pid interface{}, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/gitlab-ci", url.QueryEscape(project)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// SetHipChatServiceOptions represents the available SetHipChatService() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#edit-hipchat-service +type SetHipChatServiceOptions struct { + Token *string `url:"token,omitempty" json:"token,omitempty" ` + Room *string `url:"room,omitempty" json:"room,omitempty"` +} + +// SetHipChatService sets HipChat service for a project +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#edit-hipchat-service +func (s *ServicesService) SetHipChatService(pid interface{}, opt *SetHipChatServiceOptions, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/hipchat", url.QueryEscape(project)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteHipChatService deletes HipChat service for project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#delete-hipchat-service +func (s *ServicesService) DeleteHipChatService(pid interface{}, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/hipchat", url.QueryEscape(project)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DroneCIService represents Drone CI service settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#drone-ci +type DroneCIService struct { + Service + Properties *DroneCIServiceProperties `json:"properties"` +} + +// DroneCIServiceProperties represents Drone CI specific properties. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#drone-ci +type DroneCIServiceProperties struct { + Token string `json:"token"` + DroneURL string `json:"drone_url"` + EnableSSLVerification bool `json:"enable_ssl_verification"` +} + +// GetDroneCIService gets Drone CI service settings for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#get-drone-ci-service-settings +func (s *ServicesService) GetDroneCIService(pid interface{}, options ...OptionFunc) (*DroneCIService, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/services/drone-ci", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + svc := new(DroneCIService) + resp, err := s.client.Do(req, svc) + if err != nil { + return nil, resp, err + } + + return svc, resp, err +} + +// SetDroneCIServiceOptions represents the available SetDroneCIService() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#createedit-drone-ci-service +type SetDroneCIServiceOptions struct { + Token *string `url:"token" json:"token" ` + DroneURL *string `url:"drone_url" json:"drone_url"` + EnableSSLVerification *bool `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"` +} + +// SetDroneCIService sets Drone CI service for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#createedit-drone-ci-service +func (s *ServicesService) SetDroneCIService(pid interface{}, opt *SetDroneCIServiceOptions, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/drone-ci", url.QueryEscape(project)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteDroneCIService deletes Drone CI service settings for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#delete-drone-ci-service +func (s *ServicesService) DeleteDroneCIService(pid interface{}, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/drone-ci", url.QueryEscape(project)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// SlackService represents Slack service settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#slack +type SlackService struct { + Service + Properties *SlackServiceProperties `json:"properties"` +} + +// SlackServiceProperties represents Slack specific properties. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#slack +type SlackServiceProperties struct { + NotifyOnlyBrokenPipelines bool `json:"notify_only_broken_pipelines"` +} + +// GetSlackService gets Slack service settings for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#get-slack-service-settings +func (s *ServicesService) GetSlackService(pid interface{}, options ...OptionFunc) (*SlackService, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/services/slack", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + svc := new(SlackService) + resp, err := s.client.Do(req, svc) + if err != nil { + return nil, resp, err + } + + return svc, resp, err +} + +// SetSlackServiceOptions represents the available SetSlackService() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#edit-slack-service +type SetSlackServiceOptions struct { + WebHook *string `url:"webhook,omitempty" json:"webhook,omitempty" ` + Username *string `url:"username,omitempty" json:"username,omitempty" ` + Channel *string `url:"channel,omitempty" json:"channel,omitempty"` +} + +// SetSlackService sets Slack service for a project +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#edit-slack-service +func (s *ServicesService) SetSlackService(pid interface{}, opt *SetSlackServiceOptions, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/slack", url.QueryEscape(project)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteSlackService deletes Slack service for project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#delete-slack-service +func (s *ServicesService) DeleteSlackService(pid interface{}, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/slack", url.QueryEscape(project)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// JiraService represents Jira service settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#jira +type JiraService struct { + Service + Properties *JiraServiceProperties `json:"properties"` +} + +// JiraServiceProperties represents Jira specific properties. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#jira +type JiraServiceProperties struct { + URL *string `url:"url,omitempty" json:"url,omitempty"` + ProjectKey *string `url:"project_key,omitempty" json:"project_key,omitempty" ` + Username *string `url:"username,omitempty" json:"username,omitempty" ` + Password *string `url:"password,omitempty" json:"password,omitempty" ` + JiraIssueTransitionID *string `url:"jira_issue_transition_id,omitempty" json:"jira_issue_transition_id,omitempty"` +} + +// GetJiraService gets Jira service settings for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#get-jira-service-settings +func (s *ServicesService) GetJiraService(pid interface{}, options ...OptionFunc) (*JiraService, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/services/jira", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + svc := new(JiraService) + resp, err := s.client.Do(req, svc) + if err != nil { + return nil, resp, err + } + + return svc, resp, err +} + +// SetJiraServiceOptions represents the available SetJiraService() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#edit-jira-service +type SetJiraServiceOptions JiraServiceProperties + +// SetJiraService sets Jira service for a project +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#edit-jira-service +func (s *ServicesService) SetJiraService(pid interface{}, opt *SetJiraServiceOptions, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/jira", url.QueryEscape(project)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteJiraService deletes Jira service for project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#delete-jira-service +func (s *ServicesService) DeleteJiraService(pid interface{}, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/jira", url.QueryEscape(project)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// JenkinsCIService represents Jenkins CI service settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/services.html#jenkins-ci +type JenkinsCIService struct { + Service + Properties *JenkinsCIServiceProperties `json:"properties"` +} + +// JenkinsCIServiceProperties represents Jenkins CI specific properties. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/services.html#jenkins-ci +type JenkinsCIServiceProperties struct { + URL *string `url:"jenkins_url,omitempty" json:"jenkins_url,omitempty"` + ProjectName *string `url:"project_name,omitempty" json:"project_name,omitempty"` + Username *string `url:"username,omitempty" json:"username,omitempty"` +} + +// GetJenkinsCIService gets Jenkins CI service settings for a project. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/services.html#get-jenkins-ci-service-settings +func (s *ServicesService) GetJenkinsCIService(pid interface{}, options ...OptionFunc) (*JenkinsCIService, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/services/jenkins", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + svc := new(JenkinsCIService) + resp, err := s.client.Do(req, svc) + if err != nil { + return nil, resp, err + } + + return svc, resp, err +} + +// SetJenkinsCIServiceOptions represents the available SetJenkinsCIService() +// options. +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/services.html#jenkins-ci +type SetJenkinsCIServiceOptions struct { + URL *string `url:"jenkins_url,omitempty" json:"jenkins_url,omitempty"` + ProjectName *string `url:"project_name,omitempty" json:"project_name,omitempty"` + Username *string `url:"username,omitempty" json:"username,omitempty"` + Password *string `url:"password,omitempty" json:"password,omitempty"` +} + +// SetJenkinsCIService sets Jenkins service for a project +// +// GitLab API docs: +// https://docs.gitlab.com/ee/api/services.html#create-edit-jenkins-ci-service +func (s *ServicesService) SetJenkinsCIService(pid interface{}, opt *SetJenkinsCIServiceOptions, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/jenkins", url.QueryEscape(project)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteJenkinsCIService deletes Jenkins CI service for project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/services.html#delete-jira-service +func (s *ServicesService) DeleteJenkinsCIService(pid interface{}, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/services/jenkins", url.QueryEscape(project)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/session.go b/vendor/github.com/xanzy/go-gitlab/session.go new file mode 100644 index 00000000..f89fdbe5 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/session.go @@ -0,0 +1,78 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import "time" + +// SessionService handles communication with the session related methods of +// the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/session.html +type SessionService struct { + client *Client +} + +// Session represents a GitLab session. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/session.html#session +type Session struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` + Name string `json:"name"` + PrivateToken string `json:"private_token"` + Blocked bool `json:"blocked"` + CreatedAt *time.Time `json:"created_at"` + Bio interface{} `json:"bio"` + Skype string `json:"skype"` + Linkedin string `json:"linkedin"` + Twitter string `json:"twitter"` + WebsiteURL string `json:"website_url"` + DarkScheme bool `json:"dark_scheme"` + ThemeID int `json:"theme_id"` + IsAdmin bool `json:"is_admin"` + CanCreateGroup bool `json:"can_create_group"` + CanCreateTeam bool `json:"can_create_team"` + CanCreateProject bool `json:"can_create_project"` +} + +// GetSessionOptions represents the available Session() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/session.html#session +type GetSessionOptions struct { + Login *string `url:"login,omitempty" json:"login,omitempty"` + Email *string `url:"email,omitempty" json:"email,omitempty"` + Password *string `url:"password,omitempty" json:"password,omitempty"` +} + +// GetSession logs in to get private token. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/session.html#session +func (s *SessionService) GetSession(opt *GetSessionOptions, options ...OptionFunc) (*Session, *Response, error) { + req, err := s.client.NewRequest("POST", "session", opt, options) + if err != nil { + return nil, nil, err + } + + session := new(Session) + resp, err := s.client.Do(req, session) + if err != nil { + return nil, resp, err + } + + return session, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/settings.go b/vendor/github.com/xanzy/go-gitlab/settings.go new file mode 100644 index 00000000..fde9910f --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/settings.go @@ -0,0 +1,265 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import "time" + +// SettingsService handles communication with the application SettingsService +// related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/settings.html +type SettingsService struct { + client *Client +} + +// Settings represents the GitLab application settings. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/settings.html +type Settings struct { + ID int `json:"id"` + CreatedAt *time.Time `json:"created_at"` + UpdatedAt *time.Time `json:"updated_at"` + AdminNotificationEmail string `json:"admin_notification_email"` + AfterSignOutPath string `json:"after_sign_out_path"` + AfterSignUpText string `json:"after_sign_up_text"` + AkismetAPIKey string `json:"akismet_api_key"` + AkismetEnabled bool `json:"akismet_enabled"` + CircuitbreakerAccessRetries int `json:"circuitbreaker_access_retries"` + CircuitbreakerBackoffThreshold int `json:"circuitbreaker_backoff_threshold"` + CircuitbreakerFailureCountThreshold int `json:"circuitbreaker_failure_count_threshold"` + CircuitbreakerFailureResetTime int `json:"circuitbreaker_failure_reset_time"` + CircuitbreakerFailureWaitTime int `json:"circuitbreaker_failure_wait_time"` + CircuitbreakerStorageTimeout int `json:"circuitbreaker_storage_timeout"` + ClientsideSentryDSN string `json:"clientside_sentry_dsn"` + ClientsideSentryEnabled bool `json:"clientside_sentry_enabled"` + ContainerRegistryTokenExpireDelay int `json:"container_registry_token_expire_delay"` + DefaultArtifactsExpireIn string `json:"default_artifacts_expire_in"` + DefaultBranchProtection int `json:"default_branch_protection"` + DefaultGroupVisibility string `json:"default_group_visibility"` + DefaultProjectVisibility string `json:"default_project_visibility"` + DefaultProjectsLimit int `json:"default_projects_limit"` + DefaultSnippetVisibility string `json:"default_snippet_visibility"` + DisabledOauthSignInSources []string `json:"disabled_oauth_sign_in_sources"` + DomainBlacklistEnabled bool `json:"domain_blacklist_enabled"` + DomainBlacklist []string `json:"domain_blacklist"` + DomainWhitelist []string `json:"domain_whitelist"` + DSAKeyRestriction int `json:"dsa_key_restriction"` + ECDSAKeyRestriction int `json:"ecdsa_key_restriction"` + Ed25519KeyRestriction int `json:"ed25519_key_restriction"` + EmailAuthorInBody bool `json:"email_author_in_body"` + EnabledGitAccessProtocol string `json:"enabled_git_access_protocol"` + GravatarEnabled bool `json:"gravatar_enabled"` + HelpPageHideCommercialContent bool `json:"help_page_hide_commercial_content"` + HelpPageSupportURL string `json:"help_page_support_url"` + HomePageURL string `json:"home_page_url"` + HousekeepingBitmapsEnabled bool `json:"housekeeping_bitmaps_enabled"` + HousekeepingEnabled bool `json:"housekeeping_enabled"` + HousekeepingFullRepackPeriod int `json:"housekeeping_full_repack_period"` + HousekeepingGcPeriod int `json:"housekeeping_gc_period"` + HousekeepingIncrementalRepackPeriod int `json:"housekeeping_incremental_repack_period"` + HTMLEmailsEnabled bool `json:"html_emails_enabled"` + ImportSources []string `json:"import_sources"` + KodingEnabled bool `json:"koding_enabled"` + KodingURL string `json:"koding_url"` + MaxArtifactsSize int `json:"max_artifacts_size"` + MaxAttachmentSize int `json:"max_attachment_size"` + MaxPagesSize int `json:"max_pages_size"` + MetricsEnabled bool `json:"metrics_enabled"` + MetricsHost string `json:"metrics_host"` + MetricsMethodCallThreshold int `json:"metrics_method_call_threshold"` + MetricsPacketSize int `json:"metrics_packet_size"` + MetricsPoolSize int `json:"metrics_pool_size"` + MetricsPort int `json:"metrics_port"` + MetricsSampleInterval int `json:"metrics_sample_interval"` + MetricsTimeout int `json:"metrics_timeout"` + PasswordAuthenticationEnabledForWeb bool `json:"password_authentication_enabled_for_web"` + PasswordAuthenticationEnabledForGit bool `json:"password_authentication_enabled_for_git"` + PerformanceBarAllowedGroupID string `json:"performance_bar_allowed_group_id"` + PerformanceBarEnabled bool `json:"performance_bar_enabled"` + PlantumlEnabled bool `json:"plantuml_enabled"` + PlantumlURL string `json:"plantuml_url"` + PollingIntervalMultiplier float64 `json:"polling_interval_multiplier"` + ProjectExportEnabled bool `json:"project_export_enabled"` + PrometheusMetricsEnabled bool `json:"prometheus_metrics_enabled"` + RecaptchaEnabled bool `json:"recaptcha_enabled"` + RecaptchaPrivateKey string `json:"recaptcha_private_key"` + RecaptchaSiteKey string `json:"recaptcha_site_key"` + RepositoryChecksEnabled bool `json:"repository_checks_enabled"` + RepositoryStorages []string `json:"repository_storages"` + RequireTwoFactorAuthentication bool `json:"require_two_factor_authentication"` + RestrictedVisibilityLevels []VisibilityValue `json:"restricted_visibility_levels"` + RsaKeyRestriction int `json:"rsa_key_restriction"` + SendUserConfirmationEmail bool `json:"send_user_confirmation_email"` + SentryDSN string `json:"sentry_dsn"` + SentryEnabled bool `json:"sentry_enabled"` + SessionExpireDelay int `json:"session_expire_delay"` + SharedRunnersEnabled bool `json:"shared_runners_enabled"` + SharedRunnersText string `json:"shared_runners_text"` + SidekiqThrottlingEnabled bool `json:"sidekiq_throttling_enabled"` + SidekiqThrottlingFactor float64 `json:"sidekiq_throttling_factor"` + SidekiqThrottlingQueues []string `json:"sidekiq_throttling_queues"` + SignInText string `json:"sign_in_text"` + SignupEnabled bool `json:"signup_enabled"` + TerminalMaxSessionTime int `json:"terminal_max_session_time"` + TwoFactorGracePeriod int `json:"two_factor_grace_period"` + UniqueIPsLimitEnabled bool `json:"unique_ips_limit_enabled"` + UniqueIPsLimitPerUser int `json:"unique_ips_limit_per_user"` + UniqueIPsLimitTimeWindow int `json:"unique_ips_limit_time_window"` + UsagePingEnabled bool `json:"usage_ping_enabled"` + UserDefaultExternal bool `json:"user_default_external"` + UserOauthApplications bool `json:"user_oauth_applications"` + VersionCheckEnabled bool `json:"version_check_enabled"` +} + +func (s Settings) String() string { + return Stringify(s) +} + +// GetSettings gets the current application settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/settings.html#get-current-application.settings +func (s *SettingsService) GetSettings(options ...OptionFunc) (*Settings, *Response, error) { + req, err := s.client.NewRequest("GET", "application/settings", nil, options) + if err != nil { + return nil, nil, err + } + + as := new(Settings) + resp, err := s.client.Do(req, as) + if err != nil { + return nil, resp, err + } + + return as, resp, err +} + +// UpdateSettingsOptions represents the available UpdateSettings() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/settings.html#change-application.settings +type UpdateSettingsOptions struct { + AdminNotificationEmail *string `url:"admin_notification_email,omitempty" json:"admin_notification_email,omitempty"` + AfterSignOutPath *string `url:"after_sign_out_path,omitempty" json:"after_sign_out_path,omitempty"` + AfterSignUpText *string `url:"after_sign_up_text,omitempty" json:"after_sign_up_text,omitempty"` + AkismetAPIKey *string `url:"akismet_api_key,omitempty" json:"akismet_api_key,omitempty"` + AkismetEnabled *bool `url:"akismet_enabled,omitempty" json:"akismet_enabled,omitempty"` + CircuitbreakerAccessRetries *int `url:"circuitbreaker_access_retries,omitempty" json:"circuitbreaker_access_retries,omitempty"` + CircuitbreakerBackoffThreshold *int `url:"circuitbreaker_backoff_threshold,omitempty" json:"circuitbreaker_backoff_threshold,omitempty"` + CircuitbreakerFailureCountThreshold *int `url:"circuitbreaker_failure_count_threshold,omitempty" json:"circuitbreaker_failure_count_threshold,omitempty"` + CircuitbreakerFailureResetTime *int `url:"circuitbreaker_failure_reset_time,omitempty" json:"circuitbreaker_failure_reset_time,omitempty"` + CircuitbreakerFailureWaitTime *int `url:"circuitbreaker_failure_wait_time,omitempty" json:"circuitbreaker_failure_wait_time,omitempty"` + CircuitbreakerStorageTimeout *int `url:"circuitbreaker_storage_timeout,omitempty" json:"circuitbreaker_storage_timeout,omitempty"` + ClientsideSentryDSN *string `url:"clientside_sentry_dsn,omitempty" json:"clientside_sentry_dsn,omitempty"` + ClientsideSentryEnabled *bool `url:"clientside_sentry_enabled,omitempty" json:"clientside_sentry_enabled,omitempty"` + ContainerRegistryTokenExpireDelay *int `url:"container_registry_token_expire_delay,omitempty" json:"container_registry_token_expire_delay,omitempty"` + DefaultArtifactsExpireIn *string `url:"default_artifacts_expire_in,omitempty" json:"default_artifacts_expire_in,omitempty"` + DefaultBranchProtection *int `url:"default_branch_protection,omitempty" json:"default_branch_protection,omitempty"` + DefaultGroupVisibility *string `url:"default_group_visibility,omitempty" json:"default_group_visibility,omitempty"` + DefaultProjectVisibility *string `url:"default_project_visibility,omitempty" json:"default_project_visibility,omitempty"` + DefaultProjectsLimit *int `url:"default_projects_limit,omitempty" json:"default_projects_limit,omitempty"` + DefaultSnippetVisibility *string `url:"default_snippet_visibility,omitempty" json:"default_snippet_visibility,omitempty"` + DisabledOauthSignInSources []string `url:"disabled_oauth_sign_in_sources,omitempty" json:"disabled_oauth_sign_in_sources,omitempty"` + DomainBlacklistEnabled *bool `url:"domain_blacklist_enabled,omitempty" json:"domain_blacklist_enabled,omitempty"` + DomainBlacklist []string `url:"domain_blacklist,omitempty" json:"domain_blacklist,omitempty"` + DomainWhitelist []string `url:"domain_whitelist,omitempty" json:"domain_whitelist,omitempty"` + DSAKeyRestriction *int `url:"dsa_key_restriction,omitempty" json:"dsa_key_restriction,omitempty"` + ECDSAKeyRestriction *int `url:"ecdsa_key_restriction,omitempty" json:"ecdsa_key_restriction,omitempty"` + Ed25519KeyRestriction *int `url:"ed25519_key_restriction,omitempty" json:"ed25519_key_restriction,omitempty"` + EmailAuthorInBody *bool `url:"email_author_in_body,omitempty" json:"email_author_in_body,omitempty"` + EnabledGitAccessProtocol *string `url:"enabled_git_access_protocol,omitempty" json:"enabled_git_access_protocol,omitempty"` + GravatarEnabled *bool `url:"gravatar_enabled,omitempty" json:"gravatar_enabled,omitempty"` + HelpPageHideCommercialContent *bool `url:"help_page_hide_commercial_content,omitempty" json:"help_page_hide_commercial_content,omitempty"` + HelpPageSupportURL *string `url:"help_page_support_url,omitempty" json:"help_page_support_url,omitempty"` + HomePageURL *string `url:"home_page_url,omitempty" json:"home_page_url,omitempty"` + HousekeepingBitmapsEnabled *bool `url:"housekeeping_bitmaps_enabled,omitempty" json:"housekeeping_bitmaps_enabled,omitempty"` + HousekeepingEnabled *bool `url:"housekeeping_enabled,omitempty" json:"housekeeping_enabled,omitempty"` + HousekeepingFullRepackPeriod *int `url:"housekeeping_full_repack_period,omitempty" json:"housekeeping_full_repack_period,omitempty"` + HousekeepingGcPeriod *int `url:"housekeeping_gc_period,omitempty" json:"housekeeping_gc_period,omitempty"` + HousekeepingIncrementalRepackPeriod *int `url:"housekeeping_incremental_repack_period,omitempty" json:"housekeeping_incremental_repack_period,omitempty"` + HTMLEmailsEnabled *bool `url:"html_emails_enabled,omitempty" json:"html_emails_enabled,omitempty"` + ImportSources []string `url:"import_sources,omitempty" json:"import_sources,omitempty"` + KodingEnabled *bool `url:"koding_enabled,omitempty" json:"koding_enabled,omitempty"` + KodingURL *string `url:"koding_url,omitempty" json:"koding_url,omitempty"` + MaxArtifactsSize *int `url:"max_artifacts_size,omitempty" json:"max_artifacts_size,omitempty"` + MaxAttachmentSize *int `url:"max_attachment_size,omitempty" json:"max_attachment_size,omitempty"` + MaxPagesSize *int `url:"max_pages_size,omitempty" json:"max_pages_size,omitempty"` + MetricsEnabled *bool `url:"metrics_enabled,omitempty" json:"metrics_enabled,omitempty"` + MetricsHost *string `url:"metrics_host,omitempty" json:"metrics_host,omitempty"` + MetricsMethodCallThreshold *int `url:"metrics_method_call_threshold,omitempty" json:"metrics_method_call_threshold,omitempty"` + MetricsPacketSize *int `url:"metrics_packet_size,omitempty" json:"metrics_packet_size,omitempty"` + MetricsPoolSize *int `url:"metrics_pool_size,omitempty" json:"metrics_pool_size,omitempty"` + MetricsPort *int `url:"metrics_port,omitempty" json:"metrics_port,omitempty"` + MetricsSampleInterval *int `url:"metrics_sample_interval,omitempty" json:"metrics_sample_interval,omitempty"` + MetricsTimeout *int `url:"metrics_timeout,omitempty" json:"metrics_timeout,omitempty"` + PasswordAuthenticationEnabledForWeb *bool `url:"password_authentication_enabled_for_web,omitempty" json:"password_authentication_enabled_for_web,omitempty"` + PasswordAuthenticationEnabledForGit *bool `url:"password_authentication_enabled_for_git,omitempty" json:"password_authentication_enabled_for_git,omitempty"` + PerformanceBarAllowedGroupID *string `url:"performance_bar_allowed_group_id,omitempty" json:"performance_bar_allowed_group_id,omitempty"` + PerformanceBarEnabled *bool `url:"performance_bar_enabled,omitempty" json:"performance_bar_enabled,omitempty"` + PlantumlEnabled *bool `url:"plantuml_enabled,omitempty" json:"plantuml_enabled,omitempty"` + PlantumlURL *string `url:"plantuml_url,omitempty" json:"plantuml_url,omitempty"` + PollingIntervalMultiplier *float64 `url:"polling_interval_multiplier,omitempty" json:"polling_interval_multiplier,omitempty"` + ProjectExportEnabled *bool `url:"project_export_enabled,omitempty" json:"project_export_enabled,omitempty"` + PrometheusMetricsEnabled *bool `url:"prometheus_metrics_enabled,omitempty" json:"prometheus_metrics_enabled,omitempty"` + RecaptchaEnabled *bool `url:"recaptcha_enabled,omitempty" json:"recaptcha_enabled,omitempty"` + RecaptchaPrivateKey *string `url:"recaptcha_private_key,omitempty" json:"recaptcha_private_key,omitempty"` + RecaptchaSiteKey *string `url:"recaptcha_site_key,omitempty" json:"recaptcha_site_key,omitempty"` + RepositoryChecksEnabled *bool `url:"repository_checks_enabled,omitempty" json:"repository_checks_enabled,omitempty"` + RepositoryStorages []string `url:"repository_storages,omitempty" json:"repository_storages,omitempty"` + RequireTwoFactorAuthentication *bool `url:"require_two_factor_authentication,omitempty" json:"require_two_factor_authentication,omitempty"` + RestrictedVisibilityLevels []VisibilityValue `url:"restricted_visibility_levels,omitempty" json:"restricted_visibility_levels,omitempty"` + RsaKeyRestriction *int `url:"rsa_key_restriction,omitempty" json:"rsa_key_restriction,omitempty"` + SendUserConfirmationEmail *bool `url:"send_user_confirmation_email,omitempty" json:"send_user_confirmation_email,omitempty"` + SentryDSN *string `url:"sentry_dsn,omitempty" json:"sentry_dsn,omitempty"` + SentryEnabled *bool `url:"sentry_enabled,omitempty" json:"sentry_enabled,omitempty"` + SessionExpireDelay *int `url:"session_expire_delay,omitempty" json:"session_expire_delay,omitempty"` + SharedRunnersEnabled *bool `url:"shared_runners_enabled,omitempty" json:"shared_runners_enabled,omitempty"` + SharedRunnersText *string `url:"shared_runners_text,omitempty" json:"shared_runners_text,omitempty"` + SidekiqThrottlingEnabled *bool `url:"sidekiq_throttling_enabled,omitempty" json:"sidekiq_throttling_enabled,omitempty"` + SidekiqThrottlingFactor *float64 `url:"sidekiq_throttling_factor,omitempty" json:"sidekiq_throttling_factor,omitempty"` + SidekiqThrottlingQueues []string `url:"sidekiq_throttling_queues,omitempty" json:"sidekiq_throttling_queues,omitempty"` + SignInText *string `url:"sign_in_text,omitempty" json:"sign_in_text,omitempty"` + SignupEnabled *bool `url:"signup_enabled,omitempty" json:"signup_enabled,omitempty"` + TerminalMaxSessionTime *int `url:"terminal_max_session_time,omitempty" json:"terminal_max_session_time,omitempty"` + TwoFactorGracePeriod *int `url:"two_factor_grace_period,omitempty" json:"two_factor_grace_period,omitempty"` + UniqueIPsLimitEnabled *bool `url:"unique_ips_limit_enabled,omitempty" json:"unique_ips_limit_enabled,omitempty"` + UniqueIPsLimitPerUser *int `url:"unique_ips_limit_per_user,omitempty" json:"unique_ips_limit_per_user,omitempty"` + UniqueIPsLimitTimeWindow *int `url:"unique_ips_limit_time_window,omitempty" json:"unique_ips_limit_time_window,omitempty"` + UsagePingEnabled *bool `url:"usage_ping_enabled,omitempty" json:"usage_ping_enabled,omitempty"` + UserDefaultExternal *bool `url:"user_default_external,omitempty" json:"user_default_external,omitempty"` + UserOauthApplications *bool `url:"user_oauth_applications,omitempty" json:"user_oauth_applications,omitempty"` + VersionCheckEnabled *bool `url:"version_check_enabled,omitempty" json:"version_check_enabled,omitempty"` +} + +// UpdateSettings updates the application settings. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/settings.html#change-application.settings +func (s *SettingsService) UpdateSettings(opt *UpdateSettingsOptions, options ...OptionFunc) (*Settings, *Response, error) { + req, err := s.client.NewRequest("PUT", "application/settings", opt, options) + if err != nil { + return nil, nil, err + } + + as := new(Settings) + resp, err := s.client.Do(req, as) + if err != nil { + return nil, resp, err + } + + return as, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/sidekiq_metrics.go b/vendor/github.com/xanzy/go-gitlab/sidekiq_metrics.go new file mode 100644 index 00000000..83e77024 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/sidekiq_metrics.go @@ -0,0 +1,154 @@ +// +// Copyright 2018, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import "time" + +// SidekiqService handles communication with the sidekiq service +// +// GitLab API docs: https://docs.gitlab.com/ce/api/sidekiq_metrics.html +type SidekiqService struct { + client *Client +} + +// QueueMetrics represents the GitLab sidekiq queue metrics. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-queue-metrics +type QueueMetrics struct { + Queues map[string]struct { + Backlog int `json:"backlog"` + Latency int `json:"latency"` + } `json:"queues"` +} + +// GetQueueMetrics lists information about all the registered queues, +// their backlog and their latency. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-queue-metrics +func (s *SidekiqService) GetQueueMetrics(options ...OptionFunc) (*QueueMetrics, *Response, error) { + req, err := s.client.NewRequest("GET", "/sidekiq/queue_metrics", nil, options) + if err != nil { + return nil, nil, err + } + + q := new(QueueMetrics) + resp, err := s.client.Do(req, q) + if err != nil { + return nil, resp, err + } + + return q, resp, err +} + +// ProcessMetrics represents the GitLab sidekiq process metrics. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-process-metrics +type ProcessMetrics struct { + Processes []struct { + Hostname string `json:"hostname"` + Pid int `json:"pid"` + Tag string `json:"tag"` + StartedAt *time.Time `json:"started_at"` + Queues []string `json:"queues"` + Labels []string `json:"labels"` + Concurrency int `json:"concurrency"` + Busy int `json:"busy"` + } `json:"processes"` +} + +// GetProcessMetrics lists information about all the Sidekiq workers registered +// to process your queues. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-process-metrics +func (s *SidekiqService) GetProcessMetrics(options ...OptionFunc) (*ProcessMetrics, *Response, error) { + req, err := s.client.NewRequest("GET", "/sidekiq/process_metrics", nil, options) + if err != nil { + return nil, nil, err + } + + p := new(ProcessMetrics) + resp, err := s.client.Do(req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, err +} + +// JobStats represents the GitLab sidekiq job stats. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-job-statistics +type JobStats struct { + Jobs struct { + Processed int `json:"processed"` + Failed int `json:"failed"` + Enqueued int `json:"enqueued"` + } `json:"jobs"` +} + +// GetJobStats list information about the jobs that Sidekiq has performed. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-job-statistics +func (s *SidekiqService) GetJobStats(options ...OptionFunc) (*JobStats, *Response, error) { + req, err := s.client.NewRequest("GET", "/sidekiq/job_stats", nil, options) + if err != nil { + return nil, nil, err + } + + j := new(JobStats) + resp, err := s.client.Do(req, j) + if err != nil { + return nil, resp, err + } + + return j, resp, err +} + +// CompoundMetrics represents the GitLab sidekiq compounded stats. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-a-compound-response-of-all-the-previously-mentioned-metrics +type CompoundMetrics struct { + QueueMetrics + ProcessMetrics + JobStats +} + +// GetCompoundMetrics lists all the currently available information about Sidekiq. +// Get a compound response of all the previously mentioned metrics +// +// GitLab API docs: https://docs.gitlab.com/ce/api/sidekiq_metrics.html#get-the-current-job-statistics +func (s *SidekiqService) GetCompoundMetrics(options ...OptionFunc) (*CompoundMetrics, *Response, error) { + req, err := s.client.NewRequest("GET", "/sidekiq/compound_metrics", nil, options) + if err != nil { + return nil, nil, err + } + + c := new(CompoundMetrics) + resp, err := s.client.Do(req, c) + if err != nil { + return nil, resp, err + } + + return c, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/snippets.go b/vendor/github.com/xanzy/go-gitlab/snippets.go new file mode 100644 index 00000000..be232c8c --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/snippets.go @@ -0,0 +1,230 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "bytes" + "fmt" + "time" +) + +// SnippetsService handles communication with the snippets +// related methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html +type SnippetsService struct { + client *Client +} + +// Snippet represents a GitLab snippet. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html +type Snippet struct { + ID int `json:"id"` + Title string `json:"title"` + FileName string `json:"file_name"` + Description string `json:"description"` + Author struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + } `json:"author"` + UpdatedAt *time.Time `json:"updated_at"` + CreatedAt *time.Time `json:"created_at"` + WebURL string `json:"web_url"` + RawURL string `json:"raw_url"` +} + +func (s Snippet) String() string { + return Stringify(s) +} + +// ListSnippetsOptions represents the available ListSnippets() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html#list-snippets +type ListSnippetsOptions ListOptions + +// ListSnippets gets a list of snippets. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/snippets.html#list-snippets +func (s *SnippetsService) ListSnippets(opt *ListSnippetsOptions, options ...OptionFunc) ([]*Snippet, *Response, error) { + req, err := s.client.NewRequest("GET", "snippets", opt, options) + if err != nil { + return nil, nil, err + } + + var ps []*Snippet + resp, err := s.client.Do(req, &ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} + +// GetSnippet gets a single snippet +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/snippets.html#single-snippet +func (s *SnippetsService) GetSnippet(snippet int, options ...OptionFunc) (*Snippet, *Response, error) { + u := fmt.Sprintf("snippets/%d", snippet) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + ps := new(Snippet) + resp, err := s.client.Do(req, ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} + +// CreateSnippetOptions represents the available CreateSnippet() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/snippets.html#create-new-snippet +type CreateSnippetOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + Content *string `url:"content,omitempty" json:"content,omitempty"` + Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` +} + +// CreateSnippet creates a new snippet. The user must have permission +// to create new snippets. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/snippets.html#create-new-snippet +func (s *SnippetsService) CreateSnippet(opt *CreateSnippetOptions, options ...OptionFunc) (*Snippet, *Response, error) { + req, err := s.client.NewRequest("POST", "snippets", opt, options) + if err != nil { + return nil, nil, err + } + + ps := new(Snippet) + resp, err := s.client.Do(req, ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} + +// UpdateSnippetOptions represents the available UpdateSnippet() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/snippets.html#update-snippet +type UpdateSnippetOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + FileName *string `url:"file_name,omitempty" json:"file_name,omitempty"` + Description *string `url:"description,omitempty" json:"description,omitempty"` + Content *string `url:"content,omitempty" json:"content,omitempty"` + Visibility *VisibilityValue `url:"visibility,omitempty" json:"visibility,omitempty"` +} + +// UpdateSnippet updates an existing snippet. The user must have +// permission to change an existing snippet. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/snippets.html#update-snippet +func (s *SnippetsService) UpdateSnippet(snippet int, opt *UpdateSnippetOptions, options ...OptionFunc) (*Snippet, *Response, error) { + u := fmt.Sprintf("snippets/%d", snippet) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + ps := new(Snippet) + resp, err := s.client.Do(req, ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} + +// DeleteSnippet deletes an existing snippet. This is an idempotent +// function and deleting a non-existent snippet still returns a 200 OK status +// code. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/snippets.html#delete-snippet +func (s *SnippetsService) DeleteSnippet(snippet int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("snippets/%d", snippet) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// SnippetContent returns the raw snippet as plain text. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/snippets.html#snippet-content +func (s *SnippetsService) SnippetContent(snippet int, options ...OptionFunc) ([]byte, *Response, error) { + u := fmt.Sprintf("snippets/%d/raw", snippet) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var b bytes.Buffer + resp, err := s.client.Do(req, &b) + if err != nil { + return nil, resp, err + } + + return b.Bytes(), resp, err +} + +// ExploreSnippetsOptions represents the available ExploreSnippets() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/snippets.html#explore-all-public-snippets +type ExploreSnippetsOptions ListOptions + +// ExploreSnippets gets the list of public snippets. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/snippets.html#explore-all-public-snippets +func (s *SnippetsService) ExploreSnippets(opt *ExploreSnippetsOptions, options ...OptionFunc) ([]*Snippet, *Response, error) { + req, err := s.client.NewRequest("GET", "snippets/public", nil, options) + if err != nil { + return nil, nil, err + } + + var ps []*Snippet + resp, err := s.client.Do(req, &ps) + if err != nil { + return nil, resp, err + } + + return ps, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/strings.go b/vendor/github.com/xanzy/go-gitlab/strings.go new file mode 100644 index 00000000..aeefb6b8 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/strings.go @@ -0,0 +1,94 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "bytes" + "fmt" + + "reflect" +) + +// Stringify attempts to create a reasonable string representation of types in +// the GitHub library. It does things like resolve pointers to their values +// and omits struct fields with nil values. +func Stringify(message interface{}) string { + var buf bytes.Buffer + v := reflect.ValueOf(message) + stringifyValue(&buf, v) + return buf.String() +} + +// stringifyValue was heavily inspired by the goprotobuf library. +func stringifyValue(buf *bytes.Buffer, val reflect.Value) { + if val.Kind() == reflect.Ptr && val.IsNil() { + buf.WriteString("") + return + } + + v := reflect.Indirect(val) + + switch v.Kind() { + case reflect.String: + fmt.Fprintf(buf, `"%s"`, v) + case reflect.Slice: + buf.WriteByte('[') + for i := 0; i < v.Len(); i++ { + if i > 0 { + buf.WriteByte(' ') + } + + stringifyValue(buf, v.Index(i)) + } + + buf.WriteByte(']') + return + case reflect.Struct: + if v.Type().Name() != "" { + buf.WriteString(v.Type().String()) + } + + buf.WriteByte('{') + + var sep bool + for i := 0; i < v.NumField(); i++ { + fv := v.Field(i) + if fv.Kind() == reflect.Ptr && fv.IsNil() { + continue + } + if fv.Kind() == reflect.Slice && fv.IsNil() { + continue + } + + if sep { + buf.WriteString(", ") + } else { + sep = true + } + + buf.WriteString(v.Type().Field(i).Name) + buf.WriteByte(':') + stringifyValue(buf, fv) + } + + buf.WriteByte('}') + default: + if v.CanInterface() { + fmt.Fprint(buf, v.Interface()) + } + } +} diff --git a/vendor/github.com/xanzy/go-gitlab/system_hooks.go b/vendor/github.com/xanzy/go-gitlab/system_hooks.go new file mode 100644 index 00000000..d5209d4f --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/system_hooks.go @@ -0,0 +1,143 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "time" +) + +// SystemHooksService handles communication with the system hooks related +// methods of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html +type SystemHooksService struct { + client *Client +} + +// Hook represents a GitLap system hook. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html +type Hook struct { + ID int `json:"id"` + URL string `json:"url"` + CreatedAt *time.Time `json:"created_at"` +} + +func (h Hook) String() string { + return Stringify(h) +} + +// ListHooks gets a list of system hooks. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/system_hooks.html#list-system-hooks +func (s *SystemHooksService) ListHooks(options ...OptionFunc) ([]*Hook, *Response, error) { + req, err := s.client.NewRequest("GET", "hooks", nil, options) + if err != nil { + return nil, nil, err + } + + var h []*Hook + resp, err := s.client.Do(req, &h) + if err != nil { + return nil, resp, err + } + + return h, resp, err +} + +// AddHookOptions represents the available AddHook() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/system_hooks.html#add-new-system-hook-hook +type AddHookOptions struct { + URL *string `url:"url,omitempty" json:"url,omitempty"` +} + +// AddHook adds a new system hook hook. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/system_hooks.html#add-new-system-hook-hook +func (s *SystemHooksService) AddHook(opt *AddHookOptions, options ...OptionFunc) (*Hook, *Response, error) { + req, err := s.client.NewRequest("POST", "hooks", opt, options) + if err != nil { + return nil, nil, err + } + + h := new(Hook) + resp, err := s.client.Do(req, h) + if err != nil { + return nil, resp, err + } + + return h, resp, err +} + +// HookEvent represents an event trigger by a GitLab system hook. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/system_hooks.html +type HookEvent struct { + EventName string `json:"event_name"` + Name string `json:"name"` + Path string `json:"path"` + ProjectID int `json:"project_id"` + OwnerName string `json:"owner_name"` + OwnerEmail string `json:"owner_email"` +} + +func (h HookEvent) String() string { + return Stringify(h) +} + +// TestHook tests a system hook. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/system_hooks.html#test-system-hook +func (s *SystemHooksService) TestHook(hook int, options ...OptionFunc) (*HookEvent, *Response, error) { + u := fmt.Sprintf("hooks/%d", hook) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + h := new(HookEvent) + resp, err := s.client.Do(req, h) + if err != nil { + return nil, resp, err + } + + return h, resp, err +} + +// DeleteHook deletes a system hook. This is an idempotent API function and +// returns 200 OK even if the hook is not available. If the hook is deleted it +// is also returned as JSON. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/system_hooks.html#delete-system-hook +func (s *SystemHooksService) DeleteHook(hook int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("hooks/%d", hook) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/tags.go b/vendor/github.com/xanzy/go-gitlab/tags.go new file mode 100644 index 00000000..b726410e --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/tags.go @@ -0,0 +1,232 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "fmt" + "net/url" +) + +// TagsService handles communication with the tags related methods +// of the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/tags.html +type TagsService struct { + client *Client +} + +// Tag represents a GitLab tag. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/tags.html +type Tag struct { + Commit *Commit `json:"commit"` + Release *Release `json:"release"` + Name string `json:"name"` + Message string `json:"message"` +} + +// Release represents a GitLab version release. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/tags.html +type Release struct { + TagName string `json:"tag_name"` + Description string `json:"description"` +} + +func (t Tag) String() string { + return Stringify(t) +} + +// ListTagsOptions represents the available ListTags() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/tags.html#list-project-repository-tags +type ListTagsOptions ListOptions + +// ListTags gets a list of tags from a project, sorted by name in reverse +// alphabetical order. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/tags.html#list-project-repository-tags +func (s *TagsService) ListTags(pid interface{}, opt *ListTagsOptions, options ...OptionFunc) ([]*Tag, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/tags", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var t []*Tag + resp, err := s.client.Do(req, &t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// GetTag a specific repository tag determined by its name. It returns 200 together +// with the tag information if the tag exists. It returns 404 if the tag does not exist. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/tags.html#get-a-single-repository-tag +func (s *TagsService) GetTag(pid interface{}, tag string, options ...OptionFunc) (*Tag, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/tags/%s", url.QueryEscape(project), tag) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var t *Tag + resp, err := s.client.Do(req, &t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// CreateTagOptions represents the available CreateTag() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/tags.html#create-a-new-tag +type CreateTagOptions struct { + TagName *string `url:"tag_name,omitempty" json:"tag_name,omitempty"` + Ref *string `url:"ref,omitempty" json:"ref,omitempty"` + Message *string `url:"message,omitempty" json:"message,omitempty"` + ReleaseDescription *string `url:"release_description:omitempty" json:"release_description,omitempty"` +} + +// CreateTag creates a new tag in the repository that points to the supplied ref. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/tags.html#create-a-new-tag +func (s *TagsService) CreateTag(pid interface{}, opt *CreateTagOptions, options ...OptionFunc) (*Tag, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/tags", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + t := new(Tag) + resp, err := s.client.Do(req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// DeleteTag deletes a tag of a repository with given name. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/tags.html#delete-a-tag +func (s *TagsService) DeleteTag(pid interface{}, tag string, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/repository/tags/%s", url.QueryEscape(project), tag) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// CreateReleaseOptions represents the available CreateRelease() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/tags.html#create-a-new-release +type CreateReleaseOptions struct { + Description *string `url:"description:omitempty" json:"description,omitempty"` +} + +// CreateRelease Add release notes to the existing git tag. +// If there already exists a release for the given tag, status code 409 is returned. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/tags.html#create-a-new-release +func (s *TagsService) CreateRelease(pid interface{}, tag string, opt *CreateReleaseOptions, options ...OptionFunc) (*Release, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/tags/%s/release", url.QueryEscape(project), tag) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + r := new(Release) + resp, err := s.client.Do(req, r) + if err != nil { + return nil, resp, err + } + + return r, resp, err +} + +// UpdateReleaseOptions represents the available UpdateRelease() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/tags.html#update-a-release +type UpdateReleaseOptions struct { + Description *string `url:"description:omitempty" json:"description,omitempty"` +} + +// UpdateRelease Updates the release notes of a given release. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/tags.html#update-a-release +func (s *TagsService) UpdateRelease(pid interface{}, tag string, opt *UpdateReleaseOptions, options ...OptionFunc) (*Release, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/repository/tags/%s/release", url.QueryEscape(project), tag) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + r := new(Release) + resp, err := s.client.Do(req, r) + if err != nil { + return nil, resp, err + } + + return r, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/time_stats.go b/vendor/github.com/xanzy/go-gitlab/time_stats.go new file mode 100644 index 00000000..5e3bff90 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/time_stats.go @@ -0,0 +1,163 @@ +package gitlab + +import ( + "fmt" + "net/url" +) + +// timeStatsService handles communication with the time tracking related +// methods of the GitLab API. +// +// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html +type timeStatsService struct { + client *Client +} + +// TimeStats represents the time estimates and time spent for an issue. +// +// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html +type TimeStats struct { + HumanTimeEstimate string `json:"human_time_estimate"` + HumanTotalTimeSpent string `json:"human_total_time_spent"` + TimeEstimate int `json:"time_estimate"` + TotalTimeSpent int `json:"total_time_spent"` +} + +func (t TimeStats) String() string { + return Stringify(t) +} + +// SetTimeEstimateOptions represents the available SetTimeEstimate() +// options. +// +// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html +type SetTimeEstimateOptions struct { + Duration *string `url:"duration,omitempty" json:"duration,omitempty"` +} + +// setTimeEstimate sets the time estimate for a single project issue. +// +// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html +func (s *timeStatsService) setTimeEstimate(pid interface{}, entity string, issue int, opt *SetTimeEstimateOptions, options ...OptionFunc) (*TimeStats, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/time_estimate", url.QueryEscape(project), entity, issue) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + t := new(TimeStats) + resp, err := s.client.Do(req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// resetTimeEstimate resets the time estimate for a single project issue. +// +// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html +func (s *timeStatsService) resetTimeEstimate(pid interface{}, entity string, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/reset_time_estimate", url.QueryEscape(project), entity, issue) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + t := new(TimeStats) + resp, err := s.client.Do(req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// AddSpentTimeOptions represents the available AddSpentTime() options. +// +// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html +type AddSpentTimeOptions struct { + Duration *string `url:"duration,omitempty" json:"duration,omitempty"` +} + +// addSpentTime adds spent time for a single project issue. +// +// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html +func (s *timeStatsService) addSpentTime(pid interface{}, entity string, issue int, opt *AddSpentTimeOptions, options ...OptionFunc) (*TimeStats, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/add_spent_time", url.QueryEscape(project), entity, issue) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + t := new(TimeStats) + resp, err := s.client.Do(req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// resetSpentTime resets the spent time for a single project issue. +// +// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html +func (s *timeStatsService) resetSpentTime(pid interface{}, entity string, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/reset_spent_time", url.QueryEscape(project), entity, issue) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, nil, err + } + + t := new(TimeStats) + resp, err := s.client.Do(req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// getTimeSpent gets the spent time for a single project issue. +// +// GitLab docs: https://docs.gitlab.com/ce/workflow/time_tracking.html +func (s *timeStatsService) getTimeSpent(pid interface{}, entity string, issue int, options ...OptionFunc) (*TimeStats, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/%s/%d/time_stats", url.QueryEscape(project), entity, issue) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + t := new(TimeStats) + resp, err := s.client.Do(req, t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/todos.go b/vendor/github.com/xanzy/go-gitlab/todos.go new file mode 100644 index 00000000..db58eddb --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/todos.go @@ -0,0 +1,175 @@ +package gitlab + +import "time" +import "fmt" + +// TodosService handles communication with the todos related methods of +// the Gitlab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html +type TodosService struct { + client *Client +} + +// TodoAction represents the available actions that can be performed on a todo. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html +type TodoAction string + +// The available todo actions. +const ( + TodoAssigned TodoAction = "assigned" + TodoMentioned TodoAction = "mentioned" + TodoBuildFailed TodoAction = "build_failed" + TodoMarked TodoAction = "marked" + TodoApprovalRequired TodoAction = "approval_required" + TodoDirectlyAddressed TodoAction = "directly_addressed" +) + +// TodoTarget represents a todo target of type Issue or MergeRequest +type TodoTarget struct { + // TODO: replace both Assignee and Author structs with v4 User struct + Assignee struct { + Name string `json:"name"` + Username string `json:"username"` + ID int `json:"id"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + } `json:"assignee"` + Author struct { + Name string `json:"name"` + Username string `json:"username"` + ID int `json:"id"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + } `json:"author"` + CreatedAt *time.Time `json:"created_at"` + Description string `json:"description"` + Downvotes int `json:"downvotes"` + ID int `json:"id"` + IID int `json:"iid"` + Labels []string `json:"labels"` + Milestone Milestone `json:"milestone"` + ProjectID int `json:"project_id"` + State string `json:"state"` + Subscribed bool `json:"subscribed"` + Title string `json:"title"` + UpdatedAt *time.Time `json:"updated_at"` + Upvotes int `json:"upvotes"` + UserNotesCount int `json:"user_notes_count"` + WebURL string `json:"web_url"` + + // Only available for type Issue + Confidential bool `json:"confidential"` + DueDate string `json:"due_date"` + Weight int `json:"weight"` + + // Only available for type MergeRequest + ApprovalsBeforeMerge bool `json:"approvals_before_merge"` + ForceRemoveSourceBranch bool `json:"force_remove_source_branch"` + MergeCommitSha string `json:"merge_commit_sha"` + MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"` + MergeStatus string `json:"merge_status"` + Sha string `json:"sha"` + ShouldRemoveSourceBranch bool `json:"should_remove_source_branch"` + SourceBranch string `json:"source_branch"` + SourceProjectID int `json:"source_project_id"` + Squash bool `json:"squash"` + TargetBranch string `json:"target_branch"` + TargetProjectID int `json:"target_project_id"` + WorkInProgress bool `json:"work_in_progress"` +} + +// Todo represents a GitLab todo. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html +type Todo struct { + ID int `json:"id"` + Project struct { + ID int `json:"id"` + HTTPURLToRepo string `json:"http_url_to_repo"` + WebURL string `json:"web_url"` + Name string `json:"name"` + NameWithNamespace string `json:"name_with_namespace"` + Path string `json:"path"` + PathWithNamespace string `json:"path_with_namespace"` + } `json:"project"` + Author struct { + ID int `json:"id"` + Name string `json:"name"` + Username string `json:"username"` + State string `json:"state"` + AvatarURL string `json:"avatar_url"` + WebURL string `json:"web_url"` + } `json:"author"` + ActionName TodoAction `json:"action_name"` + TargetType string `json:"target_type"` + Target TodoTarget `json:"target"` + TargetURL string `json:"target_url"` + Body string `json:"body"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` +} + +func (t Todo) String() string { + return Stringify(t) +} + +// ListTodosOptions represents the available ListTodos() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#get-a-list-of-todos +type ListTodosOptions struct { + Action *TodoAction `url:"action,omitempty" json:"action,omitempty"` + AuthorID *int `url:"author_id,omitempty" json:"author_id,omitempty"` + ProjectID *int `url:"project_id,omitempty" json:"project_id,omitempty"` + State *string `url:"state,omitempty" json:"state,omitempty"` + Type *string `url:"type,omitempty" json:"type,omitempty"` +} + +// ListTodos lists all todos created by authenticated user. +// When no filter is applied, it returns all pending todos for the current user. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/todos.html#get-a-list-of-todos +func (s *TodosService) ListTodos(opt *ListTodosOptions, options ...OptionFunc) ([]*Todo, *Response, error) { + req, err := s.client.NewRequest("GET", "todos", opt, options) + if err != nil { + return nil, nil, err + } + + var t []*Todo + resp, err := s.client.Do(req, &t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// MarkTodoAsDone marks a single pending todo given by its ID for the current user as done. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#mark-a-todo-as-done +func (s *TodosService) MarkTodoAsDone(id int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("todos/%d/mark_as_done", id) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// MarkAllTodosAsDone marks all pending todos for the current user as done. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#mark-all-todos-as-done +func (s *TodosService) MarkAllTodosAsDone(options ...OptionFunc) (*Response, error) { + req, err := s.client.NewRequest("POST", "todos/mark_as_done", nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/vendor/github.com/xanzy/go-gitlab/users.go b/vendor/github.com/xanzy/go-gitlab/users.go new file mode 100644 index 00000000..a619ab03 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/users.go @@ -0,0 +1,767 @@ +// +// Copyright 2017, Sander van Harmelen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +import ( + "errors" + "fmt" + "time" +) + +// UsersService handles communication with the user related methods of +// the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html +type UsersService struct { + client *Client +} + +// User represents a GitLab user. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html +type User struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` + Name string `json:"name"` + State string `json:"state"` + CreatedAt *time.Time `json:"created_at"` + Bio string `json:"bio"` + Location string `json:"location"` + Skype string `json:"skype"` + Linkedin string `json:"linkedin"` + Twitter string `json:"twitter"` + WebsiteURL string `json:"website_url"` + Organization string `json:"organization"` + ExternUID string `json:"extern_uid"` + Provider string `json:"provider"` + ThemeID int `json:"theme_id"` + LastActivityOn *ISOTime `json:"last_activity_on"` + ColorSchemeID int `json:"color_scheme_id"` + IsAdmin bool `json:"is_admin"` + AvatarURL string `json:"avatar_url"` + CanCreateGroup bool `json:"can_create_group"` + CanCreateProject bool `json:"can_create_project"` + ProjectsLimit int `json:"projects_limit"` + CurrentSignInAt *time.Time `json:"current_sign_in_at"` + LastSignInAt *time.Time `json:"last_sign_in_at"` + TwoFactorEnabled bool `json:"two_factor_enabled"` + Identities []*UserIdentity `json:"identities"` + External bool `json:"external"` +} + +// UserIdentity represents a user identity. +type UserIdentity struct { + Provider string `json:"provider"` + ExternUID string `json:"extern_uid"` +} + +// ListUsersOptions represents the available ListUsers() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-users +type ListUsersOptions struct { + ListOptions + Active *bool `url:"active,omitempty" json:"active,omitempty"` + Blocked *bool `url:"blocked,omitempty" json:"blocked,omitempty"` + + // The options below are only available for admins. + Search *string `url:"search,omitempty" json:"search,omitempty"` + Username *string `url:"username,omitempty" json:"username,omitempty"` + ExternalUID *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"` + Provider *string `url:"provider,omitempty" json:"provider,omitempty"` + CreatedBefore *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"` + CreatedAfter *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"` + OrderBy *string `url:"order_by,omitempty" json:"order_by,omitempty"` + Sort *string `url:"sort,omitempty" json:"sort,omitempty"` +} + +// ListUsers gets a list of users. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-users +func (s *UsersService) ListUsers(opt *ListUsersOptions, options ...OptionFunc) ([]*User, *Response, error) { + req, err := s.client.NewRequest("GET", "users", opt, options) + if err != nil { + return nil, nil, err + } + + var usr []*User + resp, err := s.client.Do(req, &usr) + if err != nil { + return nil, resp, err + } + + return usr, resp, err +} + +// GetUser gets a single user. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-user +func (s *UsersService) GetUser(user int, options ...OptionFunc) (*User, *Response, error) { + u := fmt.Sprintf("users/%d", user) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + usr := new(User) + resp, err := s.client.Do(req, usr) + if err != nil { + return nil, resp, err + } + + return usr, resp, err +} + +// CreateUserOptions represents the available CreateUser() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-creation +type CreateUserOptions struct { + Email *string `url:"email,omitempty" json:"email,omitempty"` + Password *string `url:"password,omitempty" json:"password,omitempty"` + ResetPassword *bool `url:"reset_password,omitempty" json:"reset_password,omitempty"` + Username *string `url:"username,omitempty" json:"username,omitempty"` + Name *string `url:"name,omitempty" json:"name,omitempty"` + Skype *string `url:"skype,omitempty" json:"skype,omitempty"` + Linkedin *string `url:"linkedin,omitempty" json:"linkedin,omitempty"` + Twitter *string `url:"twitter,omitempty" json:"twitter,omitempty"` + WebsiteURL *string `url:"website_url,omitempty" json:"website_url,omitempty"` + Organization *string `url:"organization,omitempty" json:"organization,omitempty"` + ProjectsLimit *int `url:"projects_limit,omitempty" json:"projects_limit,omitempty"` + ExternUID *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"` + Provider *string `url:"provider,omitempty" json:"provider,omitempty"` + Bio *string `url:"bio,omitempty" json:"bio,omitempty"` + Location *string `url:"location,omitempty" json:"location,omitempty"` + Admin *bool `url:"admin,omitempty" json:"admin,omitempty"` + CanCreateGroup *bool `url:"can_create_group,omitempty" json:"can_create_group,omitempty"` + SkipConfirmation *bool `url:"skip_confirmation,omitempty" json:"skip_confirmation,omitempty"` + External *bool `url:"external,omitempty" json:"external,omitempty"` +} + +// CreateUser creates a new user. Note only administrators can create new users. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-creation +func (s *UsersService) CreateUser(opt *CreateUserOptions, options ...OptionFunc) (*User, *Response, error) { + req, err := s.client.NewRequest("POST", "users", opt, options) + if err != nil { + return nil, nil, err + } + + usr := new(User) + resp, err := s.client.Do(req, usr) + if err != nil { + return nil, resp, err + } + + return usr, resp, err +} + +// ModifyUserOptions represents the available ModifyUser() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-modification +type ModifyUserOptions struct { + Email *string `url:"email,omitempty" json:"email,omitempty"` + Password *string `url:"password,omitempty" json:"password,omitempty"` + Username *string `url:"username,omitempty" json:"username,omitempty"` + Name *string `url:"name,omitempty" json:"name,omitempty"` + Skype *string `url:"skype,omitempty" json:"skype,omitempty"` + Linkedin *string `url:"linkedin,omitempty" json:"linkedin,omitempty"` + Twitter *string `url:"twitter,omitempty" json:"twitter,omitempty"` + WebsiteURL *string `url:"website_url,omitempty" json:"website_url,omitempty"` + Organization *string `url:"organization,omitempty" json:"organization,omitempty"` + ProjectsLimit *int `url:"projects_limit,omitempty" json:"projects_limit,omitempty"` + ExternUID *string `url:"extern_uid,omitempty" json:"extern_uid,omitempty"` + Provider *string `url:"provider,omitempty" json:"provider,omitempty"` + Bio *string `url:"bio,omitempty" json:"bio,omitempty"` + Location *string `url:"location,omitempty" json:"location,omitempty"` + Admin *bool `url:"admin,omitempty" json:"admin,omitempty"` + CanCreateGroup *bool `url:"can_create_group,omitempty" json:"can_create_group,omitempty"` + SkipReconfirmation *bool `url:"skip_reconfirmation,omitempty" json:"skip_reconfirmation,omitempty"` + External *bool `url:"external,omitempty" json:"external,omitempty"` +} + +// ModifyUser modifies an existing user. Only administrators can change attributes +// of a user. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-modification +func (s *UsersService) ModifyUser(user int, opt *ModifyUserOptions, options ...OptionFunc) (*User, *Response, error) { + u := fmt.Sprintf("users/%d", user) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + usr := new(User) + resp, err := s.client.Do(req, usr) + if err != nil { + return nil, resp, err + } + + return usr, resp, err +} + +// DeleteUser deletes a user. Available only for administrators. This is an +// idempotent function, calling this function for a non-existent user id still +// returns a status code 200 OK. The JSON response differs if the user was +// actually deleted or not. In the former the user is returned and in the +// latter not. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#user-deletion +func (s *UsersService) DeleteUser(user int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("users/%d", user) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// CurrentUser gets currently authenticated user. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#current-user +func (s *UsersService) CurrentUser(options ...OptionFunc) (*User, *Response, error) { + req, err := s.client.NewRequest("GET", "user", nil, options) + if err != nil { + return nil, nil, err + } + + usr := new(User) + resp, err := s.client.Do(req, usr) + if err != nil { + return nil, resp, err + } + + return usr, resp, err +} + +// SSHKey represents a SSH key. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-ssh-keys +type SSHKey struct { + ID int `json:"id"` + Title string `json:"title"` + Key string `json:"key"` + CreatedAt *time.Time `json:"created_at"` +} + +// ListSSHKeys gets a list of currently authenticated user's SSH keys. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-ssh-keys +func (s *UsersService) ListSSHKeys(options ...OptionFunc) ([]*SSHKey, *Response, error) { + req, err := s.client.NewRequest("GET", "user/keys", nil, options) + if err != nil { + return nil, nil, err + } + + var k []*SSHKey + resp, err := s.client.Do(req, &k) + if err != nil { + return nil, resp, err + } + + return k, resp, err +} + +// ListSSHKeysForUserOptions represents the available ListSSHKeysForUser() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#list-ssh-keys-for-user +type ListSSHKeysForUserOptions ListOptions + +// ListSSHKeysForUser gets a list of a specified user's SSH keys. Available +// only for admin +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#list-ssh-keys-for-user +func (s *UsersService) ListSSHKeysForUser(user int, opt *ListSSHKeysForUserOptions, options ...OptionFunc) ([]*SSHKey, *Response, error) { + u := fmt.Sprintf("users/%d/keys", user) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var k []*SSHKey + resp, err := s.client.Do(req, &k) + if err != nil { + return nil, resp, err + } + + return k, resp, err +} + +// GetSSHKey gets a single key. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-ssh-key +func (s *UsersService) GetSSHKey(key int, options ...OptionFunc) (*SSHKey, *Response, error) { + u := fmt.Sprintf("user/keys/%d", key) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + k := new(SSHKey) + resp, err := s.client.Do(req, k) + if err != nil { + return nil, resp, err + } + + return k, resp, err +} + +// AddSSHKeyOptions represents the available AddSSHKey() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#add-ssh-key +type AddSSHKeyOptions struct { + Title *string `url:"title,omitempty" json:"title,omitempty"` + Key *string `url:"key,omitempty" json:"key,omitempty"` +} + +// AddSSHKey creates a new key owned by the currently authenticated user. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-ssh-key +func (s *UsersService) AddSSHKey(opt *AddSSHKeyOptions, options ...OptionFunc) (*SSHKey, *Response, error) { + req, err := s.client.NewRequest("POST", "user/keys", opt, options) + if err != nil { + return nil, nil, err + } + + k := new(SSHKey) + resp, err := s.client.Do(req, k) + if err != nil { + return nil, resp, err + } + + return k, resp, err +} + +// AddSSHKeyForUser creates new key owned by specified user. Available only for +// admin. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-ssh-key-for-user +func (s *UsersService) AddSSHKeyForUser(user int, opt *AddSSHKeyOptions, options ...OptionFunc) (*SSHKey, *Response, error) { + u := fmt.Sprintf("users/%d/keys", user) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + k := new(SSHKey) + resp, err := s.client.Do(req, k) + if err != nil { + return nil, resp, err + } + + return k, resp, err +} + +// DeleteSSHKey deletes key owned by currently authenticated user. This is an +// idempotent function and calling it on a key that is already deleted or not +// available results in 200 OK. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#delete-ssh-key-for-current-owner +func (s *UsersService) DeleteSSHKey(key int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("user/keys/%d", key) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteSSHKeyForUser deletes key owned by a specified user. Available only +// for admin. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#delete-ssh-key-for-given-user +func (s *UsersService) DeleteSSHKeyForUser(user, key int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("users/%d/keys/%d", user, key) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// BlockUser blocks the specified user. Available only for admin. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#block-user +func (s *UsersService) BlockUser(user int, options ...OptionFunc) error { + u := fmt.Sprintf("users/%d/block", user) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return err + } + + resp, err := s.client.Do(req, nil) + if err != nil { + return err + } + + switch resp.StatusCode { + case 201: + return nil + case 403: + return errors.New("Cannot block a user that is already blocked by LDAP synchronization") + case 404: + return errors.New("User does not exist") + default: + return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode) + } +} + +// UnblockUser unblocks the specified user. Available only for admin. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#unblock-user +func (s *UsersService) UnblockUser(user int, options ...OptionFunc) error { + u := fmt.Sprintf("users/%d/unblock", user) + + req, err := s.client.NewRequest("POST", u, nil, options) + if err != nil { + return err + } + + resp, err := s.client.Do(req, nil) + if err != nil { + return err + } + + switch resp.StatusCode { + case 201: + return nil + case 403: + return errors.New("Cannot unblock a user that is blocked by LDAP synchronization") + case 404: + return errors.New("User does not exist") + default: + return fmt.Errorf("Received unexpected result code: %d", resp.StatusCode) + } +} + +// Email represents an Email. +// +// GitLab API docs: https://doc.gitlab.com/ce/api/users.html#list-emails +type Email struct { + ID int `json:"id"` + Email string `json:"email"` +} + +// ListEmails gets a list of currently authenticated user's Emails. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#list-emails +func (s *UsersService) ListEmails(options ...OptionFunc) ([]*Email, *Response, error) { + req, err := s.client.NewRequest("GET", "user/emails", nil, options) + if err != nil { + return nil, nil, err + } + + var e []*Email + resp, err := s.client.Do(req, &e) + if err != nil { + return nil, resp, err + } + + return e, resp, err +} + +// ListEmailsForUserOptions represents the available ListEmailsForUser() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#list-emails-for-user +type ListEmailsForUserOptions ListOptions + +// ListEmailsForUser gets a list of a specified user's Emails. Available +// only for admin +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#list-emails-for-user +func (s *UsersService) ListEmailsForUser(user int, opt *ListEmailsForUserOptions, options ...OptionFunc) ([]*Email, *Response, error) { + u := fmt.Sprintf("users/%d/emails", user) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var e []*Email + resp, err := s.client.Do(req, &e) + if err != nil { + return nil, resp, err + } + + return e, resp, err +} + +// GetEmail gets a single email. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#single-email +func (s *UsersService) GetEmail(email int, options ...OptionFunc) (*Email, *Response, error) { + u := fmt.Sprintf("user/emails/%d", email) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + e := new(Email) + resp, err := s.client.Do(req, e) + if err != nil { + return nil, resp, err + } + + return e, resp, err +} + +// AddEmailOptions represents the available AddEmail() options. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/projects.html#add-email +type AddEmailOptions struct { + Email *string `url:"email,omitempty" json:"email,omitempty"` +} + +// AddEmail creates a new email owned by the currently authenticated user. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-email +func (s *UsersService) AddEmail(opt *AddEmailOptions, options ...OptionFunc) (*Email, *Response, error) { + req, err := s.client.NewRequest("POST", "user/emails", opt, options) + if err != nil { + return nil, nil, err + } + + e := new(Email) + resp, err := s.client.Do(req, e) + if err != nil { + return nil, resp, err + } + + return e, resp, err +} + +// AddEmailForUser creates new email owned by specified user. Available only for +// admin. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/users.html#add-email-for-user +func (s *UsersService) AddEmailForUser(user int, opt *AddEmailOptions, options ...OptionFunc) (*Email, *Response, error) { + u := fmt.Sprintf("users/%d/emails", user) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + e := new(Email) + resp, err := s.client.Do(req, e) + if err != nil { + return nil, resp, err + } + + return e, resp, err +} + +// DeleteEmail deletes email owned by currently authenticated user. This is an +// idempotent function and calling it on a key that is already deleted or not +// available results in 200 OK. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#delete-email-for-current-owner +func (s *UsersService) DeleteEmail(email int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("user/emails/%d", email) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// DeleteEmailForUser deletes email owned by a specified user. Available only +// for admin. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#delete-email-for-given-user +func (s *UsersService) DeleteEmailForUser(user, email int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("users/%d/emails/%d", user, email) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// ImpersonationToken represents an impersonation token. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user +type ImpersonationToken struct { + ID int `json:"id"` + Name string `json:"name"` + Active bool `json:"active"` + Token string `json:"token"` + Scopes []string `json:"scopes"` + Revoked bool `json:"revoked"` + CreatedAt *time.Time `json:"created_at"` + ExpiresAt *ISOTime `json:"expires_at"` +} + +// GetAllImpersonationTokensOptions represents the available +// GetAllImpersonationTokens() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user +type GetAllImpersonationTokensOptions struct { + ListOptions + State *string `url:"state,omitempty" json:"state,omitempty"` +} + +// GetAllImpersonationTokens retrieves all impersonation tokens of a user. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#get-all-impersonation-tokens-of-a-user +func (s *UsersService) GetAllImpersonationTokens(user int, opt *GetAllImpersonationTokensOptions, options ...OptionFunc) ([]*ImpersonationToken, *Response, error) { + u := fmt.Sprintf("users/%d/impersonation_tokens", user) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var ts []*ImpersonationToken + resp, err := s.client.Do(req, &ts) + if err != nil { + return nil, resp, err + } + + return ts, resp, err +} + +// GetImpersonationToken retrieves an impersonation token of a user. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#get-an-impersonation-token-of-a-user +func (s *UsersService) GetImpersonationToken(user, token int, options ...OptionFunc) (*ImpersonationToken, *Response, error) { + u := fmt.Sprintf("users/%d/impersonation_tokens/%d", user, token) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + t := new(ImpersonationToken) + resp, err := s.client.Do(req, &t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// CreateImpersonationTokenOptions represents the available +// CreateImpersonationToken() options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#create-an-impersonation-token +type CreateImpersonationTokenOptions struct { + Name *string `url:"name,omitempty" json:"name,omitempty"` + Scopes *[]string `url:"scopes,omitempty" json:"scopes,omitempty"` + ExpiresAt *time.Time `url:"expires_at,omitempty" json:"expires_at,omitempty"` +} + +// CreateImpersonationToken creates an impersonation token. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#create-an-impersonation-token +func (s *UsersService) CreateImpersonationToken(user int, opt *CreateImpersonationTokenOptions, options ...OptionFunc) (*ImpersonationToken, *Response, error) { + u := fmt.Sprintf("users/%d/impersonation_tokens", user) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + t := new(ImpersonationToken) + resp, err := s.client.Do(req, &t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} + +// RevokeImpersonationToken revokes an impersonation token. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#revoke-an-impersonation-token +func (s *UsersService) RevokeImpersonationToken(user, token int, options ...OptionFunc) (*Response, error) { + u := fmt.Sprintf("users/%d/impersonation_tokens/%d", user, token) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// UserActivity represents an entry in the user/activities response +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only +type UserActivity struct { + Username string `json:"username"` + LastActivityOn *ISOTime `json:"last_activity_on"` +} + +// GetUserActivitiesOptions represents the options for GetUserActivities +// +// GitLap API docs: +// https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only +type GetUserActivitiesOptions struct { + From *ISOTime `url:"from,omitempty" json:"from,omitempty"` +} + +// GetUserActivities retrieves user activities (admin only) +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/users.html#get-user-activities-admin-only +func (s *UsersService) GetUserActivities(opt *GetUserActivitiesOptions, options ...OptionFunc) ([]*UserActivity, *Response, error) { + req, err := s.client.NewRequest("GET", "user/activities", opt, options) + if err != nil { + return nil, nil, err + } + + var t []*UserActivity + resp, err := s.client.Do(req, &t) + if err != nil { + return nil, resp, err + } + + return t, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/validate.go b/vendor/github.com/xanzy/go-gitlab/validate.go new file mode 100644 index 00000000..a88e1884 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/validate.go @@ -0,0 +1,40 @@ +package gitlab + +// ValidateService handles communication with the validation related methods of +// the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/lint.html +type ValidateService struct { + client *Client +} + +// LintResult represents the linting results. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/lint.html +type LintResult struct { + Status string `json:"status"` + Errors []string `json:"errors"` +} + +// Lint validates .gitlab-ci.yml content. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/lint.html +func (s *ValidateService) Lint(content string, options ...OptionFunc) (*LintResult, *Response, error) { + var opts struct { + Content string `url:"content,omitempty" json:"content,omitempty"` + } + opts.Content = content + + req, err := s.client.NewRequest("POST", "ci/lint", &opts, options) + if err != nil { + return nil, nil, err + } + + l := new(LintResult) + resp, err := s.client.Do(req, l) + if err != nil { + return nil, resp, err + } + + return l, resp, nil +} diff --git a/vendor/github.com/xanzy/go-gitlab/version.go b/vendor/github.com/xanzy/go-gitlab/version.go new file mode 100644 index 00000000..f1a3a7f5 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/version.go @@ -0,0 +1,56 @@ +// +// Copyright 2017, Andrea Funto' +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package gitlab + +// VersionService handles communication with the GitLab server instance to +// retrieve its version information via the GitLab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/version.md +type VersionService struct { + client *Client +} + +// Version represents a GitLab instance version. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/version.md +type Version struct { + Version string `json:"version"` + Revision string `json:"revision"` +} + +func (s Version) String() string { + return Stringify(s) +} + +// GetVersion gets a GitLab server instance version; it is only available to +// authenticated users. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/version.md +func (s *VersionService) GetVersion() (*Version, *Response, error) { + req, err := s.client.NewRequest("GET", "version", nil, nil) + if err != nil { + return nil, nil, err + } + + v := new(Version) + resp, err := s.client.Do(req, v) + if err != nil { + return nil, resp, err + } + + return v, resp, err +} diff --git a/vendor/github.com/xanzy/go-gitlab/wikis.go b/vendor/github.com/xanzy/go-gitlab/wikis.go new file mode 100644 index 00000000..72889851 --- /dev/null +++ b/vendor/github.com/xanzy/go-gitlab/wikis.go @@ -0,0 +1,204 @@ +// Copyright 2017, Stany MARCEL +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gitlab + +import ( + "fmt" + "net/url" +) + +// WikisService handles communication with the wikis related methods of +// the Gitlab API. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html +type WikisService struct { + client *Client +} + +// WikiFormat represents the available wiki formats. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html +type WikiFormat string + +// The available wiki formats. +const ( + WikiFormatMarkdown WikiFormat = "markdown" + WikiFormatRFoc WikiFormat = "rdoc" + WikiFormatASCIIDoc WikiFormat = "asciidoc" +) + +// Wiki represents a GitLab wiki. +// +// GitLab API docs: https://docs.gitlab.com/ce/api/wikis.html +type Wiki struct { + Content string `json:"content"` + Format WikiFormat `json:"format"` + Slug string `json:"slug"` + Title string `json:"title"` +} + +func (w Wiki) String() string { + return Stringify(w) +} + +// ListWikisOptions represents the available ListWikis options. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/wikis.html#list-wiki-pages +type ListWikisOptions struct { + WithContent *bool `url:"with_content,omitempty" json:"with_content,omitempty"` +} + +// ListWikis lists all pages of the wiki of the given project id. +// When with_content is set, it also returns the content of the pages. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/wikis.html#list-wiki-pages +func (s *WikisService) ListWikis(pid interface{}, opt *ListWikisOptions, options ...OptionFunc) ([]*Wiki, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/wikis", url.QueryEscape(project)) + + req, err := s.client.NewRequest("GET", u, opt, options) + if err != nil { + return nil, nil, err + } + + var w []*Wiki + resp, err := s.client.Do(req, &w) + if err != nil { + return nil, resp, err + } + + return w, resp, err +} + +// GetWikiPage gets a wiki page for a given project. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/wikis.html#get-a-wiki-page +func (s *WikisService) GetWikiPage(pid interface{}, slug string, options ...OptionFunc) (*Wiki, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/wikis/%s", url.QueryEscape(project), url.QueryEscape(slug)) + + req, err := s.client.NewRequest("GET", u, nil, options) + if err != nil { + return nil, nil, err + } + + var w *Wiki + resp, err := s.client.Do(req, &w) + if err != nil { + return nil, resp, err + } + + return w, resp, err +} + +// CreateWikiPageOptions represents options to CreateWikiPage. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/wikis.html#create-a-new-wiki-page +type CreateWikiPageOptions struct { + Content *string `url:"content" json:"content"` + Title *string `url:"title" json:"title"` + Format *string `url:"format,omitempty" json:"format,omitempty"` +} + +// CreateWikiPage creates a new wiki page for the given repository with +// the given title, slug, and content. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/wikis.html#create-a-new-wiki-page +func (s *WikisService) CreateWikiPage(pid interface{}, opt *CreateWikiPageOptions, options ...OptionFunc) (*Wiki, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/wikis", url.QueryEscape(project)) + + req, err := s.client.NewRequest("POST", u, opt, options) + if err != nil { + return nil, nil, err + } + + w := new(Wiki) + resp, err := s.client.Do(req, w) + if err != nil { + return nil, resp, err + } + + return w, resp, err +} + +// EditWikiPageOptions represents options to EditWikiPage. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/wikis.html#edit-an-existing-wiki-page +type EditWikiPageOptions struct { + Content *string `url:"content" json:"content"` + Title *string `url:"title" json:"title"` + Format *string `url:"format,omitempty" json:"format,omitempty"` +} + +// EditWikiPage Updates an existing wiki page. At least one parameter is +// required to update the wiki page. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/wikis.html#edit-an-existing-wiki-page +func (s *WikisService) EditWikiPage(pid interface{}, slug string, opt *EditWikiPageOptions, options ...OptionFunc) (*Wiki, *Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, nil, err + } + u := fmt.Sprintf("projects/%s/wikis/%s", url.QueryEscape(project), url.QueryEscape(slug)) + + req, err := s.client.NewRequest("PUT", u, opt, options) + if err != nil { + return nil, nil, err + } + + w := new(Wiki) + resp, err := s.client.Do(req, w) + if err != nil { + return nil, resp, err + } + + return w, resp, err +} + +// DeleteWikiPage deletes a wiki page with a given slug. +// +// GitLab API docs: +// https://docs.gitlab.com/ce/api/wikis.html#delete-a-wiki-page +func (s *WikisService) DeleteWikiPage(pid interface{}, slug string, options ...OptionFunc) (*Response, error) { + project, err := parseID(pid) + if err != nil { + return nil, err + } + u := fmt.Sprintf("projects/%s/wikis/%s", url.QueryEscape(project), url.QueryEscape(slug)) + + req, err := s.client.NewRequest("DELETE", u, nil, options) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/wtf.go b/wtf.go index c258177d..949d5ffc 100644 --- a/wtf.go +++ b/wtf.go @@ -18,6 +18,7 @@ import ( "github.com/senorprogrammer/wtf/gcal" "github.com/senorprogrammer/wtf/git" "github.com/senorprogrammer/wtf/github" + "github.com/senorprogrammer/wtf/gitlab" "github.com/senorprogrammer/wtf/help" "github.com/senorprogrammer/wtf/ipinfo" "github.com/senorprogrammer/wtf/jira" @@ -182,6 +183,8 @@ func addWidget(app *tview.Application, pages *tview.Pages, widgetName string) { Widgets = append(Widgets, git.NewWidget(app, pages)) case "github": Widgets = append(Widgets, github.NewWidget(app, pages)) + case "gitlab": + Widgets = append(Widgets, gitlab.NewWidget(app, pages)) case "ipinfo": Widgets = append(Widgets, ipinfo.NewWidget()) case "jira": @@ -222,6 +225,7 @@ func makeWidgets(app *tview.Application, pages *tview.Pages) { gcal.Config = Config git.Config = Config github.Config = Config + gitlab.Config = Config ipinfo.Config = Config jira.Config = Config newrelic.Config = Config From d38eb622afead5e9024b6c80afb8b2d44fb5280e Mon Sep 17 00:00:00 2001 From: Mark Old Date: Fri, 8 Jun 2018 13:32:04 -0700 Subject: [PATCH 02/58] add docs for gitlab --- _site/content/posts/modules/gitlab.md | 89 ++++++++ _site/static/imgs/modules/gitlab.png | Bin 0 -> 57615 bytes .../hyde-hyde/layouts/partials/sidebar.html | 1 + docs/404.html | 1 + docs/categories/index.html | 1 + docs/imgs/modules/gitlab.png | Bin 0 -> 57615 bytes docs/index.html | 1 + docs/index.xml | 17 +- .../posts/configuration/attributes/index.html | 1 + docs/posts/configuration/index.html | 1 + docs/posts/configuration/iterm2/index.html | 1 + docs/posts/glossary/index.html | 1 + docs/posts/index.html | 8 + docs/posts/index.xml | 17 +- docs/posts/installation/index.html | 1 + docs/posts/modules/bamboohr/index.html | 1 + docs/posts/modules/clocks/index.html | 1 + docs/posts/modules/cmdrunner/index.html | 1 + .../cryptocurrencies/bittrex/index.html | 1 + .../cryptocurrencies/cryptolive/index.html | 1 + docs/posts/modules/gcal/index.html | 1 + docs/posts/modules/git/index.html | 1 + docs/posts/modules/github/index.html | 1 + docs/posts/modules/gitlab/index.html | 203 ++++++++++++++++++ docs/posts/modules/index.html | 1 + docs/posts/modules/ipinfo/index.html | 1 + docs/posts/modules/jira/index.html | 1 + docs/posts/modules/newrelic/index.html | 1 + docs/posts/modules/opsgenie/index.html | 1 + docs/posts/modules/power/index.html | 1 + docs/posts/modules/prettyweather/index.html | 1 + docs/posts/modules/security/index.html | 1 + docs/posts/modules/textfile/index.html | 1 + docs/posts/modules/todo/index.html | 1 + docs/posts/modules/weather/index.html | 1 + docs/posts/overview/index.html | 1 + docs/sitemap.xml | 9 +- docs/tags/index.html | 1 + 38 files changed, 369 insertions(+), 4 deletions(-) create mode 100644 _site/content/posts/modules/gitlab.md create mode 100644 _site/static/imgs/modules/gitlab.png create mode 100644 docs/imgs/modules/gitlab.png create mode 100644 docs/posts/modules/gitlab/index.html diff --git a/_site/content/posts/modules/gitlab.md b/_site/content/posts/modules/gitlab.md new file mode 100644 index 00000000..917c9b02 --- /dev/null +++ b/_site/content/posts/modules/gitlab.md @@ -0,0 +1,89 @@ +--- +title: "Gitlab" +date: 2018-06-08T13:14:11-07:00 +draft: false +--- + +Displays information about your projects hosted on Gitlab: + + +#### Open Approval Requests + +All open merge requests that are requesting your approval. + +#### Open Merge Requests + +All open merge requests created by you. + +gitlab screenshot + +## Source Code + +```bash +wtf/gitlab/ +``` + +## Required ENV Variables + +Key: `WTF_GITLAB_TOKEN`
+Action: A Gitlab personal access token. Requires at least `api` access. + +## Keyboard Commands + +Key: `/`
+Action: Open/close the widget's help window. + +Key: `h`
+Action: Show the previous project. + +Key: `l`
+Action: Show the next project. + +Key: `←`
+Action: Show the previous project. + +Key: `→`
+Action: Show the next project. + +## Configuration + +```yaml +gitlab: + enabled: true + position: + top: 2 + left: 3 + height: 2 + width: 2 + refreshInterval: 300 + projects: + tasks: "gitlab-org/release" + gitlab-ce: "gitlab-org" + username: "senorprogrammer" +``` + +### Attributes + +`enabled`
+Determines whether or not this module is executed and if its data displayed onscreen.
+Values: `true`, `false`. + +`position`
+Defines where in the grid this module's widget will be displayed.
+ +`refreshInterval`
+How often, in seconds, this module will update its data.
+Values: A positive integer, `0..n`. + +`domain`
+_Optional_. Your Gitlab corporate domain.
+Values: A valid URI. + +`projects`
+A list of key/value pairs each describing a Gitlab project to fetch data +for.
+Key: The name of the project.
+Value: The namespace of the project. + +`username`
+Your Gitlab username. Used to figure out which requests require your approval diff --git a/_site/static/imgs/modules/gitlab.png b/_site/static/imgs/modules/gitlab.png new file mode 100644 index 0000000000000000000000000000000000000000..6e806a4183470ce449f0266c695da7f93d08ea64 GIT binary patch literal 57615 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 z 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 + diff --git a/docs/404.html b/docs/404.html index a6f51b08..1116a3f3 100644 --- a/docs/404.html +++ b/docs/404.html @@ -70,6 +70,7 @@ + diff --git a/docs/categories/index.html b/docs/categories/index.html index b52bb86e..5f82b96c 100644 --- a/docs/categories/index.html +++ b/docs/categories/index.html @@ -72,6 +72,7 @@ + diff --git a/docs/imgs/modules/gitlab.png b/docs/imgs/modules/gitlab.png new file mode 100644 index 0000000000000000000000000000000000000000..6e806a4183470ce449f0266c695da7f93d08ea64 GIT binary patch literal 57615 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 z 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 + diff --git a/docs/index.xml b/docs/index.xml index a86b5ce2..24c88a39 100644 --- a/docs/index.xml +++ b/docs/index.xml @@ -6,11 +6,26 @@ Recent content on WTF - A Terminal Dashboard Hugo -- gohugo.io en-us - Mon, 04 Jun 2018 20:06:40 -0700 + Fri, 08 Jun 2018 13:14:11 -0700 + + Gitlab + https://wtfutil.com/posts/modules/gitlab/ + Fri, 08 Jun 2018 13:14:11 -0700 + + https://wtfutil.com/posts/modules/gitlab/ + Displays information about your projects hosted on Gitlab: +Open Approval Requests All open merge requests that are requesting your approval. +Open Merge Requests All open merge requests created by you. +Source Code wtf/gitlab/ Required ENV Variables Key: WTF_GITLAB_TOKEN Action: A Gitlab personal access token. Requires at least api access. +Keyboard Commands Key: / Action: Open/close the widget&rsquo;s help window. +Key: h Action: Show the previous project. +Key: l Action: Show the next project. + + Bittrex https://wtfutil.com/posts/modules/cryptocurrencies/bittrex/ diff --git a/docs/posts/configuration/attributes/index.html b/docs/posts/configuration/attributes/index.html index a5354fce..a234b153 100644 --- a/docs/posts/configuration/attributes/index.html +++ b/docs/posts/configuration/attributes/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/configuration/index.html b/docs/posts/configuration/index.html index ec410d85..be506a80 100644 --- a/docs/posts/configuration/index.html +++ b/docs/posts/configuration/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/configuration/iterm2/index.html b/docs/posts/configuration/iterm2/index.html index dcb4d6c6..d26019da 100644 --- a/docs/posts/configuration/iterm2/index.html +++ b/docs/posts/configuration/iterm2/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/glossary/index.html b/docs/posts/glossary/index.html index 9a4f7187..ac4c33bc 100644 --- a/docs/posts/glossary/index.html +++ b/docs/posts/glossary/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/index.html b/docs/posts/index.html index ae588754..53ee2da5 100644 --- a/docs/posts/index.html +++ b/docs/posts/index.html @@ -72,6 +72,7 @@ + @@ -99,6 +100,13 @@

Posts

  • + + Gitlab + + + + +
  • Bittrex diff --git a/docs/posts/index.xml b/docs/posts/index.xml index 2dc5ba0f..5a805397 100644 --- a/docs/posts/index.xml +++ b/docs/posts/index.xml @@ -6,11 +6,26 @@ Recent content in Posts on WTF - A Terminal Dashboard Hugo -- gohugo.io en-us - Mon, 04 Jun 2018 20:06:40 -0700 + Fri, 08 Jun 2018 13:14:11 -0700 + + Gitlab + https://wtfutil.com/posts/modules/gitlab/ + Fri, 08 Jun 2018 13:14:11 -0700 + + https://wtfutil.com/posts/modules/gitlab/ + Displays information about your projects hosted on Gitlab: +Open Approval Requests All open merge requests that are requesting your approval. +Open Merge Requests All open merge requests created by you. +Source Code wtf/gitlab/ Required ENV Variables Key: WTF_GITLAB_TOKEN Action: A Gitlab personal access token. Requires at least api access. +Keyboard Commands Key: / Action: Open/close the widget&rsquo;s help window. +Key: h Action: Show the previous project. +Key: l Action: Show the next project. + + Bittrex https://wtfutil.com/posts/modules/cryptocurrencies/bittrex/ diff --git a/docs/posts/installation/index.html b/docs/posts/installation/index.html index 1237a416..d60d40fe 100644 --- a/docs/posts/installation/index.html +++ b/docs/posts/installation/index.html @@ -70,6 +70,7 @@
  • + diff --git a/docs/posts/modules/bamboohr/index.html b/docs/posts/modules/bamboohr/index.html index 240a8181..c899d2a2 100644 --- a/docs/posts/modules/bamboohr/index.html +++ b/docs/posts/modules/bamboohr/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/clocks/index.html b/docs/posts/modules/clocks/index.html index 04333353..d72cba91 100644 --- a/docs/posts/modules/clocks/index.html +++ b/docs/posts/modules/clocks/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/cmdrunner/index.html b/docs/posts/modules/cmdrunner/index.html index 1ec0afca..19ddb2e7 100644 --- a/docs/posts/modules/cmdrunner/index.html +++ b/docs/posts/modules/cmdrunner/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/cryptocurrencies/bittrex/index.html b/docs/posts/modules/cryptocurrencies/bittrex/index.html index f9f033eb..e35a1e81 100644 --- a/docs/posts/modules/cryptocurrencies/bittrex/index.html +++ b/docs/posts/modules/cryptocurrencies/bittrex/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/cryptocurrencies/cryptolive/index.html b/docs/posts/modules/cryptocurrencies/cryptolive/index.html index 832af988..82e90b66 100644 --- a/docs/posts/modules/cryptocurrencies/cryptolive/index.html +++ b/docs/posts/modules/cryptocurrencies/cryptolive/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/gcal/index.html b/docs/posts/modules/gcal/index.html index 7e6f4a4b..9ce5f87b 100644 --- a/docs/posts/modules/gcal/index.html +++ b/docs/posts/modules/gcal/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/git/index.html b/docs/posts/modules/git/index.html index e958c4f1..1b88ee7b 100644 --- a/docs/posts/modules/git/index.html +++ b/docs/posts/modules/git/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/github/index.html b/docs/posts/modules/github/index.html index eb556adb..24f15d91 100644 --- a/docs/posts/modules/github/index.html +++ b/docs/posts/modules/github/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/gitlab/index.html b/docs/posts/modules/gitlab/index.html new file mode 100644 index 00000000..dfec84ee --- /dev/null +++ b/docs/posts/modules/gitlab/index.html @@ -0,0 +1,203 @@ + + + + + + + + + + + + +Gitlab | WTF - A Terminal Dashboard + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    Gitlab

    + +
    + +
    + + + +

    Displays information about your projects hosted on Gitlab:

    + +

    Open Approval Requests

    + +

    All open merge requests that are requesting your approval.

    + +

    Open Merge Requests

    + +

    All open merge requests created by you.

    + +

    gitlab screenshot

    + +

    Source Code

    +
    wtf/gitlab/
    +

    Required ENV Variables

    + +

    Key: WTF_GITLAB_TOKEN
    +Action: A Gitlab personal access token. Requires at least api access.

    + +

    Keyboard Commands

    + +

    Key: /
    +Action: Open/close the widget’s help window.

    + +

    Key: h
    +Action: Show the previous project.

    + +

    Key: l
    +Action: Show the next project.

    + +

    Key:
    +Action: Show the previous project.

    + +

    Key:
    +Action: Show the next project.

    + +

    Configuration

    +
    gitlab:
    +  enabled: true
    +  position:
    +    top: 2
    +    left: 3
    +    height: 2
    +    width: 2
    +  refreshInterval: 300
    +  projects:
    +    tasks: "gitlab-org/release"
    +    gitlab-ce: "gitlab-org"
    +  username: "senorprogrammer"
    +

    Attributes

    + +

    enabled
    +Determines whether or not this module is executed and if its data displayed onscreen.
    +Values: true, false.

    + +

    position
    +Defines where in the grid this module’s widget will be displayed.

    + +

    refreshInterval
    +How often, in seconds, this module will update its data.
    +Values: A positive integer, 0..n.

    + +

    domain
    +Optional. Your Gitlab corporate domain.
    +Values: A valid URI.

    + +

    projects
    +A list of key/value pairs each describing a Gitlab project to fetch data +for.
    +Key: The name of the project.
    +Value: The namespace of the project.

    + +

    username
    +Your Gitlab username. Used to figure out which requests require your approval

    + +
    + + +
    + + + + diff --git a/docs/posts/modules/index.html b/docs/posts/modules/index.html index fad43ff2..7593f6c8 100644 --- a/docs/posts/modules/index.html +++ b/docs/posts/modules/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/ipinfo/index.html b/docs/posts/modules/ipinfo/index.html index f3cd4865..75bddff5 100644 --- a/docs/posts/modules/ipinfo/index.html +++ b/docs/posts/modules/ipinfo/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/jira/index.html b/docs/posts/modules/jira/index.html index 4a60fb7a..a0fe2031 100644 --- a/docs/posts/modules/jira/index.html +++ b/docs/posts/modules/jira/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/newrelic/index.html b/docs/posts/modules/newrelic/index.html index eac8a8db..579f9e6b 100644 --- a/docs/posts/modules/newrelic/index.html +++ b/docs/posts/modules/newrelic/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/opsgenie/index.html b/docs/posts/modules/opsgenie/index.html index dd2eef1a..4c84483b 100644 --- a/docs/posts/modules/opsgenie/index.html +++ b/docs/posts/modules/opsgenie/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/power/index.html b/docs/posts/modules/power/index.html index 7cbb1d72..f26431e8 100644 --- a/docs/posts/modules/power/index.html +++ b/docs/posts/modules/power/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/prettyweather/index.html b/docs/posts/modules/prettyweather/index.html index d6bd7e91..14d18b24 100644 --- a/docs/posts/modules/prettyweather/index.html +++ b/docs/posts/modules/prettyweather/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/security/index.html b/docs/posts/modules/security/index.html index 04437186..f4d3a710 100644 --- a/docs/posts/modules/security/index.html +++ b/docs/posts/modules/security/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/textfile/index.html b/docs/posts/modules/textfile/index.html index c18d9229..74d61c44 100644 --- a/docs/posts/modules/textfile/index.html +++ b/docs/posts/modules/textfile/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/todo/index.html b/docs/posts/modules/todo/index.html index 9ffa4bc6..57e22e08 100644 --- a/docs/posts/modules/todo/index.html +++ b/docs/posts/modules/todo/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/modules/weather/index.html b/docs/posts/modules/weather/index.html index f22a2a21..d640e763 100644 --- a/docs/posts/modules/weather/index.html +++ b/docs/posts/modules/weather/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/posts/overview/index.html b/docs/posts/overview/index.html index beef7287..bc59f931 100644 --- a/docs/posts/overview/index.html +++ b/docs/posts/overview/index.html @@ -70,6 +70,7 @@ + diff --git a/docs/sitemap.xml b/docs/sitemap.xml index 64670468..e4f727c5 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -2,6 +2,11 @@ + + https://wtfutil.com/posts/modules/gitlab/ + 2018-06-08T13:14:11-07:00 + + https://wtfutil.com/posts/modules/cryptocurrencies/bittrex/ 2018-06-04T20:06:40-07:00 @@ -134,7 +139,7 @@ https://wtfutil.com/posts/ - 2018-06-04T20:06:40-07:00 + 2018-06-08T13:14:11-07:00 0 @@ -145,7 +150,7 @@ https://wtfutil.com/ - 2018-06-04T20:06:40-07:00 + 2018-06-08T13:14:11-07:00 0 diff --git a/docs/tags/index.html b/docs/tags/index.html index 68425b68..b567b5ee 100644 --- a/docs/tags/index.html +++ b/docs/tags/index.html @@ -72,6 +72,7 @@ + From eb547136cf3fa5e4fa852f63d2d67e0b931288d1 Mon Sep 17 00:00:00 2001 From: DavidB Date: Sat, 9 Jun 2018 20:49:12 +0300 Subject: [PATCH 03/58] Added simple jenkins module that enables watching jenkins views build status --- jenkins/client.go | 64 ++++++++++++++++++++++++++++++++++++ jenkins/job.go | 8 +++++ jenkins/view.go | 10 ++++++ jenkins/widget.go | 83 +++++++++++++++++++++++++++++++++++++++++++++++ wtf.go | 4 +++ 5 files changed, 169 insertions(+) create mode 100644 jenkins/client.go create mode 100644 jenkins/job.go create mode 100644 jenkins/view.go create mode 100644 jenkins/widget.go diff --git a/jenkins/client.go b/jenkins/client.go new file mode 100644 index 00000000..e599b9f7 --- /dev/null +++ b/jenkins/client.go @@ -0,0 +1,64 @@ +package jenkins + +import ( + "bytes" + "encoding/json" + "io" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + +func Create(jenkinsURL string, username string, apiKey string) (*View, error) { + const apiSuffix = "api/json?pretty=true" + parsedSuffix, err := url.Parse(apiSuffix) + if err != nil { + return &View{}, err + } + + parsedJenkinsURL, err := url.Parse(ensureLastSlash(jenkinsURL)) + if err != nil { + return &View{}, err + } + jenkinsAPIURL := parsedJenkinsURL.ResolveReference(parsedSuffix) + + req, err := http.NewRequest("GET", jenkinsAPIURL.String(), nil) + req.SetBasicAuth(username, apiKey) + + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + + if err != nil { + return &View{}, err + } + + view := &View{} + parseJson(view, resp.Body) + + return view, nil +} + +func ensureLastSlash(URL string) string { + return strings.TrimRight(URL, "/") + "/" +} + +/* -------------------- Unexported Functions -------------------- */ + + +func parseJson(obj interface{}, text io.Reader) { + jsonStream, err := ioutil.ReadAll(text) + if err != nil { + panic(err) + } + + decoder := json.NewDecoder(bytes.NewReader(jsonStream)) + + for { + if err := decoder.Decode(obj); err == io.EOF { + break + } else if err != nil { + panic(err) + } + } +} diff --git a/jenkins/job.go b/jenkins/job.go new file mode 100644 index 00000000..e360e0f6 --- /dev/null +++ b/jenkins/job.go @@ -0,0 +1,8 @@ +package jenkins + +type Job struct { + Class string `json:"_class"` + Name string `json:"name"` + Url string `json:"url"` + Color string `json:"color"` +} diff --git a/jenkins/view.go b/jenkins/view.go new file mode 100644 index 00000000..9041b297 --- /dev/null +++ b/jenkins/view.go @@ -0,0 +1,10 @@ +package jenkins + +type View struct { + Class string `json:"_class"` + Description string `json:"description"` + Jobs []Job `json:"jobs"` + Name string `json:"name"` + Property []string `json:"property"` + url string `json:"url"` +} diff --git a/jenkins/widget.go b/jenkins/widget.go new file mode 100644 index 00000000..a922fbbf --- /dev/null +++ b/jenkins/widget.go @@ -0,0 +1,83 @@ +package jenkins + +import ( + "fmt" + "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" + "os" +) + +// Config is a pointer to the global config object +var Config *config.Config + +type Widget struct { + wtf.TextWidget +} + +func NewWidget() *Widget { + widget := Widget{ + TextWidget: wtf.NewTextWidget("Jenkins", "jenkins", false), + } + + return &widget +} + +/* -------------------- Exported Functions -------------------- */ + +func (widget *Widget) Refresh() { + if widget.Disabled() { + return + } + + view, err := Create(Config.UString("wtf.mods.jenkins.url"), + Config.UString("wtf.mods.jenkins.user"), os.Getenv("WTF_JENKINS_API_KEY")) + + widget.UpdateRefreshedAt() + widget.View.Clear() + + if err != nil { + widget.View.SetWrap(true) + widget.View.SetTitle(fmt.Sprintf(" %s ", widget.Name)) + fmt.Fprintf(widget.View, "%v", err) + } else { + widget.View.SetWrap(false) + widget.View.SetTitle( + fmt.Sprintf( + " %s: [green] ", + widget.Name, + ), + ) + fmt.Fprintf(widget.View, "%s", widget.contentFrom(view)) + } +} + +/* -------------------- Unexported Functions -------------------- */ + +func (widget *Widget) contentFrom(view *View) string { + str := fmt.Sprintf(" [red]%s[white]\n", view.Name); + + for _, job := range view.Jobs { + str = str + fmt.Sprintf( + " [%s]%-6s[white]\n", + widget.jobColor(&job), + job.Name, + ) + } + + return str +} + +func (widget *Widget) jobColor(job *Job) string { + var color string + + switch job.Color { + case "blue": + color = "green" + case "red": + color = "red" + default: + color = "white" + } + + return color +} diff --git a/wtf.go b/wtf.go index 2c27fb13..5822eb6b 100644 --- a/wtf.go +++ b/wtf.go @@ -23,6 +23,7 @@ import ( "github.com/senorprogrammer/wtf/gspreadsheets" "github.com/senorprogrammer/wtf/help" "github.com/senorprogrammer/wtf/ipinfo" + "github.com/senorprogrammer/wtf/jenkins" "github.com/senorprogrammer/wtf/jira" "github.com/senorprogrammer/wtf/newrelic" "github.com/senorprogrammer/wtf/opsgenie" @@ -191,6 +192,8 @@ func addWidget(app *tview.Application, pages *tview.Pages, widgetName string) { Widgets = append(Widgets, gspreadsheets.NewWidget()) case "ipinfo": Widgets = append(Widgets, ipinfo.NewWidget()) + case "jenkins": + Widgets = append(Widgets, jenkins.NewWidget()) case "jira": Widgets = append(Widgets, jira.NewWidget()) case "newrelic": @@ -232,6 +235,7 @@ func makeWidgets(app *tview.Application, pages *tview.Pages) { github.Config = Config gspreadsheets.Config = Config ipinfo.Config = Config + jenkins.Config = Config jira.Config = Config newrelic.Config = Config opsgenie.Config = Config From e73037c84cd4598e62a68bfc702b5c32eada62fb Mon Sep 17 00:00:00 2001 From: DavidB Date: Sat, 9 Jun 2018 21:16:19 +0300 Subject: [PATCH 04/58] Added jenkins module documentation --- _site/content/posts/modules/jenkins.md | 52 +++++++++++++++++++++++++ _site/static/imgs/modules/jenkins.png | Bin 0 -> 13073 bytes 2 files changed, 52 insertions(+) create mode 100644 _site/content/posts/modules/jenkins.md create mode 100644 _site/static/imgs/modules/jenkins.png diff --git a/_site/content/posts/modules/jenkins.md b/_site/content/posts/modules/jenkins.md new file mode 100644 index 00000000..c4873621 --- /dev/null +++ b/_site/content/posts/modules/jenkins.md @@ -0,0 +1,52 @@ +--- +title: "Modules: Jenkins" +date: 2018-06-09T20:53:35-07:00 +draft: false +--- + +Displays jenkins status of given builds in a project or view + +jenkins screenshot + +## Source Code + +```bash +wtf/jenkins/ +``` + +## Required ENV Variables + +Key: `WTF_JENKINS_API_KEY`
    +Value: Your Jenkins API key. + +## Keyboard Commands + +None. + +## Configuration + +```yaml +jenkins: + user: "username" + url: "https://jenkins.domain.com/jenkins/view_url" + enabled: true + position: + top: 2 + left: 3 + height: 2 + width: 3 + refreshInterval: 300 +``` + +### Attributes + +`user`
    +Your Jenkins username.
    + +`url`
    +The url to your Jenkins project or view.
    +Values: A valid URI. + +`refreshInterval`
    +How often, in seconds, this module will update its data.
    +Values: A positive integer, `0..n`. diff --git a/_site/static/imgs/modules/jenkins.png b/_site/static/imgs/modules/jenkins.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd3521ffb929449ddbeb72429eb58487ded468a GIT binary patch literal 13073 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 Date: Sun, 10 Jun 2018 00:16:40 +0300 Subject: [PATCH 05/58] Temporary changed username. --- .travis.yml | 10 ++-- README.md | 10 ++-- _sample_configs/complex_config.yml | 6 +-- .../content/posts/configuration/attributes.md | 2 +- _site/content/posts/installation.md | 6 +-- _site/content/posts/modules/gcal.md | 2 +- _site/content/posts/modules/git.md | 2 +- _site/content/posts/modules/github.md | 4 +- _site/content/posts/overview.md | 2 +- _site/themes/hyde-hyde/layouts/index.html | 4 +- .../hyde-hyde/layouts/partials/sidebar.html | 2 +- bamboohr/item.go | 2 +- bamboohr/widget.go | 2 +- bargraph/widget.go | 2 +- clocks/clock.go | 2 +- clocks/display.go | 2 +- clocks/widget.go | 2 +- cmdrunner/widget.go | 2 +- cryptoexchanges/bittrex/widget.go | 2 +- cryptoexchanges/cryptolive/widget.go | 2 +- docs/404.html | 2 +- docs/categories/index.html | 2 +- docs/index.html | 6 +-- docs/index.xml | 4 +- .../posts/configuration/attributes/index.html | 4 +- docs/posts/configuration/index.html | 2 +- docs/posts/configuration/iterm2/index.html | 2 +- docs/posts/glossary/index.html | 2 +- docs/posts/index.html | 2 +- docs/posts/index.xml | 4 +- docs/posts/installation/index.html | 8 ++-- docs/posts/modules/bamboohr/index.html | 2 +- docs/posts/modules/bittrex/index.html | 2 +- docs/posts/modules/clocks/index.html | 2 +- docs/posts/modules/cmdrunner/index.html | 2 +- .../cryptocurrencies/bittrex/index.html | 2 +- .../cryptocurrencies/cryptolive/index.html | 2 +- docs/posts/modules/cryptolive/index.html | 2 +- docs/posts/modules/gcal/index.html | 4 +- docs/posts/modules/git/index.html | 4 +- docs/posts/modules/github/index.html | 6 +-- docs/posts/modules/index.html | 2 +- docs/posts/modules/ipinfo/index.html | 2 +- docs/posts/modules/jira/index.html | 2 +- docs/posts/modules/newrelic/index.html | 2 +- docs/posts/modules/opsgenie/index.html | 2 +- docs/posts/modules/power/index.html | 2 +- docs/posts/modules/prettyweather/index.html | 2 +- docs/posts/modules/security/index.html | 2 +- docs/posts/modules/textfile/index.html | 2 +- docs/posts/modules/todo/index.html | 2 +- docs/posts/modules/weather/index.html | 2 +- docs/posts/overview/index.html | 4 +- docs/tags/index.html | 2 +- gcal/client.go | 2 +- gcal/widget.go | 2 +- git/display.go | 2 +- git/git_repo.go | 2 +- git/widget.go | 2 +- github/display.go | 2 +- github/widget.go | 2 +- gspreadsheets/client.go | 2 +- gspreadsheets/widget.go | 2 +- help/help.go | 10 ++-- ipinfo/widget.go | 2 +- jira/widget.go | 2 +- newrelic/widget.go | 2 +- opsgenie/widget.go | 2 +- power/battery.go | 2 +- power/battery_linux.go | 2 +- power/source.go | 2 +- power/widget.go | 2 +- prettyweather/widget.go | 2 +- security/dns.go | 2 +- security/firewall.go | 2 +- security/users.go | 2 +- security/widget.go | 2 +- security/wifi.go | 2 +- status/widget.go | 2 +- system/system_info.go | 2 +- system/widget.go | 2 +- textfile/widget.go | 2 +- todo/display.go | 2 +- todo/widget.go | 2 +- weather/display.go | 2 +- weather/widget.go | 2 +- wtf.go | 48 +++++++++---------- wtf/config_files.go | 2 +- wtf_tests/position_test.go | 2 +- wtf_tests/utils_test.go | 2 +- 90 files changed, 144 insertions(+), 144 deletions(-) diff --git a/.travis.yml b/.travis.yml index b20b9c4a..c90dfc89 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,9 @@ go: sudo: false before_install: # Make sure travis builds work for forks - - mkdir -p $TRAVIS_BUILD_DIR $GOPATH/src/github.com/senorprogrammer - - test ! -d $GOPATH/src/github.com/senorprogrammer/wtf && mv $TRAVIS_BUILD_DIR $GOPATH/src/github.com/senorprogrammer/wtf || true - - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/senorprogrammer/wtf - - cd $HOME/gopath/src/github.com/senorprogrammer/wtf + - mkdir -p $TRAVIS_BUILD_DIR $GOPATH/src/github.com/andrewzolotukhin + - test ! -d $GOPATH/src/github.com/andrewzolotukhin/wtf && mv $TRAVIS_BUILD_DIR $GOPATH/src/github.com/andrewzolotukhin/wtf || true + - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/andrewzolotukhin/wtf + - cd $HOME/gopath/src/github.com/andrewzolotukhin/wtf -script: go get ./... && go get github.com/go-test/deep && go test -v github.com/senorprogrammer/wtf/wtf_tests +script: go get ./... && go get github.com/go-test/deep && go test -v github.com/andrewzolotukhin/wtf/wtf_tests diff --git a/README.md b/README.md index 705c2be5..7d5fb882 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

    - +

    @@ -21,13 +21,13 @@ displaying infrequently-needed, but very important, daily data. **Note:** WTF is _only_ compatible with Go versions **1.9.2** or later. It currently _does not_ compile with `gccgo`. ```bash -go get -u github.com/senorprogrammer/wtf -cd $GOPATH/src/github.com/senorprogrammer/wtf +go get -u github.com/andrewzolotukhin/wtf +cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run ``` -Or [download the latest binary](https://github.com/senorprogrammer/wtf/releases). +Or [download the latest binary](https://github.com/andrewzolotukhin/wtf/releases). ## Support @@ -70,7 +70,7 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduc ## Authors -* Chris Cummer, [senorprogrammer](https://github.com/senorprogrammer) +* Chris Cummer, [andrewzolotukhin](https://github.com/andrewzolotukhin) ## License diff --git a/_sample_configs/complex_config.yml b/_sample_configs/complex_config.yml index e07aa209..48c68c36 100644 --- a/_sample_configs/complex_config.yml +++ b/_sample_configs/complex_config.yml @@ -108,7 +108,7 @@ wtf: width: 3 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/senorprogrammer/wtf" + - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" github: enabled: true position: @@ -119,8 +119,8 @@ wtf: refreshInterval: 300 repositories: repo-name: "owner id" - wtf: "senorprogrammer" - username: "senorprogrammer" + wtf: "andrewzolotukhin" + username: "andrewzolotukhin" jira: colors: rows: diff --git a/_site/content/posts/configuration/attributes.md b/_site/content/posts/configuration/attributes.md index 2850875e..0339bcdf 100644 --- a/_site/content/posts/configuration/attributes.md +++ b/_site/content/posts/configuration/attributes.md @@ -5,7 +5,7 @@ draft: false --- The following top-level attributes are configurable in `config.yml`. -See this example config file for more details. +See this example config file for more details. ```yaml wtf: diff --git a/_site/content/posts/installation.md b/_site/content/posts/installation.md index dcc4aafa..51c230cc 100644 --- a/_site/content/posts/installation.md +++ b/_site/content/posts/installation.md @@ -11,8 +11,8 @@ There are two ways to install WTF: Get this repo and install the dependencies: ```bash -go get -u github.com/senorprogrammer/wtf -cd $GOPATH/src/github.com/senorprogrammer/wtf +go get -u github.com/andrewzolotukhin/wtf +cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run ``` @@ -23,7 +23,7 @@ and that should probably do it. Grab the latest version from here: ```bash -https://github.com/senorprogrammer/wtf/releases +https://github.com/andrewzolotukhin/wtf/releases ``` expand it, and `cd` into the resulting directory. Then run: diff --git a/_site/content/posts/modules/gcal.md b/_site/content/posts/modules/gcal.md index ef6a70dd..57528fb9 100644 --- a/_site/content/posts/modules/gcal.md +++ b/_site/content/posts/modules/gcal.md @@ -9,7 +9,7 @@ Displays your upcoming Google calendar events. gcal screenshot **Not:** Setting up access to Google Calendars for Go is a bit unobvious. Check out Google's [Go Quickstart](https://developers.google.com/calendar/quickstart/go) -first and if you have problems, then take a look at this [comment by WesleydeSouza](https://github.com/senorprogrammer/wtf/issues/83#issuecomment-393665229) which offers a slightly different approach. +first and if you have problems, then take a look at this [comment by WesleydeSouza](https://github.com/andrewzolotukhin/wtf/issues/83#issuecomment-393665229) which offers a slightly different approach. ## Source Code diff --git a/_site/content/posts/modules/git.md b/_site/content/posts/modules/git.md index e0a6a1f2..d47a17fa 100644 --- a/_site/content/posts/modules/git.md +++ b/_site/content/posts/modules/git.md @@ -62,7 +62,7 @@ git: width: 2 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/senorprogrammer/wtf" + - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" - "/Users/user/fakeapp" ``` diff --git a/_site/content/posts/modules/github.md b/_site/content/posts/modules/github.md index 3cfee576..c0b93f4f 100644 --- a/_site/content/posts/modules/github.md +++ b/_site/content/posts/modules/github.md @@ -58,8 +58,8 @@ github: refreshInterval: 300 repositories: wesker-api: "UmbrellaCorp" - wtf: "senorprogrammer" - username: "senorprogrammer" + wtf: "andrewzolotukhin" + username: "andrewzolotukhin" ``` ### Attributes diff --git a/_site/content/posts/overview.md b/_site/content/posts/overview.md index 126715d7..14745096 100644 --- a/_site/content/posts/overview.md +++ b/_site/content/posts/overview.md @@ -12,7 +12,7 @@ visible, but might check in on every now and then. ## Quick Start -1. Download the stand-alone, compiled binary. +1. Download the stand-alone, compiled binary. 2. Unzip the downloaded file. 3. From the command line, `cd` into the newly-created `/wtf` directory. 4. From the command line, run the app: `./wtf` diff --git a/_site/themes/hyde-hyde/layouts/index.html b/_site/themes/hyde-hyde/layouts/index.html index 888abc24..27a35c8f 100644 --- a/_site/themes/hyde-hyde/layouts/index.html +++ b/_site/themes/hyde-hyde/layouts/index.html @@ -27,9 +27,9 @@ It even has weather. And clocks. And emoji.

    - Download Latest + Download Latest - On Github + On Github

    diff --git a/_site/themes/hyde-hyde/layouts/partials/sidebar.html b/_site/themes/hyde-hyde/layouts/partials/sidebar.html index fe5c83e2..e5e1709d 100644 --- a/_site/themes/hyde-hyde/layouts/partials/sidebar.html +++ b/_site/themes/hyde-hyde/layouts/partials/sidebar.html @@ -17,7 +17,7 @@

    - +
    diff --git a/bamboohr/item.go b/bamboohr/item.go index cc18590b..e7533e5c 100644 --- a/bamboohr/item.go +++ b/bamboohr/item.go @@ -4,7 +4,7 @@ import ( "fmt" //"time" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) type Item struct { diff --git a/bamboohr/widget.go b/bamboohr/widget.go index 1e9eb751..20b26eb1 100644 --- a/bamboohr/widget.go +++ b/bamboohr/widget.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/bargraph/widget.go b/bargraph/widget.go index 0e798952..ba7668f3 100644 --- a/bargraph/widget.go +++ b/bargraph/widget.go @@ -9,7 +9,7 @@ import ( "time" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/clocks/clock.go b/clocks/clock.go index fc4965fc..6d0e9615 100644 --- a/clocks/clock.go +++ b/clocks/clock.go @@ -3,7 +3,7 @@ package clocks import ( "time" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) type Clock struct { diff --git a/clocks/display.go b/clocks/display.go index 6cc7d60f..4fcd425d 100644 --- a/clocks/display.go +++ b/clocks/display.go @@ -3,7 +3,7 @@ package clocks import ( "fmt" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) func (widget *Widget) display(clocks []Clock) { diff --git a/clocks/widget.go b/clocks/widget.go index d6d6ee2a..be59c0f6 100644 --- a/clocks/widget.go +++ b/clocks/widget.go @@ -4,7 +4,7 @@ import ( "time" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cmdrunner/widget.go b/cmdrunner/widget.go index 0708527e..1dae8097 100644 --- a/cmdrunner/widget.go +++ b/cmdrunner/widget.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cryptoexchanges/bittrex/widget.go b/cryptoexchanges/bittrex/widget.go index 7bbf1003..5096774e 100644 --- a/cryptoexchanges/bittrex/widget.go +++ b/cryptoexchanges/bittrex/widget.go @@ -8,7 +8,7 @@ import ( "net/http" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cryptoexchanges/cryptolive/widget.go b/cryptoexchanges/cryptolive/widget.go index daaefa0e..8b7d5d99 100644 --- a/cryptoexchanges/cryptolive/widget.go +++ b/cryptoexchanges/cryptolive/widget.go @@ -7,7 +7,7 @@ import ( "time" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/docs/404.html b/docs/404.html index a6f51b08..62a99081 100644 --- a/docs/404.html +++ b/docs/404.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/categories/index.html b/docs/categories/index.html index b52bb86e..ec96925d 100644 --- a/docs/categories/index.html +++ b/docs/categories/index.html @@ -60,7 +60,7 @@ - +
    @@ -119,9 +119,9 @@ It even has weather. And clocks. And emoji.

    - Download Latest + Download Latest - On Github + On Github

    diff --git a/docs/index.xml b/docs/index.xml index a86b5ce2..2cfdb584 100644 --- a/docs/index.xml +++ b/docs/index.xml @@ -123,9 +123,9 @@ Quick Start Download the stand-alone, compiled binary. Unzip the downloaded fil https://wtfutil.com/posts/installation/ There are two ways to install WTF: From Source Get this repo and install the dependencies: -go get -u github.com/senorprogrammer/wtf cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run and that should probably do it. +go get -u github.com/andrewzolotukhin/wtf cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run and that should probably do it. As a Binary Grab the latest version from here: -https://github.com/senorprogrammer/wtf/releases expand it, and cd into the resulting directory. Then run: +https://github.com/andrewzolotukhin/wtf/releases expand it, and cd into the resulting directory. Then run: ./wtf and that should also do it. diff --git a/docs/posts/configuration/attributes/index.html b/docs/posts/configuration/attributes/index.html index a5354fce..48ee6a51 100644 --- a/docs/posts/configuration/attributes/index.html +++ b/docs/posts/configuration/attributes/index.html @@ -58,7 +58,7 @@

    - +
    @@ -114,7 +114,7 @@

    The following top-level attributes are configurable in config.yml. -See this example config file for more details.

    +See this example config file for more details.

    wtf:
       colors:
         background: "red"
    diff --git a/docs/posts/configuration/index.html b/docs/posts/configuration/index.html
    index ec410d85..d00dc4ed 100644
    --- a/docs/posts/configuration/index.html
    +++ b/docs/posts/configuration/index.html
    @@ -58,7 +58,7 @@
             
             
             
    -        
    +        
           
    diff --git a/docs/posts/configuration/iterm2/index.html b/docs/posts/configuration/iterm2/index.html index dcb4d6c6..3756a2a5 100644 --- a/docs/posts/configuration/iterm2/index.html +++ b/docs/posts/configuration/iterm2/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/glossary/index.html b/docs/posts/glossary/index.html index 9a4f7187..e4eb732f 100644 --- a/docs/posts/glossary/index.html +++ b/docs/posts/glossary/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/index.xml b/docs/posts/index.xml index 2dc5ba0f..3cba90d2 100644 --- a/docs/posts/index.xml +++ b/docs/posts/index.xml @@ -123,9 +123,9 @@ Quick Start Download the stand-alone, compiled binary. Unzip the downloaded fil https://wtfutil.com/posts/installation/ There are two ways to install WTF: From Source Get this repo and install the dependencies: -go get -u github.com/senorprogrammer/wtf cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run and that should probably do it. +go get -u github.com/andrewzolotukhin/wtf cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run and that should probably do it. As a Binary Grab the latest version from here: -https://github.com/senorprogrammer/wtf/releases expand it, and cd into the resulting directory. Then run: +https://github.com/andrewzolotukhin/wtf/releases expand it, and cd into the resulting directory. Then run: ./wtf and that should also do it. diff --git a/docs/posts/installation/index.html b/docs/posts/installation/index.html index 1237a416..046714fa 100644 --- a/docs/posts/installation/index.html +++ b/docs/posts/installation/index.html @@ -58,7 +58,7 @@ - +
    @@ -118,8 +118,8 @@

    From Source

    Get this repo and install the dependencies:

    -
    go get -u github.com/senorprogrammer/wtf
    -cd $GOPATH/src/github.com/senorprogrammer/wtf
    +
    go get -u github.com/andrewzolotukhin/wtf
    +cd $GOPATH/src/github.com/andrewzolotukhin/wtf
     make install
     make run

    and that should probably do it.

    @@ -127,7 +127,7 @@ make run

    As a Binary

    Grab the latest version from here:

    -
    https://github.com/senorprogrammer/wtf/releases
    +
    https://github.com/andrewzolotukhin/wtf/releases

    expand it, and cd into the resulting directory. Then run:

    ./wtf

    and that should also do it.

    diff --git a/docs/posts/modules/bamboohr/index.html b/docs/posts/modules/bamboohr/index.html index 240a8181..2c88de07 100644 --- a/docs/posts/modules/bamboohr/index.html +++ b/docs/posts/modules/bamboohr/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/bittrex/index.html b/docs/posts/modules/bittrex/index.html index 8ab9753c..ebe5ffd2 100644 --- a/docs/posts/modules/bittrex/index.html +++ b/docs/posts/modules/bittrex/index.html @@ -72,7 +72,7 @@ iTerm2
diff --git a/docs/posts/modules/clocks/index.html b/docs/posts/modules/clocks/index.html index 04333353..cbe3f548 100644 --- a/docs/posts/modules/clocks/index.html +++ b/docs/posts/modules/clocks/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cmdrunner/index.html b/docs/posts/modules/cmdrunner/index.html index 1ec0afca..5045938e 100644 --- a/docs/posts/modules/cmdrunner/index.html +++ b/docs/posts/modules/cmdrunner/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptocurrencies/bittrex/index.html b/docs/posts/modules/cryptocurrencies/bittrex/index.html index f9f033eb..bd942540 100644 --- a/docs/posts/modules/cryptocurrencies/bittrex/index.html +++ b/docs/posts/modules/cryptocurrencies/bittrex/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptocurrencies/cryptolive/index.html b/docs/posts/modules/cryptocurrencies/cryptolive/index.html index 832af988..e4d955ce 100644 --- a/docs/posts/modules/cryptocurrencies/cryptolive/index.html +++ b/docs/posts/modules/cryptocurrencies/cryptolive/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptolive/index.html b/docs/posts/modules/cryptolive/index.html index 63395a42..b4bfaccb 100644 --- a/docs/posts/modules/cryptolive/index.html +++ b/docs/posts/modules/cryptolive/index.html @@ -72,7 +72,7 @@ iTerm2
diff --git a/docs/posts/modules/gcal/index.html b/docs/posts/modules/gcal/index.html index 7e6f4a4b..f3dc25a2 100644 --- a/docs/posts/modules/gcal/index.html +++ b/docs/posts/modules/gcal/index.html @@ -58,7 +58,7 @@ - +
    @@ -118,7 +118,7 @@

    gcal screenshot

    Not: Setting up access to Google Calendars for Go is a bit unobvious. Check out Google’s Go Quickstart -first and if you have problems, then take a look at this comment by WesleydeSouza which offers a slightly different approach.

    +first and if you have problems, then take a look at this comment by WesleydeSouza which offers a slightly different approach.

    Source Code

    wtf/gcal/
    diff --git a/docs/posts/modules/git/index.html b/docs/posts/modules/git/index.html index e958c4f1..859d2e97 100644 --- a/docs/posts/modules/git/index.html +++ b/docs/posts/modules/git/index.html @@ -58,7 +58,7 @@ - +
    @@ -165,7 +165,7 @@ commit, and their status.

    width: 2 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/senorprogrammer/wtf" + - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" - "/Users/user/fakeapp"

    Attributes

    diff --git a/docs/posts/modules/github/index.html b/docs/posts/modules/github/index.html index eb556adb..edd073db 100644 --- a/docs/posts/modules/github/index.html +++ b/docs/posts/modules/github/index.html @@ -58,7 +58,7 @@ - +
    @@ -160,8 +160,8 @@ refreshInterval: 300 repositories: wesker-api: "UmbrellaCorp" - wtf: "senorprogrammer" - username: "senorprogrammer" + wtf: "andrewzolotukhin" + username: "andrewzolotukhin"

    Attributes

    enabled
    diff --git a/docs/posts/modules/index.html b/docs/posts/modules/index.html index fad43ff2..c38fde22 100644 --- a/docs/posts/modules/index.html +++ b/docs/posts/modules/index.html @@ -58,7 +58,7 @@

    - +
    diff --git a/docs/posts/modules/ipinfo/index.html b/docs/posts/modules/ipinfo/index.html index f3cd4865..b9f5de42 100644 --- a/docs/posts/modules/ipinfo/index.html +++ b/docs/posts/modules/ipinfo/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/jira/index.html b/docs/posts/modules/jira/index.html index 4a60fb7a..e7fa004e 100644 --- a/docs/posts/modules/jira/index.html +++ b/docs/posts/modules/jira/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/newrelic/index.html b/docs/posts/modules/newrelic/index.html index eac8a8db..2308dd5f 100644 --- a/docs/posts/modules/newrelic/index.html +++ b/docs/posts/modules/newrelic/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/opsgenie/index.html b/docs/posts/modules/opsgenie/index.html index dd2eef1a..01b445f8 100644 --- a/docs/posts/modules/opsgenie/index.html +++ b/docs/posts/modules/opsgenie/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/power/index.html b/docs/posts/modules/power/index.html index 7cbb1d72..0f2680a7 100644 --- a/docs/posts/modules/power/index.html +++ b/docs/posts/modules/power/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/prettyweather/index.html b/docs/posts/modules/prettyweather/index.html index d6bd7e91..4643e031 100644 --- a/docs/posts/modules/prettyweather/index.html +++ b/docs/posts/modules/prettyweather/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/security/index.html b/docs/posts/modules/security/index.html index 04437186..fb3d84f0 100644 --- a/docs/posts/modules/security/index.html +++ b/docs/posts/modules/security/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/textfile/index.html b/docs/posts/modules/textfile/index.html index c18d9229..dcc9451e 100644 --- a/docs/posts/modules/textfile/index.html +++ b/docs/posts/modules/textfile/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/todo/index.html b/docs/posts/modules/todo/index.html index 9ffa4bc6..e268ec38 100644 --- a/docs/posts/modules/todo/index.html +++ b/docs/posts/modules/todo/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/weather/index.html b/docs/posts/modules/weather/index.html index f22a2a21..ec437990 100644 --- a/docs/posts/modules/weather/index.html +++ b/docs/posts/modules/weather/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/overview/index.html b/docs/posts/overview/index.html index beef7287..bb073f93 100644 --- a/docs/posts/overview/index.html +++ b/docs/posts/overview/index.html @@ -58,7 +58,7 @@ - +
    @@ -122,7 +122,7 @@ visible, but might check in on every now and then.

    Quick Start

      -
    1. Download the stand-alone, compiled binary.
    2. +
    3. Download the stand-alone, compiled binary.
    4. Unzip the downloaded file.
    5. From the command line, cd into the newly-created /wtf directory.
    6. From the command line, run the app: ./wtf
    7. diff --git a/docs/tags/index.html b/docs/tags/index.html index 68425b68..8fe879ec 100644 --- a/docs/tags/index.html +++ b/docs/tags/index.html @@ -60,7 +60,7 @@ - +
    diff --git a/gcal/client.go b/gcal/client.go index de655620..698fe3b8 100644 --- a/gcal/client.go +++ b/gcal/client.go @@ -18,7 +18,7 @@ import ( "path/filepath" "time" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/calendar/v3" diff --git a/gcal/widget.go b/gcal/widget.go index 487c8daa..9a9b5a59 100644 --- a/gcal/widget.go +++ b/gcal/widget.go @@ -7,7 +7,7 @@ import ( "time" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" "google.golang.org/api/calendar/v3" ) diff --git a/git/display.go b/git/display.go index 8140615b..27d84893 100644 --- a/git/display.go +++ b/git/display.go @@ -5,7 +5,7 @@ import ( "strings" "unicode/utf8" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) func (widget *Widget) display() { diff --git a/git/git_repo.go b/git/git_repo.go index 5d3ba090..5852eeb6 100644 --- a/git/git_repo.go +++ b/git/git_repo.go @@ -5,7 +5,7 @@ import ( "os/exec" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) type GitRepo struct { diff --git a/git/widget.go b/git/widget.go index 89aad5a2..762f6833 100644 --- a/git/widget.go +++ b/git/widget.go @@ -4,7 +4,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/github/display.go b/github/display.go index e9346367..d61c2665 100644 --- a/github/display.go +++ b/github/display.go @@ -3,7 +3,7 @@ package github import ( "fmt" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) func (widget *Widget) display() { diff --git a/github/widget.go b/github/widget.go index 717f1bab..b6f22662 100644 --- a/github/widget.go +++ b/github/widget.go @@ -4,7 +4,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/gspreadsheets/client.go b/gspreadsheets/client.go index 1cf16321..7d48a2a4 100644 --- a/gspreadsheets/client.go +++ b/gspreadsheets/client.go @@ -18,7 +18,7 @@ import ( "path/filepath" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" "golang.org/x/oauth2" "golang.org/x/oauth2/google" sheets "google.golang.org/api/sheets/v4" diff --git a/gspreadsheets/widget.go b/gspreadsheets/widget.go index e754ce74..1a4bd220 100644 --- a/gspreadsheets/widget.go +++ b/gspreadsheets/widget.go @@ -3,7 +3,7 @@ package gspreadsheets import ( "fmt" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" sheets "google.golang.org/api/sheets/v4" ) diff --git a/help/help.go b/help/help.go index cf79c930..a2cf1e79 100644 --- a/help/help.go +++ b/help/help.go @@ -4,11 +4,11 @@ import ( "fmt" "os" - "github.com/senorprogrammer/wtf/git" - "github.com/senorprogrammer/wtf/github" - "github.com/senorprogrammer/wtf/textfile" - "github.com/senorprogrammer/wtf/todo" - "github.com/senorprogrammer/wtf/weather" + "github.com/andrewzolotukhin/wtf/git" + "github.com/andrewzolotukhin/wtf/github" + "github.com/andrewzolotukhin/wtf/textfile" + "github.com/andrewzolotukhin/wtf/todo" + "github.com/andrewzolotukhin/wtf/weather" ) func DisplayModuleInfo(moduleName string) { diff --git a/ipinfo/widget.go b/ipinfo/widget.go index 62db1732..c445ecae 100644 --- a/ipinfo/widget.go +++ b/ipinfo/widget.go @@ -9,7 +9,7 @@ import ( "bytes" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/jira/widget.go b/jira/widget.go index 6ca9670e..2709eff2 100644 --- a/jira/widget.go +++ b/jira/widget.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/newrelic/widget.go b/newrelic/widget.go index ca16966f..b765758b 100644 --- a/newrelic/widget.go +++ b/newrelic/widget.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" nr "github.com/yfronto/newrelic" ) diff --git a/opsgenie/widget.go b/opsgenie/widget.go index 314b832a..dbb9eed2 100644 --- a/opsgenie/widget.go +++ b/opsgenie/widget.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/power/battery.go b/power/battery.go index 08b7fdfe..96c57262 100644 --- a/power/battery.go +++ b/power/battery.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) const TimeRegExp = "^(?:\\d|[01]\\d|2[0-3]):[0-5]\\d" diff --git a/power/battery_linux.go b/power/battery_linux.go index 693d95b6..720c110d 100644 --- a/power/battery_linux.go +++ b/power/battery_linux.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) var batteryState string diff --git a/power/source.go b/power/source.go index e6eff36c..f28e7c2f 100644 --- a/power/source.go +++ b/power/source.go @@ -7,7 +7,7 @@ import ( "regexp" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) const SingleQuotesRegExp = "'(.*)'" diff --git a/power/widget.go b/power/widget.go index d3d3a996..c7be5b01 100644 --- a/power/widget.go +++ b/power/widget.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/prettyweather/widget.go b/prettyweather/widget.go index c0ef7596..4e579b2c 100644 --- a/prettyweather/widget.go +++ b/prettyweather/widget.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/security/dns.go b/security/dns.go index 2408c2c1..5a458744 100644 --- a/security/dns.go +++ b/security/dns.go @@ -5,7 +5,7 @@ import ( "runtime" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) /* -------------------- Exported Functions -------------------- */ diff --git a/security/firewall.go b/security/firewall.go index 6323b5e1..828c3bf0 100644 --- a/security/firewall.go +++ b/security/firewall.go @@ -5,7 +5,7 @@ import ( "runtime" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) const osxFirewallCmd = "/usr/libexec/ApplicationFirewall/socketfilterfw" diff --git a/security/users.go b/security/users.go index b8fe5164..77a41243 100644 --- a/security/users.go +++ b/security/users.go @@ -7,7 +7,7 @@ import ( "runtime" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) /* -------------------- Exported Functions -------------------- */ diff --git a/security/widget.go b/security/widget.go index f5769b8e..cdcc7ac1 100644 --- a/security/widget.go +++ b/security/widget.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/security/wifi.go b/security/wifi.go index 30b75767..b152a7ba 100644 --- a/security/wifi.go +++ b/security/wifi.go @@ -4,7 +4,7 @@ import ( "os/exec" "runtime" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // https://github.com/yelinaung/wifi-name/blob/master/wifi-name.go diff --git a/status/widget.go b/status/widget.go index 3bd71599..67bb6977 100644 --- a/status/widget.go +++ b/status/widget.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/system/system_info.go b/system/system_info.go index 1582ebe7..eb8d5c2d 100644 --- a/system/system_info.go +++ b/system/system_info.go @@ -5,7 +5,7 @@ import ( "runtime" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) type SystemInfo struct { diff --git a/system/widget.go b/system/widget.go index c13ed5ea..530e8400 100644 --- a/system/widget.go +++ b/system/widget.go @@ -5,7 +5,7 @@ import ( "time" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/textfile/widget.go b/textfile/widget.go index 2bc3afe6..5aa5b426 100644 --- a/textfile/widget.go +++ b/textfile/widget.go @@ -7,7 +7,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/todo/display.go b/todo/display.go index d25d20cb..ea20f873 100644 --- a/todo/display.go +++ b/todo/display.go @@ -3,7 +3,7 @@ package todo import ( "fmt" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) const checkWidth = 4 diff --git a/todo/widget.go b/todo/widget.go index 00dcb984..93014f29 100644 --- a/todo/widget.go +++ b/todo/widget.go @@ -7,7 +7,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" "gopkg.in/yaml.v2" ) diff --git a/weather/display.go b/weather/display.go index 1b237789..84711640 100644 --- a/weather/display.go +++ b/weather/display.go @@ -5,7 +5,7 @@ import ( "strings" owm "github.com/briandowns/openweathermap" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) func (widget *Widget) display() { diff --git a/weather/widget.go b/weather/widget.go index 992c7207..dce962ee 100644 --- a/weather/widget.go +++ b/weather/widget.go @@ -7,7 +7,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object. diff --git a/wtf.go b/wtf.go index 22659cd7..71443c45 100644 --- a/wtf.go +++ b/wtf.go @@ -10,30 +10,30 @@ import ( "github.com/olebedev/config" "github.com/radovskyb/watcher" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/bamboohr" - "github.com/senorprogrammer/wtf/bargraph" - "github.com/senorprogrammer/wtf/clocks" - "github.com/senorprogrammer/wtf/cmdrunner" - "github.com/senorprogrammer/wtf/cryptoexchanges/bittrex" - "github.com/senorprogrammer/wtf/cryptoexchanges/cryptolive" - "github.com/senorprogrammer/wtf/gcal" - "github.com/senorprogrammer/wtf/gspreadsheets" - "github.com/senorprogrammer/wtf/git" - "github.com/senorprogrammer/wtf/github" - "github.com/senorprogrammer/wtf/help" - "github.com/senorprogrammer/wtf/ipinfo" - "github.com/senorprogrammer/wtf/jira" - "github.com/senorprogrammer/wtf/newrelic" - "github.com/senorprogrammer/wtf/opsgenie" - "github.com/senorprogrammer/wtf/power" - "github.com/senorprogrammer/wtf/prettyweather" - "github.com/senorprogrammer/wtf/security" - "github.com/senorprogrammer/wtf/status" - "github.com/senorprogrammer/wtf/system" - "github.com/senorprogrammer/wtf/textfile" - "github.com/senorprogrammer/wtf/todo" - "github.com/senorprogrammer/wtf/weather" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/bamboohr" + "github.com/andrewzolotukhin/wtf/bargraph" + "github.com/andrewzolotukhin/wtf/clocks" + "github.com/andrewzolotukhin/wtf/cmdrunner" + "github.com/andrewzolotukhin/wtf/cryptoexchanges/bittrex" + "github.com/andrewzolotukhin/wtf/cryptoexchanges/cryptolive" + "github.com/andrewzolotukhin/wtf/gcal" + "github.com/andrewzolotukhin/wtf/gspreadsheets" + "github.com/andrewzolotukhin/wtf/git" + "github.com/andrewzolotukhin/wtf/github" + "github.com/andrewzolotukhin/wtf/help" + "github.com/andrewzolotukhin/wtf/ipinfo" + "github.com/andrewzolotukhin/wtf/jira" + "github.com/andrewzolotukhin/wtf/newrelic" + "github.com/andrewzolotukhin/wtf/opsgenie" + "github.com/andrewzolotukhin/wtf/power" + "github.com/andrewzolotukhin/wtf/prettyweather" + "github.com/andrewzolotukhin/wtf/security" + "github.com/andrewzolotukhin/wtf/status" + "github.com/andrewzolotukhin/wtf/system" + "github.com/andrewzolotukhin/wtf/textfile" + "github.com/andrewzolotukhin/wtf/todo" + "github.com/andrewzolotukhin/wtf/weather" + "github.com/andrewzolotukhin/wtf/wtf" ) /* -------------------- Functions -------------------- */ diff --git a/wtf/config_files.go b/wtf/config_files.go index ff57654d..2e60351d 100644 --- a/wtf/config_files.go +++ b/wtf/config_files.go @@ -63,7 +63,7 @@ func LoadConfigFile(filePath string) *config.Config { cfg, err := config.ParseYamlFile(absPath) if err != nil { - fmt.Println("\n\n\033[1m ERROR:\033[0m Could not load '\033[0;33mconfig.yml\033[0m'.\n Please add a \033[0;33mconfig.yml\033[0m file to your \033[0;33m~/.wtf\033[0m directory.\n See \033[1;34mhttps://github.com/senorprogrammer/wtf\033[0m for details.\n") + fmt.Println("\n\n\033[1m ERROR:\033[0m Could not load '\033[0;33mconfig.yml\033[0m'.\n Please add a \033[0;33mconfig.yml\033[0m file to your \033[0;33m~/.wtf\033[0m directory.\n See \033[1;34mhttps://github.com/andrewzolotukhin/wtf\033[0m for details.\n") fmt.Printf(" %s\n", err.Error()) os.Exit(1) } diff --git a/wtf_tests/position_test.go b/wtf_tests/position_test.go index 370a3373..7dd5e8c5 100644 --- a/wtf_tests/position_test.go +++ b/wtf_tests/position_test.go @@ -3,7 +3,7 @@ package wtf_tests import ( "testing" - . "github.com/senorprogrammer/wtf/wtf" + . "github.com/andrewzolotukhin/wtf/wtf" ) func TestPosition(t *testing.T) { diff --git a/wtf_tests/utils_test.go b/wtf_tests/utils_test.go index a069301c..2d347150 100644 --- a/wtf_tests/utils_test.go +++ b/wtf_tests/utils_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/go-test/deep" - . "github.com/senorprogrammer/wtf/wtf" + . "github.com/andrewzolotukhin/wtf/wtf" ) /* -------------------- Exclude() -------------------- */ From e633d4d617ffdabf8cec5cd57dcd85feb0cdd971 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 01:48:01 +0300 Subject: [PATCH 06/58] Added widget for blockfolio --- blockfolio/widget.go | 106 +++++++++++++++++++++++++++++++++++++++++++ wtf.go | 14 ++++-- 2 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 blockfolio/widget.go diff --git a/blockfolio/widget.go b/blockfolio/widget.go new file mode 100644 index 00000000..04ed4cd8 --- /dev/null +++ b/blockfolio/widget.go @@ -0,0 +1,106 @@ +package blockfolio + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + + "github.com/andrewzolotukhin/wtf/wtf" + "github.com/olebedev/config" + "github.com/rivo/tview" +) + +// Config is a pointer to the global config object +var Config *config.Config + +type Widget struct { + wtf.TextWidget + + app *tview.Application + device_token string +} + +func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { + widget := Widget{ + TextWidget: wtf.NewTextWidget(" Blockfolio ", "blockfolio", true), + device_token: Config.UString("wtf.mods.blockfolio.device_token"), + } + + return &widget +} + +/* -------------------- Exported Functions -------------------- */ + +func (widget *Widget) Refresh() { + widget.UpdateRefreshedAt() + widget.View.SetTitle(" Blockfolio ") + + positions, _ := Fetch(widget.device_token) + if _ != nil { + return + } + widget.View.SetText(fmt.Sprintf("%s", contentFrom(positions))) +} + +/* -------------------- Unexported Functions -------------------- */ +func contentFrom(positions AllPositionsResponse) string { + res := "" + for i := 0; i < len(positions.PositionList); i++ { + res = res + "a" + } + + return res +} + +//always the same +const magic = "edtopjhgn2345piuty89whqejfiobh89-2q453" + +type Position struct { + Coin string `json:coin` + LastPriceFiat float32 `json:lastPriceFiat` + TwentyFourHourPercentChangeFiat float32 `json:twentyFourHourPercentChangeFiat` + Quantity float32 `json:quantity` + HoldingValueFiat float32 `json:holdingValueFiat` +} + +type AllPositionsResponse struct { + PositionList []Position `json:positionList` +} + +func MakeApiRequest(token string, method string) ([]byte, error) { + client := &http.Client{} + url := "https://api-v0.blockfolio.com/rest/" + method + "/" + token + "?use_alias=true&fiat_currency=USD" + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + req.Header.Add("magic", magic) + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return body, err +} + +func GetAllPositions(token string) (*AllPositionsResponse, error) { + jsn, err := MakeApiRequest(token, "get_all_positions") + var parsed AllPositionsResponse + + err = json.Unmarshal(jsn, &parsed) + if err != nil { + log.Fatalf("Failed to parse json %v", err) + return nil, err + } + return &parsed, err +} + +func Fetch(token string) (*AllPositionsResponse, error) { + return GetAllPositions(token) +} diff --git a/wtf.go b/wtf.go index 71443c45..d2b41a68 100644 --- a/wtf.go +++ b/wtf.go @@ -6,20 +6,17 @@ import ( "os" "time" - "github.com/gdamore/tcell" - "github.com/olebedev/config" - "github.com/radovskyb/watcher" - "github.com/rivo/tview" "github.com/andrewzolotukhin/wtf/bamboohr" "github.com/andrewzolotukhin/wtf/bargraph" + "github.com/andrewzolotukhin/wtf/blockfolio" "github.com/andrewzolotukhin/wtf/clocks" "github.com/andrewzolotukhin/wtf/cmdrunner" "github.com/andrewzolotukhin/wtf/cryptoexchanges/bittrex" "github.com/andrewzolotukhin/wtf/cryptoexchanges/cryptolive" "github.com/andrewzolotukhin/wtf/gcal" - "github.com/andrewzolotukhin/wtf/gspreadsheets" "github.com/andrewzolotukhin/wtf/git" "github.com/andrewzolotukhin/wtf/github" + "github.com/andrewzolotukhin/wtf/gspreadsheets" "github.com/andrewzolotukhin/wtf/help" "github.com/andrewzolotukhin/wtf/ipinfo" "github.com/andrewzolotukhin/wtf/jira" @@ -34,6 +31,10 @@ import ( "github.com/andrewzolotukhin/wtf/todo" "github.com/andrewzolotukhin/wtf/weather" "github.com/andrewzolotukhin/wtf/wtf" + "github.com/gdamore/tcell" + "github.com/olebedev/config" + "github.com/radovskyb/watcher" + "github.com/rivo/tview" ) /* -------------------- Functions -------------------- */ @@ -210,6 +211,8 @@ func addWidget(app *tview.Application, pages *tview.Pages, widgetName string) { Widgets = append(Widgets, todo.NewWidget(app, pages)) case "weather": Widgets = append(Widgets, weather.NewWidget(app, pages)) + case "blockfolio": + Widgets = append(Widgets, blockfolio.NewWidget(app, pages)) default: } } @@ -240,6 +243,7 @@ func makeWidgets(app *tview.Application, pages *tview.Pages) { textfile.Config = Config todo.Config = Config weather.Config = Config + blockfolio.Config = Config wtf.Config = Config mods, _ := Config.Map("wtf.mods") From 51ce54583306464862f4481032e27d0e695d6818 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 01:51:15 +0300 Subject: [PATCH 07/58] Fixed error --- blockfolio/widget.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 04ed4cd8..3254c3b3 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -37,15 +37,15 @@ func (widget *Widget) Refresh() { widget.UpdateRefreshedAt() widget.View.SetTitle(" Blockfolio ") - positions, _ := Fetch(widget.device_token) - if _ != nil { + positions, err := Fetch(widget.device_token) + if err != nil { return } widget.View.SetText(fmt.Sprintf("%s", contentFrom(positions))) } /* -------------------- Unexported Functions -------------------- */ -func contentFrom(positions AllPositionsResponse) string { +func contentFrom(positions *AllPositionsResponse) string { res := "" for i := 0; i < len(positions.PositionList); i++ { res = res + "a" From cf005c48f5a5a940dd8955d2449eb2a3250ddaf7 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:04:49 +0300 Subject: [PATCH 08/58] Added formating --- blockfolio/widget.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 3254c3b3..0ae8da6e 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -47,8 +47,16 @@ func (widget *Widget) Refresh() { /* -------------------- Unexported Functions -------------------- */ func contentFrom(positions *AllPositionsResponse) string { res := "" + colorName := Config.USTRING("wtf.mods.blockfolio.colors.name") + colorPrice := Config.USTRING("wtf.mods.blockfolio.colors.price") + colorGrows := Config.USTRING("wtf.mods.blockfolio.colors.grows") + colorDrop := Config.USTRING("wtf.mods.blockfolio.colors.drop") for i := 0; i < len(positions.PositionList); i++ { - res = res + "a" + colorForChange := colorGrows + if positions.PositionList[i].TwentyFourHourPercentChangeFiat <= 0 { + colorForChange = colorDrop + } + res = res + fmt.Sprintf(" [%s]%6s - [%s]%.2f", colorName, positions.PositionList[i].Coin, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat) } return res From 934023ef1d1b33d3bec9881f813f59d1a4347000 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:06:40 +0300 Subject: [PATCH 09/58] Fixed typo --- blockfolio/widget.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 0ae8da6e..dee6befe 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -47,10 +47,10 @@ func (widget *Widget) Refresh() { /* -------------------- Unexported Functions -------------------- */ func contentFrom(positions *AllPositionsResponse) string { res := "" - colorName := Config.USTRING("wtf.mods.blockfolio.colors.name") - colorPrice := Config.USTRING("wtf.mods.blockfolio.colors.price") - colorGrows := Config.USTRING("wtf.mods.blockfolio.colors.grows") - colorDrop := Config.USTRING("wtf.mods.blockfolio.colors.drop") + colorName := Config.UString("wtf.mods.blockfolio.colors.name") + colorPrice := Config.UString("wtf.mods.blockfolio.colors.price") + colorGrows := Config.UString("wtf.mods.blockfolio.colors.grows") + colorDrop := Config.UString("wtf.mods.blockfolio.colors.drop") for i := 0; i < len(positions.PositionList); i++ { colorForChange := colorGrows if positions.PositionList[i].TwentyFourHourPercentChangeFiat <= 0 { From 05289885d36e39ed1558670dbc0ec5f7d7f1edf2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:09:06 +0300 Subject: [PATCH 10/58] Fix --- blockfolio/widget.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index dee6befe..03c1e3cf 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -48,7 +48,7 @@ func (widget *Widget) Refresh() { func contentFrom(positions *AllPositionsResponse) string { res := "" colorName := Config.UString("wtf.mods.blockfolio.colors.name") - colorPrice := Config.UString("wtf.mods.blockfolio.colors.price") +// colorPrice := Config.UString("wtf.mods.blockfolio.colors.price") colorGrows := Config.UString("wtf.mods.blockfolio.colors.grows") colorDrop := Config.UString("wtf.mods.blockfolio.colors.drop") for i := 0; i < len(positions.PositionList); i++ { @@ -56,7 +56,7 @@ func contentFrom(positions *AllPositionsResponse) string { if positions.PositionList[i].TwentyFourHourPercentChangeFiat <= 0 { colorForChange = colorDrop } - res = res + fmt.Sprintf(" [%s]%6s - [%s]%.2f", colorName, positions.PositionList[i].Coin, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat) + res = res + fmt.Sprintf(" [%s]%6s - ([%s]%.2f\%)", colorName, positions.PositionList[i].Coin, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat) } return res From 557aa15e058fe10f31ddc6d919af2c36ff2526f6 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:10:30 +0300 Subject: [PATCH 11/58] Fix --- blockfolio/widget.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 03c1e3cf..307b30bc 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -48,7 +48,7 @@ func (widget *Widget) Refresh() { func contentFrom(positions *AllPositionsResponse) string { res := "" colorName := Config.UString("wtf.mods.blockfolio.colors.name") -// colorPrice := Config.UString("wtf.mods.blockfolio.colors.price") + // colorPrice := Config.UString("wtf.mods.blockfolio.colors.price") colorGrows := Config.UString("wtf.mods.blockfolio.colors.grows") colorDrop := Config.UString("wtf.mods.blockfolio.colors.drop") for i := 0; i < len(positions.PositionList); i++ { @@ -56,7 +56,7 @@ func contentFrom(positions *AllPositionsResponse) string { if positions.PositionList[i].TwentyFourHourPercentChangeFiat <= 0 { colorForChange = colorDrop } - res = res + fmt.Sprintf(" [%s]%6s - ([%s]%.2f\%)", colorName, positions.PositionList[i].Coin, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat) + res = res + fmt.Sprintf(" [%s]%6s - ([%s]%.2f%)", colorName, positions.PositionList[i].Coin, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat) } return res From cdca85a10a41f331541f25343fa9b68fd955062a Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:16:26 +0300 Subject: [PATCH 12/58] Fix --- blockfolio/widget.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 307b30bc..cb146574 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -48,7 +48,6 @@ func (widget *Widget) Refresh() { func contentFrom(positions *AllPositionsResponse) string { res := "" colorName := Config.UString("wtf.mods.blockfolio.colors.name") - // colorPrice := Config.UString("wtf.mods.blockfolio.colors.price") colorGrows := Config.UString("wtf.mods.blockfolio.colors.grows") colorDrop := Config.UString("wtf.mods.blockfolio.colors.drop") for i := 0; i < len(positions.PositionList); i++ { @@ -56,7 +55,7 @@ func contentFrom(positions *AllPositionsResponse) string { if positions.PositionList[i].TwentyFourHourPercentChangeFiat <= 0 { colorForChange = colorDrop } - res = res + fmt.Sprintf(" [%s]%6s - ([%s]%.2f%)", colorName, positions.PositionList[i].Coin, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat) + res = res + fmt.Sprintf("[%s]%6s - %3d ([%s]%.2f [%s]%.2f%)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].HoldingValueFiat/1000, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat) } return res From aff01f7fde597dbece4a4e4736a42f1aad1ab386 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:23:16 +0300 Subject: [PATCH 13/58] Added total --- blockfolio/widget.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index cb146574..c9f49be6 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -50,13 +50,16 @@ func contentFrom(positions *AllPositionsResponse) string { colorName := Config.UString("wtf.mods.blockfolio.colors.name") colorGrows := Config.UString("wtf.mods.blockfolio.colors.grows") colorDrop := Config.UString("wtf.mods.blockfolio.colors.drop") + totalFiat := 0 for i := 0; i < len(positions.PositionList); i++ { colorForChange := colorGrows if positions.PositionList[i].TwentyFourHourPercentChangeFiat <= 0 { colorForChange = colorDrop } - res = res + fmt.Sprintf("[%s]%6s - %3d ([%s]%.2f [%s]%.2f%)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].HoldingValueFiat/1000, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat) + totalFiat += positions.PositionList[i].HoldingValueFiat + res = res + fmt.Sprintf("[%s]%6s - %5.2f ([%s]%.2fk [%s]%.2f%)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].HoldingValueFiat/1000, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat) } + res = res + fmt.Sprintf("\n[%s]Total value: $%.2f", "green", totalFiat/1000) return res } From 82e81b9a218a88648c89f8e39a774b14f9e92c6c Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:24:46 +0300 Subject: [PATCH 14/58] Fix --- blockfolio/widget.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index c9f49be6..2fe23e51 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -50,7 +50,7 @@ func contentFrom(positions *AllPositionsResponse) string { colorName := Config.UString("wtf.mods.blockfolio.colors.name") colorGrows := Config.UString("wtf.mods.blockfolio.colors.grows") colorDrop := Config.UString("wtf.mods.blockfolio.colors.drop") - totalFiat := 0 + totalFiat := 0.0 for i := 0; i < len(positions.PositionList); i++ { colorForChange := colorGrows if positions.PositionList[i].TwentyFourHourPercentChangeFiat <= 0 { From 71364c92f8737b68172c8486003a4da4939386fa Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:26:36 +0300 Subject: [PATCH 15/58] Fix --- blockfolio/widget.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 2fe23e51..9458fd24 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -50,7 +50,8 @@ func contentFrom(positions *AllPositionsResponse) string { colorName := Config.UString("wtf.mods.blockfolio.colors.name") colorGrows := Config.UString("wtf.mods.blockfolio.colors.grows") colorDrop := Config.UString("wtf.mods.blockfolio.colors.drop") - totalFiat := 0.0 + var totalFiat float32 + totalFiat = 0.0 for i := 0; i < len(positions.PositionList); i++ { colorForChange := colorGrows if positions.PositionList[i].TwentyFourHourPercentChangeFiat <= 0 { From 6b515d8d51bed6b246ce63b02dd4fb1d9847b71b Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:29:49 +0300 Subject: [PATCH 16/58] Fix --- blockfolio/widget.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 9458fd24..aca5c1dc 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -58,9 +58,9 @@ func contentFrom(positions *AllPositionsResponse) string { colorForChange = colorDrop } totalFiat += positions.PositionList[i].HoldingValueFiat - res = res + fmt.Sprintf("[%s]%6s - %5.2f ([%s]%.2fk [%s]%.2f%)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].HoldingValueFiat/1000, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat) + res = res + fmt.Sprintf("[%s]%6s - %5.2f ([%s]%.2fk [%s]%.2f%s)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].HoldingValueFiat/1000, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat, "%") } - res = res + fmt.Sprintf("\n[%s]Total value: $%.2f", "green", totalFiat/1000) + res = res + fmt.Sprintf("\n[%s]Total value: $%.2fk", "green", totalFiat/1000) return res } From 4cadaf0ccee74655727bbccfc6d09a24d282a2a4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:34:43 +0300 Subject: [PATCH 17/58] Fix --- blockfolio/widget.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index aca5c1dc..657e4c7d 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -24,7 +24,7 @@ type Widget struct { func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { widget := Widget{ - TextWidget: wtf.NewTextWidget(" Blockfolio ", "blockfolio", true), + TextWidget: wtf.NewTextWidget(" Blockfolio ", "blockfolio", false), device_token: Config.UString("wtf.mods.blockfolio.device_token"), } @@ -58,7 +58,7 @@ func contentFrom(positions *AllPositionsResponse) string { colorForChange = colorDrop } totalFiat += positions.PositionList[i].HoldingValueFiat - res = res + fmt.Sprintf("[%s]%6s - %5.2f ([%s]%.2fk [%s]%.2f%s)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].HoldingValueFiat/1000, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat, "%") + res = res + fmt.Sprintf("[%s]%-6s - %5.2f ([%s]%.2fk [%s]%.2f%s)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].HoldingValueFiat/1000, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat, "%") } res = res + fmt.Sprintf("\n[%s]Total value: $%.2fk", "green", totalFiat/1000) From d3d70f8450df7796209eb16292d12ab133362266 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:44:26 +0300 Subject: [PATCH 18/58] Added displayHoldings setting --- blockfolio/widget.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 657e4c7d..6e2d156c 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -50,6 +50,7 @@ func contentFrom(positions *AllPositionsResponse) string { colorName := Config.UString("wtf.mods.blockfolio.colors.name") colorGrows := Config.UString("wtf.mods.blockfolio.colors.grows") colorDrop := Config.UString("wtf.mods.blockfolio.colors.drop") + displayHoldings := Config.UBool("wtf.mods.blockfolio.displayHoldings") var totalFiat float32 totalFiat = 0.0 for i := 0; i < len(positions.PositionList); i++ { @@ -58,9 +59,15 @@ func contentFrom(positions *AllPositionsResponse) string { colorForChange = colorDrop } totalFiat += positions.PositionList[i].HoldingValueFiat - res = res + fmt.Sprintf("[%s]%-6s - %5.2f ([%s]%.2fk [%s]%.2f%s)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].HoldingValueFiat/1000, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat, "%") + if displayHoldings { + res = res + fmt.Sprintf("[%s]%-6s - %5.2f ([%s]%.3fk [%s]%.2f%s)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].HoldingValueFiat/1000, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat, "%") + } else { + res = res + fmt.Sprintf("[%s]%-6s - %5.2f ([%s]%.2f%s)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat, "%") + } + } + if displayHoldings { + res = res + fmt.Sprintf("\n[%s]Total value: $%.3fk", "green", totalFiat/1000) } - res = res + fmt.Sprintf("\n[%s]Total value: $%.2fk", "green", totalFiat/1000) return res } From 856491ae49edd313915c9baa47668b6a1b2a853b Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:47:00 +0300 Subject: [PATCH 19/58] Fix --- blockfolio/widget.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 6e2d156c..66f3a727 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -62,7 +62,7 @@ func contentFrom(positions *AllPositionsResponse) string { if displayHoldings { res = res + fmt.Sprintf("[%s]%-6s - %5.2f ([%s]%.3fk [%s]%.2f%s)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].HoldingValueFiat/1000, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat, "%") } else { - res = res + fmt.Sprintf("[%s]%-6s - %5.2f ([%s]%.2f%s)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat, "%") + res = res + fmt.Sprintf("[%s]%-6s - %5.2f ([%s]%.2f%s)\n", colorName, positions.PositionList[i].Coin, positions.PositionList[i].Quantity, colorForChange, positions.PositionList[i].TwentyFourHourPercentChangeFiat, "%") } } if displayHoldings { From 6288c701566a9b3b2677788937f2642603822b82 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:50:16 +0300 Subject: [PATCH 20/58] Returned names of repo --- .travis.yml | 10 ++-- README.md | 10 ++-- _sample_configs/complex_config.yml | 6 +-- .../content/posts/configuration/attributes.md | 2 +- _site/content/posts/installation.md | 6 +-- _site/content/posts/modules/gcal.md | 2 +- _site/content/posts/modules/git.md | 2 +- _site/content/posts/modules/github.md | 4 +- _site/content/posts/overview.md | 2 +- _site/themes/hyde-hyde/layouts/index.html | 4 +- .../hyde-hyde/layouts/partials/sidebar.html | 2 +- bamboohr/item.go | 2 +- bamboohr/widget.go | 2 +- bargraph/widget.go | 2 +- clocks/clock.go | 2 +- clocks/display.go | 2 +- clocks/widget.go | 2 +- cmdrunner/widget.go | 2 +- cryptoexchanges/bittrex/widget.go | 2 +- cryptoexchanges/cryptolive/widget.go | 2 +- docs/404.html | 2 +- docs/categories/index.html | 2 +- docs/index.html | 6 +-- docs/index.xml | 4 +- .../posts/configuration/attributes/index.html | 4 +- docs/posts/configuration/index.html | 2 +- docs/posts/configuration/iterm2/index.html | 2 +- docs/posts/glossary/index.html | 2 +- docs/posts/index.html | 2 +- docs/posts/index.xml | 4 +- docs/posts/installation/index.html | 8 +-- docs/posts/modules/bamboohr/index.html | 2 +- docs/posts/modules/bittrex/index.html | 2 +- docs/posts/modules/clocks/index.html | 2 +- docs/posts/modules/cmdrunner/index.html | 2 +- .../cryptocurrencies/bittrex/index.html | 2 +- .../cryptocurrencies/cryptolive/index.html | 2 +- docs/posts/modules/cryptolive/index.html | 2 +- docs/posts/modules/gcal/index.html | 4 +- docs/posts/modules/git/index.html | 4 +- docs/posts/modules/github/index.html | 6 +-- docs/posts/modules/index.html | 2 +- docs/posts/modules/ipinfo/index.html | 2 +- docs/posts/modules/jira/index.html | 2 +- docs/posts/modules/newrelic/index.html | 2 +- docs/posts/modules/opsgenie/index.html | 2 +- docs/posts/modules/power/index.html | 2 +- docs/posts/modules/prettyweather/index.html | 2 +- docs/posts/modules/security/index.html | 2 +- docs/posts/modules/textfile/index.html | 2 +- docs/posts/modules/todo/index.html | 2 +- docs/posts/modules/weather/index.html | 2 +- docs/posts/overview/index.html | 4 +- docs/tags/index.html | 2 +- gcal/client.go | 2 +- gcal/widget.go | 2 +- git/display.go | 2 +- git/git_repo.go | 2 +- git/widget.go | 2 +- github/display.go | 2 +- github/widget.go | 2 +- gspreadsheets/client.go | 2 +- gspreadsheets/widget.go | 2 +- help/help.go | 10 ++-- ipinfo/widget.go | 2 +- jira/widget.go | 2 +- newrelic/widget.go | 2 +- opsgenie/widget.go | 2 +- power/battery.go | 2 +- power/battery_linux.go | 2 +- power/source.go | 2 +- power/widget.go | 2 +- prettyweather/widget.go | 2 +- security/dns.go | 2 +- security/firewall.go | 2 +- security/users.go | 2 +- security/widget.go | 2 +- security/wifi.go | 2 +- status/widget.go | 2 +- system/system_info.go | 2 +- system/widget.go | 2 +- textfile/widget.go | 2 +- todo/display.go | 2 +- todo/widget.go | 2 +- weather/display.go | 2 +- weather/widget.go | 2 +- wtf.go | 50 +++++++++---------- wtf/config_files.go | 2 +- wtf_tests/position_test.go | 2 +- wtf_tests/utils_test.go | 2 +- 90 files changed, 145 insertions(+), 145 deletions(-) diff --git a/.travis.yml b/.travis.yml index c90dfc89..b20b9c4a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,9 @@ go: sudo: false before_install: # Make sure travis builds work for forks - - mkdir -p $TRAVIS_BUILD_DIR $GOPATH/src/github.com/andrewzolotukhin - - test ! -d $GOPATH/src/github.com/andrewzolotukhin/wtf && mv $TRAVIS_BUILD_DIR $GOPATH/src/github.com/andrewzolotukhin/wtf || true - - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/andrewzolotukhin/wtf - - cd $HOME/gopath/src/github.com/andrewzolotukhin/wtf + - mkdir -p $TRAVIS_BUILD_DIR $GOPATH/src/github.com/senorprogrammer + - test ! -d $GOPATH/src/github.com/senorprogrammer/wtf && mv $TRAVIS_BUILD_DIR $GOPATH/src/github.com/senorprogrammer/wtf || true + - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/senorprogrammer/wtf + - cd $HOME/gopath/src/github.com/senorprogrammer/wtf -script: go get ./... && go get github.com/go-test/deep && go test -v github.com/andrewzolotukhin/wtf/wtf_tests +script: go get ./... && go get github.com/go-test/deep && go test -v github.com/senorprogrammer/wtf/wtf_tests diff --git a/README.md b/README.md index 7d5fb882..705c2be5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

    - +

    @@ -21,13 +21,13 @@ displaying infrequently-needed, but very important, daily data. **Note:** WTF is _only_ compatible with Go versions **1.9.2** or later. It currently _does not_ compile with `gccgo`. ```bash -go get -u github.com/andrewzolotukhin/wtf -cd $GOPATH/src/github.com/andrewzolotukhin/wtf +go get -u github.com/senorprogrammer/wtf +cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run ``` -Or [download the latest binary](https://github.com/andrewzolotukhin/wtf/releases). +Or [download the latest binary](https://github.com/senorprogrammer/wtf/releases). ## Support @@ -70,7 +70,7 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduc ## Authors -* Chris Cummer, [andrewzolotukhin](https://github.com/andrewzolotukhin) +* Chris Cummer, [senorprogrammer](https://github.com/senorprogrammer) ## License diff --git a/_sample_configs/complex_config.yml b/_sample_configs/complex_config.yml index 48c68c36..e07aa209 100644 --- a/_sample_configs/complex_config.yml +++ b/_sample_configs/complex_config.yml @@ -108,7 +108,7 @@ wtf: width: 3 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" + - "/Users/chris/go/src/github.com/senorprogrammer/wtf" github: enabled: true position: @@ -119,8 +119,8 @@ wtf: refreshInterval: 300 repositories: repo-name: "owner id" - wtf: "andrewzolotukhin" - username: "andrewzolotukhin" + wtf: "senorprogrammer" + username: "senorprogrammer" jira: colors: rows: diff --git a/_site/content/posts/configuration/attributes.md b/_site/content/posts/configuration/attributes.md index 0339bcdf..2850875e 100644 --- a/_site/content/posts/configuration/attributes.md +++ b/_site/content/posts/configuration/attributes.md @@ -5,7 +5,7 @@ draft: false --- The following top-level attributes are configurable in `config.yml`. -See this example config file for more details. +See this example config file for more details. ```yaml wtf: diff --git a/_site/content/posts/installation.md b/_site/content/posts/installation.md index 51c230cc..dcc4aafa 100644 --- a/_site/content/posts/installation.md +++ b/_site/content/posts/installation.md @@ -11,8 +11,8 @@ There are two ways to install WTF: Get this repo and install the dependencies: ```bash -go get -u github.com/andrewzolotukhin/wtf -cd $GOPATH/src/github.com/andrewzolotukhin/wtf +go get -u github.com/senorprogrammer/wtf +cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run ``` @@ -23,7 +23,7 @@ and that should probably do it. Grab the latest version from here: ```bash -https://github.com/andrewzolotukhin/wtf/releases +https://github.com/senorprogrammer/wtf/releases ``` expand it, and `cd` into the resulting directory. Then run: diff --git a/_site/content/posts/modules/gcal.md b/_site/content/posts/modules/gcal.md index 57528fb9..ef6a70dd 100644 --- a/_site/content/posts/modules/gcal.md +++ b/_site/content/posts/modules/gcal.md @@ -9,7 +9,7 @@ Displays your upcoming Google calendar events. gcal screenshot **Not:** Setting up access to Google Calendars for Go is a bit unobvious. Check out Google's [Go Quickstart](https://developers.google.com/calendar/quickstart/go) -first and if you have problems, then take a look at this [comment by WesleydeSouza](https://github.com/andrewzolotukhin/wtf/issues/83#issuecomment-393665229) which offers a slightly different approach. +first and if you have problems, then take a look at this [comment by WesleydeSouza](https://github.com/senorprogrammer/wtf/issues/83#issuecomment-393665229) which offers a slightly different approach. ## Source Code diff --git a/_site/content/posts/modules/git.md b/_site/content/posts/modules/git.md index d47a17fa..e0a6a1f2 100644 --- a/_site/content/posts/modules/git.md +++ b/_site/content/posts/modules/git.md @@ -62,7 +62,7 @@ git: width: 2 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" + - "/Users/chris/go/src/github.com/senorprogrammer/wtf" - "/Users/user/fakeapp" ``` diff --git a/_site/content/posts/modules/github.md b/_site/content/posts/modules/github.md index c0b93f4f..3cfee576 100644 --- a/_site/content/posts/modules/github.md +++ b/_site/content/posts/modules/github.md @@ -58,8 +58,8 @@ github: refreshInterval: 300 repositories: wesker-api: "UmbrellaCorp" - wtf: "andrewzolotukhin" - username: "andrewzolotukhin" + wtf: "senorprogrammer" + username: "senorprogrammer" ``` ### Attributes diff --git a/_site/content/posts/overview.md b/_site/content/posts/overview.md index 14745096..126715d7 100644 --- a/_site/content/posts/overview.md +++ b/_site/content/posts/overview.md @@ -12,7 +12,7 @@ visible, but might check in on every now and then. ## Quick Start -1. Download the stand-alone, compiled binary. +1. Download the stand-alone, compiled binary. 2. Unzip the downloaded file. 3. From the command line, `cd` into the newly-created `/wtf` directory. 4. From the command line, run the app: `./wtf` diff --git a/_site/themes/hyde-hyde/layouts/index.html b/_site/themes/hyde-hyde/layouts/index.html index 27a35c8f..888abc24 100644 --- a/_site/themes/hyde-hyde/layouts/index.html +++ b/_site/themes/hyde-hyde/layouts/index.html @@ -27,9 +27,9 @@ It even has weather. And clocks. And emoji.

    - Download Latest + Download Latest - On Github + On Github

    diff --git a/_site/themes/hyde-hyde/layouts/partials/sidebar.html b/_site/themes/hyde-hyde/layouts/partials/sidebar.html index e5e1709d..fe5c83e2 100644 --- a/_site/themes/hyde-hyde/layouts/partials/sidebar.html +++ b/_site/themes/hyde-hyde/layouts/partials/sidebar.html @@ -17,7 +17,7 @@

    - +
    diff --git a/bamboohr/item.go b/bamboohr/item.go index e7533e5c..cc18590b 100644 --- a/bamboohr/item.go +++ b/bamboohr/item.go @@ -4,7 +4,7 @@ import ( "fmt" //"time" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) type Item struct { diff --git a/bamboohr/widget.go b/bamboohr/widget.go index 20b26eb1..1e9eb751 100644 --- a/bamboohr/widget.go +++ b/bamboohr/widget.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/bargraph/widget.go b/bargraph/widget.go index ba7668f3..0e798952 100644 --- a/bargraph/widget.go +++ b/bargraph/widget.go @@ -9,7 +9,7 @@ import ( "time" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/clocks/clock.go b/clocks/clock.go index 6d0e9615..fc4965fc 100644 --- a/clocks/clock.go +++ b/clocks/clock.go @@ -3,7 +3,7 @@ package clocks import ( "time" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) type Clock struct { diff --git a/clocks/display.go b/clocks/display.go index 4fcd425d..6cc7d60f 100644 --- a/clocks/display.go +++ b/clocks/display.go @@ -3,7 +3,7 @@ package clocks import ( "fmt" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) func (widget *Widget) display(clocks []Clock) { diff --git a/clocks/widget.go b/clocks/widget.go index be59c0f6..d6d6ee2a 100644 --- a/clocks/widget.go +++ b/clocks/widget.go @@ -4,7 +4,7 @@ import ( "time" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cmdrunner/widget.go b/cmdrunner/widget.go index 1dae8097..0708527e 100644 --- a/cmdrunner/widget.go +++ b/cmdrunner/widget.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cryptoexchanges/bittrex/widget.go b/cryptoexchanges/bittrex/widget.go index 5096774e..7bbf1003 100644 --- a/cryptoexchanges/bittrex/widget.go +++ b/cryptoexchanges/bittrex/widget.go @@ -8,7 +8,7 @@ import ( "net/http" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cryptoexchanges/cryptolive/widget.go b/cryptoexchanges/cryptolive/widget.go index 8b7d5d99..daaefa0e 100644 --- a/cryptoexchanges/cryptolive/widget.go +++ b/cryptoexchanges/cryptolive/widget.go @@ -7,7 +7,7 @@ import ( "time" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/docs/404.html b/docs/404.html index 62a99081..a6f51b08 100644 --- a/docs/404.html +++ b/docs/404.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/categories/index.html b/docs/categories/index.html index ec96925d..b52bb86e 100644 --- a/docs/categories/index.html +++ b/docs/categories/index.html @@ -60,7 +60,7 @@ - +
    @@ -119,9 +119,9 @@ It even has weather. And clocks. And emoji.

    - Download Latest + Download Latest - On Github + On Github

    diff --git a/docs/index.xml b/docs/index.xml index 2cfdb584..a86b5ce2 100644 --- a/docs/index.xml +++ b/docs/index.xml @@ -123,9 +123,9 @@ Quick Start Download the stand-alone, compiled binary. Unzip the downloaded fil https://wtfutil.com/posts/installation/ There are two ways to install WTF: From Source Get this repo and install the dependencies: -go get -u github.com/andrewzolotukhin/wtf cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run and that should probably do it. +go get -u github.com/senorprogrammer/wtf cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run and that should probably do it. As a Binary Grab the latest version from here: -https://github.com/andrewzolotukhin/wtf/releases expand it, and cd into the resulting directory. Then run: +https://github.com/senorprogrammer/wtf/releases expand it, and cd into the resulting directory. Then run: ./wtf and that should also do it. diff --git a/docs/posts/configuration/attributes/index.html b/docs/posts/configuration/attributes/index.html index 48ee6a51..a5354fce 100644 --- a/docs/posts/configuration/attributes/index.html +++ b/docs/posts/configuration/attributes/index.html @@ -58,7 +58,7 @@

    - +
    @@ -114,7 +114,7 @@

    The following top-level attributes are configurable in config.yml. -See this example config file for more details.

    +See this example config file for more details.

    wtf:
       colors:
         background: "red"
    diff --git a/docs/posts/configuration/index.html b/docs/posts/configuration/index.html
    index d00dc4ed..ec410d85 100644
    --- a/docs/posts/configuration/index.html
    +++ b/docs/posts/configuration/index.html
    @@ -58,7 +58,7 @@
             
             
             
    -        
    +        
           
    diff --git a/docs/posts/configuration/iterm2/index.html b/docs/posts/configuration/iterm2/index.html index 3756a2a5..dcb4d6c6 100644 --- a/docs/posts/configuration/iterm2/index.html +++ b/docs/posts/configuration/iterm2/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/glossary/index.html b/docs/posts/glossary/index.html index e4eb732f..9a4f7187 100644 --- a/docs/posts/glossary/index.html +++ b/docs/posts/glossary/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/index.xml b/docs/posts/index.xml index 3cba90d2..2dc5ba0f 100644 --- a/docs/posts/index.xml +++ b/docs/posts/index.xml @@ -123,9 +123,9 @@ Quick Start Download the stand-alone, compiled binary. Unzip the downloaded fil https://wtfutil.com/posts/installation/ There are two ways to install WTF: From Source Get this repo and install the dependencies: -go get -u github.com/andrewzolotukhin/wtf cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run and that should probably do it. +go get -u github.com/senorprogrammer/wtf cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run and that should probably do it. As a Binary Grab the latest version from here: -https://github.com/andrewzolotukhin/wtf/releases expand it, and cd into the resulting directory. Then run: +https://github.com/senorprogrammer/wtf/releases expand it, and cd into the resulting directory. Then run: ./wtf and that should also do it. diff --git a/docs/posts/installation/index.html b/docs/posts/installation/index.html index 046714fa..1237a416 100644 --- a/docs/posts/installation/index.html +++ b/docs/posts/installation/index.html @@ -58,7 +58,7 @@ - +
    @@ -118,8 +118,8 @@

    From Source

    Get this repo and install the dependencies:

    -
    go get -u github.com/andrewzolotukhin/wtf
    -cd $GOPATH/src/github.com/andrewzolotukhin/wtf
    +
    go get -u github.com/senorprogrammer/wtf
    +cd $GOPATH/src/github.com/senorprogrammer/wtf
     make install
     make run

    and that should probably do it.

    @@ -127,7 +127,7 @@ make run

    As a Binary

    Grab the latest version from here:

    -
    https://github.com/andrewzolotukhin/wtf/releases
    +
    https://github.com/senorprogrammer/wtf/releases

    expand it, and cd into the resulting directory. Then run:

    ./wtf

    and that should also do it.

    diff --git a/docs/posts/modules/bamboohr/index.html b/docs/posts/modules/bamboohr/index.html index 2c88de07..240a8181 100644 --- a/docs/posts/modules/bamboohr/index.html +++ b/docs/posts/modules/bamboohr/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/bittrex/index.html b/docs/posts/modules/bittrex/index.html index ebe5ffd2..8ab9753c 100644 --- a/docs/posts/modules/bittrex/index.html +++ b/docs/posts/modules/bittrex/index.html @@ -72,7 +72,7 @@ iTerm2
diff --git a/docs/posts/modules/clocks/index.html b/docs/posts/modules/clocks/index.html index cbe3f548..04333353 100644 --- a/docs/posts/modules/clocks/index.html +++ b/docs/posts/modules/clocks/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cmdrunner/index.html b/docs/posts/modules/cmdrunner/index.html index 5045938e..1ec0afca 100644 --- a/docs/posts/modules/cmdrunner/index.html +++ b/docs/posts/modules/cmdrunner/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptocurrencies/bittrex/index.html b/docs/posts/modules/cryptocurrencies/bittrex/index.html index bd942540..f9f033eb 100644 --- a/docs/posts/modules/cryptocurrencies/bittrex/index.html +++ b/docs/posts/modules/cryptocurrencies/bittrex/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptocurrencies/cryptolive/index.html b/docs/posts/modules/cryptocurrencies/cryptolive/index.html index e4d955ce..832af988 100644 --- a/docs/posts/modules/cryptocurrencies/cryptolive/index.html +++ b/docs/posts/modules/cryptocurrencies/cryptolive/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptolive/index.html b/docs/posts/modules/cryptolive/index.html index b4bfaccb..63395a42 100644 --- a/docs/posts/modules/cryptolive/index.html +++ b/docs/posts/modules/cryptolive/index.html @@ -72,7 +72,7 @@ iTerm2
diff --git a/docs/posts/modules/gcal/index.html b/docs/posts/modules/gcal/index.html index f3dc25a2..7e6f4a4b 100644 --- a/docs/posts/modules/gcal/index.html +++ b/docs/posts/modules/gcal/index.html @@ -58,7 +58,7 @@ - +
    @@ -118,7 +118,7 @@

    gcal screenshot

    Not: Setting up access to Google Calendars for Go is a bit unobvious. Check out Google’s Go Quickstart -first and if you have problems, then take a look at this comment by WesleydeSouza which offers a slightly different approach.

    +first and if you have problems, then take a look at this comment by WesleydeSouza which offers a slightly different approach.

    Source Code

    wtf/gcal/
    diff --git a/docs/posts/modules/git/index.html b/docs/posts/modules/git/index.html index 859d2e97..e958c4f1 100644 --- a/docs/posts/modules/git/index.html +++ b/docs/posts/modules/git/index.html @@ -58,7 +58,7 @@ - +
    @@ -165,7 +165,7 @@ commit, and their status.

    width: 2 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" + - "/Users/chris/go/src/github.com/senorprogrammer/wtf" - "/Users/user/fakeapp"

    Attributes

    diff --git a/docs/posts/modules/github/index.html b/docs/posts/modules/github/index.html index edd073db..eb556adb 100644 --- a/docs/posts/modules/github/index.html +++ b/docs/posts/modules/github/index.html @@ -58,7 +58,7 @@ - +
    @@ -160,8 +160,8 @@ refreshInterval: 300 repositories: wesker-api: "UmbrellaCorp" - wtf: "andrewzolotukhin" - username: "andrewzolotukhin" + wtf: "senorprogrammer" + username: "senorprogrammer"

    Attributes

    enabled
    diff --git a/docs/posts/modules/index.html b/docs/posts/modules/index.html index c38fde22..fad43ff2 100644 --- a/docs/posts/modules/index.html +++ b/docs/posts/modules/index.html @@ -58,7 +58,7 @@

    - +
    diff --git a/docs/posts/modules/ipinfo/index.html b/docs/posts/modules/ipinfo/index.html index b9f5de42..f3cd4865 100644 --- a/docs/posts/modules/ipinfo/index.html +++ b/docs/posts/modules/ipinfo/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/jira/index.html b/docs/posts/modules/jira/index.html index e7fa004e..4a60fb7a 100644 --- a/docs/posts/modules/jira/index.html +++ b/docs/posts/modules/jira/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/newrelic/index.html b/docs/posts/modules/newrelic/index.html index 2308dd5f..eac8a8db 100644 --- a/docs/posts/modules/newrelic/index.html +++ b/docs/posts/modules/newrelic/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/opsgenie/index.html b/docs/posts/modules/opsgenie/index.html index 01b445f8..dd2eef1a 100644 --- a/docs/posts/modules/opsgenie/index.html +++ b/docs/posts/modules/opsgenie/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/power/index.html b/docs/posts/modules/power/index.html index 0f2680a7..7cbb1d72 100644 --- a/docs/posts/modules/power/index.html +++ b/docs/posts/modules/power/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/prettyweather/index.html b/docs/posts/modules/prettyweather/index.html index 4643e031..d6bd7e91 100644 --- a/docs/posts/modules/prettyweather/index.html +++ b/docs/posts/modules/prettyweather/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/security/index.html b/docs/posts/modules/security/index.html index fb3d84f0..04437186 100644 --- a/docs/posts/modules/security/index.html +++ b/docs/posts/modules/security/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/textfile/index.html b/docs/posts/modules/textfile/index.html index dcc9451e..c18d9229 100644 --- a/docs/posts/modules/textfile/index.html +++ b/docs/posts/modules/textfile/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/todo/index.html b/docs/posts/modules/todo/index.html index e268ec38..9ffa4bc6 100644 --- a/docs/posts/modules/todo/index.html +++ b/docs/posts/modules/todo/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/weather/index.html b/docs/posts/modules/weather/index.html index ec437990..f22a2a21 100644 --- a/docs/posts/modules/weather/index.html +++ b/docs/posts/modules/weather/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/overview/index.html b/docs/posts/overview/index.html index bb073f93..beef7287 100644 --- a/docs/posts/overview/index.html +++ b/docs/posts/overview/index.html @@ -58,7 +58,7 @@ - +
    @@ -122,7 +122,7 @@ visible, but might check in on every now and then.

    Quick Start

      -
    1. Download the stand-alone, compiled binary.
    2. +
    3. Download the stand-alone, compiled binary.
    4. Unzip the downloaded file.
    5. From the command line, cd into the newly-created /wtf directory.
    6. From the command line, run the app: ./wtf
    7. diff --git a/docs/tags/index.html b/docs/tags/index.html index 8fe879ec..68425b68 100644 --- a/docs/tags/index.html +++ b/docs/tags/index.html @@ -60,7 +60,7 @@ - +
    diff --git a/gcal/client.go b/gcal/client.go index 698fe3b8..de655620 100644 --- a/gcal/client.go +++ b/gcal/client.go @@ -18,7 +18,7 @@ import ( "path/filepath" "time" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/calendar/v3" diff --git a/gcal/widget.go b/gcal/widget.go index 9a9b5a59..487c8daa 100644 --- a/gcal/widget.go +++ b/gcal/widget.go @@ -7,7 +7,7 @@ import ( "time" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" "google.golang.org/api/calendar/v3" ) diff --git a/git/display.go b/git/display.go index 27d84893..8140615b 100644 --- a/git/display.go +++ b/git/display.go @@ -5,7 +5,7 @@ import ( "strings" "unicode/utf8" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) func (widget *Widget) display() { diff --git a/git/git_repo.go b/git/git_repo.go index 5852eeb6..5d3ba090 100644 --- a/git/git_repo.go +++ b/git/git_repo.go @@ -5,7 +5,7 @@ import ( "os/exec" "strings" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) type GitRepo struct { diff --git a/git/widget.go b/git/widget.go index 762f6833..89aad5a2 100644 --- a/git/widget.go +++ b/git/widget.go @@ -4,7 +4,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/github/display.go b/github/display.go index d61c2665..e9346367 100644 --- a/github/display.go +++ b/github/display.go @@ -3,7 +3,7 @@ package github import ( "fmt" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) func (widget *Widget) display() { diff --git a/github/widget.go b/github/widget.go index b6f22662..717f1bab 100644 --- a/github/widget.go +++ b/github/widget.go @@ -4,7 +4,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/gspreadsheets/client.go b/gspreadsheets/client.go index 7d48a2a4..1cf16321 100644 --- a/gspreadsheets/client.go +++ b/gspreadsheets/client.go @@ -18,7 +18,7 @@ import ( "path/filepath" "strings" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" "golang.org/x/oauth2" "golang.org/x/oauth2/google" sheets "google.golang.org/api/sheets/v4" diff --git a/gspreadsheets/widget.go b/gspreadsheets/widget.go index 1a4bd220..e754ce74 100644 --- a/gspreadsheets/widget.go +++ b/gspreadsheets/widget.go @@ -3,7 +3,7 @@ package gspreadsheets import ( "fmt" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" "github.com/olebedev/config" sheets "google.golang.org/api/sheets/v4" ) diff --git a/help/help.go b/help/help.go index a2cf1e79..cf79c930 100644 --- a/help/help.go +++ b/help/help.go @@ -4,11 +4,11 @@ import ( "fmt" "os" - "github.com/andrewzolotukhin/wtf/git" - "github.com/andrewzolotukhin/wtf/github" - "github.com/andrewzolotukhin/wtf/textfile" - "github.com/andrewzolotukhin/wtf/todo" - "github.com/andrewzolotukhin/wtf/weather" + "github.com/senorprogrammer/wtf/git" + "github.com/senorprogrammer/wtf/github" + "github.com/senorprogrammer/wtf/textfile" + "github.com/senorprogrammer/wtf/todo" + "github.com/senorprogrammer/wtf/weather" ) func DisplayModuleInfo(moduleName string) { diff --git a/ipinfo/widget.go b/ipinfo/widget.go index c445ecae..62db1732 100644 --- a/ipinfo/widget.go +++ b/ipinfo/widget.go @@ -9,7 +9,7 @@ import ( "bytes" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/jira/widget.go b/jira/widget.go index 2709eff2..6ca9670e 100644 --- a/jira/widget.go +++ b/jira/widget.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/newrelic/widget.go b/newrelic/widget.go index b765758b..ca16966f 100644 --- a/newrelic/widget.go +++ b/newrelic/widget.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" nr "github.com/yfronto/newrelic" ) diff --git a/opsgenie/widget.go b/opsgenie/widget.go index dbb9eed2..314b832a 100644 --- a/opsgenie/widget.go +++ b/opsgenie/widget.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/power/battery.go b/power/battery.go index 96c57262..08b7fdfe 100644 --- a/power/battery.go +++ b/power/battery.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) const TimeRegExp = "^(?:\\d|[01]\\d|2[0-3]):[0-5]\\d" diff --git a/power/battery_linux.go b/power/battery_linux.go index 720c110d..693d95b6 100644 --- a/power/battery_linux.go +++ b/power/battery_linux.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) var batteryState string diff --git a/power/source.go b/power/source.go index f28e7c2f..e6eff36c 100644 --- a/power/source.go +++ b/power/source.go @@ -7,7 +7,7 @@ import ( "regexp" "strings" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) const SingleQuotesRegExp = "'(.*)'" diff --git a/power/widget.go b/power/widget.go index c7be5b01..d3d3a996 100644 --- a/power/widget.go +++ b/power/widget.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/prettyweather/widget.go b/prettyweather/widget.go index 4e579b2c..c0ef7596 100644 --- a/prettyweather/widget.go +++ b/prettyweather/widget.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/security/dns.go b/security/dns.go index 5a458744..2408c2c1 100644 --- a/security/dns.go +++ b/security/dns.go @@ -5,7 +5,7 @@ import ( "runtime" "strings" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) /* -------------------- Exported Functions -------------------- */ diff --git a/security/firewall.go b/security/firewall.go index 828c3bf0..6323b5e1 100644 --- a/security/firewall.go +++ b/security/firewall.go @@ -5,7 +5,7 @@ import ( "runtime" "strings" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) const osxFirewallCmd = "/usr/libexec/ApplicationFirewall/socketfilterfw" diff --git a/security/users.go b/security/users.go index 77a41243..b8fe5164 100644 --- a/security/users.go +++ b/security/users.go @@ -7,7 +7,7 @@ import ( "runtime" "strings" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) /* -------------------- Exported Functions -------------------- */ diff --git a/security/widget.go b/security/widget.go index cdcc7ac1..f5769b8e 100644 --- a/security/widget.go +++ b/security/widget.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/security/wifi.go b/security/wifi.go index b152a7ba..30b75767 100644 --- a/security/wifi.go +++ b/security/wifi.go @@ -4,7 +4,7 @@ import ( "os/exec" "runtime" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // https://github.com/yelinaung/wifi-name/blob/master/wifi-name.go diff --git a/status/widget.go b/status/widget.go index 67bb6977..3bd71599 100644 --- a/status/widget.go +++ b/status/widget.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/system/system_info.go b/system/system_info.go index eb8d5c2d..1582ebe7 100644 --- a/system/system_info.go +++ b/system/system_info.go @@ -5,7 +5,7 @@ import ( "runtime" "strings" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) type SystemInfo struct { diff --git a/system/widget.go b/system/widget.go index 530e8400..c13ed5ea 100644 --- a/system/widget.go +++ b/system/widget.go @@ -5,7 +5,7 @@ import ( "time" "github.com/olebedev/config" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/textfile/widget.go b/textfile/widget.go index 5aa5b426..2bc3afe6 100644 --- a/textfile/widget.go +++ b/textfile/widget.go @@ -7,7 +7,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/todo/display.go b/todo/display.go index ea20f873..d25d20cb 100644 --- a/todo/display.go +++ b/todo/display.go @@ -3,7 +3,7 @@ package todo import ( "fmt" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) const checkWidth = 4 diff --git a/todo/widget.go b/todo/widget.go index 93014f29..00dcb984 100644 --- a/todo/widget.go +++ b/todo/widget.go @@ -7,7 +7,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" "gopkg.in/yaml.v2" ) diff --git a/weather/display.go b/weather/display.go index 84711640..1b237789 100644 --- a/weather/display.go +++ b/weather/display.go @@ -5,7 +5,7 @@ import ( "strings" owm "github.com/briandowns/openweathermap" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) func (widget *Widget) display() { diff --git a/weather/widget.go b/weather/widget.go index dce962ee..992c7207 100644 --- a/weather/widget.go +++ b/weather/widget.go @@ -7,7 +7,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object. diff --git a/wtf.go b/wtf.go index d2b41a68..0580fc0f 100644 --- a/wtf.go +++ b/wtf.go @@ -6,31 +6,31 @@ import ( "os" "time" - "github.com/andrewzolotukhin/wtf/bamboohr" - "github.com/andrewzolotukhin/wtf/bargraph" - "github.com/andrewzolotukhin/wtf/blockfolio" - "github.com/andrewzolotukhin/wtf/clocks" - "github.com/andrewzolotukhin/wtf/cmdrunner" - "github.com/andrewzolotukhin/wtf/cryptoexchanges/bittrex" - "github.com/andrewzolotukhin/wtf/cryptoexchanges/cryptolive" - "github.com/andrewzolotukhin/wtf/gcal" - "github.com/andrewzolotukhin/wtf/git" - "github.com/andrewzolotukhin/wtf/github" - "github.com/andrewzolotukhin/wtf/gspreadsheets" - "github.com/andrewzolotukhin/wtf/help" - "github.com/andrewzolotukhin/wtf/ipinfo" - "github.com/andrewzolotukhin/wtf/jira" - "github.com/andrewzolotukhin/wtf/newrelic" - "github.com/andrewzolotukhin/wtf/opsgenie" - "github.com/andrewzolotukhin/wtf/power" - "github.com/andrewzolotukhin/wtf/prettyweather" - "github.com/andrewzolotukhin/wtf/security" - "github.com/andrewzolotukhin/wtf/status" - "github.com/andrewzolotukhin/wtf/system" - "github.com/andrewzolotukhin/wtf/textfile" - "github.com/andrewzolotukhin/wtf/todo" - "github.com/andrewzolotukhin/wtf/weather" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/bamboohr" + "github.com/senorprogrammer/wtf/bargraph" + "github.com/senorprogrammer/wtf/blockfolio" + "github.com/senorprogrammer/wtf/clocks" + "github.com/senorprogrammer/wtf/cmdrunner" + "github.com/senorprogrammer/wtf/cryptoexchanges/bittrex" + "github.com/senorprogrammer/wtf/cryptoexchanges/cryptolive" + "github.com/senorprogrammer/wtf/gcal" + "github.com/senorprogrammer/wtf/git" + "github.com/senorprogrammer/wtf/github" + "github.com/senorprogrammer/wtf/gspreadsheets" + "github.com/senorprogrammer/wtf/help" + "github.com/senorprogrammer/wtf/ipinfo" + "github.com/senorprogrammer/wtf/jira" + "github.com/senorprogrammer/wtf/newrelic" + "github.com/senorprogrammer/wtf/opsgenie" + "github.com/senorprogrammer/wtf/power" + "github.com/senorprogrammer/wtf/prettyweather" + "github.com/senorprogrammer/wtf/security" + "github.com/senorprogrammer/wtf/status" + "github.com/senorprogrammer/wtf/system" + "github.com/senorprogrammer/wtf/textfile" + "github.com/senorprogrammer/wtf/todo" + "github.com/senorprogrammer/wtf/weather" + "github.com/senorprogrammer/wtf/wtf" "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/radovskyb/watcher" diff --git a/wtf/config_files.go b/wtf/config_files.go index 2e60351d..ff57654d 100644 --- a/wtf/config_files.go +++ b/wtf/config_files.go @@ -63,7 +63,7 @@ func LoadConfigFile(filePath string) *config.Config { cfg, err := config.ParseYamlFile(absPath) if err != nil { - fmt.Println("\n\n\033[1m ERROR:\033[0m Could not load '\033[0;33mconfig.yml\033[0m'.\n Please add a \033[0;33mconfig.yml\033[0m file to your \033[0;33m~/.wtf\033[0m directory.\n See \033[1;34mhttps://github.com/andrewzolotukhin/wtf\033[0m for details.\n") + fmt.Println("\n\n\033[1m ERROR:\033[0m Could not load '\033[0;33mconfig.yml\033[0m'.\n Please add a \033[0;33mconfig.yml\033[0m file to your \033[0;33m~/.wtf\033[0m directory.\n See \033[1;34mhttps://github.com/senorprogrammer/wtf\033[0m for details.\n") fmt.Printf(" %s\n", err.Error()) os.Exit(1) } diff --git a/wtf_tests/position_test.go b/wtf_tests/position_test.go index 7dd5e8c5..370a3373 100644 --- a/wtf_tests/position_test.go +++ b/wtf_tests/position_test.go @@ -3,7 +3,7 @@ package wtf_tests import ( "testing" - . "github.com/andrewzolotukhin/wtf/wtf" + . "github.com/senorprogrammer/wtf/wtf" ) func TestPosition(t *testing.T) { diff --git a/wtf_tests/utils_test.go b/wtf_tests/utils_test.go index 2d347150..a069301c 100644 --- a/wtf_tests/utils_test.go +++ b/wtf_tests/utils_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/go-test/deep" - . "github.com/andrewzolotukhin/wtf/wtf" + . "github.com/senorprogrammer/wtf/wtf" ) /* -------------------- Exclude() -------------------- */ From 585d4cc10e21aca6e81413cc9d172acc6583116b Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 02:58:04 +0300 Subject: [PATCH 21/58] Updated config --- _sample_configs/complex_config.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/_sample_configs/complex_config.yml b/_sample_configs/complex_config.yml index e07aa209..57e3f41c 100644 --- a/_sample_configs/complex_config.yml +++ b/_sample_configs/complex_config.yml @@ -218,3 +218,17 @@ wtf: width: 1 refreshInterval: 90 tempUnit: "C" + blockfolio: + enabled: true + displayHoldings: true + refreshInterval: 400 + device_token: "device token here, you can find how to get it here https://github.com/bob6664569/blockfolio-api-client" + colors: + name: blue + grows: green + drop: red + position: + top: 3 + left: 1 + width: 1 + height: 1 \ No newline at end of file From 608815ac855dbfd7287fbc0868d6efd0f5b55f77 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 03:07:43 +0300 Subject: [PATCH 22/58] Fixed name --- blockfolio/widget.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 66f3a727..968cd7f1 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -7,9 +7,9 @@ import ( "log" "net/http" - "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" "github.com/rivo/tview" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object From da1ffdd817557e6f369c84c26b4acaa2f6ce0a7b Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 03:15:58 +0300 Subject: [PATCH 23/58] Changed name to andrewzolotukhin --- .travis.yml | 10 +- README.md | 10 +- _sample_configs/complex_config.yml | 6 +- .../content/posts/configuration/attributes.md | 2 +- _site/content/posts/installation.md | 6 +- _site/content/posts/modules/gcal.md | 2 +- _site/content/posts/modules/git.md | 2 +- _site/content/posts/modules/github.md | 4 +- _site/content/posts/overview.md | 2 +- _site/themes/hyde-hyde/layouts/index.html | 4 +- .../hyde-hyde/layouts/partials/sidebar.html | 2 +- bamboohr/item.go | 2 +- bamboohr/widget.go | 2 +- bargraph/widget.go | 2 +- blockfolio/widget.go | 2 +- cfg/config_files.go | 4 +- clocks/clock.go | 2 +- clocks/display.go | 2 +- clocks/widget.go | 2 +- cmdrunner/widget.go | 2 +- cryptoexchanges/bittrex/widget.go | 2 +- cryptoexchanges/cryptolive/widget.go | 2 +- docs/404.html | 2 +- docs/categories/index.html | 2 +- docs/index.html | 6 +- docs/index.xml | 4 +- .../posts/configuration/attributes/index.html | 4 +- docs/posts/configuration/index.html | 2 +- docs/posts/configuration/iterm2/index.html | 2 +- docs/posts/glossary/index.html | 2 +- docs/posts/index.html | 2 +- docs/posts/index.xml | 4 +- docs/posts/installation/index.html | 8 +- docs/posts/modules/bamboohr/index.html | 2 +- docs/posts/modules/bittrex/index.html | 2 +- docs/posts/modules/clocks/index.html | 2 +- docs/posts/modules/cmdrunner/index.html | 2 +- .../cryptocurrencies/bittrex/index.html | 2 +- .../cryptocurrencies/cryptolive/index.html | 2 +- docs/posts/modules/cryptolive/index.html | 2 +- docs/posts/modules/gcal/index.html | 4 +- docs/posts/modules/git/index.html | 4 +- docs/posts/modules/github/index.html | 6 +- docs/posts/modules/index.html | 2 +- docs/posts/modules/ipinfo/index.html | 2 +- docs/posts/modules/jira/index.html | 2 +- docs/posts/modules/newrelic/index.html | 2 +- docs/posts/modules/opsgenie/index.html | 2 +- docs/posts/modules/power/index.html | 2 +- docs/posts/modules/prettyweather/index.html | 2 +- docs/posts/modules/security/index.html | 2 +- docs/posts/modules/textfile/index.html | 2 +- docs/posts/modules/todo/index.html | 2 +- docs/posts/modules/weather/index.html | 2 +- docs/posts/overview/index.html | 4 +- docs/tags/index.html | 2 +- gcal/client.go | 2 +- gcal/widget.go | 2 +- git/display.go | 2 +- git/git_repo.go | 2 +- git/widget.go | 2 +- github/display.go | 2 +- github/widget.go | 2 +- gspreadsheets/client.go | 2 +- gspreadsheets/widget.go | 2 +- help/help.go | 10 +- ipapi/widget.go | 2 +- ipinfo/widget.go | 2 +- jira/widget.go | 2 +- newrelic/widget.go | 2 +- opsgenie/widget.go | 2 +- power/battery.go | 2 +- power/battery_linux.go | 2 +- power/source.go | 2 +- power/widget.go | 2 +- prettyweather/widget.go | 2 +- security/dns.go | 2 +- security/firewall.go | 2 +- security/users.go | 2 +- security/widget.go | 2 +- security/wifi.go | 2 +- status/widget.go | 2 +- system/system_info.go | 2 +- system/widget.go | 2 +- textfile/widget.go | 2 +- todo/display.go | 2 +- todo/widget.go | 4 +- weather/display.go | 2 +- weather/widget.go | 2 +- wtf.go | 54 +++--- wtf/config_files.go | 172 ++++++++++++++++++ wtf_tests/position_test.go | 2 +- wtf_tests/utils_test.go | 2 +- 93 files changed, 323 insertions(+), 151 deletions(-) create mode 100644 wtf/config_files.go diff --git a/.travis.yml b/.travis.yml index b20b9c4a..c90dfc89 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,9 @@ go: sudo: false before_install: # Make sure travis builds work for forks - - mkdir -p $TRAVIS_BUILD_DIR $GOPATH/src/github.com/senorprogrammer - - test ! -d $GOPATH/src/github.com/senorprogrammer/wtf && mv $TRAVIS_BUILD_DIR $GOPATH/src/github.com/senorprogrammer/wtf || true - - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/senorprogrammer/wtf - - cd $HOME/gopath/src/github.com/senorprogrammer/wtf + - mkdir -p $TRAVIS_BUILD_DIR $GOPATH/src/github.com/andrewzolotukhin + - test ! -d $GOPATH/src/github.com/andrewzolotukhin/wtf && mv $TRAVIS_BUILD_DIR $GOPATH/src/github.com/andrewzolotukhin/wtf || true + - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/andrewzolotukhin/wtf + - cd $HOME/gopath/src/github.com/andrewzolotukhin/wtf -script: go get ./... && go get github.com/go-test/deep && go test -v github.com/senorprogrammer/wtf/wtf_tests +script: go get ./... && go get github.com/go-test/deep && go test -v github.com/andrewzolotukhin/wtf/wtf_tests diff --git a/README.md b/README.md index d9a53bd7..5e2177ac 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

    - +

    @@ -20,13 +20,13 @@ displaying infrequently-needed, but very important, daily data. **Note:** WTF is _only_ compatible with Go versions **1.9.2** or later. It currently _does not_ compile with `gccgo`. ```bash -go get -u github.com/senorprogrammer/wtf -cd $GOPATH/src/github.com/senorprogrammer/wtf +go get -u github.com/andrewzolotukhin/wtf +cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run ``` -Or [download the latest binary](https://github.com/senorprogrammer/wtf/releases). +Or [download the latest binary](https://github.com/andrewzolotukhin/wtf/releases). ## Support @@ -48,7 +48,7 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduc ## Authors -* Chris Cummer, [senorprogrammer](https://github.com/senorprogrammer) +* Chris Cummer, [andrewzolotukhin](https://github.com/andrewzolotukhin) ## License diff --git a/_sample_configs/complex_config.yml b/_sample_configs/complex_config.yml index 57e3f41c..52fc8507 100644 --- a/_sample_configs/complex_config.yml +++ b/_sample_configs/complex_config.yml @@ -108,7 +108,7 @@ wtf: width: 3 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/senorprogrammer/wtf" + - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" github: enabled: true position: @@ -119,8 +119,8 @@ wtf: refreshInterval: 300 repositories: repo-name: "owner id" - wtf: "senorprogrammer" - username: "senorprogrammer" + wtf: "andrewzolotukhin" + username: "andrewzolotukhin" jira: colors: rows: diff --git a/_site/content/posts/configuration/attributes.md b/_site/content/posts/configuration/attributes.md index 2850875e..0339bcdf 100644 --- a/_site/content/posts/configuration/attributes.md +++ b/_site/content/posts/configuration/attributes.md @@ -5,7 +5,7 @@ draft: false --- The following top-level attributes are configurable in `config.yml`. -See this example config file for more details. +See this example config file for more details. ```yaml wtf: diff --git a/_site/content/posts/installation.md b/_site/content/posts/installation.md index dcc4aafa..51c230cc 100644 --- a/_site/content/posts/installation.md +++ b/_site/content/posts/installation.md @@ -11,8 +11,8 @@ There are two ways to install WTF: Get this repo and install the dependencies: ```bash -go get -u github.com/senorprogrammer/wtf -cd $GOPATH/src/github.com/senorprogrammer/wtf +go get -u github.com/andrewzolotukhin/wtf +cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run ``` @@ -23,7 +23,7 @@ and that should probably do it. Grab the latest version from here: ```bash -https://github.com/senorprogrammer/wtf/releases +https://github.com/andrewzolotukhin/wtf/releases ``` expand it, and `cd` into the resulting directory. Then run: diff --git a/_site/content/posts/modules/gcal.md b/_site/content/posts/modules/gcal.md index ef6a70dd..57528fb9 100644 --- a/_site/content/posts/modules/gcal.md +++ b/_site/content/posts/modules/gcal.md @@ -9,7 +9,7 @@ Displays your upcoming Google calendar events. gcal screenshot **Not:** Setting up access to Google Calendars for Go is a bit unobvious. Check out Google's [Go Quickstart](https://developers.google.com/calendar/quickstart/go) -first and if you have problems, then take a look at this [comment by WesleydeSouza](https://github.com/senorprogrammer/wtf/issues/83#issuecomment-393665229) which offers a slightly different approach. +first and if you have problems, then take a look at this [comment by WesleydeSouza](https://github.com/andrewzolotukhin/wtf/issues/83#issuecomment-393665229) which offers a slightly different approach. ## Source Code diff --git a/_site/content/posts/modules/git.md b/_site/content/posts/modules/git.md index e0a6a1f2..d47a17fa 100644 --- a/_site/content/posts/modules/git.md +++ b/_site/content/posts/modules/git.md @@ -62,7 +62,7 @@ git: width: 2 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/senorprogrammer/wtf" + - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" - "/Users/user/fakeapp" ``` diff --git a/_site/content/posts/modules/github.md b/_site/content/posts/modules/github.md index 3cfee576..c0b93f4f 100644 --- a/_site/content/posts/modules/github.md +++ b/_site/content/posts/modules/github.md @@ -58,8 +58,8 @@ github: refreshInterval: 300 repositories: wesker-api: "UmbrellaCorp" - wtf: "senorprogrammer" - username: "senorprogrammer" + wtf: "andrewzolotukhin" + username: "andrewzolotukhin" ``` ### Attributes diff --git a/_site/content/posts/overview.md b/_site/content/posts/overview.md index 126715d7..14745096 100644 --- a/_site/content/posts/overview.md +++ b/_site/content/posts/overview.md @@ -12,7 +12,7 @@ visible, but might check in on every now and then. ## Quick Start -1. Download the stand-alone, compiled binary. +1. Download the stand-alone, compiled binary. 2. Unzip the downloaded file. 3. From the command line, `cd` into the newly-created `/wtf` directory. 4. From the command line, run the app: `./wtf` diff --git a/_site/themes/hyde-hyde/layouts/index.html b/_site/themes/hyde-hyde/layouts/index.html index d6fed31f..88cef7ab 100644 --- a/_site/themes/hyde-hyde/layouts/index.html +++ b/_site/themes/hyde-hyde/layouts/index.html @@ -27,8 +27,8 @@ It even has weather. And clocks. And emoji.

    - Download Latest - Source on Github + Download Latest + Source on Github Chat on Gitter

    diff --git a/_site/themes/hyde-hyde/layouts/partials/sidebar.html b/_site/themes/hyde-hyde/layouts/partials/sidebar.html index 7d593f21..a1f9fc61 100644 --- a/_site/themes/hyde-hyde/layouts/partials/sidebar.html +++ b/_site/themes/hyde-hyde/layouts/partials/sidebar.html @@ -17,7 +17,7 @@

    - +
    diff --git a/bamboohr/item.go b/bamboohr/item.go index cc18590b..e7533e5c 100644 --- a/bamboohr/item.go +++ b/bamboohr/item.go @@ -4,7 +4,7 @@ import ( "fmt" //"time" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) type Item struct { diff --git a/bamboohr/widget.go b/bamboohr/widget.go index 1e9eb751..c83f9d76 100644 --- a/bamboohr/widget.go +++ b/bamboohr/widget.go @@ -3,8 +3,8 @@ package bamboohr import ( "fmt" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/bargraph/widget.go b/bargraph/widget.go index 0e798952..399ce415 100644 --- a/bargraph/widget.go +++ b/bargraph/widget.go @@ -8,8 +8,8 @@ import ( "math/rand" "time" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 968cd7f1..7594366f 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -9,7 +9,7 @@ import ( "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cfg/config_files.go b/cfg/config_files.go index 85e848e8..b571ad04 100644 --- a/cfg/config_files.go +++ b/cfg/config_files.go @@ -5,8 +5,8 @@ import ( "io/ioutil" "os" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) func ConfigDir() (string, error) { @@ -64,7 +64,7 @@ func LoadConfigFile(filePath string) *config.Config { cfg, err := config.ParseYamlFile(absPath) if err != nil { - fmt.Println("\n\n\033[1m ERROR:\033[0m Could not load '\033[0;33mconfig.yml\033[0m'.\n Please add a \033[0;33mconfig.yml\033[0m file to your \033[0;33m~/.wtf\033[0m directory.\n See \033[1;34mhttps://github.com/senorprogrammer/wtf\033[0m for details.\n") + fmt.Println("\n\n\033[1m ERROR:\033[0m Could not load '\033[0;33mconfig.yml\033[0m'.\n Please add a \033[0;33mconfig.yml\033[0m file to your \033[0;33m~/.wtf\033[0m directory.\n See \033[1;34mhttps://github.com/andrewzolotukhin/wtf\033[0m for details.\n") fmt.Printf(" %s\n", err.Error()) os.Exit(1) } diff --git a/clocks/clock.go b/clocks/clock.go index fc4965fc..6d0e9615 100644 --- a/clocks/clock.go +++ b/clocks/clock.go @@ -3,7 +3,7 @@ package clocks import ( "time" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) type Clock struct { diff --git a/clocks/display.go b/clocks/display.go index 6cc7d60f..4fcd425d 100644 --- a/clocks/display.go +++ b/clocks/display.go @@ -3,7 +3,7 @@ package clocks import ( "fmt" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) func (widget *Widget) display(clocks []Clock) { diff --git a/clocks/widget.go b/clocks/widget.go index d6d6ee2a..1134ac71 100644 --- a/clocks/widget.go +++ b/clocks/widget.go @@ -3,8 +3,8 @@ package clocks import ( "time" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cmdrunner/widget.go b/cmdrunner/widget.go index 0708527e..0a0e0bf6 100644 --- a/cmdrunner/widget.go +++ b/cmdrunner/widget.go @@ -5,8 +5,8 @@ import ( "os/exec" "strings" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cryptoexchanges/bittrex/widget.go b/cryptoexchanges/bittrex/widget.go index 7bbf1003..5fa6e3d0 100644 --- a/cryptoexchanges/bittrex/widget.go +++ b/cryptoexchanges/bittrex/widget.go @@ -7,8 +7,8 @@ import ( "net/http" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cryptoexchanges/cryptolive/widget.go b/cryptoexchanges/cryptolive/widget.go index daaefa0e..a6f3aa59 100644 --- a/cryptoexchanges/cryptolive/widget.go +++ b/cryptoexchanges/cryptolive/widget.go @@ -6,8 +6,8 @@ import ( "net/http" "time" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/docs/404.html b/docs/404.html index 262aef29..31fc242c 100644 --- a/docs/404.html +++ b/docs/404.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/categories/index.html b/docs/categories/index.html index 8803ffb8..9766807a 100644 --- a/docs/categories/index.html +++ b/docs/categories/index.html @@ -60,7 +60,7 @@ - +
    @@ -119,8 +119,8 @@ It even has weather. And clocks. And emoji.

    - Download Latest - Source on Github + Download Latest + Source on Github Chat on Gitter

    diff --git a/docs/index.xml b/docs/index.xml index 28d48bd1..1f3a63f5 100644 --- a/docs/index.xml +++ b/docs/index.xml @@ -122,9 +122,9 @@ Quick Start Download the stand-alone, compiled binary. Unzip the downloaded fil https://wtfutil.com/posts/installation/ There are two ways to install WTF: From Source Get this repo and install the dependencies: -go get -u github.com/senorprogrammer/wtf cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run and that should probably do it. +go get -u github.com/andrewzolotukhin/wtf cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run and that should probably do it. As a Binary Grab the latest version from here: -https://github.com/senorprogrammer/wtf/releases expand it, and cd into the resulting directory. Then run: +https://github.com/andrewzolotukhin/wtf/releases expand it, and cd into the resulting directory. Then run: ./wtf and that should also do it. diff --git a/docs/posts/configuration/attributes/index.html b/docs/posts/configuration/attributes/index.html index bd308fdf..d8fd2e1a 100644 --- a/docs/posts/configuration/attributes/index.html +++ b/docs/posts/configuration/attributes/index.html @@ -58,7 +58,7 @@

    - +
    @@ -114,7 +114,7 @@

    The following top-level attributes are configurable in config.yml. -See this example config file for more details.

    +See this example config file for more details.

    wtf:
       colors:
         background: "red"
    diff --git a/docs/posts/configuration/index.html b/docs/posts/configuration/index.html
    index 067aab24..bed8adf4 100644
    --- a/docs/posts/configuration/index.html
    +++ b/docs/posts/configuration/index.html
    @@ -58,7 +58,7 @@
             
             
             
    -        
    +        
           
    diff --git a/docs/posts/configuration/iterm2/index.html b/docs/posts/configuration/iterm2/index.html index ba679394..0dc9de92 100644 --- a/docs/posts/configuration/iterm2/index.html +++ b/docs/posts/configuration/iterm2/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/glossary/index.html b/docs/posts/glossary/index.html index b88135ae..960fbca6 100644 --- a/docs/posts/glossary/index.html +++ b/docs/posts/glossary/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/index.xml b/docs/posts/index.xml index 71eef75b..d328d821 100644 --- a/docs/posts/index.xml +++ b/docs/posts/index.xml @@ -122,9 +122,9 @@ Quick Start Download the stand-alone, compiled binary. Unzip the downloaded fil https://wtfutil.com/posts/installation/ There are two ways to install WTF: From Source Get this repo and install the dependencies: -go get -u github.com/senorprogrammer/wtf cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run and that should probably do it. +go get -u github.com/andrewzolotukhin/wtf cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run and that should probably do it. As a Binary Grab the latest version from here: -https://github.com/senorprogrammer/wtf/releases expand it, and cd into the resulting directory. Then run: +https://github.com/andrewzolotukhin/wtf/releases expand it, and cd into the resulting directory. Then run: ./wtf and that should also do it. diff --git a/docs/posts/installation/index.html b/docs/posts/installation/index.html index 57c8acd7..3fdd42f3 100644 --- a/docs/posts/installation/index.html +++ b/docs/posts/installation/index.html @@ -58,7 +58,7 @@ - +
    @@ -118,8 +118,8 @@

    From Source

    Get this repo and install the dependencies:

    -
    go get -u github.com/senorprogrammer/wtf
    -cd $GOPATH/src/github.com/senorprogrammer/wtf
    +
    go get -u github.com/andrewzolotukhin/wtf
    +cd $GOPATH/src/github.com/andrewzolotukhin/wtf
     make install
     make run

    and that should probably do it.

    @@ -127,7 +127,7 @@ make run

    As a Binary

    Grab the latest version from here:

    -
    https://github.com/senorprogrammer/wtf/releases
    +
    https://github.com/andrewzolotukhin/wtf/releases

    expand it, and cd into the resulting directory. Then run:

    ./wtf

    and that should also do it.

    diff --git a/docs/posts/modules/bamboohr/index.html b/docs/posts/modules/bamboohr/index.html index e3b3ac7c..cdf207c3 100644 --- a/docs/posts/modules/bamboohr/index.html +++ b/docs/posts/modules/bamboohr/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/bittrex/index.html b/docs/posts/modules/bittrex/index.html index 8ab9753c..ebe5ffd2 100644 --- a/docs/posts/modules/bittrex/index.html +++ b/docs/posts/modules/bittrex/index.html @@ -72,7 +72,7 @@ iTerm2
diff --git a/docs/posts/modules/clocks/index.html b/docs/posts/modules/clocks/index.html index 71a519c8..e2814986 100644 --- a/docs/posts/modules/clocks/index.html +++ b/docs/posts/modules/clocks/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cmdrunner/index.html b/docs/posts/modules/cmdrunner/index.html index edca5f69..2ff80736 100644 --- a/docs/posts/modules/cmdrunner/index.html +++ b/docs/posts/modules/cmdrunner/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptocurrencies/bittrex/index.html b/docs/posts/modules/cryptocurrencies/bittrex/index.html index 18730b2b..01975238 100644 --- a/docs/posts/modules/cryptocurrencies/bittrex/index.html +++ b/docs/posts/modules/cryptocurrencies/bittrex/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptocurrencies/cryptolive/index.html b/docs/posts/modules/cryptocurrencies/cryptolive/index.html index f84dea13..3f55416f 100644 --- a/docs/posts/modules/cryptocurrencies/cryptolive/index.html +++ b/docs/posts/modules/cryptocurrencies/cryptolive/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptolive/index.html b/docs/posts/modules/cryptolive/index.html index 63395a42..b4bfaccb 100644 --- a/docs/posts/modules/cryptolive/index.html +++ b/docs/posts/modules/cryptolive/index.html @@ -72,7 +72,7 @@ iTerm2
diff --git a/docs/posts/modules/gcal/index.html b/docs/posts/modules/gcal/index.html index fa6de93d..d459e933 100644 --- a/docs/posts/modules/gcal/index.html +++ b/docs/posts/modules/gcal/index.html @@ -58,7 +58,7 @@ - +
    @@ -118,7 +118,7 @@

    gcal screenshot

    Not: Setting up access to Google Calendars for Go is a bit unobvious. Check out Google’s Go Quickstart -first and if you have problems, then take a look at this comment by WesleydeSouza which offers a slightly different approach.

    +first and if you have problems, then take a look at this comment by WesleydeSouza which offers a slightly different approach.

    Source Code

    wtf/gcal/
    diff --git a/docs/posts/modules/git/index.html b/docs/posts/modules/git/index.html index 0ab526af..9eedd440 100644 --- a/docs/posts/modules/git/index.html +++ b/docs/posts/modules/git/index.html @@ -58,7 +58,7 @@ - +
    @@ -165,7 +165,7 @@ commit, and their status.

    width: 2 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/senorprogrammer/wtf" + - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" - "/Users/user/fakeapp"

    Attributes

    diff --git a/docs/posts/modules/github/index.html b/docs/posts/modules/github/index.html index 55afa1e3..47d0d7d2 100644 --- a/docs/posts/modules/github/index.html +++ b/docs/posts/modules/github/index.html @@ -58,7 +58,7 @@ - +
    @@ -160,8 +160,8 @@ refreshInterval: 300 repositories: wesker-api: "UmbrellaCorp" - wtf: "senorprogrammer" - username: "senorprogrammer" + wtf: "andrewzolotukhin" + username: "andrewzolotukhin"

    Attributes

    enabled
    diff --git a/docs/posts/modules/index.html b/docs/posts/modules/index.html index 5ffb2199..2dee71d0 100644 --- a/docs/posts/modules/index.html +++ b/docs/posts/modules/index.html @@ -58,7 +58,7 @@

    - +
    diff --git a/docs/posts/modules/ipinfo/index.html b/docs/posts/modules/ipinfo/index.html index 5f3994cb..5db5c836 100644 --- a/docs/posts/modules/ipinfo/index.html +++ b/docs/posts/modules/ipinfo/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/jira/index.html b/docs/posts/modules/jira/index.html index 258cb919..52287193 100644 --- a/docs/posts/modules/jira/index.html +++ b/docs/posts/modules/jira/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/newrelic/index.html b/docs/posts/modules/newrelic/index.html index db3a032b..1e715c30 100644 --- a/docs/posts/modules/newrelic/index.html +++ b/docs/posts/modules/newrelic/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/opsgenie/index.html b/docs/posts/modules/opsgenie/index.html index ff57d7cb..24468b0e 100644 --- a/docs/posts/modules/opsgenie/index.html +++ b/docs/posts/modules/opsgenie/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/power/index.html b/docs/posts/modules/power/index.html index e42e346c..373e58b5 100644 --- a/docs/posts/modules/power/index.html +++ b/docs/posts/modules/power/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/prettyweather/index.html b/docs/posts/modules/prettyweather/index.html index a0c4d36b..58c11182 100644 --- a/docs/posts/modules/prettyweather/index.html +++ b/docs/posts/modules/prettyweather/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/security/index.html b/docs/posts/modules/security/index.html index 98c131b0..da556e57 100644 --- a/docs/posts/modules/security/index.html +++ b/docs/posts/modules/security/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/textfile/index.html b/docs/posts/modules/textfile/index.html index a8e53ab4..c0d5dd98 100644 --- a/docs/posts/modules/textfile/index.html +++ b/docs/posts/modules/textfile/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/todo/index.html b/docs/posts/modules/todo/index.html index 6c105daa..44c93f04 100644 --- a/docs/posts/modules/todo/index.html +++ b/docs/posts/modules/todo/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/weather/index.html b/docs/posts/modules/weather/index.html index 7021ceb2..5dc1508c 100644 --- a/docs/posts/modules/weather/index.html +++ b/docs/posts/modules/weather/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/overview/index.html b/docs/posts/overview/index.html index a3d75261..3c57251d 100644 --- a/docs/posts/overview/index.html +++ b/docs/posts/overview/index.html @@ -58,7 +58,7 @@ - +
    @@ -122,7 +122,7 @@ visible, but might check in on every now and then.

    Quick Start

      -
    1. Download the stand-alone, compiled binary.
    2. +
    3. Download the stand-alone, compiled binary.
    4. Unzip the downloaded file.
    5. From the command line, cd into the newly-created /wtf directory.
    6. From the command line, run the app: ./wtf
    7. diff --git a/docs/tags/index.html b/docs/tags/index.html index 9681fff7..8ed850a0 100644 --- a/docs/tags/index.html +++ b/docs/tags/index.html @@ -60,7 +60,7 @@ - +
    diff --git a/gcal/client.go b/gcal/client.go index de655620..698fe3b8 100644 --- a/gcal/client.go +++ b/gcal/client.go @@ -18,7 +18,7 @@ import ( "path/filepath" "time" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/calendar/v3" diff --git a/gcal/widget.go b/gcal/widget.go index 487c8daa..6cc3a972 100644 --- a/gcal/widget.go +++ b/gcal/widget.go @@ -6,8 +6,8 @@ import ( "strings" "time" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" "google.golang.org/api/calendar/v3" ) diff --git a/git/display.go b/git/display.go index 8140615b..27d84893 100644 --- a/git/display.go +++ b/git/display.go @@ -5,7 +5,7 @@ import ( "strings" "unicode/utf8" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) func (widget *Widget) display() { diff --git a/git/git_repo.go b/git/git_repo.go index 5d3ba090..5852eeb6 100644 --- a/git/git_repo.go +++ b/git/git_repo.go @@ -5,7 +5,7 @@ import ( "os/exec" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) type GitRepo struct { diff --git a/git/widget.go b/git/widget.go index 894d71b5..f3bf8e6a 100644 --- a/git/widget.go +++ b/git/widget.go @@ -1,10 +1,10 @@ package git import ( + "github.com/andrewzolotukhin/wtf/wtf" "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/github/display.go b/github/display.go index e9346367..d61c2665 100644 --- a/github/display.go +++ b/github/display.go @@ -3,7 +3,7 @@ package github import ( "fmt" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) func (widget *Widget) display() { diff --git a/github/widget.go b/github/widget.go index 717f1bab..5718827a 100644 --- a/github/widget.go +++ b/github/widget.go @@ -1,10 +1,10 @@ package github import ( + "github.com/andrewzolotukhin/wtf/wtf" "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/gspreadsheets/client.go b/gspreadsheets/client.go index 1cf16321..7d48a2a4 100644 --- a/gspreadsheets/client.go +++ b/gspreadsheets/client.go @@ -18,7 +18,7 @@ import ( "path/filepath" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" "golang.org/x/oauth2" "golang.org/x/oauth2/google" sheets "google.golang.org/api/sheets/v4" diff --git a/gspreadsheets/widget.go b/gspreadsheets/widget.go index 680869cf..de462ffe 100644 --- a/gspreadsheets/widget.go +++ b/gspreadsheets/widget.go @@ -3,8 +3,8 @@ package gspreadsheets import ( "fmt" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" sheets "google.golang.org/api/sheets/v4" ) diff --git a/help/help.go b/help/help.go index cf79c930..a2cf1e79 100644 --- a/help/help.go +++ b/help/help.go @@ -4,11 +4,11 @@ import ( "fmt" "os" - "github.com/senorprogrammer/wtf/git" - "github.com/senorprogrammer/wtf/github" - "github.com/senorprogrammer/wtf/textfile" - "github.com/senorprogrammer/wtf/todo" - "github.com/senorprogrammer/wtf/weather" + "github.com/andrewzolotukhin/wtf/git" + "github.com/andrewzolotukhin/wtf/github" + "github.com/andrewzolotukhin/wtf/textfile" + "github.com/andrewzolotukhin/wtf/todo" + "github.com/andrewzolotukhin/wtf/weather" ) func DisplayModuleInfo(moduleName string) { diff --git a/ipapi/widget.go b/ipapi/widget.go index d65f2456..f8d36559 100644 --- a/ipapi/widget.go +++ b/ipapi/widget.go @@ -9,8 +9,8 @@ import ( "bytes" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/ipinfo/widget.go b/ipinfo/widget.go index 62db1732..c445ecae 100644 --- a/ipinfo/widget.go +++ b/ipinfo/widget.go @@ -9,7 +9,7 @@ import ( "bytes" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/jira/widget.go b/jira/widget.go index 6ca9670e..35bced7d 100644 --- a/jira/widget.go +++ b/jira/widget.go @@ -3,8 +3,8 @@ package jira import ( "fmt" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/newrelic/widget.go b/newrelic/widget.go index ca16966f..feb89768 100644 --- a/newrelic/widget.go +++ b/newrelic/widget.go @@ -3,8 +3,8 @@ package newrelic import ( "fmt" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" nr "github.com/yfronto/newrelic" ) diff --git a/opsgenie/widget.go b/opsgenie/widget.go index 314b832a..dbb9eed2 100644 --- a/opsgenie/widget.go +++ b/opsgenie/widget.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/power/battery.go b/power/battery.go index 08b7fdfe..96c57262 100644 --- a/power/battery.go +++ b/power/battery.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) const TimeRegExp = "^(?:\\d|[01]\\d|2[0-3]):[0-5]\\d" diff --git a/power/battery_linux.go b/power/battery_linux.go index 693d95b6..720c110d 100644 --- a/power/battery_linux.go +++ b/power/battery_linux.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) var batteryState string diff --git a/power/source.go b/power/source.go index e6eff36c..f28e7c2f 100644 --- a/power/source.go +++ b/power/source.go @@ -7,7 +7,7 @@ import ( "regexp" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) const SingleQuotesRegExp = "'(.*)'" diff --git a/power/widget.go b/power/widget.go index d3d3a996..f323b8b4 100644 --- a/power/widget.go +++ b/power/widget.go @@ -3,8 +3,8 @@ package power import ( "fmt" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/prettyweather/widget.go b/prettyweather/widget.go index c0ef7596..4bae5c73 100644 --- a/prettyweather/widget.go +++ b/prettyweather/widget.go @@ -6,8 +6,8 @@ import ( "net/http" "strings" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/security/dns.go b/security/dns.go index 2408c2c1..5a458744 100644 --- a/security/dns.go +++ b/security/dns.go @@ -5,7 +5,7 @@ import ( "runtime" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) /* -------------------- Exported Functions -------------------- */ diff --git a/security/firewall.go b/security/firewall.go index 6323b5e1..828c3bf0 100644 --- a/security/firewall.go +++ b/security/firewall.go @@ -5,7 +5,7 @@ import ( "runtime" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) const osxFirewallCmd = "/usr/libexec/ApplicationFirewall/socketfilterfw" diff --git a/security/users.go b/security/users.go index b8fe5164..77a41243 100644 --- a/security/users.go +++ b/security/users.go @@ -7,7 +7,7 @@ import ( "runtime" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) /* -------------------- Exported Functions -------------------- */ diff --git a/security/widget.go b/security/widget.go index f5769b8e..231fec2e 100644 --- a/security/widget.go +++ b/security/widget.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/security/wifi.go b/security/wifi.go index 30b75767..b152a7ba 100644 --- a/security/wifi.go +++ b/security/wifi.go @@ -4,7 +4,7 @@ import ( "os/exec" "runtime" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // https://github.com/yelinaung/wifi-name/blob/master/wifi-name.go diff --git a/status/widget.go b/status/widget.go index 3bd71599..764a4a67 100644 --- a/status/widget.go +++ b/status/widget.go @@ -3,8 +3,8 @@ package status import ( "fmt" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/system/system_info.go b/system/system_info.go index 1582ebe7..eb8d5c2d 100644 --- a/system/system_info.go +++ b/system/system_info.go @@ -5,7 +5,7 @@ import ( "runtime" "strings" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) type SystemInfo struct { diff --git a/system/widget.go b/system/widget.go index c13ed5ea..82b88da1 100644 --- a/system/widget.go +++ b/system/widget.go @@ -4,8 +4,8 @@ import ( "fmt" "time" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/textfile/widget.go b/textfile/widget.go index 2bc3afe6..5aa5b426 100644 --- a/textfile/widget.go +++ b/textfile/widget.go @@ -7,7 +7,7 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/todo/display.go b/todo/display.go index d25d20cb..ea20f873 100644 --- a/todo/display.go +++ b/todo/display.go @@ -3,7 +3,7 @@ package todo import ( "fmt" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/wtf" ) const checkWidth = 4 diff --git a/todo/widget.go b/todo/widget.go index e06c007c..3ddc1004 100644 --- a/todo/widget.go +++ b/todo/widget.go @@ -7,8 +7,8 @@ import ( "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/cfg" - "github.com/senorprogrammer/wtf/wtf" + "github.com/andrewzolotukhin/wtf/cfg" + "github.com/andrewzolotukhin/wtf/wtf" "gopkg.in/yaml.v2" ) diff --git a/weather/display.go b/weather/display.go index 9acd9e3d..b82bd241 100644 --- a/weather/display.go +++ b/weather/display.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" + "github.com/andrewzolotukhin/wtf/wtf" owm "github.com/briandowns/openweathermap" - "github.com/senorprogrammer/wtf/wtf" ) func (widget *Widget) display() { diff --git a/weather/widget.go b/weather/widget.go index 8a1176cb..4e9ee015 100644 --- a/weather/widget.go +++ b/weather/widget.go @@ -3,11 +3,11 @@ package weather import ( "os" + "github.com/andrewzolotukhin/wtf/wtf" owm "github.com/briandowns/openweathermap" "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object. diff --git a/wtf.go b/wtf.go index bf8163c2..69ecfaa6 100644 --- a/wtf.go +++ b/wtf.go @@ -6,37 +6,37 @@ import ( "os" "time" + "github.com/andrewzolotukhin/wtf/bamboohr" + "github.com/andrewzolotukhin/wtf/bargraph" + "github.com/andrewzolotukhin/wtf/blockfolio" + "github.com/andrewzolotukhin/wtf/cfg" + "github.com/andrewzolotukhin/wtf/clocks" + "github.com/andrewzolotukhin/wtf/cmdrunner" + "github.com/andrewzolotukhin/wtf/cryptoexchanges/bittrex" + "github.com/andrewzolotukhin/wtf/cryptoexchanges/cryptolive" + "github.com/andrewzolotukhin/wtf/gcal" + "github.com/andrewzolotukhin/wtf/git" + "github.com/andrewzolotukhin/wtf/github" + "github.com/andrewzolotukhin/wtf/gspreadsheets" + "github.com/andrewzolotukhin/wtf/help" + "github.com/andrewzolotukhin/wtf/ipapi" + "github.com/andrewzolotukhin/wtf/ipinfo" + "github.com/andrewzolotukhin/wtf/jira" + "github.com/andrewzolotukhin/wtf/newrelic" + "github.com/andrewzolotukhin/wtf/opsgenie" + "github.com/andrewzolotukhin/wtf/power" + "github.com/andrewzolotukhin/wtf/prettyweather" + "github.com/andrewzolotukhin/wtf/security" + "github.com/andrewzolotukhin/wtf/status" + "github.com/andrewzolotukhin/wtf/system" + "github.com/andrewzolotukhin/wtf/textfile" + "github.com/andrewzolotukhin/wtf/todo" + "github.com/andrewzolotukhin/wtf/weather" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/radovskyb/watcher" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/bamboohr" - "github.com/senorprogrammer/wtf/bargraph" - "github.com/senorprogrammer/wtf/blockfolio" - "github.com/senorprogrammer/wtf/cfg" - "github.com/senorprogrammer/wtf/clocks" - "github.com/senorprogrammer/wtf/cmdrunner" - "github.com/senorprogrammer/wtf/cryptoexchanges/bittrex" - "github.com/senorprogrammer/wtf/cryptoexchanges/cryptolive" - "github.com/senorprogrammer/wtf/gcal" - "github.com/senorprogrammer/wtf/git" - "github.com/senorprogrammer/wtf/github" - "github.com/senorprogrammer/wtf/gspreadsheets" - "github.com/senorprogrammer/wtf/help" - "github.com/senorprogrammer/wtf/ipapi" - "github.com/senorprogrammer/wtf/ipinfo" - "github.com/senorprogrammer/wtf/jira" - "github.com/senorprogrammer/wtf/newrelic" - "github.com/senorprogrammer/wtf/opsgenie" - "github.com/senorprogrammer/wtf/power" - "github.com/senorprogrammer/wtf/prettyweather" - "github.com/senorprogrammer/wtf/security" - "github.com/senorprogrammer/wtf/status" - "github.com/senorprogrammer/wtf/system" - "github.com/senorprogrammer/wtf/textfile" - "github.com/senorprogrammer/wtf/todo" - "github.com/senorprogrammer/wtf/weather" - "github.com/senorprogrammer/wtf/wtf" ) /* -------------------- Functions -------------------- */ diff --git a/wtf/config_files.go b/wtf/config_files.go new file mode 100644 index 00000000..2e60351d --- /dev/null +++ b/wtf/config_files.go @@ -0,0 +1,172 @@ +package wtf + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/olebedev/config" +) + +func ConfigDir() (string, error) { + configDir, err := ExpandHomeDir("~/.wtf/") + if err != nil { + return "", err + } + + return configDir, nil +} + +// CreateConfigDir creates the .wtf directory in the user's home dir +func CreateConfigDir() { + configDir, _ := ConfigDir() + + if _, err := os.Stat(configDir); os.IsNotExist(err) { + err := os.Mkdir(configDir, os.ModePerm) + if err != nil { + panic(err) + } + } +} + +// CreateFile creates the named file in the config directory, if it does not already exist. +// If the file exists it does not recreate it. +// If successful, eturns the absolute path to the file +// If unsuccessful, returns an error +func CreateFile(fileName string) (string, error) { + configDir, err := ConfigDir() + if err != nil { + return "", err + } + + filePath := fmt.Sprintf("%s/%s", configDir, fileName) + + // Check if the file already exists; if it does not, create it + _, err = os.Stat(filePath) + if err != nil { + if os.IsNotExist(err) { + _, err = os.Create(filePath) + if err != nil { + return "", err + } + } else { + return "", err + } + } + + return filePath, nil +} + +// LoadConfigFile loads the config.yml file to configure the app +func LoadConfigFile(filePath string) *config.Config { + absPath, _ := ExpandHomeDir(filePath) + + cfg, err := config.ParseYamlFile(absPath) + if err != nil { + fmt.Println("\n\n\033[1m ERROR:\033[0m Could not load '\033[0;33mconfig.yml\033[0m'.\n Please add a \033[0;33mconfig.yml\033[0m file to your \033[0;33m~/.wtf\033[0m directory.\n See \033[1;34mhttps://github.com/andrewzolotukhin/wtf\033[0m for details.\n") + fmt.Printf(" %s\n", err.Error()) + os.Exit(1) + } + + return cfg +} + +func ReadConfigFile(fileName string) (string, error) { + configDir, err := ConfigDir() + if err != nil { + return "", err + } + + filePath := fmt.Sprintf("%s/%s", configDir, fileName) + + fileData, err := ReadFileBytes(filePath) + if err != nil { + return "", err + } + + return string(fileData), nil +} + +// WriteConfigFile creates a simple config file in the config directory if +// one does not already exist +func WriteConfigFile() { + filePath, err := CreateFile("config.yml") + if err != nil { + panic(err) + } + + // If the file is empty, write to it + file, err := os.Stat(filePath) + + if file.Size() == 0 { + err = ioutil.WriteFile(filePath, []byte(simpleConfig), 0644) + if err != nil { + panic(err) + } + } +} + +const simpleConfig = `wtf: + colors: + border: + focusable: darkslateblue + focused: orange + normal: gray + grid: + columns: [40, 40] + rows: [13, 13, 4] + refreshInterval: 1 + mods: + clocks: + colors: + rows: + even: "lightblue" + odd: "white" + enabled: true + locations: + Avignon: "Europe/Paris" + Barcelona: "Europe/Madrid" + Dubai: "Asia/Dubai" + Vancouver: "America/Vancouver" + Toronto: "America/Toronto" + position: + top: 0 + left: 0 + height: 1 + width: 1 + refreshInterval: 15 + sort: "alphabetical" + security: + enabled: true + position: + top: 1 + left: 0 + height: 1 + width: 1 + refreshInterval: 3600 + status: + enabled: true + position: + top: 2 + left: 0 + height: 1 + width: 2 + refreshInterval: 1 + system: + enabled: true + position: + top: 0 + left: 1 + height: 1 + width: 1 + refreshInterval: 3600 + textfile: + enabled: true + filePath: "~/.wtf/config.yml" + position: + top: 1 + left: 1 + height: 1 + width: 1 + refreshInterval: 30 +` diff --git a/wtf_tests/position_test.go b/wtf_tests/position_test.go index 370a3373..7dd5e8c5 100644 --- a/wtf_tests/position_test.go +++ b/wtf_tests/position_test.go @@ -3,7 +3,7 @@ package wtf_tests import ( "testing" - . "github.com/senorprogrammer/wtf/wtf" + . "github.com/andrewzolotukhin/wtf/wtf" ) func TestPosition(t *testing.T) { diff --git a/wtf_tests/utils_test.go b/wtf_tests/utils_test.go index a069301c..8f020ec1 100644 --- a/wtf_tests/utils_test.go +++ b/wtf_tests/utils_test.go @@ -3,8 +3,8 @@ package wtf_tests import ( "testing" + . "github.com/andrewzolotukhin/wtf/wtf" "github.com/go-test/deep" - . "github.com/senorprogrammer/wtf/wtf" ) /* -------------------- Exclude() -------------------- */ From bd0f3e1e56b90994f6f606fd8d3541affbe224d2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 03:19:26 +0300 Subject: [PATCH 24/58] Fixed name --- circleci/widget.go | 3 ++- wtf.go | 56 +++++++++++++++++++++++----------------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/circleci/widget.go b/circleci/widget.go index 0e3d6a28..e0e9f7bc 100644 --- a/circleci/widget.go +++ b/circleci/widget.go @@ -2,8 +2,9 @@ package circleci import ( "fmt" + + "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" - "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/wtf.go b/wtf.go index acb0d8d3..73bc1a49 100644 --- a/wtf.go +++ b/wtf.go @@ -6,38 +6,38 @@ import ( "os" "time" + "github.com/andrewzolotukhin/wtf/bamboohr" + "github.com/andrewzolotukhin/wtf/bargraph" + "github.com/andrewzolotukhin/wtf/blockfolio" + "github.com/andrewzolotukhin/wtf/cfg" + "github.com/andrewzolotukhin/wtf/circleci" + "github.com/andrewzolotukhin/wtf/clocks" + "github.com/andrewzolotukhin/wtf/cmdrunner" + "github.com/andrewzolotukhin/wtf/cryptoexchanges/bittrex" + "github.com/andrewzolotukhin/wtf/cryptoexchanges/cryptolive" + "github.com/andrewzolotukhin/wtf/gcal" + "github.com/andrewzolotukhin/wtf/git" + "github.com/andrewzolotukhin/wtf/github" + "github.com/andrewzolotukhin/wtf/gspreadsheets" + "github.com/andrewzolotukhin/wtf/help" + "github.com/andrewzolotukhin/wtf/ipapi" + "github.com/andrewzolotukhin/wtf/ipinfo" + "github.com/andrewzolotukhin/wtf/jira" + "github.com/andrewzolotukhin/wtf/newrelic" + "github.com/andrewzolotukhin/wtf/opsgenie" + "github.com/andrewzolotukhin/wtf/power" + "github.com/andrewzolotukhin/wtf/prettyweather" + "github.com/andrewzolotukhin/wtf/security" + "github.com/andrewzolotukhin/wtf/status" + "github.com/andrewzolotukhin/wtf/system" + "github.com/andrewzolotukhin/wtf/textfile" + "github.com/andrewzolotukhin/wtf/todo" + "github.com/andrewzolotukhin/wtf/weather" + "github.com/andrewzolotukhin/wtf/wtf" "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/radovskyb/watcher" "github.com/rivo/tview" - "github.com/senorprogrammer/wtf/bamboohr" - "github.com/senorprogrammer/wtf/bargraph" - "github.com/senorprogrammer/wtf/blockfolio" - "github.com/senorprogrammer/wtf/cfg" - "github.com/senorprogrammer/wtf/circleci" - "github.com/senorprogrammer/wtf/clocks" - "github.com/senorprogrammer/wtf/cmdrunner" - "github.com/senorprogrammer/wtf/cryptoexchanges/bittrex" - "github.com/senorprogrammer/wtf/cryptoexchanges/cryptolive" - "github.com/senorprogrammer/wtf/gcal" - "github.com/senorprogrammer/wtf/git" - "github.com/senorprogrammer/wtf/github" - "github.com/senorprogrammer/wtf/gspreadsheets" - "github.com/senorprogrammer/wtf/help" - "github.com/senorprogrammer/wtf/ipapi" - "github.com/senorprogrammer/wtf/ipinfo" - "github.com/senorprogrammer/wtf/jira" - "github.com/senorprogrammer/wtf/newrelic" - "github.com/senorprogrammer/wtf/opsgenie" - "github.com/senorprogrammer/wtf/power" - "github.com/senorprogrammer/wtf/prettyweather" - "github.com/senorprogrammer/wtf/security" - "github.com/senorprogrammer/wtf/status" - "github.com/senorprogrammer/wtf/system" - "github.com/senorprogrammer/wtf/textfile" - "github.com/senorprogrammer/wtf/todo" - "github.com/senorprogrammer/wtf/weather" - "github.com/senorprogrammer/wtf/wtf" ) /* -------------------- Functions -------------------- */ From a558ee948f8ad31a3bf3e17aec232b12698388da Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 Jun 2018 03:36:53 +0300 Subject: [PATCH 25/58] Reverted names --- .travis.yml | 10 ++-- README.md | 10 ++-- _sample_configs/complex_config.yml | 6 +- .../content/posts/configuration/attributes.md | 2 +- _site/content/posts/installation.md | 6 +- _site/content/posts/modules/gcal.md | 2 +- _site/content/posts/modules/git.md | 2 +- _site/content/posts/modules/github.md | 4 +- _site/content/posts/overview.md | 2 +- _site/themes/hyde-hyde/layouts/index.html | 4 +- .../hyde-hyde/layouts/partials/sidebar.html | 2 +- bamboohr/item.go | 2 +- bamboohr/widget.go | 2 +- bargraph/widget.go | 2 +- blockfolio/widget.go | 2 +- cfg/config_files.go | 4 +- circleci/widget.go | 2 +- clocks/clock.go | 2 +- clocks/display.go | 2 +- clocks/widget.go | 2 +- cmdrunner/widget.go | 2 +- cryptoexchanges/bittrex/widget.go | 2 +- cryptoexchanges/cryptolive/widget.go | 2 +- docs/404.html | 2 +- docs/categories/index.html | 2 +- docs/index.html | 6 +- docs/index.xml | 4 +- .../posts/configuration/attributes/index.html | 4 +- docs/posts/configuration/index.html | 2 +- docs/posts/configuration/iterm2/index.html | 2 +- docs/posts/glossary/index.html | 2 +- docs/posts/index.html | 2 +- docs/posts/index.xml | 4 +- docs/posts/installation/index.html | 8 +-- docs/posts/modules/bamboohr/index.html | 2 +- docs/posts/modules/bittrex/index.html | 2 +- docs/posts/modules/clocks/index.html | 2 +- docs/posts/modules/cmdrunner/index.html | 2 +- .../cryptocurrencies/bittrex/index.html | 2 +- .../cryptocurrencies/cryptolive/index.html | 2 +- docs/posts/modules/cryptolive/index.html | 2 +- docs/posts/modules/gcal/index.html | 4 +- docs/posts/modules/git/index.html | 4 +- docs/posts/modules/github/index.html | 6 +- docs/posts/modules/index.html | 2 +- docs/posts/modules/ipinfo/index.html | 2 +- docs/posts/modules/jira/index.html | 2 +- docs/posts/modules/newrelic/index.html | 2 +- docs/posts/modules/opsgenie/index.html | 2 +- docs/posts/modules/power/index.html | 2 +- docs/posts/modules/prettyweather/index.html | 2 +- docs/posts/modules/security/index.html | 2 +- docs/posts/modules/textfile/index.html | 2 +- docs/posts/modules/todo/index.html | 2 +- docs/posts/modules/weather/index.html | 2 +- docs/posts/overview/index.html | 4 +- docs/tags/index.html | 2 +- gcal/client.go | 2 +- gcal/widget.go | 2 +- git/display.go | 2 +- git/git_repo.go | 2 +- git/widget.go | 2 +- github/display.go | 2 +- github/widget.go | 2 +- gspreadsheets/client.go | 2 +- gspreadsheets/widget.go | 2 +- help/help.go | 10 ++-- ipapi/widget.go | 2 +- ipinfo/widget.go | 2 +- jira/widget.go | 2 +- newrelic/widget.go | 2 +- opsgenie/widget.go | 2 +- power/battery.go | 2 +- power/battery_linux.go | 2 +- power/source.go | 2 +- power/widget.go | 2 +- prettyweather/widget.go | 2 +- security/dns.go | 2 +- security/firewall.go | 2 +- security/users.go | 2 +- security/widget.go | 2 +- security/wifi.go | 2 +- status/widget.go | 2 +- system/system_info.go | 2 +- system/widget.go | 2 +- textfile/widget.go | 2 +- todo/display.go | 2 +- todo/widget.go | 4 +- weather/display.go | 2 +- weather/widget.go | 2 +- wtf.go | 56 +++++++++---------- wtf/config_files.go | 2 +- wtf_tests/position_test.go | 2 +- wtf_tests/utils_test.go | 2 +- 94 files changed, 154 insertions(+), 154 deletions(-) diff --git a/.travis.yml b/.travis.yml index c90dfc89..b20b9c4a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,9 @@ go: sudo: false before_install: # Make sure travis builds work for forks - - mkdir -p $TRAVIS_BUILD_DIR $GOPATH/src/github.com/andrewzolotukhin - - test ! -d $GOPATH/src/github.com/andrewzolotukhin/wtf && mv $TRAVIS_BUILD_DIR $GOPATH/src/github.com/andrewzolotukhin/wtf || true - - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/andrewzolotukhin/wtf - - cd $HOME/gopath/src/github.com/andrewzolotukhin/wtf + - mkdir -p $TRAVIS_BUILD_DIR $GOPATH/src/github.com/senorprogrammer + - test ! -d $GOPATH/src/github.com/senorprogrammer/wtf && mv $TRAVIS_BUILD_DIR $GOPATH/src/github.com/senorprogrammer/wtf || true + - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/senorprogrammer/wtf + - cd $HOME/gopath/src/github.com/senorprogrammer/wtf -script: go get ./... && go get github.com/go-test/deep && go test -v github.com/andrewzolotukhin/wtf/wtf_tests +script: go get ./... && go get github.com/go-test/deep && go test -v github.com/senorprogrammer/wtf/wtf_tests diff --git a/README.md b/README.md index 5e2177ac..d9a53bd7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

    - +

    @@ -20,13 +20,13 @@ displaying infrequently-needed, but very important, daily data. **Note:** WTF is _only_ compatible with Go versions **1.9.2** or later. It currently _does not_ compile with `gccgo`. ```bash -go get -u github.com/andrewzolotukhin/wtf -cd $GOPATH/src/github.com/andrewzolotukhin/wtf +go get -u github.com/senorprogrammer/wtf +cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run ``` -Or [download the latest binary](https://github.com/andrewzolotukhin/wtf/releases). +Or [download the latest binary](https://github.com/senorprogrammer/wtf/releases). ## Support @@ -48,7 +48,7 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduc ## Authors -* Chris Cummer, [andrewzolotukhin](https://github.com/andrewzolotukhin) +* Chris Cummer, [senorprogrammer](https://github.com/senorprogrammer) ## License diff --git a/_sample_configs/complex_config.yml b/_sample_configs/complex_config.yml index 52fc8507..57e3f41c 100644 --- a/_sample_configs/complex_config.yml +++ b/_sample_configs/complex_config.yml @@ -108,7 +108,7 @@ wtf: width: 3 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" + - "/Users/chris/go/src/github.com/senorprogrammer/wtf" github: enabled: true position: @@ -119,8 +119,8 @@ wtf: refreshInterval: 300 repositories: repo-name: "owner id" - wtf: "andrewzolotukhin" - username: "andrewzolotukhin" + wtf: "senorprogrammer" + username: "senorprogrammer" jira: colors: rows: diff --git a/_site/content/posts/configuration/attributes.md b/_site/content/posts/configuration/attributes.md index 0339bcdf..2850875e 100644 --- a/_site/content/posts/configuration/attributes.md +++ b/_site/content/posts/configuration/attributes.md @@ -5,7 +5,7 @@ draft: false --- The following top-level attributes are configurable in `config.yml`. -See this example config file for more details. +See this example config file for more details. ```yaml wtf: diff --git a/_site/content/posts/installation.md b/_site/content/posts/installation.md index 51c230cc..dcc4aafa 100644 --- a/_site/content/posts/installation.md +++ b/_site/content/posts/installation.md @@ -11,8 +11,8 @@ There are two ways to install WTF: Get this repo and install the dependencies: ```bash -go get -u github.com/andrewzolotukhin/wtf -cd $GOPATH/src/github.com/andrewzolotukhin/wtf +go get -u github.com/senorprogrammer/wtf +cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run ``` @@ -23,7 +23,7 @@ and that should probably do it. Grab the latest version from here: ```bash -https://github.com/andrewzolotukhin/wtf/releases +https://github.com/senorprogrammer/wtf/releases ``` expand it, and `cd` into the resulting directory. Then run: diff --git a/_site/content/posts/modules/gcal.md b/_site/content/posts/modules/gcal.md index 57528fb9..ef6a70dd 100644 --- a/_site/content/posts/modules/gcal.md +++ b/_site/content/posts/modules/gcal.md @@ -9,7 +9,7 @@ Displays your upcoming Google calendar events. gcal screenshot **Not:** Setting up access to Google Calendars for Go is a bit unobvious. Check out Google's [Go Quickstart](https://developers.google.com/calendar/quickstart/go) -first and if you have problems, then take a look at this [comment by WesleydeSouza](https://github.com/andrewzolotukhin/wtf/issues/83#issuecomment-393665229) which offers a slightly different approach. +first and if you have problems, then take a look at this [comment by WesleydeSouza](https://github.com/senorprogrammer/wtf/issues/83#issuecomment-393665229) which offers a slightly different approach. ## Source Code diff --git a/_site/content/posts/modules/git.md b/_site/content/posts/modules/git.md index d47a17fa..e0a6a1f2 100644 --- a/_site/content/posts/modules/git.md +++ b/_site/content/posts/modules/git.md @@ -62,7 +62,7 @@ git: width: 2 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" + - "/Users/chris/go/src/github.com/senorprogrammer/wtf" - "/Users/user/fakeapp" ``` diff --git a/_site/content/posts/modules/github.md b/_site/content/posts/modules/github.md index c0b93f4f..3cfee576 100644 --- a/_site/content/posts/modules/github.md +++ b/_site/content/posts/modules/github.md @@ -58,8 +58,8 @@ github: refreshInterval: 300 repositories: wesker-api: "UmbrellaCorp" - wtf: "andrewzolotukhin" - username: "andrewzolotukhin" + wtf: "senorprogrammer" + username: "senorprogrammer" ``` ### Attributes diff --git a/_site/content/posts/overview.md b/_site/content/posts/overview.md index 14745096..126715d7 100644 --- a/_site/content/posts/overview.md +++ b/_site/content/posts/overview.md @@ -12,7 +12,7 @@ visible, but might check in on every now and then. ## Quick Start -1. Download the stand-alone, compiled binary. +1. Download the stand-alone, compiled binary. 2. Unzip the downloaded file. 3. From the command line, `cd` into the newly-created `/wtf` directory. 4. From the command line, run the app: `./wtf` diff --git a/_site/themes/hyde-hyde/layouts/index.html b/_site/themes/hyde-hyde/layouts/index.html index 88cef7ab..d6fed31f 100644 --- a/_site/themes/hyde-hyde/layouts/index.html +++ b/_site/themes/hyde-hyde/layouts/index.html @@ -27,8 +27,8 @@ It even has weather. And clocks. And emoji.

    - Download Latest - Source on Github + Download Latest + Source on Github Chat on Gitter

    diff --git a/_site/themes/hyde-hyde/layouts/partials/sidebar.html b/_site/themes/hyde-hyde/layouts/partials/sidebar.html index a1f9fc61..7d593f21 100644 --- a/_site/themes/hyde-hyde/layouts/partials/sidebar.html +++ b/_site/themes/hyde-hyde/layouts/partials/sidebar.html @@ -17,7 +17,7 @@

    - +
    diff --git a/bamboohr/item.go b/bamboohr/item.go index e7533e5c..cc18590b 100644 --- a/bamboohr/item.go +++ b/bamboohr/item.go @@ -4,7 +4,7 @@ import ( "fmt" //"time" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) type Item struct { diff --git a/bamboohr/widget.go b/bamboohr/widget.go index c83f9d76..073b29d4 100644 --- a/bamboohr/widget.go +++ b/bamboohr/widget.go @@ -3,7 +3,7 @@ package bamboohr import ( "fmt" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" "github.com/olebedev/config" ) diff --git a/bargraph/widget.go b/bargraph/widget.go index 399ce415..33b7ca09 100644 --- a/bargraph/widget.go +++ b/bargraph/widget.go @@ -8,7 +8,7 @@ import ( "math/rand" "time" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" "github.com/olebedev/config" ) diff --git a/blockfolio/widget.go b/blockfolio/widget.go index 7594366f..968cd7f1 100644 --- a/blockfolio/widget.go +++ b/blockfolio/widget.go @@ -9,7 +9,7 @@ import ( "github.com/olebedev/config" "github.com/rivo/tview" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cfg/config_files.go b/cfg/config_files.go index b571ad04..85e848e8 100644 --- a/cfg/config_files.go +++ b/cfg/config_files.go @@ -5,8 +5,8 @@ import ( "io/ioutil" "os" - "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" ) func ConfigDir() (string, error) { @@ -64,7 +64,7 @@ func LoadConfigFile(filePath string) *config.Config { cfg, err := config.ParseYamlFile(absPath) if err != nil { - fmt.Println("\n\n\033[1m ERROR:\033[0m Could not load '\033[0;33mconfig.yml\033[0m'.\n Please add a \033[0;33mconfig.yml\033[0m file to your \033[0;33m~/.wtf\033[0m directory.\n See \033[1;34mhttps://github.com/andrewzolotukhin/wtf\033[0m for details.\n") + fmt.Println("\n\n\033[1m ERROR:\033[0m Could not load '\033[0;33mconfig.yml\033[0m'.\n Please add a \033[0;33mconfig.yml\033[0m file to your \033[0;33m~/.wtf\033[0m directory.\n See \033[1;34mhttps://github.com/senorprogrammer/wtf\033[0m for details.\n") fmt.Printf(" %s\n", err.Error()) os.Exit(1) } diff --git a/circleci/widget.go b/circleci/widget.go index e0e9f7bc..ee99323c 100644 --- a/circleci/widget.go +++ b/circleci/widget.go @@ -3,8 +3,8 @@ package circleci import ( "fmt" - "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/clocks/clock.go b/clocks/clock.go index 6d0e9615..fc4965fc 100644 --- a/clocks/clock.go +++ b/clocks/clock.go @@ -3,7 +3,7 @@ package clocks import ( "time" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) type Clock struct { diff --git a/clocks/display.go b/clocks/display.go index 4fcd425d..6cc7d60f 100644 --- a/clocks/display.go +++ b/clocks/display.go @@ -3,7 +3,7 @@ package clocks import ( "fmt" - "github.com/andrewzolotukhin/wtf/wtf" + "github.com/senorprogrammer/wtf/wtf" ) func (widget *Widget) display(clocks []Clock) { diff --git a/clocks/widget.go b/clocks/widget.go index 1134ac71..d6d6ee2a 100644 --- a/clocks/widget.go +++ b/clocks/widget.go @@ -3,8 +3,8 @@ package clocks import ( "time" - "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cmdrunner/widget.go b/cmdrunner/widget.go index 0a0e0bf6..0708527e 100644 --- a/cmdrunner/widget.go +++ b/cmdrunner/widget.go @@ -5,8 +5,8 @@ import ( "os/exec" "strings" - "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cryptoexchanges/bittrex/widget.go b/cryptoexchanges/bittrex/widget.go index 5fa6e3d0..7bbf1003 100644 --- a/cryptoexchanges/bittrex/widget.go +++ b/cryptoexchanges/bittrex/widget.go @@ -7,8 +7,8 @@ import ( "net/http" - "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/cryptoexchanges/cryptolive/widget.go b/cryptoexchanges/cryptolive/widget.go index a6f3aa59..daaefa0e 100644 --- a/cryptoexchanges/cryptolive/widget.go +++ b/cryptoexchanges/cryptolive/widget.go @@ -6,8 +6,8 @@ import ( "net/http" "time" - "github.com/andrewzolotukhin/wtf/wtf" "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" ) // Config is a pointer to the global config object diff --git a/docs/404.html b/docs/404.html index 31fc242c..262aef29 100644 --- a/docs/404.html +++ b/docs/404.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/categories/index.html b/docs/categories/index.html index 9766807a..8803ffb8 100644 --- a/docs/categories/index.html +++ b/docs/categories/index.html @@ -60,7 +60,7 @@ - +
    @@ -119,8 +119,8 @@ It even has weather. And clocks. And emoji.

    - Download Latest - Source on Github + Download Latest + Source on Github Chat on Gitter

    diff --git a/docs/index.xml b/docs/index.xml index 1f3a63f5..28d48bd1 100644 --- a/docs/index.xml +++ b/docs/index.xml @@ -122,9 +122,9 @@ Quick Start Download the stand-alone, compiled binary. Unzip the downloaded fil https://wtfutil.com/posts/installation/ There are two ways to install WTF: From Source Get this repo and install the dependencies: -go get -u github.com/andrewzolotukhin/wtf cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run and that should probably do it. +go get -u github.com/senorprogrammer/wtf cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run and that should probably do it. As a Binary Grab the latest version from here: -https://github.com/andrewzolotukhin/wtf/releases expand it, and cd into the resulting directory. Then run: +https://github.com/senorprogrammer/wtf/releases expand it, and cd into the resulting directory. Then run: ./wtf and that should also do it. diff --git a/docs/posts/configuration/attributes/index.html b/docs/posts/configuration/attributes/index.html index d8fd2e1a..bd308fdf 100644 --- a/docs/posts/configuration/attributes/index.html +++ b/docs/posts/configuration/attributes/index.html @@ -58,7 +58,7 @@

    - +
    @@ -114,7 +114,7 @@

    The following top-level attributes are configurable in config.yml. -See this example config file for more details.

    +See this example config file for more details.

    wtf:
       colors:
         background: "red"
    diff --git a/docs/posts/configuration/index.html b/docs/posts/configuration/index.html
    index bed8adf4..067aab24 100644
    --- a/docs/posts/configuration/index.html
    +++ b/docs/posts/configuration/index.html
    @@ -58,7 +58,7 @@
             
             
             
    -        
    +        
           
    diff --git a/docs/posts/configuration/iterm2/index.html b/docs/posts/configuration/iterm2/index.html index 0dc9de92..ba679394 100644 --- a/docs/posts/configuration/iterm2/index.html +++ b/docs/posts/configuration/iterm2/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/glossary/index.html b/docs/posts/glossary/index.html index 960fbca6..b88135ae 100644 --- a/docs/posts/glossary/index.html +++ b/docs/posts/glossary/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/index.xml b/docs/posts/index.xml index d328d821..71eef75b 100644 --- a/docs/posts/index.xml +++ b/docs/posts/index.xml @@ -122,9 +122,9 @@ Quick Start Download the stand-alone, compiled binary. Unzip the downloaded fil https://wtfutil.com/posts/installation/ There are two ways to install WTF: From Source Get this repo and install the dependencies: -go get -u github.com/andrewzolotukhin/wtf cd $GOPATH/src/github.com/andrewzolotukhin/wtf make install make run and that should probably do it. +go get -u github.com/senorprogrammer/wtf cd $GOPATH/src/github.com/senorprogrammer/wtf make install make run and that should probably do it. As a Binary Grab the latest version from here: -https://github.com/andrewzolotukhin/wtf/releases expand it, and cd into the resulting directory. Then run: +https://github.com/senorprogrammer/wtf/releases expand it, and cd into the resulting directory. Then run: ./wtf and that should also do it. diff --git a/docs/posts/installation/index.html b/docs/posts/installation/index.html index 3fdd42f3..57c8acd7 100644 --- a/docs/posts/installation/index.html +++ b/docs/posts/installation/index.html @@ -58,7 +58,7 @@ - +
    @@ -118,8 +118,8 @@

    From Source

    Get this repo and install the dependencies:

    -
    go get -u github.com/andrewzolotukhin/wtf
    -cd $GOPATH/src/github.com/andrewzolotukhin/wtf
    +
    go get -u github.com/senorprogrammer/wtf
    +cd $GOPATH/src/github.com/senorprogrammer/wtf
     make install
     make run

    and that should probably do it.

    @@ -127,7 +127,7 @@ make run

    As a Binary

    Grab the latest version from here:

    -
    https://github.com/andrewzolotukhin/wtf/releases
    +
    https://github.com/senorprogrammer/wtf/releases

    expand it, and cd into the resulting directory. Then run:

    ./wtf

    and that should also do it.

    diff --git a/docs/posts/modules/bamboohr/index.html b/docs/posts/modules/bamboohr/index.html index cdf207c3..e3b3ac7c 100644 --- a/docs/posts/modules/bamboohr/index.html +++ b/docs/posts/modules/bamboohr/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/bittrex/index.html b/docs/posts/modules/bittrex/index.html index ebe5ffd2..8ab9753c 100644 --- a/docs/posts/modules/bittrex/index.html +++ b/docs/posts/modules/bittrex/index.html @@ -72,7 +72,7 @@ iTerm2
diff --git a/docs/posts/modules/clocks/index.html b/docs/posts/modules/clocks/index.html index e2814986..71a519c8 100644 --- a/docs/posts/modules/clocks/index.html +++ b/docs/posts/modules/clocks/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cmdrunner/index.html b/docs/posts/modules/cmdrunner/index.html index 2ff80736..edca5f69 100644 --- a/docs/posts/modules/cmdrunner/index.html +++ b/docs/posts/modules/cmdrunner/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptocurrencies/bittrex/index.html b/docs/posts/modules/cryptocurrencies/bittrex/index.html index 01975238..18730b2b 100644 --- a/docs/posts/modules/cryptocurrencies/bittrex/index.html +++ b/docs/posts/modules/cryptocurrencies/bittrex/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptocurrencies/cryptolive/index.html b/docs/posts/modules/cryptocurrencies/cryptolive/index.html index 3f55416f..f84dea13 100644 --- a/docs/posts/modules/cryptocurrencies/cryptolive/index.html +++ b/docs/posts/modules/cryptocurrencies/cryptolive/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/cryptolive/index.html b/docs/posts/modules/cryptolive/index.html index b4bfaccb..63395a42 100644 --- a/docs/posts/modules/cryptolive/index.html +++ b/docs/posts/modules/cryptolive/index.html @@ -72,7 +72,7 @@ iTerm2
diff --git a/docs/posts/modules/gcal/index.html b/docs/posts/modules/gcal/index.html index d459e933..fa6de93d 100644 --- a/docs/posts/modules/gcal/index.html +++ b/docs/posts/modules/gcal/index.html @@ -58,7 +58,7 @@ - +
    @@ -118,7 +118,7 @@

    gcal screenshot

    Not: Setting up access to Google Calendars for Go is a bit unobvious. Check out Google’s Go Quickstart -first and if you have problems, then take a look at this comment by WesleydeSouza which offers a slightly different approach.

    +first and if you have problems, then take a look at this comment by WesleydeSouza which offers a slightly different approach.

    Source Code

    wtf/gcal/
    diff --git a/docs/posts/modules/git/index.html b/docs/posts/modules/git/index.html index 9eedd440..0ab526af 100644 --- a/docs/posts/modules/git/index.html +++ b/docs/posts/modules/git/index.html @@ -58,7 +58,7 @@ - +
    @@ -165,7 +165,7 @@ commit, and their status.

    width: 2 refreshInterval: 8 repositories: - - "/Users/chris/go/src/github.com/andrewzolotukhin/wtf" + - "/Users/chris/go/src/github.com/senorprogrammer/wtf" - "/Users/user/fakeapp"

    Attributes

    diff --git a/docs/posts/modules/github/index.html b/docs/posts/modules/github/index.html index 47d0d7d2..55afa1e3 100644 --- a/docs/posts/modules/github/index.html +++ b/docs/posts/modules/github/index.html @@ -58,7 +58,7 @@ - +
    @@ -160,8 +160,8 @@ refreshInterval: 300 repositories: wesker-api: "UmbrellaCorp" - wtf: "andrewzolotukhin" - username: "andrewzolotukhin" + wtf: "senorprogrammer" + username: "senorprogrammer"

    Attributes

    enabled
    diff --git a/docs/posts/modules/index.html b/docs/posts/modules/index.html index 2dee71d0..5ffb2199 100644 --- a/docs/posts/modules/index.html +++ b/docs/posts/modules/index.html @@ -58,7 +58,7 @@

    - +
    diff --git a/docs/posts/modules/ipinfo/index.html b/docs/posts/modules/ipinfo/index.html index 5db5c836..5f3994cb 100644 --- a/docs/posts/modules/ipinfo/index.html +++ b/docs/posts/modules/ipinfo/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/jira/index.html b/docs/posts/modules/jira/index.html index 52287193..258cb919 100644 --- a/docs/posts/modules/jira/index.html +++ b/docs/posts/modules/jira/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/newrelic/index.html b/docs/posts/modules/newrelic/index.html index 1e715c30..db3a032b 100644 --- a/docs/posts/modules/newrelic/index.html +++ b/docs/posts/modules/newrelic/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/opsgenie/index.html b/docs/posts/modules/opsgenie/index.html index 24468b0e..ff57d7cb 100644 --- a/docs/posts/modules/opsgenie/index.html +++ b/docs/posts/modules/opsgenie/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/power/index.html b/docs/posts/modules/power/index.html index 373e58b5..e42e346c 100644 --- a/docs/posts/modules/power/index.html +++ b/docs/posts/modules/power/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/prettyweather/index.html b/docs/posts/modules/prettyweather/index.html index 58c11182..a0c4d36b 100644 --- a/docs/posts/modules/prettyweather/index.html +++ b/docs/posts/modules/prettyweather/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/security/index.html b/docs/posts/modules/security/index.html index da556e57..98c131b0 100644 --- a/docs/posts/modules/security/index.html +++ b/docs/posts/modules/security/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/textfile/index.html b/docs/posts/modules/textfile/index.html index c0d5dd98..a8e53ab4 100644 --- a/docs/posts/modules/textfile/index.html +++ b/docs/posts/modules/textfile/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/todo/index.html b/docs/posts/modules/todo/index.html index 44c93f04..6c105daa 100644 --- a/docs/posts/modules/todo/index.html +++ b/docs/posts/modules/todo/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/modules/weather/index.html b/docs/posts/modules/weather/index.html index 5dc1508c..7021ceb2 100644 --- a/docs/posts/modules/weather/index.html +++ b/docs/posts/modules/weather/index.html @@ -58,7 +58,7 @@ - +
    diff --git a/docs/posts/overview/index.html b/docs/posts/overview/index.html index 3c57251d..a3d75261 100644 --- a/docs/posts/overview/index.html +++ b/docs/posts/overview/index.html @@ -58,7 +58,7 @@ - +
    @@ -122,7 +122,7 @@ visible, but might check in on every now and then.

    Quick Start

      -
    1. Download the stand-alone, compiled binary.
    2. +
    3. Download the stand-alone, compiled binary.
    4. Unzip the downloaded file.
    5. From the command line, cd into the newly-created /wtf directory.
    6. From the command line, run the app: ./wtf
    7. diff --git a/docs/tags/index.html b/docs/tags/index.html index 8ed850a0..9681fff7 100644 --- a/docs/tags/index.html +++ b/docs/tags/index.html @@ -60,7 +60,7 @@ - +