From 9d8596a14c3442953ca89d02af7d5e9a8b1a4f96 Mon Sep 17 00:00:00 2001 From: guange <8863824@gmail.com> Date: Sat, 1 Aug 2015 18:48:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Egitlab=20adapter=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E9=80=82=E9=85=8Dgitlab=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 2 +- app/controllers/repositories_controller.rb | 9 +- app/models/repository/gitlab.rb | 259 +++++++++++++ config/initializers/gitlab_config.rb | 2 +- lib/gitlab-cli/Gemfile | 4 + lib/gitlab-cli/LICENSE.txt | 24 ++ lib/gitlab-cli/README.md | 121 ++++++ lib/gitlab-cli/Rakefile | 9 + lib/gitlab-cli/bin/gitlab | 7 + lib/gitlab-cli/gitlab.gemspec | 26 ++ lib/gitlab-cli/lib/gitlab.rb | 37 ++ lib/gitlab-cli/lib/gitlab/api.rb | 17 + lib/gitlab-cli/lib/gitlab/cli.rb | 47 +++ lib/gitlab-cli/lib/gitlab/cli_helpers.rb | 175 +++++++++ lib/gitlab-cli/lib/gitlab/client.rb | 18 + lib/gitlab-cli/lib/gitlab/client/branches.rb | 79 ++++ lib/gitlab-cli/lib/gitlab/client/groups.rb | 88 +++++ lib/gitlab-cli/lib/gitlab/client/issues.rb | 92 +++++ .../lib/gitlab/client/merge_requests.rb | 107 ++++++ .../lib/gitlab/client/milestones.rb | 57 +++ lib/gitlab-cli/lib/gitlab/client/notes.rb | 106 ++++++ lib/gitlab-cli/lib/gitlab/client/projects.rb | 300 +++++++++++++++ .../lib/gitlab/client/repositories.rb | 89 +++++ lib/gitlab-cli/lib/gitlab/client/snippets.rb | 86 +++++ .../lib/gitlab/client/system_hooks.rb | 58 +++ lib/gitlab-cli/lib/gitlab/client/users.rb | 123 ++++++ lib/gitlab-cli/lib/gitlab/configuration.rb | 39 ++ lib/gitlab-cli/lib/gitlab/error.rb | 42 +++ lib/gitlab-cli/lib/gitlab/help.rb | 44 +++ lib/gitlab-cli/lib/gitlab/objectified_hash.rb | 24 ++ lib/gitlab-cli/lib/gitlab/request.rb | 113 ++++++ lib/gitlab-cli/lib/gitlab/shell.rb | 51 +++ lib/gitlab-cli/lib/gitlab/version.rb | 3 + lib/gitlab-cli/spec/fixtures/branch.json | 1 + lib/gitlab-cli/spec/fixtures/branches.json | 1 + .../spec/fixtures/comment_merge_request.json | 1 + .../spec/fixtures/create_branch.json | 1 + .../spec/fixtures/create_merge_request.json | 1 + .../spec/fixtures/error_already_exists.json | 1 + lib/gitlab-cli/spec/fixtures/group.json | 60 +++ .../spec/fixtures/group_create.json | 1 + .../spec/fixtures/group_member.json | 1 + .../spec/fixtures/group_member_delete.json | 1 + .../spec/fixtures/group_members.json | 1 + lib/gitlab-cli/spec/fixtures/groups.json | 2 + lib/gitlab-cli/spec/fixtures/issue.json | 1 + lib/gitlab-cli/spec/fixtures/issues.json | 1 + lib/gitlab-cli/spec/fixtures/key.json | 1 + lib/gitlab-cli/spec/fixtures/keys.json | 1 + .../spec/fixtures/merge_request.json | 1 + .../spec/fixtures/merge_request_comments.json | 1 + .../spec/fixtures/merge_requests.json | 1 + lib/gitlab-cli/spec/fixtures/milestone.json | 1 + lib/gitlab-cli/spec/fixtures/milestones.json | 1 + lib/gitlab-cli/spec/fixtures/note.json | 1 + lib/gitlab-cli/spec/fixtures/notes.json | 1 + lib/gitlab-cli/spec/fixtures/project.json | 1 + .../spec/fixtures/project_commit.json | 13 + .../spec/fixtures/project_commit_diff.json | 10 + .../spec/fixtures/project_commits.json | 1 + .../spec/fixtures/project_delete_key.json | 8 + .../spec/fixtures/project_events.json | 1 + .../spec/fixtures/project_for_user.json | 1 + .../spec/fixtures/project_fork_link.json | 1 + .../spec/fixtures/project_hook.json | 1 + .../spec/fixtures/project_hooks.json | 1 + .../spec/fixtures/project_issues.json | 1 + lib/gitlab-cli/spec/fixtures/project_key.json | 6 + .../spec/fixtures/project_keys.json | 6 + .../spec/fixtures/project_tags.json | 1 + lib/gitlab-cli/spec/fixtures/projects.json | 1 + .../spec/fixtures/protect_branch.json | 1 + lib/gitlab-cli/spec/fixtures/session.json | 1 + lib/gitlab-cli/spec/fixtures/snippet.json | 1 + lib/gitlab-cli/spec/fixtures/snippets.json | 1 + lib/gitlab-cli/spec/fixtures/system_hook.json | 1 + .../spec/fixtures/system_hook_test.json | 1 + .../spec/fixtures/system_hooks.json | 1 + lib/gitlab-cli/spec/fixtures/tag.json | 1 + lib/gitlab-cli/spec/fixtures/team_member.json | 1 + .../spec/fixtures/team_members.json | 1 + .../spec/fixtures/unprotect_branch.json | 1 + .../spec/fixtures/update_merge_request.json | 1 + lib/gitlab-cli/spec/fixtures/user.json | 1 + lib/gitlab-cli/spec/fixtures/users.json | 1 + lib/gitlab-cli/spec/gitlab/cli_spec.rb | 80 ++++ .../spec/gitlab/client/branches_spec.rb | 103 +++++ .../spec/gitlab/client/groups_spec.rb | 111 ++++++ .../spec/gitlab/client/issues_spec.rb | 122 ++++++ .../spec/gitlab/client/merge_requests_spec.rb | 124 ++++++ .../spec/gitlab/client/milestones_spec.rb | 66 ++++ .../spec/gitlab/client/notes_spec.rb | 156 ++++++++ .../spec/gitlab/client/projects_spec.rb | 357 ++++++++++++++++++ .../spec/gitlab/client/repositories_spec.rb | 92 +++++ .../spec/gitlab/client/snippets_spec.rb | 85 +++++ .../spec/gitlab/client/system_hooks_spec.rb | 69 ++++ .../spec/gitlab/client/users_spec.rb | 192 ++++++++++ .../spec/gitlab/objectified_hash_spec.rb | 23 ++ lib/gitlab-cli/spec/gitlab/request_spec.rb | 48 +++ lib/gitlab-cli/spec/gitlab_spec.rb | 65 ++++ lib/gitlab-cli/spec/spec_helper.rb | 74 ++++ lib/redmine/scm/adapters/gitlab_adapter.rb | 287 ++++++++++++++ lib/trustie.rb | 1 + lib/trustie/gitlab/api.rb | 35 ++ lib/trustie/gitlab/helper.rb | 0 spec/requests/gitlab_request_spec.rb | 13 + 106 files changed, 4502 insertions(+), 9 deletions(-) create mode 100644 app/models/repository/gitlab.rb create mode 100644 lib/gitlab-cli/Gemfile create mode 100644 lib/gitlab-cli/LICENSE.txt create mode 100644 lib/gitlab-cli/README.md create mode 100644 lib/gitlab-cli/Rakefile create mode 100644 lib/gitlab-cli/bin/gitlab create mode 100644 lib/gitlab-cli/gitlab.gemspec create mode 100644 lib/gitlab-cli/lib/gitlab.rb create mode 100644 lib/gitlab-cli/lib/gitlab/api.rb create mode 100644 lib/gitlab-cli/lib/gitlab/cli.rb create mode 100644 lib/gitlab-cli/lib/gitlab/cli_helpers.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/branches.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/groups.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/issues.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/merge_requests.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/milestones.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/notes.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/projects.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/repositories.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/snippets.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/system_hooks.rb create mode 100644 lib/gitlab-cli/lib/gitlab/client/users.rb create mode 100644 lib/gitlab-cli/lib/gitlab/configuration.rb create mode 100644 lib/gitlab-cli/lib/gitlab/error.rb create mode 100644 lib/gitlab-cli/lib/gitlab/help.rb create mode 100644 lib/gitlab-cli/lib/gitlab/objectified_hash.rb create mode 100644 lib/gitlab-cli/lib/gitlab/request.rb create mode 100644 lib/gitlab-cli/lib/gitlab/shell.rb create mode 100644 lib/gitlab-cli/lib/gitlab/version.rb create mode 100644 lib/gitlab-cli/spec/fixtures/branch.json create mode 100644 lib/gitlab-cli/spec/fixtures/branches.json create mode 100644 lib/gitlab-cli/spec/fixtures/comment_merge_request.json create mode 100644 lib/gitlab-cli/spec/fixtures/create_branch.json create mode 100644 lib/gitlab-cli/spec/fixtures/create_merge_request.json create mode 100644 lib/gitlab-cli/spec/fixtures/error_already_exists.json create mode 100644 lib/gitlab-cli/spec/fixtures/group.json create mode 100644 lib/gitlab-cli/spec/fixtures/group_create.json create mode 100644 lib/gitlab-cli/spec/fixtures/group_member.json create mode 100644 lib/gitlab-cli/spec/fixtures/group_member_delete.json create mode 100644 lib/gitlab-cli/spec/fixtures/group_members.json create mode 100644 lib/gitlab-cli/spec/fixtures/groups.json create mode 100644 lib/gitlab-cli/spec/fixtures/issue.json create mode 100644 lib/gitlab-cli/spec/fixtures/issues.json create mode 100644 lib/gitlab-cli/spec/fixtures/key.json create mode 100644 lib/gitlab-cli/spec/fixtures/keys.json create mode 100644 lib/gitlab-cli/spec/fixtures/merge_request.json create mode 100644 lib/gitlab-cli/spec/fixtures/merge_request_comments.json create mode 100644 lib/gitlab-cli/spec/fixtures/merge_requests.json create mode 100644 lib/gitlab-cli/spec/fixtures/milestone.json create mode 100644 lib/gitlab-cli/spec/fixtures/milestones.json create mode 100644 lib/gitlab-cli/spec/fixtures/note.json create mode 100644 lib/gitlab-cli/spec/fixtures/notes.json create mode 100644 lib/gitlab-cli/spec/fixtures/project.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_commit.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_commit_diff.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_commits.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_delete_key.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_events.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_for_user.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_fork_link.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_hook.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_hooks.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_issues.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_key.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_keys.json create mode 100644 lib/gitlab-cli/spec/fixtures/project_tags.json create mode 100644 lib/gitlab-cli/spec/fixtures/projects.json create mode 100644 lib/gitlab-cli/spec/fixtures/protect_branch.json create mode 100644 lib/gitlab-cli/spec/fixtures/session.json create mode 100644 lib/gitlab-cli/spec/fixtures/snippet.json create mode 100644 lib/gitlab-cli/spec/fixtures/snippets.json create mode 100644 lib/gitlab-cli/spec/fixtures/system_hook.json create mode 100644 lib/gitlab-cli/spec/fixtures/system_hook_test.json create mode 100644 lib/gitlab-cli/spec/fixtures/system_hooks.json create mode 100644 lib/gitlab-cli/spec/fixtures/tag.json create mode 100644 lib/gitlab-cli/spec/fixtures/team_member.json create mode 100644 lib/gitlab-cli/spec/fixtures/team_members.json create mode 100644 lib/gitlab-cli/spec/fixtures/unprotect_branch.json create mode 100644 lib/gitlab-cli/spec/fixtures/update_merge_request.json create mode 100644 lib/gitlab-cli/spec/fixtures/user.json create mode 100644 lib/gitlab-cli/spec/fixtures/users.json create mode 100644 lib/gitlab-cli/spec/gitlab/cli_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/branches_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/groups_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/issues_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/merge_requests_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/milestones_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/notes_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/projects_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/repositories_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/snippets_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/system_hooks_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/client/users_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/objectified_hash_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab/request_spec.rb create mode 100644 lib/gitlab-cli/spec/gitlab_spec.rb create mode 100644 lib/gitlab-cli/spec/spec_helper.rb create mode 100644 lib/redmine/scm/adapters/gitlab_adapter.rb create mode 100644 lib/trustie/gitlab/api.rb create mode 100644 lib/trustie/gitlab/helper.rb create mode 100644 spec/requests/gitlab_request_spec.rb diff --git a/Gemfile b/Gemfile index eaaff1d01..d5c8c35d0 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ unless RUBY_PLATFORM =~ /w32/ gem 'iconv' end -gem 'gitlab' +gem 'gitlab', path: 'lib/gitlab-cli' gem 'rest-client' gem "mysql2", "= 0.3.18" gem 'redis-rails' diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 7b364a46b..7219f4c08 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -251,16 +251,11 @@ update end end - if params[:to] == 'gitlab' - g = Gitlab.client - g.post('/session', body: {email: User.current.mail, password: User.current.hashed_password}) - redirect_to "http://192.168.41.130:3000/gitlab-org/gitlab-shell/tree/master" - return - end - #if( !User.current.member_of?(@project) || @project.hidden_repo) @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty? + + # :name, :path, :kind, :size, :lastrev, :changeset @entries = @repository.entries(@path, @rev) @changeset = @repository.find_changeset_by_name(@rev) diff --git a/app/models/repository/gitlab.rb b/app/models/repository/gitlab.rb new file mode 100644 index 000000000..5ec725660 --- /dev/null +++ b/app/models/repository/gitlab.rb @@ -0,0 +1,259 @@ +#coding=utf-8 + +require 'redmine/scm/adapters/git_adapter' + +class Repository::Gitlab < Repository + + attr_protected :root_url + validates_presence_of :url + + def self.human_attribute_name(attribute_key_name, *args) + attr_name = attribute_key_name.to_s + if attr_name == "url" + attr_name = "path_to_repository" + end + super(attr_name, *args) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::GitlabAdapter + end + + def self.scm_name + 'Gitlab' + end + + def commits(authors, start_date, end_date, branch='master') + scm.commits(authors, start_date, end_date,branch).map {|commit| + [commit[:author], commit[:num]] + } + end + + def report_last_commit + extra_report_last_commit + end + + def extra_report_last_commit + return false if extra_info.nil? + v = extra_info["extra_report_last_commit"] + return false if v.nil? + v.to_s != '0' + end + + def supports_directory_revisions? + true + end + + def supports_revision_graph? + true + end + + def repo_log_encoding + 'UTF-8' + end + + # Returns the identifier for the given git changeset + def self.changeset_identifier(changeset) + changeset.scmid + end + + # Returns the readable identifier for the given git changeset + def self.format_changeset_identifier(changeset) + changeset.revision[0, 8] + end + + def branches + scm.branches + end + + def tags + scm.tags + end + + def default_branch + scm.default_branch + rescue Exception => e + logger.error "git: error during get default branch: #{e.message}" + nil + end + + def find_changeset_by_name(name) + if name.present? + changesets.where(:revision => name.to_s).first || + changesets.where('scmid LIKE ?', "#{name}%").first + end + end + + def entries(path=nil, identifier=nil) + entries = scm.entries(path, identifier, :report_last_commit => extra_report_last_commit) + load_entries_changesets(entries) + entries + end + + # With SCMs that have a sequential commit numbering, + # such as Subversion and Mercurial, + # Redmine is able to be clever and only fetch changesets + # going forward from the most recent one it knows about. + # + # However, Git does not have a sequential commit numbering. + # + # In order to fetch only new adding revisions, + # Redmine needs to save "heads". + # + # In Git and Mercurial, revisions are not in date order. + # Redmine Mercurial fixed issues. + # * Redmine Takes Too Long On Large Mercurial Repository + # http://www.redmine.org/issues/3449 + # * Sorting for changesets might go wrong on Mercurial repos + # http://www.redmine.org/issues/3567 + # + # Database revision column is text, so Redmine can not sort by revision. + # Mercurial has revision number, and revision number guarantees revision order. + # Redmine Mercurial model stored revisions ordered by database id to database. + # So, Redmine Mercurial model can use correct ordering revisions. + # + # Redmine Mercurial adapter uses "hg log -r 0:tip --limit 10" + # to get limited revisions from old to new. + # But, Git 1.7.3.4 does not support --reverse with -n or --skip. + # + # The repository can still be fully reloaded by calling #clear_changesets + # before fetching changesets (eg. for offline resync) + def fetch_changesets + scm_brs = branches + return if scm_brs.nil? || scm_brs.empty? + + h1 = extra_info || {} + h = h1.dup + repo_heads = scm_brs.map{ |br| br.scmid } + h["heads"] ||= [] + prev_db_heads = h["heads"].dup + if prev_db_heads.empty? + prev_db_heads += heads_from_branches_hash + end + return if prev_db_heads.sort == repo_heads.sort + + h["db_consistent"] ||= {} + if changesets.count == 0 + h["db_consistent"]["ordering"] = 1 + merge_extra_info(h) + self.save + elsif ! h["db_consistent"].has_key?("ordering") + h["db_consistent"]["ordering"] = 0 + merge_extra_info(h) + self.save + end + save_revisions(prev_db_heads, repo_heads) + end + + def save_revisions(prev_db_heads, repo_heads) + h = {} + opts = {} + opts[:reverse] = true + opts[:excludes] = prev_db_heads + opts[:includes] = repo_heads + + revisions = scm.revisions('', nil, nil, opts) + return if revisions.blank? + + # Make the search for existing revisions in the database in a more sufficient manner + # + # Git branch is the reference to the specific revision. + # Git can *delete* remote branch and *re-push* branch. + # + # $ git push remote :branch + # $ git push remote branch + # + # After deleting branch, revisions remain in repository until "git gc". + # On git 1.7.2.3, default pruning date is 2 weeks. + # So, "git log --not deleted_branch_head_revision" return code is 0. + # + # After re-pushing branch, "git log" returns revisions which are saved in database. + # So, Redmine needs to scan revisions and database every time. + # + # This is replacing the one-after-one queries. + # Find all revisions, that are in the database, and then remove them from the revision array. + # Then later we won't need any conditions for db existence. + # Query for several revisions at once, and remove them from the revisions array, if they are there. + # Do this in chunks, to avoid eventual memory problems (in case of tens of thousands of commits). + # If there are no revisions (because the original code's algorithm filtered them), + # then this part will be stepped over. + # We make queries, just if there is any revision. + limit = 100 + offset = 0 + revisions_copy = revisions.clone # revisions will change + while offset < revisions_copy.size + recent_changesets_slice = changesets.find( + :all, + :conditions => [ + 'scmid IN (?)', + revisions_copy.slice(offset, limit).map{|x| x.scmid} + ] + ) + # Subtract revisions that redmine already knows about + recent_revisions = recent_changesets_slice.map{|c| c.scmid} + revisions.reject!{|r| recent_revisions.include?(r.scmid)} + offset += limit + end + + revisions.each do |rev| + transaction do + # There is no search in the db for this revision, because above we ensured, + # that it's not in the db. + save_revision(rev) + end + end + h["heads"] = repo_heads.dup + merge_extra_info(h) + self.save + end + private :save_revisions + + def save_revision(rev) + parents = (rev.parents || []).collect{|rp| find_changeset_by_name(rp)}.compact + changeset = Changeset.create( + :repository => self, + :revision => rev.identifier, + :scmid => rev.scmid, + :committer => rev.author, + :committed_on => rev.time, + :comments => rev.message, + :parents => parents + ) + unless changeset.new_record? + rev.paths.each { |change| changeset.create_change(change) } + end + changeset + end + private :save_revision + + def heads_from_branches_hash + h1 = extra_info || {} + h = h1.dup + h["branches"] ||= {} + h['branches'].map{|br, hs| hs['last_scmid']} + end + + def latest_changesets(path,rev,limit=10) + revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false) + return [] if revisions.nil? || revisions.empty? + + changesets.find( + :all, + :conditions => [ + "scmid IN (?)", + revisions.map!{|c| c.scmid} + ] + ) + end + + def clear_extra_info_of_changesets + return if extra_info.nil? + v = extra_info["extra_report_last_commit"] + write_attribute(:extra_info, nil) + h = {} + h["extra_report_last_commit"] = v + merge_extra_info(h) + self.save + end + private :clear_extra_info_of_changesets +end diff --git a/config/initializers/gitlab_config.rb b/config/initializers/gitlab_config.rb index 4041b45f4..61fc12287 100644 --- a/config/initializers/gitlab_config.rb +++ b/config/initializers/gitlab_config.rb @@ -1,7 +1,7 @@ Gitlab.configure do |config| # config.endpoint = 'http://192.168.41.130:3000/trustie/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT'] # config.private_token = 'cK15gUDwvt8EEkzwQ_63' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN'] - config.endpoint = 'http://gitlab.trustie.net/trustie/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT'] + config.endpoint = 'http://git.trustie.net/trustie/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT'] config.private_token = 'fxm19wjRAs4REgTJwgtn' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN'] # Optional # config.user_agent = 'Custom User Agent' # user agent, default: 'Gitlab Ruby Gem [version]' diff --git a/lib/gitlab-cli/Gemfile b/lib/gitlab-cli/Gemfile new file mode 100644 index 000000000..54fbdf177 --- /dev/null +++ b/lib/gitlab-cli/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +# Specify your gem's dependencies in gitlab.gemspec +gemspec diff --git a/lib/gitlab-cli/LICENSE.txt b/lib/gitlab-cli/LICENSE.txt new file mode 100644 index 000000000..2c289176d --- /dev/null +++ b/lib/gitlab-cli/LICENSE.txt @@ -0,0 +1,24 @@ +Copyright (c) 2012-2014 Nihad Abbasov +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/gitlab-cli/README.md b/lib/gitlab-cli/README.md new file mode 100644 index 000000000..1aa73996c --- /dev/null +++ b/lib/gitlab-cli/README.md @@ -0,0 +1,121 @@ +# Gitlab + +[![Build Status](https://travis-ci.org/NARKOZ/gitlab.png)](http://travis-ci.org/NARKOZ/gitlab) + +[website](http://narkoz.github.io/gitlab) | +[documentation](http://rubydoc.info/gems/gitlab/frames) + +Gitlab is a Ruby wrapper and CLI for the [GitLab API](https://github.com/gitlabhq/gitlabhq/tree/master/doc/api#gitlab-api). + +## Installation + +Install it from rubygems: + +```sh +gem install gitlab +``` + +Or add to a Gemfile: + +```ruby +gem 'gitlab' +# gem 'gitlab', :git => 'git://github.com/NARKOZ/gitlab.git' +``` + +## Usage + +Configuration example: + +```ruby +Gitlab.configure do |config| + config.endpoint = 'https://example.net/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT'] + config.private_token = 'qEsq1pt6HJPaNciie3MG' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN'] + # Optional + # config.user_agent = 'Custom User Agent' # user agent, default: 'Gitlab Ruby Gem [version]' + # config.sudo = 'user' # username for sudo mode, default: nil +end +``` + +(Note: If you are using Gitlab.com's hosted service, your endpoint will be `https://gitlab.com/api/v3`) + +Usage examples: + +```ruby +# set an API endpoint +Gitlab.endpoint = 'http://example.net/api/v3' +# => "http://example.net/api/v3" + +# set a user private token +Gitlab.private_token = 'qEsq1pt6HJPaNciie3MG' +# => "qEsq1pt6HJPaNciie3MG" + +# list projects +Gitlab.projects(:per_page => 5) +# => [#1, "code"=>"brute", "name"=>"Brute", "description"=>nil, "path"=>"brute", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:56Z"}>, #2, "code"=>"mozart", "name"=>"Mozart", "description"=>nil, "path"=>"mozart", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:57Z"}>, #3, "code"=>"gitlab", "name"=>"Gitlab", "description"=>nil, "path"=>"gitlab", "default_branch"=>nil, "owner"=>#1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:58Z"}>] + +# initialize a new client +g = Gitlab.client(:endpoint => 'https://api.example.com', :private_token => 'qEsq1pt6HJPaNciie3MG') +# => # + +# get a user +user = g.user +# => #1, "email"=>"john@example.com", "name"=>"John Smith", "bio"=>nil, "skype"=>"", "linkedin"=>"", "twitter"=>"john", "dark_scheme"=>false, "theme_id"=>1, "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}> + +# get a user's email +user.email +# => "john@example.com" + +# set a sudo mode to perform API calls as another user +Gitlab.sudo = 'other_user' +# => "other_user" + +# disable a sudo mode +Gitlab.sudo = nil +# => nil +``` + +For more information, refer to [documentation](http://rubydoc.info/gems/gitlab/frames). + +## CLI + +Usage examples: + +```sh +# list users +gitlab users + +# get current user +gitlab user + +# get a user +gitlab user 2 + +# filter output +gitlab user --only=id,username + +gitlab user --except=email,bio +``` + +## CLI Shell + +Usage examples: + +```sh +# start shell session +gitlab shell + +# list available commands +gitlab> help + +# list groups +gitlab> groups + +# protect a branch +gitlab> protect_branch 1 master +``` + +For more information, refer to [website](http://narkoz.github.io/gitlab). + +## License + +Released under the BSD 2-clause license. See LICENSE.txt for details. diff --git a/lib/gitlab-cli/Rakefile b/lib/gitlab-cli/Rakefile new file mode 100644 index 000000000..bf451bdcb --- /dev/null +++ b/lib/gitlab-cli/Rakefile @@ -0,0 +1,9 @@ +require "bundler/gem_tasks" + +require 'rspec/core/rake_task' +RSpec::Core::RakeTask.new(:spec) do |spec| + spec.pattern = FileList['spec/**/*_spec.rb'] + spec.rspec_opts = ['--color', '--format d'] +end + +task :default => :spec diff --git a/lib/gitlab-cli/bin/gitlab b/lib/gitlab-cli/bin/gitlab new file mode 100644 index 000000000..af0fd0cc0 --- /dev/null +++ b/lib/gitlab-cli/bin/gitlab @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +$:.unshift File.expand_path('../../lib', __FILE__) + +require 'gitlab/cli' + +Gitlab::CLI.start(ARGV) diff --git a/lib/gitlab-cli/gitlab.gemspec b/lib/gitlab-cli/gitlab.gemspec new file mode 100644 index 000000000..7d5f30862 --- /dev/null +++ b/lib/gitlab-cli/gitlab.gemspec @@ -0,0 +1,26 @@ +# -*- encoding: utf-8 -*- +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'gitlab/version' + +Gem::Specification.new do |gem| + gem.name = "gitlab" + gem.version = Gitlab::VERSION + gem.authors = ["Nihad Abbasov"] + gem.email = ["mail@narkoz.me"] + gem.description = %q{Ruby client and CLI for GitLab API} + gem.summary = %q{A Ruby wrapper and CLI for the GitLab API} + gem.homepage = "https://github.com/narkoz/gitlab" + + gem.files = `git ls-files`.split($/) + gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } + gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) + gem.require_paths = ["lib"] + + gem.add_runtime_dependency 'httparty' + gem.add_runtime_dependency 'terminal-table' + + gem.add_development_dependency 'rake' + gem.add_development_dependency 'rspec' + gem.add_development_dependency 'webmock' +end diff --git a/lib/gitlab-cli/lib/gitlab.rb b/lib/gitlab-cli/lib/gitlab.rb new file mode 100644 index 000000000..95c382678 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab.rb @@ -0,0 +1,37 @@ +require 'gitlab/version' +require 'gitlab/objectified_hash' +require 'gitlab/configuration' +require 'gitlab/error' +require 'gitlab/request' +require 'gitlab/api' +require 'gitlab/client' + +module Gitlab + extend Configuration + + # Alias for Gitlab::Client.new + # + # @return [Gitlab::Client] + def self.client(options={}) + Gitlab::Client.new(options) + end + + # Delegate to Gitlab::Client + def self.method_missing(method, *args, &block) + return super unless client.respond_to?(method) + client.send(method, *args, &block) + end + + # Delegate to Gitlab::Client + def self.respond_to?(method) + return client.respond_to?(method) || super + end + + # Returns an unsorted array of available client methods. + # + # @return [Array] + def self.actions + hidden = /endpoint|private_token|user_agent|sudo|get|post|put|\Adelete\z|validate|set_request_defaults/ + (Gitlab::Client.instance_methods - Object.methods).reject {|e| e[hidden]} + end +end diff --git a/lib/gitlab-cli/lib/gitlab/api.rb b/lib/gitlab-cli/lib/gitlab/api.rb new file mode 100644 index 000000000..62b3f47dc --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/api.rb @@ -0,0 +1,17 @@ +module Gitlab + # @private + class API < Request + # @private + attr_accessor(*Configuration::VALID_OPTIONS_KEYS) + + # Creates a new API. + # @raise [Error:MissingCredentials] + def initialize(options={}) + options = Gitlab.options.merge(options) + Configuration::VALID_OPTIONS_KEYS.each do |key| + send("#{key}=", options[key]) + end + set_request_defaults @endpoint, @private_token, @sudo + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/cli.rb b/lib/gitlab-cli/lib/gitlab/cli.rb new file mode 100644 index 000000000..57c2aa5b4 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/cli.rb @@ -0,0 +1,47 @@ +require 'gitlab' +require 'terminal-table/import' +require_relative 'cli_helpers' +require_relative 'shell' + +class Gitlab::CLI + extend Helpers + + def self.start(args) + command = args.shift.strip rescue 'help' + run(command, args) + end + + def self.run(cmd, args=[]) + case cmd + when 'help' + puts actions_table + when 'info' + endpoint = Gitlab.endpoint ? Gitlab.endpoint : 'not set' + private_token = Gitlab.private_token ? Gitlab.private_token : 'not set' + puts "Gitlab endpoint is #{endpoint}" + puts "Gitlab private token is #{private_token}" + puts "Ruby Version is #{RUBY_VERSION}" + puts "Gitlab Ruby Gem #{Gitlab::VERSION}" + when '-v', '--version' + puts "Gitlab Ruby Gem #{Gitlab::VERSION}" + when 'shell' + Gitlab::Shell.start + else + unless valid_command?(cmd) + puts "Unknown command. Run `gitlab help` for a list of available commands." + exit(1) + end + + if args.any? && (args.last.start_with?('--only=') || args.last.start_with?('--except=')) + command_args = args[0..-2] + else + command_args = args + end + + confirm_command(cmd) + + data = gitlab_helper(cmd, command_args) { exit(1) } + output_table(cmd, args, data) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/cli_helpers.rb b/lib/gitlab-cli/lib/gitlab/cli_helpers.rb new file mode 100644 index 000000000..d1c777dc0 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/cli_helpers.rb @@ -0,0 +1,175 @@ +class Gitlab::CLI + # Defines methods related to CLI output and formatting. + module Helpers + extend self + + # Returns filtered required fields. + # + # @return [Array] + def required_fields(args) + if args.any? && args.last.start_with?('--only=') + args.last.gsub('--only=', '').split(',') + else + [] + end + end + + # Returns filtered excluded fields. + # + # @return [Array] + def excluded_fields(args) + if args.any? && args.last.start_with?('--except=') + args.last.gsub('--except=', '').split(',') + else + [] + end + end + + # Confirms command is valid. + # + # @return [Boolean] + def valid_command?(cmd) + command = cmd.is_a?(Symbol) ? cmd : cmd.to_sym + Gitlab.actions.include?(command) + end + + # Confirms command with a desctructive action. + # + # @return [String] + def confirm_command(cmd) + if cmd.start_with?('remove_') || cmd.start_with?('delete_') + puts "Are you sure? (y/n)" + if %w(y yes).include?($stdin.gets.to_s.strip.downcase) + puts 'Proceeding..' + else + puts 'Command aborted.' + exit(1) + end + end + end + + # Table with available commands. + # + # @return [String] + def actions_table + client = Gitlab::Client.new(endpoint: '') + actions = Gitlab.actions + methods = [] + + actions.each do |action| + methods << { + name: action, + owner: client.method(action).owner.to_s.gsub('Gitlab::Client::', '') + } + end + + owners = methods.map {|m| m[:owner]}.uniq.sort + methods_c = methods.group_by {|m| m[:owner]} + methods_c = methods_c.map {|_, v| [_, v.sort_by {|hv| hv[:name]}] } + methods_c = Hash[methods_c.sort_by(&:first).map {|k, v| [k, v]}] + max_column_length = methods_c.values.max_by(&:size).size + + rows = max_column_length.times.map do |i| + methods_c.keys.map do |key| + methods_c[key][i] ? methods_c[key][i][:name] : '' + end + end + + table do |t| + t.title = "Available commands (#{actions.size} total)" + t.headings = owners + + rows.each do |row| + t.add_row row + end + end + end + + # Decides which table to use. + # + # @return [String] + def output_table(cmd, args, data) + case data + when Gitlab::ObjectifiedHash + puts single_record_table(data, cmd, args) + when Array + puts multiple_record_table(data, cmd, args) + else + puts data.inspect + end + end + + # Table for a single record. + # + # @return [String] + def single_record_table(data, cmd, args) + hash = data.to_h + keys = hash.keys.sort {|x, y| x.to_s <=> y.to_s } + keys = keys & required_fields(args) if required_fields(args).any? + keys = keys - excluded_fields(args) + + table do |t| + t.title = "Gitlab.#{cmd} #{args.join(', ')}" + + keys.each_with_index do |key, index| + case value = hash[key] + when Hash + value = 'Hash' + when nil + value = 'null' + end + + t.add_row [key, value] + t.add_separator unless keys.size - 1 == index + end + end + end + + # Table for multiple records. + # + # @return [String] + def multiple_record_table(data, cmd, args) + return 'No data' if data.empty? + + arr = data.map(&:to_h) + keys = arr.first.keys.sort {|x, y| x.to_s <=> y.to_s } + keys = keys & required_fields(args) if required_fields(args).any? + keys = keys - excluded_fields(args) + + table do |t| + t.title = "Gitlab.#{cmd} #{args.join(', ')}" + t.headings = keys + + arr.each_with_index do |hash, index| + values = [] + + keys.each do |key| + case value = hash[key] + when Hash + value = 'Hash' + when nil + value = 'null' + end + + values << value + end + + t.add_row values + t.add_separator unless arr.size - 1 == index + end + end + end + + # Helper function to call Gitlab commands with args. + def gitlab_helper(cmd, args=[]) + begin + data = args.any? ? Gitlab.send(cmd, *args) : Gitlab.send(cmd) + rescue => e + puts e.message + yield if block_given? + end + + data + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client.rb b/lib/gitlab-cli/lib/gitlab/client.rb new file mode 100644 index 000000000..5cb01ce2b --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client.rb @@ -0,0 +1,18 @@ +module Gitlab + # Wrapper for the Gitlab REST API. + class Client < API + Dir[File.expand_path('../client/*.rb', __FILE__)].each {|f| require f} + + include Branches + include Groups + include Issues + include MergeRequests + include Milestones + include Notes + include Projects + include Repositories + include Snippets + include SystemHooks + include Users + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/branches.rb b/lib/gitlab-cli/lib/gitlab/client/branches.rb new file mode 100644 index 000000000..0ba3afb29 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/branches.rb @@ -0,0 +1,79 @@ +class Gitlab::Client + # Defines methods related to repositories. + module Branches + # Gets a list of project repositiory branches. + # + # @example + # Gitlab.branches(42) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def branches(project, options={}) + get("/projects/#{project}/repository/branches", :query => options) + end + alias_method :repo_branches, :branches + + # Gets information about a repository branch. + # + # @example + # Gitlab.branch(3, 'api') + # Gitlab.repo_branch(5, 'master') + # + # @param [Integer] project The ID of a project. + # @param [String] branch The name of the branch. + # @return [Gitlab::ObjectifiedHash] + def branch(project, branch) + get("/projects/#{project}/repository/branches/#{branch}") + end + + alias_method :repo_branch, :branch + + # Protects a repository branch. + # + # @example + # Gitlab.protect_branch(3, 'api') + # Gitlab.repo_protect_branch(5, 'master') + # + # @param [Integer] project The ID of a project. + # @param [String] branch The name of the branch. + # @return [Gitlab::ObjectifiedHash] + def protect_branch(project, branch) + put("/projects/#{project}/repository/branches/#{branch}/protect") + end + alias_method :repo_protect_branch, :protect_branch + + # Unprotects a repository branch. + # + # @example + # Gitlab.unprotect_branch(3, 'api') + # Gitlab.repo_unprotect_branch(5, 'master') + # + # @param [Integer] project The ID of a project. + # @param [String] branch The name of the branch. + # @return [Gitlab::ObjectifiedHash] + def unprotect_branch(project, branch) + put("/projects/#{project}/repository/branches/#{branch}/unprotect") + end + alias_method :repo_unprotect_branch, :unprotect_branch + + # Creates a repository branch. Requires Gitlab >= 6.8.x + # + # @example + # Gitlab.create_branch(3, 'api') + # Gitlab.repo_create_branch(5, 'master') + # + # @param [Integer] project The ID of a project. + # @param [String] branch The name of the new branch. + # @param [String] ref Create branch from commit sha or existing branch + # @return [Gitlab::ObjectifiedHash] + def create_branch(project, branch, ref) + post("/projects/#{project}/repository/branches",:body => {:branch_name => branch, :ref => ref}) + end + alias_method :repo_create_branch, :create_branch + + end +end + diff --git a/lib/gitlab-cli/lib/gitlab/client/groups.rb b/lib/gitlab-cli/lib/gitlab/client/groups.rb new file mode 100644 index 000000000..1ea4bf5bc --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/groups.rb @@ -0,0 +1,88 @@ +class Gitlab::Client + # Defines methods related to groups. + module Groups + # Gets a list of groups. + # + # @example + # Gitlab.groups + # Gitlab.groups(:per_page => 40) + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def groups(options={}) + get("/groups", :query => options) + end + + # Gets a single group. + # + # @example + # Gitlab.group(42) + # + # @param [Integer] id The ID of a group. + # @return [Gitlab::ObjectifiedHash] + def group(id) + get("/groups/#{id}") + end + + # Creates a new group. + # + # @param [String] name The name of a group. + # @param [String] path The path of a group. + # @return [Gitlab::ObjectifiedHash] Information about created group. + def create_group(name, path) + body = {:name => name, :path => path} + post("/groups", :body => body) + end + + # Get a list of group members. + # + # @example + # Gitlab.group_members(1) + # Gitlab.group_members(1, :per_page => 40) + # + # @param [Integer] id The ID of a group. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def group_members(id, options={}) + get("/groups/#{id}/members", :query => options) + end + + # Adds a user to group. + # + # @example + # Gitlab.add_group_member(1, 2, 40) + # + # @param [Integer] team_id The group id to add a member to. + # @param [Integer] user_id The user id of the user to add to the team. + # @param [Integer] access_level Project access level. + # @return [Gitlab::ObjectifiedHash] Information about added team member. + def add_group_member(team_id, user_id, access_level) + post("/groups/#{team_id}/members", :body => {:user_id => user_id, :access_level => access_level}) + end + + # Removes user from user group. + # + # @example + # Gitlab.remove_group_member(1, 2) + # + # @param [Integer] team_id The group ID. + # @param [Integer] user_id The ID of a user. + # @return [Gitlab::ObjectifiedHash] Information about removed team member. + def remove_group_member(team_id, user_id) + delete("/groups/#{team_id}/members/#{user_id}") + end + + # Transfers a project to a group + # + # @param [Integer] id The ID of a group. + # @param [Integer] project_id The ID of a project. + def transfer_project_to_group(id, project_id) + body = {:id => id, :project_id => project_id} + post("/groups/#{id}/projects/#{project_id}", :body => body) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/issues.rb b/lib/gitlab-cli/lib/gitlab/client/issues.rb new file mode 100644 index 000000000..7248df848 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/issues.rb @@ -0,0 +1,92 @@ +class Gitlab::Client + # Defines methods related to issues. + module Issues + # Gets a list of user's issues. + # Will return a list of project's issues if project ID passed. + # + # @example + # Gitlab.issues + # Gitlab.issues(5) + # Gitlab.issues(:per_page => 40) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def issues(project=nil, options={}) + if project.to_i.zero? + get("/issues", :query => options) + else + get("/projects/#{project}/issues", :query => options) + end + end + + # Gets a single issue. + # + # @example + # Gitlab.issue(5, 42) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] + def issue(project, id) + get("/projects/#{project}/issues/#{id}") + end + + # Creates a new issue. + # + # @param [Integer] project The ID of a project. + # @param [String] title The title of an issue. + # @param [Hash] options A customizable set of options. + # @option options [String] :description The description of an issue. + # @option options [Integer] :assignee_id The ID of a user to assign issue. + # @option options [Integer] :milestone_id The ID of a milestone to assign issue. + # @option options [String] :labels Comma-separated label names for an issue. + # @return [Gitlab::ObjectifiedHash] Information about created issue. + def create_issue(project, title, options={}) + body = {:title => title}.merge(options) + post("/projects/#{project}/issues", :body => body) + end + + # Updates an issue. + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of an issue. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of an issue. + # @option options [String] :description The description of an issue. + # @option options [Integer] :assignee_id The ID of a user to assign issue. + # @option options [Integer] :milestone_id The ID of a milestone to assign issue. + # @option options [String] :labels Comma-separated label names for an issue. + # @option options [String] :state_event The state event of an issue ('close' or 'reopen'). + # @return [Gitlab::ObjectifiedHash] Information about updated issue. + def edit_issue(project, id, options={}) + put("/projects/#{project}/issues/#{id}", :body => options) + end + + # Closes an issue. + # + # @example + # Gitlab.close_issue(3, 42) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] Information about closed issue. + def close_issue(project, id) + put("/projects/#{project}/issues/#{id}", :body => {:state_event => 'close'}) + end + + # Reopens an issue. + # + # @example + # Gitlab.reopen_issue(3, 42) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of an issue. + # @return [Gitlab::ObjectifiedHash] Information about reopened issue. + def reopen_issue(project, id) + put("/projects/#{project}/issues/#{id}", :body => {:state_event => 'reopen'}) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/merge_requests.rb b/lib/gitlab-cli/lib/gitlab/client/merge_requests.rb new file mode 100644 index 000000000..1ccc25081 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/merge_requests.rb @@ -0,0 +1,107 @@ +class Gitlab::Client + # Defines methods related to merge requests. + module MergeRequests + # Gets a list of project merge requests. + # + # @example + # Gitlab.merge_requests(5) + # Gitlab.merge_requests(:per_page => 40) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def merge_requests(project, options={}) + get("/projects/#{project}/merge_requests", :query => options) + end + + # Gets a single merge request. + # + # @example + # Gitlab.merge_request(5, 36) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a merge request. + # @return 'source_branch', :target_branch => 'target_branch') + # Gitlab.create_merge_request(5, 'New merge request', + # :source_branch => 'source_branch', :target_branch => 'target_branch', :assignee_id => 42) + # + # @param [Integer] project The ID of a project. + # @param [String] title The title of a merge request. + # @param [Hash] options A customizable set of options. + # @option options [String] :source_branch (required) The source branch name. + # @option options [String] :target_branch (required) The target branch name. + # @option options [Integer] :assignee_id (optional) The ID of a user to assign merge request. + # @return [Gitlab::ObjectifiedHash] Information about created merge request. + def create_merge_request(project, title, options={}) + check_attributes!(options, [:source_branch, :target_branch]) + + body = {:title => title}.merge(options) + post("/projects/#{project}/merge_requests", :body => body) + end + + # Updates a merge request. + # + # @example + # Gitlab.update_merge_request(5, 42, :title => 'New title') + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a merge request. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of a merge request. + # @option options [String] :source_branch The source branch name. + # @option options [String] :target_branch The target branch name. + # @option options [Integer] :assignee_id The ID of a user to assign merge request. + # @option options [String] :state_event New state (close|reopen|merge). + # @return [Gitlab::ObjectifiedHash] Information about updated merge request. + def update_merge_request(project, id, options={}) + put("/projects/#{project}/merge_request/#{id}", :body => options) + end + + # Adds a comment to a merge request. + # + # @example + # Gitlab.create_merge_request_comment(5, 1, "Awesome merge!") + # Gitlab.create_merge_request_comment('gitlab', 1, "Awesome merge!") + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a merge request. + # @param [String] note The content of a comment. + # @return [Gitlab::ObjectifiedHash] Information about created merge request comment. + def create_merge_request_comment(project, id, note) + post("/projects/#{project}/merge_request/#{id}/comments", :body => {:note => note}) + end + + # Gets the comments on a merge request. + # + # @example + # Gitlab.merge_request_comments(5, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a merge request. + # @return [Gitlab::ObjectifiedHash] The merge request's comments. + def merge_request_comments(project, id) + get("/projects/#{project}/merge_request/#{id}/comments") + end + + private + + def check_attributes!(options, attrs) + attrs.each do |attr| + unless options.has_key?(attr) || options.has_key?(attr.to_s) + raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter") + end + end + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/milestones.rb b/lib/gitlab-cli/lib/gitlab/client/milestones.rb new file mode 100644 index 000000000..4ba4d5e87 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/milestones.rb @@ -0,0 +1,57 @@ +class Gitlab::Client + # Defines methods related to milestones. + module Milestones + # Gets a list of project's milestones. + # + # @example + # Gitlab.milestones(5) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def milestones(project, options={}) + get("/projects/#{project}/milestones", :query => options) + end + + # Gets a single milestone. + # + # @example + # Gitlab.milestone(5, 36) + # + # @param [Integer, String] project The ID of a project. + # @param [Integer] id The ID of a milestone. + # @return [Gitlab::ObjectifiedHash] + def milestone(project, id) + get("/projects/#{project}/milestones/#{id}") + end + + # Creates a new milestone. + # + # @param [Integer] project The ID of a project. + # @param [String] title The title of a milestone. + # @param [Hash] options A customizable set of options. + # @option options [String] :description The description of a milestone. + # @option options [String] :due_date The due date of a milestone. + # @return [Gitlab::ObjectifiedHash] Information about created milestone. + def create_milestone(project, title, options={}) + body = {:title => title}.merge(options) + post("/projects/#{project}/milestones", :body => body) + end + + # Updates a milestone. + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a milestone. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of a milestone. + # @option options [String] :description The description of a milestone. + # @option options [String] :due_date The due date of a milestone. + # @option options [String] :state_event The state of a milestone ('close' or 'activate'). + # @return [Gitlab::ObjectifiedHash] Information about updated milestone. + def edit_milestone(project, id, options={}) + put("/projects/#{project}/milestones/#{id}", :body => options) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/notes.rb b/lib/gitlab-cli/lib/gitlab/client/notes.rb new file mode 100644 index 000000000..7d782e8e2 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/notes.rb @@ -0,0 +1,106 @@ +class Gitlab::Client + # Defines methods related to notes. + module Notes + # Gets a list of projects notes. + # + # @example + # Gitlab.notes(5) + # + # @param [Integer] project The ID of a project. + # @return [Array] + def notes(project) + get("/projects/#{project}/notes") + end + + # Gets a list of notes for a issue. + # + # @example + # Gitlab.issue_notes(5, 10) + # + # @param [Integer] project The ID of a project. + # @param [Integer] issue The ID of an issue. + # @return [Array] + def issue_notes(project, issue) + get("/projects/#{project}/issues/#{issue}/notes") + end + + # Gets a list of notes for a snippet. + # + # @example + # Gitlab.snippet_notes(5, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] snippet The ID of a snippet. + # @return [Array] + def snippet_notes(project, snippet) + get("/projects/#{project}/snippets/#{snippet}/notes") + end + + # Gets a single wall note. + # + # @example + # Gitlab.note(5, 15) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a note. + # @return [Gitlab::ObjectifiedHash] + def note(project, id) + get("/projects/#{project}/notes/#{id}") + end + + # Gets a single issue note. + # + # @example + # Gitlab.issue_note(5, 10, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] issue The ID of an issue. + # @param [Integer] id The ID of a note. + # @return [Gitlab::ObjectifiedHash] + def issue_note(project, issue, id) + get("/projects/#{project}/issues/#{issue}/notes/#{id}") + end + + # Gets a single snippet note. + # + # @example + # Gitlab.snippet_note(5, 11, 3) + # + # @param [Integer] project The ID of a project. + # @param [Integer] snippet The ID of a snippet. + # @param [Integer] id The ID of an note. + # @return [Gitlab::ObjectifiedHash] + def snippet_note(project, snippet, id) + get("/projects/#{project}/snippets/#{snippet}/notes/#{id}") + end + + # Creates a new wall note. + # + # @param [Integer] project The ID of a project. + # @param [String] body The body of a note. + # @return [Gitlab::ObjectifiedHash] Information about created note. + def create_note(project, body) + post("/projects/#{project}/notes", :body => {:body => body}) + end + + # Creates a new issue note. + # + # @param [Integer] project The ID of a project. + # @param [Integer] issue The ID of an issue. + # @param [String] body The body of a note. + # @return [Gitlab::ObjectifiedHash] Information about created note. + def create_issue_note(project, issue, body) + post("/projects/#{project}/issues/#{issue}/notes", :body => {:body => body}) + end + + # Creates a new snippet note. + # + # @param [Integer] project The ID of a project. + # @param [Integer] snippet The ID of a snippet. + # @param [String] body The body of a note. + # @return [Gitlab::ObjectifiedHash] Information about created note. + def create_snippet_note(project, snippet, body) + post("/projects/#{project}/snippets/#{snippet}/notes", :body => {:body => body}) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/projects.rb b/lib/gitlab-cli/lib/gitlab/client/projects.rb new file mode 100644 index 000000000..04ea682aa --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/projects.rb @@ -0,0 +1,300 @@ +class Gitlab::Client + # Defines methods related to projects. + module Projects + # Gets a list of projects owned by the authenticated user. + # + # @example + # Gitlab.projects + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @option options [String] :scope Scope of projects. 'owned' for list of projects owned by the authenticated user, 'all' to get all projects (admin only) + # @return [Array] + def projects(options={}) + if (options[:scope]) + get("/projects/#{options[:scope]}", :query => options) + else + get("/projects", :query => options) + end + end + + # Gets information about a project. + # + # @example + # Gitlab.project(3) + # Gitlab.project('gitlab') + # + # @param [Integer, String] id The ID or name of a project. + # @return [Gitlab::ObjectifiedHash] + def project(id) + get("/projects/#{id}") + end + + # Gets a list of project events. + # + # @example + # Gitlab.project_events(42) + # Gitlab.project_events('gitlab') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def project_events(project, options={}) + get("/projects/#{project}/events", :query => options) + end + + # Creates a new project. + # + # @example + # Gitlab.create_project('gitlab') + # Gitlab.create_project('viking', :description => 'Awesome project') + # Gitlab.create_project('Red', :wall_enabled => false) + # + # @param [String] name The name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :description The description of a project. + # @option options [String] :default_branch The default branch of a project. + # @option options [String] :group_id The group in which to create a project. + # @option options [String] :namespace_id The namespace in which to create a project. + # @option options [Boolean] :wiki_enabled The wiki integration for a project (0 = false, 1 = true). + # @option options [Boolean] :wall_enabled The wall functionality for a project (0 = false, 1 = true). + # @option options [Boolean] :issues_enabled The issues integration for a project (0 = false, 1 = true). + # @option options [Boolean] :snippets_enabled The snippets integration for a project (0 = false, 1 = true). + # @option options [Boolean] :merge_requests_enabled The merge requests functionality for a project (0 = false, 1 = true). + # @option options [Boolean] :public The setting for making a project public (0 = false, 1 = true). + # @option options [Integer] :user_id The user/owner id of a project. + # @return [Gitlab::ObjectifiedHash] Information about created project. + def create_project(name, options={}) + url = options[:user_id] ? "/projects/user/#{options[:user_id]}" : "/projects" + post(url, :body => {:name => name}.merge(options)) + end + + # Deletes a project. + # + # @example + # Gitlab.delete_project(4) + # + # @param [Integer, String] id The ID or name of a project. + # @return [Gitlab::ObjectifiedHash] Information about deleted project. + def delete_project(id) + delete("/projects/#{id}") + end + + # Gets a list of project team members. + # + # @example + # Gitlab.team_members(42) + # Gitlab.team_members('gitlab') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :query The search query. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def team_members(project, options={}) + get("/projects/#{project}/members", :query => options) + end + + # Gets a project team member. + # + # @example + # Gitlab.team_member('gitlab', 2) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a project team member. + # @return [Gitlab::ObjectifiedHash] + def team_member(project, id) + get("/projects/#{project}/members/#{id}") + end + + # Adds a user to project team. + # + # @example + # Gitlab.add_team_member('gitlab', 2, 40) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a user. + # @param [Integer] access_level The access level to project. + # @param [Hash] options A customizable set of options. + # @return [Gitlab::ObjectifiedHash] Information about added team member. + def add_team_member(project, id, access_level) + post("/projects/#{project}/members", :body => {:user_id => id, :access_level => access_level}) + end + + # Updates a team member's project access level. + # + # @example + # Gitlab.edit_team_member('gitlab', 3, 20) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a user. + # @param [Integer] access_level The access level to project. + # @param [Hash] options A customizable set of options. + # @return [Array] Information about updated team member. + def edit_team_member(project, id, access_level) + put("/projects/#{project}/members/#{id}", :body => {:access_level => access_level}) + end + + # Removes a user from project team. + # + # @example + # Gitlab.remove_team_member('gitlab', 2) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a user. + # @param [Hash] options A customizable set of options. + # @return [Gitlab::ObjectifiedHash] Information about removed team member. + def remove_team_member(project, id) + delete("/projects/#{project}/members/#{id}") + end + + # Gets a list of project hooks. + # + # @example + # Gitlab.project_hooks(42) + # Gitlab.project_hooks('gitlab') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def project_hooks(project, options={}) + get("/projects/#{project}/hooks", :query => options) + end + + # Gets a project hook. + # + # @example + # Gitlab.project_hook(42, 5) + # Gitlab.project_hook('gitlab', 5) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of a hook. + # @return [Gitlab::ObjectifiedHash] + def project_hook(project, id) + get("/projects/#{project}/hooks/#{id}") + end + + # Adds a new hook to the project. + # + # @example + # Gitlab.add_project_hook(42, 'https://api.example.net/v1/webhooks/ci') + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] url The hook URL. + # @param [Hash] options Events list (`{push_events: true, merge_requests_events: false}`). + # @return [Gitlab::ObjectifiedHash] Information about added hook. + def add_project_hook(project, url, options = {}) + available_events = [:push_events, :merge_requests_events, :issues_events] + passed_events = available_events.select { |event| options[event] } + events = Hash[passed_events.map { |event| [event, options[event]] }] + + post("/projects/#{project}/hooks", :body => {:url => url}.merge(events)) + end + + # Updates a project hook URL. + # + # @example + # Gitlab.edit_project_hook(42, 1, 'https://api.example.net/v1/webhooks/ci') + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of the hook. + # @param [String] url The hook URL. + # @return [Gitlab::ObjectifiedHash] Information about updated hook. + def edit_project_hook(project, id, url) + put("/projects/#{project}/hooks/#{id}", :body => {:url => url}) + end + + # Deletes a hook from project. + # + # @example + # Gitlab.delete_project_hook('gitlab', 4) + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] id The ID of the hook. + # @return [Gitlab::ObjectifiedHash] Information about deleted hook. + def delete_project_hook(project, id) + delete("/projects/#{project}/hooks/#{id}") + end + + # Mark this project as forked from the other + # + # @example + # Gitlab.make_forked(42, 24) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] id The ID of the project it is forked from. + # @return [Gitlab::ObjectifiedHash] Information about the forked project. + def make_forked_from(project, id) + post("/projects/#{project}/fork/#{id}") + end + + # Remove a forked_from relationship for a project. + # + # @example + # Gitlab.remove_forked(42) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] project The ID of the project it is forked from + # @return [Gitlab::ObjectifiedHash] Information about the forked project. + def remove_forked(project) + delete("/projects/#{project}/fork") + end + + # Gets a project deploy keys. + # + # @example + # Gitlab.deploy_keys(42) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def deploy_keys(project, options={}) + get("/projects/#{project}/keys", :query => options) + end + + # Gets a single project deploy key. + # + # @example + # Gitlab.deploy_key(42, 1) + # + # @param [Integer, String] project The ID of a project. + # @param [Integer] id The ID of a deploy key. + # @return [Gitlab::ObjectifiedHash] + def deploy_key(project, id) + get("/projects/#{project}/keys/#{id}") + end + + # Creates a new deploy key. + # + # @example + # Gitlab.create_deploy_key(42, 'My Key', 'Key contents') + # + # @param [Integer] project The ID of a project. + # @param [String] title The title of a deploy key. + # @param [String] key The content of a deploy key. + # @return [Gitlab::ObjectifiedHash] Information about created deploy key. + def create_deploy_key(project, title, key) + post("/projects/#{project}/keys", body: {title: title, key: key}) + end + + # Deletes a deploy key from project. + # + # @example + # Gitlab.delete_deploy_key(42, 1) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a deploy key. + # @return [Gitlab::ObjectifiedHash] Information about deleted deploy key. + def delete_deploy_key(project, id) + delete("/projects/#{project}/keys/#{id}") + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/repositories.rb b/lib/gitlab-cli/lib/gitlab/client/repositories.rb new file mode 100644 index 000000000..f489e5009 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/repositories.rb @@ -0,0 +1,89 @@ +class Gitlab::Client + # Defines methods related to repositories. + module Repositories + + def trees(project, options={}) + get "/projects/#{project}/repository/tree", query: options + end + alias_method :repo_trees, :trees + + def files(project, file_path, ref) + get "/projects/#{project}/repository/files", query: {file_path: file_path, ref: ref} + end + alias_method :repo_files, :files + + # Gets a list of project repository tags. + # + # @example + # Gitlab.tags(42) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def tags(project, options={}) + get("/projects/#{project}/repository/tags", :query => options) + end + alias_method :repo_tags, :tags + + # Creates a new project repository tag. + # + # @example + # Gitlab.create_tag(42,'new_tag','master') + # + # @param [Integer] project The ID of a project. + # @param [String] tag_name The name of the new tag. + # @param [String] ref The ref (commit sha, branch name, or another tag) the tag will point to. + # @return [Gitlab::ObjectifiedHash] + def create_tag(project, tag_name, ref) + post("/projects/#{project}/repository/tags", body: {tag_name: tag_name, ref: ref}) + end + alias_method :repo_create_tag, :create_tag + + # Gets a list of project commits. + # + # @example + # Gitlab.commits('viking') + # Gitlab.repo_commits('gitlab', :ref_name => 'api') + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :ref_name The branch or tag name of a project repository. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def commits(project, options={}) + get("/projects/#{project}/repository/commits", :query => options) + end + alias_method :repo_commits, :commits + + # Gets a specific commit identified by the commit hash or name of a branch or tag. + # + # @example + # Gitlab.commit(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + # Gitlab.repo_commit(3, 'ed899a2f4b50b4370feeea94676502b42383c746') + # + # @param [Integer] project The ID of a project. + # @param [String] sha The commit hash or name of a repository branch or tag + # @return [Gitlab::ObjectifiedHash] + def commit(project, sha) + get("/projects/#{project}/repository/commits/#{sha}") + end + alias_method :repo_commit, :commit + + # Get the diff of a commit in a project. + # + # @example + # Gitlab.commit_diff(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + # Gitlab.repo_commit_diff(3, 'ed899a2f4b50b4370feeea94676502b42383c746') + # + # @param [Integer] project The ID of a project. + # @param [String] sha The name of a repository branch or tag or if not given the default branch. + # @return [Gitlab::ObjectifiedHash] + def commit_diff(project, sha) + get("/projects/#{project}/repository/commits/#{sha}/diff") + end + alias_method :repo_commit_diff, :commit_diff + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/snippets.rb b/lib/gitlab-cli/lib/gitlab/client/snippets.rb new file mode 100644 index 000000000..594d37402 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/snippets.rb @@ -0,0 +1,86 @@ +class Gitlab::Client + # Defines methods related to snippets. + module Snippets + # Gets a list of project's snippets. + # + # @example + # Gitlab.snippets(42) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Gitlab::ObjectifiedHash] + def snippets(project, options={}) + get("/projects/#{project}/snippets", :query => options) + end + + # Gets information about a snippet. + # + # @example + # Gitlab.snippet(2, 14) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a snippet. + # @return [Gitlab::ObjectifiedHash] + def snippet(project, id) + get("/projects/#{project}/snippets/#{id}") + end + + # Creates a new snippet. + # + # @example + # Gitlab.create_snippet(42, {:title => 'REST', :file_name => 'api.rb', :code => 'some code'}) + # + # @param [Integer] project The ID of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :title (required) The title of a snippet. + # @option options [String] :file_name (required) The name of a snippet file. + # @option options [String] :code (required) The content of a snippet. + # @option options [String] :lifetime (optional) The expiration date of a snippet. + # @return [Gitlab::ObjectifiedHash] Information about created snippet. + def create_snippet(project, options={}) + check_attributes!(options, [:title, :file_name, :code]) + post("/projects/#{project}/snippets", :body => options) + end + + # Updates a snippet. + # + # @example + # Gitlab.edit_snippet(42, 34, :file_name => 'README.txt') + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a snippet. + # @param [Hash] options A customizable set of options. + # @option options [String] :title The title of a snippet. + # @option options [String] :file_name The name of a snippet file. + # @option options [String] :code The content of a snippet. + # @option options [String] :lifetime The expiration date of a snippet. + # @return [Gitlab::ObjectifiedHash] Information about updated snippet. + def edit_snippet(project, id, options={}) + put("/projects/#{project}/snippets/#{id}", :body => options) + end + + # Deletes a snippet. + # + # @example + # Gitlab.delete_snippet(2, 14) + # + # @param [Integer] project The ID of a project. + # @param [Integer] id The ID of a snippet. + # @return [Gitlab::ObjectifiedHash] Information about deleted snippet. + def delete_snippet(project, id) + delete("/projects/#{project}/snippets/#{id}") + end + + private + + def check_attributes!(options, attrs) + attrs.each do |attr| + unless options.has_key?(attr) || options.has_key?(attr.to_s) + raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter") + end + end + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/system_hooks.rb b/lib/gitlab-cli/lib/gitlab/client/system_hooks.rb new file mode 100644 index 000000000..59db4f924 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/system_hooks.rb @@ -0,0 +1,58 @@ +class Gitlab::Client + # Defines methods related to system hooks. + module SystemHooks + # Gets a list of system hooks. + # + # @example + # Gitlab.hooks + # Gitlab.system_hooks + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def hooks(options={}) + get("/hooks", query: options) + end + alias_method :system_hooks, :hooks + + # Adds a new system hook. + # + # @example + # Gitlab.add_hook('http://example.com/hook') + # Gitlab.add_system_hook('https://api.example.net/v1/hook') + # + # @param [String] url The hook URL. + # @return [Gitlab::ObjectifiedHash] + def add_hook(url) + post("/hooks", :body => {:url => url}) + end + alias_method :add_system_hook, :add_hook + + # Tests a system hook. + # + # @example + # Gitlab.hook(3) + # Gitlab.system_hook(12) + # + # @param [Integer] id The ID of a system hook. + # @return [Array] + def hook(id) + get("/hooks/#{id}") + end + alias_method :system_hook, :hook + + # Deletes a new system hook. + # + # @example + # Gitlab.delete_hook(3) + # Gitlab.delete_system_hook(12) + # + # @param [Integer] id The ID of a system hook. + # @return [Gitlab::ObjectifiedHash] + def delete_hook(id) + delete("/hooks/#{id}") + end + alias_method :delete_system_hook, :delete_hook + end +end diff --git a/lib/gitlab-cli/lib/gitlab/client/users.rb b/lib/gitlab-cli/lib/gitlab/client/users.rb new file mode 100644 index 000000000..3fc83cd1b --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/client/users.rb @@ -0,0 +1,123 @@ +class Gitlab::Client + # Defines methods related to users. + module Users + # Gets a list of users. + # + # @example + # Gitlab.users + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def users(options={}) + get("/users", :query => options) + end + + # Gets information about a user. + # Will return information about an authorized user if no ID passed. + # + # @example + # Gitlab.user + # Gitlab.user(2) + # + # @param [Integer] id The ID of a user. + # @return [Gitlab::ObjectifiedHash] + def user(id=nil) + id.to_i.zero? ? get("/user") : get("/users/#{id}") + end + + # Creates a new user. + # Requires authentication from an admin account. + # + # @param [String] email The email of a user. + # @param [String] password The password of a user. + # @param [Hash] options A customizable set of options. + # @option options [String] :name The name of a user. Defaults to email. + # @option options [String] :skype The skype of a user. + # @option options [String] :linkedin The linkedin of a user. + # @option options [String] :twitter The twitter of a user. + # @option options [Integer] :projects_limit The limit of projects for a user. + # @return [Gitlab::ObjectifiedHash] Information about created user. + def create_user(email, password, options={}) + body = {:email => email, :password => password, :name => email}.merge(options) + post("/users", :body => body) + end + + # Updates a user. + # + # @param [Integer] id The ID of a user. + # @param [Hash] options A customizable set of options. + # @option options [String] email The email of a user. + # @option options [String] password The password of a user. + # @option options [String] :name The name of a user. Defaults to email. + # @option options [String] :skype The skype of a user. + # @option options [String] :linkedin The linkedin of a user. + # @option options [String] :twitter The twitter of a user. + # @option options [Integer] :projects_limit The limit of projects for a user. + # @return [Gitlab::ObjectifiedHash] Information about created user. + def edit_user(user_id, options={}) + put("/users/#{user_id}", :body => options) + end + + # Creates a new user session. + # + # @example + # Gitlab.session('jack@example.com', 'secret12345') + # + # @param [String] email The email of a user. + # @param [String] password The password of a user. + # @return [Gitlab::ObjectifiedHash] + # @note This method doesn't require private_token to be set. + def session(email, password) + post("/session", :body => {:email => email, :password => password}) + end + + # Gets a list of user's SSH keys. + # + # @example + # Gitlab.ssh_keys + # + # @param [Hash] options A customizable set of options. + # @option options [Integer] :page The page number. + # @option options [Integer] :per_page The number of results per page. + # @return [Array] + def ssh_keys(options={}) + get("/user/keys", :query => options) + end + + # Gets information about SSH key. + # + # @example + # Gitlab.ssh_key(1) + # + # @param [Integer] id The ID of a user's SSH key. + # @return [Gitlab::ObjectifiedHash] + def ssh_key(id) + get("/user/keys/#{id}") + end + + # Creates a new SSH key. + # + # @example + # Gitlab.create_ssh_key('key title', 'key body') + # + # @param [String] title The title of an SSH key. + # @param [String] key The SSH key body. + # @return [Gitlab::ObjectifiedHash] Information about created SSH key. + def create_ssh_key(title, key) + post("/user/keys", :body => {:title => title, :key => key}) + end + + # Deletes an SSH key. + # + # @example + # Gitlab.delete_ssh_key(1) + # + # @param [Integer] id The ID of a user's SSH key. + # @return [Gitlab::ObjectifiedHash] Information about deleted SSH key. + def delete_ssh_key(id) + delete("/user/keys/#{id}") + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/configuration.rb b/lib/gitlab-cli/lib/gitlab/configuration.rb new file mode 100644 index 000000000..b36ed5a7d --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/configuration.rb @@ -0,0 +1,39 @@ +module Gitlab + # Defines constants and methods related to configuration. + module Configuration + # An array of valid keys in the options hash when configuring a Gitlab::API. + VALID_OPTIONS_KEYS = [:endpoint, :private_token, :user_agent, :sudo, :httparty].freeze + + # The user agent that will be sent to the API endpoint if none is set. + DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}".freeze + + # @private + attr_accessor(*VALID_OPTIONS_KEYS) + + # Sets all configuration options to their default values + # when this module is extended. + def self.extended(base) + base.reset + end + + # Convenience method to allow configuration options to be set in a block. + def configure + yield self + end + + # Creates a hash of options and their values. + def options + VALID_OPTIONS_KEYS.inject({}) do |option, key| + option.merge!(key => send(key)) + end + end + + # Resets all configuration options to the defaults. + def reset + self.endpoint = ENV['GITLAB_API_ENDPOINT'] + self.private_token = ENV['GITLAB_API_PRIVATE_TOKEN'] + self.sudo = nil + self.user_agent = DEFAULT_USER_AGENT + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/error.rb b/lib/gitlab-cli/lib/gitlab/error.rb new file mode 100644 index 000000000..96a8a39d6 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/error.rb @@ -0,0 +1,42 @@ +module Gitlab + module Error + # Custom error class for rescuing from all Gitlab errors. + class Error < StandardError; end + + # Raise when attributes are missing. + class MissingAttributes < Error; end + + # Raised when API endpoint credentials not configured. + class MissingCredentials < Error; end + + # Raised when impossible to parse response body. + class Parsing < Error; end + + # Raised when API endpoint returns the HTTP status code 400. + class BadRequest < Error; end + + # Raised when API endpoint returns the HTTP status code 401. + class Unauthorized < Error; end + + # Raised when API endpoint returns the HTTP status code 403. + class Forbidden < Error; end + + # Raised when API endpoint returns the HTTP status code 404. + class NotFound < Error; end + + # Raised when API endpoint returns the HTTP status code 405. + class MethodNotAllowed < Error; end + + # Raised when API endpoint returns the HTTP status code 409. + class Conflict < Error; end + + # Raised when API endpoint returns the HTTP status code 500. + class InternalServerError < Error; end + + # Raised when API endpoint returns the HTTP status code 502. + class BadGateway < Error; end + + # Raised when API endpoint returns the HTTP status code 503. + class ServiceUnavailable < Error; end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/help.rb b/lib/gitlab-cli/lib/gitlab/help.rb new file mode 100644 index 000000000..6ead8af94 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/help.rb @@ -0,0 +1,44 @@ +require 'gitlab' +require 'gitlab/cli_helpers' + +module Gitlab::Help + extend Gitlab::CLI::Helpers + + def self.get_help(methods,cmd=nil) + help = '' + + if cmd.nil? || cmd == 'help' + help = actions_table + else + ri_cmd = `which ri`.chomp + + if $? == 0 + namespace = methods.select {|m| m[:name] === cmd }.map {|m| m[:owner]+'.'+m[:name] }.shift + + if namespace + begin + ri_output = `#{ri_cmd} -T #{namespace} 2>&1`.chomp + + if $? == 0 + ri_output.gsub!(/#{cmd}\((.*?)\)/, cmd+' \1') + ri_output.gsub!(/Gitlab\./, 'gitlab> ') + ri_output.gsub!(/Gitlab\..+$/, '') + ri_output.gsub!(/\,\s?/, ' ') + help = ri_output + else + help = "Ri docs not found for #{namespace}, please install the docs to use 'help'" + end + rescue => e + puts e.message + end + else + help = "Unknown command: #{cmd}" + end + else + help = "'ri' tool not found in your PATH, please install it to use the help." + end + end + + puts help + end +end diff --git a/lib/gitlab-cli/lib/gitlab/objectified_hash.rb b/lib/gitlab-cli/lib/gitlab/objectified_hash.rb new file mode 100644 index 000000000..87ca2fc77 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/objectified_hash.rb @@ -0,0 +1,24 @@ +module Gitlab + # Converts hashes to the objects. + class ObjectifiedHash + # Creates a new ObjectifiedHash object. + def initialize(hash) + @hash = hash + @data = hash.inject({}) do |data, (key,value)| + value = ObjectifiedHash.new(value) if value.is_a? Hash + data[key.to_s] = value + data + end + end + + def to_hash + @hash + end + alias_method :to_h, :to_hash + + # Delegate to ObjectifiedHash. + def method_missing(key) + @data.key?(key.to_s) ? @data[key.to_s] : nil + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/request.rb b/lib/gitlab-cli/lib/gitlab/request.rb new file mode 100644 index 000000000..64a8f6b4c --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/request.rb @@ -0,0 +1,113 @@ +require 'httparty' +require 'json' + +module Gitlab + # @private + class Request + include HTTParty + format :json + headers 'Accept' => 'application/json' + parser Proc.new { |body, _| parse(body) } + + attr_accessor :private_token + + # Converts the response body to an ObjectifiedHash. + def self.parse(body) + body = decode(body) + + if body.is_a? Hash + ObjectifiedHash.new body + elsif body.is_a? Array + body.collect! { |e| ObjectifiedHash.new(e) } + else + raise Error::Parsing.new "Couldn't parse a response body" + end + end + + # Decodes a JSON response into Ruby object. + def self.decode(response) + begin + JSON.load response + rescue JSON::ParserError + raise Error::Parsing.new "The response is not a valid JSON" + end + end + + def get(path, options={}) + set_httparty_config(options) + set_private_token_header(options) + validate self.class.get(path, options) + end + + def post(path, options={}) + set_httparty_config(options) + set_private_token_header(options, path) + validate self.class.post(path, options) + end + + def put(path, options={}) + set_httparty_config(options) + set_private_token_header(options) + validate self.class.put(path, options) + end + + def delete(path, options={}) + set_httparty_config(options) + set_private_token_header(options) + validate self.class.delete(path, options) + end + + # Checks the response code for common errors. + # Returns parsed response for successful requests. + def validate(response) + case response.code + when 400; raise Error::BadRequest.new error_message(response) + when 401; raise Error::Unauthorized.new error_message(response) + when 403; raise Error::Forbidden.new error_message(response) + when 404; raise Error::NotFound.new error_message(response) + when 405; raise Error::MethodNotAllowed.new error_message(response) + when 409; raise Error::Conflict.new error_message(response) + when 500; raise Error::InternalServerError.new error_message(response) + when 502; raise Error::BadGateway.new error_message(response) + when 503; raise Error::ServiceUnavailable.new error_message(response) + end + + response.parsed_response + end + + # Sets a base_uri and default_params for requests. + # @raise [Error::MissingCredentials] if endpoint not set. + def set_request_defaults(endpoint, private_token, sudo=nil) + raise Error::MissingCredentials.new("Please set an endpoint to API") unless endpoint + @private_token = private_token + + self.class.base_uri endpoint + self.class.default_params :sudo => sudo + self.class.default_params.delete(:sudo) if sudo.nil? + end + + private + + # Sets a PRIVATE-TOKEN header for requests. + # @raise [Error::MissingCredentials] if private_token not set. + def set_private_token_header(options, path=nil) + unless path == '/session' + raise Error::MissingCredentials.new("Please set a private_token for user") unless @private_token + options[:headers] = {'PRIVATE-TOKEN' => @private_token} + end + end + + # Set HTTParty configuration + # @see https://github.com/jnunemaker/httparty + def set_httparty_config(options) + if self.httparty + options.merge!(self.httparty) + end + end + + def error_message(response) + "Server responded with code #{response.code}, message: #{response.parsed_response.message}. " \ + "Request URI: #{response.request.base_uri}#{response.request.path}" + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/shell.rb b/lib/gitlab-cli/lib/gitlab/shell.rb new file mode 100644 index 000000000..9253b61e3 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/shell.rb @@ -0,0 +1,51 @@ +require 'gitlab' +require 'gitlab/help' +require 'gitlab/cli_helpers' +require 'readline' + +class Gitlab::Shell + extend Gitlab::CLI::Helpers + + def self.start + actions = Gitlab.actions + + comp = proc { |s| actions.map(&:to_s).grep(/^#{Regexp.escape(s)}/) } + + Readline.completion_proc = comp + Readline.completion_append_character = ' ' + + client = Gitlab::Client.new(endpoint: '') + + while buf = Readline.readline('gitlab> ', true) + next if buf.nil? || buf.empty? + break if buf == 'exit' + + buf = buf.scan(/["][^"]+["]|\S+/).map { |word| word.gsub(/^['"]|['"]$/,'') } + cmd = buf.shift + args = buf.count > 0 ? buf : [] + + if cmd == 'help' + methods = [] + + actions.each do |action| + methods << { + name: action.to_s, + owner: client.method(action).owner.to_s + } + end + + args[0].nil? ? Gitlab::Help.get_help(methods) : Gitlab::Help.get_help(methods, args[0]) + next + end + + data = if actions.include?(cmd.to_sym) + confirm_command(cmd) + gitlab_helper(cmd, args) + else + "'#{cmd}' is not a valid command. See the 'help' for a list of valid commands." + end + + output_table(cmd, args, data) + end + end +end diff --git a/lib/gitlab-cli/lib/gitlab/version.rb b/lib/gitlab-cli/lib/gitlab/version.rb new file mode 100644 index 000000000..42ba291e0 --- /dev/null +++ b/lib/gitlab-cli/lib/gitlab/version.rb @@ -0,0 +1,3 @@ +module Gitlab + VERSION = "3.2.0" +end diff --git a/lib/gitlab-cli/spec/fixtures/branch.json b/lib/gitlab-cli/spec/fixtures/branch.json new file mode 100644 index 000000000..34a02081f --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/branch.json @@ -0,0 +1 @@ +{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected": true} diff --git a/lib/gitlab-cli/spec/fixtures/branches.json b/lib/gitlab-cli/spec/fixtures/branches.json new file mode 100644 index 000000000..05a39447d --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/branches.json @@ -0,0 +1 @@ +[{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"}},{"name":"dashboard-feed","commit":{"id":"f8f6ff065eccc6ede4d35ed87a09bb962b84ca25","parents":[{"id":"2cf8010792c3075824ee27d0f037aeb178cbbf7e"}],"tree":"e17f2157143d550891d4669c10b7446e4739bc6d","message":"add projects atom feed","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-05-31T23:42:02-07:00","committed_date":"2012-05-31T23:42:02-07:00"}},{"name":"master","commit":{"id":"2cf8010792c3075824ee27d0f037aeb178cbbf7e","parents":[{"id":"af226ae9c9af406c8a0e0bbdf364563495c2f432"},{"id":"e851cb07762aa464aae10e8b4b28de87c1a6f925"}],"tree":"6c6845838039f01723d91f395a1d2fa1dcc82522","message":"Merge pull request #868 from SaitoWu/bugfix/encoding\n\nBugfix/encoding","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-05-30T00:24:43-07:00","committed_date":"2012-05-30T00:24:43-07:00"}},{"name":"preview_notes","commit":{"id":"3749e0d99ac6bfbc65889b1b7a5310e14e7fe89a","parents":[{"id":"2483181f2c3d4ea7d2c68147b19bc07fc3937b0c"}],"tree":"f8c56161b0d6561568f088df9961362eb1ece88b","message":"pass project_id to notes preview path","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-08-09T23:46:27-07:00","committed_date":"2012-08-09T23:46:27-07:00"}},{"name":"refactoring","commit":{"id":"7c7761099cae83f59fe5780340e100be890847b2","parents":[{"id":"058d80b3363dd4fc4417ca4f60f76119188a2470"}],"tree":"d7d4a94c700dc0e84ee943019213d2358a49c413","message":"fix deprecation warnings","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-05-29T07:16:28-07:00","committed_date":"2012-05-29T07:16:28-07:00"}}] diff --git a/lib/gitlab-cli/spec/fixtures/comment_merge_request.json b/lib/gitlab-cli/spec/fixtures/comment_merge_request.json new file mode 100644 index 000000000..742f33377 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/comment_merge_request.json @@ -0,0 +1 @@ +{"note":"Cool Merge Request!","author":{"id":1,"username":"jsmith","email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-07-11T01:32:18Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/create_branch.json b/lib/gitlab-cli/spec/fixtures/create_branch.json new file mode 100644 index 000000000..0b011abdb --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/create_branch.json @@ -0,0 +1 @@ +{"name":"api","commit":{ "id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","message":"API: expose issues project id","parent_ids":["949b1df930bedace1dbd755aaa4a82e8c451a616"],"authored_date":"2012-07-25T04:22:21-07:00","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","committed_date":"2012-07-25T04:22:21-07:00","committer_name":"Nihad Abbasov","committer_email":"narkoz.2008@gmail.com"},"protected": false} diff --git a/lib/gitlab-cli/spec/fixtures/create_merge_request.json b/lib/gitlab-cli/spec/fixtures/create_merge_request.json new file mode 100644 index 000000000..c27435168 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/create_merge_request.json @@ -0,0 +1 @@ +{"id":2,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/error_already_exists.json b/lib/gitlab-cli/spec/fixtures/error_already_exists.json new file mode 100644 index 000000000..d1070f560 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/error_already_exists.json @@ -0,0 +1 @@ +{"message": "409 Already exists"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group.json b/lib/gitlab-cli/spec/fixtures/group.json new file mode 100644 index 000000000..bce3581d8 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/group.json @@ -0,0 +1,60 @@ +{"id": 10, "name": "GitLab-Group", "path": "gitlab-group", "owner_id": 6, "projects": [ + { + "id": 9, + "name": "mojito", + "description": null, + "default_branch": "master", + "owner": { + "id": 6, + "username": "jose", + "email": "jose@abc.com", + "name": "Jose Jose", + "blocked": false, + "created_at": "2013-02-06T06:54:06Z" + }, + "path": "mojito", + "path_with_namespace": "gitlab-group/mojito", + "issues_enabled": true, + "merge_requests_enabled": true, + "wall_enabled": true, + "wiki_enabled": true, + "created_at": "2013-02-06T16:59:15Z", + "namespace": { + "created_at": "2013-02-06T16:58:22Z", + "id": 10, + "name": "GitLab-Group", + "owner_id": 6, + "path": "gitlab-group", + "updated_at": "2013-02-06T16:58:22Z" + } + }, + { + "id": 10, + "name": "gitlabhq", + "description": null, + "default_branch": null, + "owner": { + "id": 6, + "username": "randx", + "email": "randx@github.com", + "name": "Dmitry Z", + "blocked": false, + "created_at": "2013-02-06T06:54:06Z" + }, + "path": "gitlabhq", + "path_with_namespace": "gitlab-group/gitlabhq", + "issues_enabled": true, + "merge_requests_enabled": true, + "wall_enabled": true, + "wiki_enabled": true, + "created_at": "2013-02-06T17:02:31Z", + "namespace": { + "created_at": "2013-02-06T16:58:22Z", + "id": 10, + "name": "GitLab-Group", + "owner_id": 6, + "path": "gitlab-group", + "updated_at": "2013-02-06T16:58:22Z" + } + } +]} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_create.json b/lib/gitlab-cli/spec/fixtures/group_create.json new file mode 100644 index 000000000..67445f68b --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/group_create.json @@ -0,0 +1 @@ +{"id":3,"name":"Gitlab-Group","path":"gitlab-group","owner_id":1} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_member.json b/lib/gitlab-cli/spec/fixtures/group_member.json new file mode 100644 index 000000000..feef54322 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/group_member.json @@ -0,0 +1 @@ +{"id":2,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-09-04T18:15:30Z","access_level":10} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_member_delete.json b/lib/gitlab-cli/spec/fixtures/group_member_delete.json new file mode 100644 index 000000000..ff052edf6 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/group_member_delete.json @@ -0,0 +1 @@ +{"created_at":"2013-09-04T18:18:15Z","group_access":10,"group_id":3,"id":2,"notification_level":3,"updated_at":"2013-09-04T18:18:15Z","user_id":2} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/group_members.json b/lib/gitlab-cli/spec/fixtures/group_members.json new file mode 100644 index 000000000..02ddc1089 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/group_members.json @@ -0,0 +1 @@ +[{"id":1,"username":"eraymond","email":"eraymond@local.host","name":"Edward Raymond","state":"active","created_at":"2013-08-30T16:16:22Z","access_level":50},{"id":1,"username":"jsmith","email":"jsmith@local.host","name":"John Smith","state":"active","created_at":"2013-08-30T16:16:22Z","access_level":50}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/groups.json b/lib/gitlab-cli/spec/fixtures/groups.json new file mode 100644 index 000000000..7d8b426a4 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/groups.json @@ -0,0 +1,2 @@ +[{"id": 3,"name": "ThreeGroup","path": "threegroup","owner_id": 1},{"id": 5,"name": "Five-Group","path": "five-group","owner_id": 2},{"id": 8,"name": "Eight Group","path": "eight-group","owner_id": 6} +] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/issue.json b/lib/gitlab-cli/spec/fixtures/issue.json new file mode 100644 index 000000000..9f70318a7 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/issue.json @@ -0,0 +1 @@ +{"id":33,"project_id":3,"title":"Beatae possimus nostrum nihil reiciendis laboriosam nihil delectus alias accusantium dolor unde.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/issues.json b/lib/gitlab-cli/spec/fixtures/issues.json new file mode 100644 index 000000000..62e4cadd2 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/issues.json @@ -0,0 +1 @@ +[{"id":1,"project_id":1,"title":"Culpa eius recusandae suscipit autem distinctio dolorum.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":6,"project_id":2,"title":"Ut in dolorum omnis sed sit aliquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":12,"project_id":3,"title":"Veniam et tempore quidem eum reprehenderit cupiditate non aut velit eaque.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":21,"project_id":1,"title":"Vitae ea aliquam et quo eligendi sapiente voluptatum labore hic nihil culpa.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":26,"project_id":2,"title":"Quo enim est nihil atque placeat voluptas neque eos voluptas.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":32,"project_id":3,"title":"Deserunt tenetur impedit est beatae voluptas voluptas quaerat quisquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/key.json b/lib/gitlab-cli/spec/fixtures/key.json new file mode 100644 index 000000000..6595c8ceb --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/key.json @@ -0,0 +1 @@ +{"id":1,"title":"narkoz@helium","key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkUsh42Nh1yefGd1jbSELn5XsY8p5Oxmau0/1HqHnjuYOaj5X+kHccFDwtmtg9Ox8ua/+WptNsiE8IUwsD3zKgEjajgwq3gMeeFdxfXwM+tEvHOOMV9meRrgRWGYCToPbT6sR7/YMAYa7cPqWSpx/oZhYfz4XtoMv3ZZT1fZMmx3MY3HwXwW8j+obJyN2K4LN0TFi9RPgWWYn0DCyb9OccmABimt3i74WoJ/OT8r6/7swce8+OSe0Q2wBhyTtvxg2vtUcoek8Af+EZaUMBwSEzEsocOCzwQvjF5XUk5o7dJ8nP8W3RE60JWX57t16eQm7lBmumLYfszpn2isd6W7a1 narkoz@helium"} diff --git a/lib/gitlab-cli/spec/fixtures/keys.json b/lib/gitlab-cli/spec/fixtures/keys.json new file mode 100644 index 000000000..d81fca6ad --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/keys.json @@ -0,0 +1 @@ +[{"id":1,"title":"narkoz@helium","key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkUsh42Nh1yefGd1jbSELn5XsY8p5Oxmau0/1HqHnjuYOaj5X+kHccFDwtmtg9Ox8ua/+WptNsiE8IUwsD3zKgEjajgwq3gMeeFdxfXwM+tEvHOOMV9meRrgRWGYCToPbT6sR7/YMAYa7cPqWSpx/oZhYfz4XtoMv3ZZT1fZMmx3MY3HwXwW8j+obJyN2K4LN0TFi9RPgWWYn0DCyb9OccmABimt3i74WoJ/OT8r6/7swce8+OSe0Q2wBhyTtvxg2vtUcoek8Af+EZaUMBwSEzEsocOCzwQvjF5XUk5o7dJ8nP8W3RE60JWX57t16eQm7lBmumLYfszpn2isd6W7a1 narkoz@helium"}] diff --git a/lib/gitlab-cli/spec/fixtures/merge_request.json b/lib/gitlab-cli/spec/fixtures/merge_request.json new file mode 100644 index 000000000..5278f4664 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/merge_request.json @@ -0,0 +1 @@ +{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/merge_request_comments.json b/lib/gitlab-cli/spec/fixtures/merge_request_comments.json new file mode 100644 index 000000000..3b9733ef3 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/merge_request_comments.json @@ -0,0 +1 @@ +[{"note":"this is the 1st comment on the 2merge merge request","author":{"id":11,"username":"admin","email":"admin@example.com","name":"A User","state":"active","created_at":"2014-03-06T08:17:35.000Z"}},{"note":"another discussion point on the 2merge request","author":{"id":12,"username":"admin","email":"admin@example.com","name":"A User","state":"active","created_at":"2014-03-06T08:17:35.000Z"}}] diff --git a/lib/gitlab-cli/spec/fixtures/merge_requests.json b/lib/gitlab-cli/spec/fixtures/merge_requests.json new file mode 100644 index 000000000..ea32ac4e6 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/merge_requests.json @@ -0,0 +1 @@ +[{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"New feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}}] diff --git a/lib/gitlab-cli/spec/fixtures/milestone.json b/lib/gitlab-cli/spec/fixtures/milestone.json new file mode 100644 index 000000000..94ea3d360 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/milestone.json @@ -0,0 +1 @@ +{"id":1,"project_id":3,"title":"3.0","description":"","due_date":"2012-10-22","closed":false,"updated_at":"2012-09-17T10:15:31Z","created_at":"2012-09-17T10:15:31Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/milestones.json b/lib/gitlab-cli/spec/fixtures/milestones.json new file mode 100644 index 000000000..f9e309af6 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/milestones.json @@ -0,0 +1 @@ +[{"id":1,"project_id":3,"title":"3.0","description":"","due_date":"2012-10-22","closed":false,"updated_at":"2012-09-17T10:15:31Z","created_at":"2012-09-17T10:15:31Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/note.json b/lib/gitlab-cli/spec/fixtures/note.json new file mode 100644 index 000000000..3f575aed3 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/note.json @@ -0,0 +1 @@ +{"id":1201,"body":"The solution is rather tricky","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"created_at":"2012-11-27T19:16:44Z"} diff --git a/lib/gitlab-cli/spec/fixtures/notes.json b/lib/gitlab-cli/spec/fixtures/notes.json new file mode 100644 index 000000000..15c0d8ca2 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/notes.json @@ -0,0 +1 @@ +[{"id":1201,"body":"The solution is rather tricky","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"created_at":"2012-11-27T19:16:44Z"},{"id":1207,"body":"I know, right?","author":{"id":1,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"created_at":"2012-11-27T19:58:21Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/project.json b/lib/gitlab-cli/spec/fixtures/project.json new file mode 100644 index 000000000..1f4f96028 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project.json @@ -0,0 +1 @@ +{"id":3,"code":"gitlab","name":"Gitlab","description":null,"path":"gitlab","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"public":false,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:58Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_commit.json b/lib/gitlab-cli/spec/fixtures/project_commit.json new file mode 100644 index 000000000..ace52b700 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_commit.json @@ -0,0 +1,13 @@ +{ + "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", + "short_id": "6104942438c", + "title": "Sanitize for network graph", + "author_name": "randx", + "author_email": "dmitriy.zaporozhets@gmail.com", + "created_at": "2012-09-20T09:06:12+03:00", + "committed_date": "2012-09-20T09:06:12+03:00", + "authored_date": "2012-09-20T09:06:12+03:00", + "parent_ids": [ + "ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba" + ] +} diff --git a/lib/gitlab-cli/spec/fixtures/project_commit_diff.json b/lib/gitlab-cli/spec/fixtures/project_commit_diff.json new file mode 100644 index 000000000..ad3dfde86 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_commit_diff.json @@ -0,0 +1,10 @@ +{ + "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files", + "new_path": "doc/update/5.4-to-6.0.md", + "old_path": "doc/update/5.4-to-6.0.md", + "a_mode": null, + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false +} diff --git a/lib/gitlab-cli/spec/fixtures/project_commits.json b/lib/gitlab-cli/spec/fixtures/project_commits.json new file mode 100644 index 000000000..58cb5020d --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_commits.json @@ -0,0 +1 @@ +[{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","short_id":"f7dd067490f","title":"API: expose issues project id","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T04:22:21-07:00"},{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616","short_id":"949b1df930b","title":"API: update docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T02:35:41-07:00"},{"id":"1b95c8bff351f6718ec31ac1de1e48c57bc95d44","short_id":"1b95c8bff35","title":"API: ability to get project by id","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-25T02:18:30-07:00"},{"id":"92d98f5a0c28bffd7b070cda190b07ab72667d58","short_id":"92d98f5a0c2","title":"Merge pull request #1118 from patthoyts/pt/ldap-missing-password","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:51:06-07:00"},{"id":"60d3e94874964a626f105d3598e1c122addcf43e","short_id":"60d3e948749","title":"Merge pull request #1122 from patthoyts/pt/missing-log","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:50:34-07:00"},{"id":"b683a71aa1230f17f9df47661c77dfeae27027de","short_id":"b683a71aa12","title":"Merge pull request #1135 from NARKOZ/api","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-25T01:48:00-07:00"},{"id":"fbb41100db35cf2def2c8b4d896b7015d56bd15b","short_id":"fbb41100db3","title":"update help section with issues API docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:52:43-07:00"},{"id":"eca823c1c7cef45cc18c6ab36d2327650c85bfc3","short_id":"eca823c1c7c","title":"Merge branch 'master' into api","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:46:36-07:00"},{"id":"024e0348904179a8dea81c01e27a5f014cf57499","short_id":"024e0348904","title":"update API docs","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:25:01-07:00"},{"id":"7b33d8cbcab3b0ee5789ec607455ab62130db69f","short_id":"7b33d8cbcab","title":"add issues API","author_name":"Nihad Abbasov","author_email":"narkoz.2008@gmail.com","created_at":"2012-07-24T05:19:51-07:00"},{"id":"6035ad7e1fe519d0c6a42731790183889e3ba31d","short_id":"6035ad7e1fe","title":"Create the githost.log file if necessary.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-21T07:32:04-07:00"},{"id":"a2d244ec062f3348f6cd1c5218c6097402c5f562","short_id":"a2d244ec062","title":"Handle LDAP missing credentials error with a flash message.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-21T01:04:05-07:00"},{"id":"8b7e404b5b6944e9c92cc270b2e5d0005781d49d","short_id":"8b7e404b5b6","title":"Up to 2.7.0","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:53:55-07:00"},{"id":"11721b0dbe82c35789be3e4fa8e14663934b2ff5","short_id":"11721b0dbe8","title":"Help section for system hooks completed","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:47:57-07:00"},{"id":"9c8a1e651716212cf50a623d98e03b8dbdb2c64a","short_id":"9c8a1e65171","title":"Fix system hook example","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:32:42-07:00"},{"id":"4261acda90ff4c61326d80cba026ae76e8551f8f","short_id":"4261acda90f","title":"move SSH keys tab closer to begining","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:27:09-07:00"},{"id":"a69fc5dd23bd502fd36892a80eec21a4c53891f8","short_id":"a69fc5dd23b","title":"Endless event loading for dsahboard","author_name":"randx","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-21T00:23:05-07:00"},{"id":"860fa1163a5fbdfec2bb01ff2d584351554dee29","short_id":"860fa1163a5","title":"Merge pull request #1117 from patthoyts/pt/user-form","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-20T14:23:49-07:00"},{"id":"787e5e94acf5e20280416c9fda105ef5b77576b3","short_id":"787e5e94acf","title":"Fix english on the edit user form.","author_name":"Pat Thoyts","author_email":"patthoyts@users.sourceforge.net","created_at":"2012-07-20T14:18:42-07:00"},{"id":"9267cb04b0b3fdf127899c4b7e636dc27fac06d3","short_id":"9267cb04b0b","title":"Merge branch 'refactoring_controllers' of dev.gitlabhq.com:gitlabhq","author_name":"Dmitriy Zaporozhets","author_email":"dmitriy.zaporozhets@gmail.com","created_at":"2012-07-20T07:24:56-07:00"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_delete_key.json b/lib/gitlab-cli/spec/fixtures/project_delete_key.json new file mode 100644 index 000000000..ed4141599 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_delete_key.json @@ -0,0 +1,8 @@ +{ + "created_at": "2013-10-05T15:05:26Z", + "fingerprint": "5c:b5:e6:b0:f5:31:65:3f:a6:b5:59:86:32:cc:15:e1", + "id": 2, + "key": "ssh-rsa ...", + "updated_at": "2013-10-05T15:05:26Z", + "user_id": null +} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_events.json b/lib/gitlab-cli/spec/fixtures/project_events.json new file mode 100644 index 000000000..4d5afc04e --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_events.json @@ -0,0 +1 @@ +[{"title":null,"project_id":2,"action_name":"opened","target_id":null,"target_type":null,"author_id":1,"data":{"before":"ac0c1aa3898d6dea54d7868ea6f9c45fd5e30c59","after":"66350dbb62a221bc619b665aef3e1e7d3b306747","ref":"refs/heads/master","user_id":1,"user_name":"Administrator","project_id":2,"repository":{"name":"gitlab-ci","url":"git@demo.gitlab.com:gitlab/gitlab-ci.git","description":"Continuous integration server for gitlabhq | Coordinator","homepage":"http://demo.gitlab.com/gitlab/gitlab-ci"},"commits":[{"id":"8cf469b039931bab37bbf025e6b69287ea3cfb0e","message":"Modify screenshot\n\nSigned-off-by: Dmitriy Zaporozhets \u003Cdummy@gmail.com\u003E","timestamp":"2014-05-20T10:34:27+00:00","url":"http://demo.gitlab.com/gitlab/gitlab-ci/commit/8cf469b039931bab37bbf025e6b69287ea3cfb0e","author":{"name":"Dummy","email":"dummy@gmail.com"}},{"id":"66350dbb62a221bc619b665aef3e1e7d3b306747","message":"Edit some code\n\nSigned-off-by: Dmitriy Zaporozhets \u003Cdummy@gmail.com\u003E","timestamp":"2014-05-20T10:35:15+00:00","url":"http://demo.gitlab.com/gitlab/gitlab-ci/commit/66350dbb62a221bc619b665aef3e1e7d3b306747","author":{"name":"Dummy","email":"dummy@gmail.com"}}],"total_commits_count":2},"target_title":null,"created_at":"2014-05-20T10:35:26.240Z"},{"title":null,"project_id":2,"action_name":"opened","target_id":2,"target_type":"MergeRequest","author_id":1,"data":null,"target_title":" Morbi et cursus leo. Sed eget vestibulum sapien","created_at":"2014-05-20T10:24:11.917Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/project_for_user.json b/lib/gitlab-cli/spec/fixtures/project_for_user.json new file mode 100644 index 000000000..e2835d865 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_for_user.json @@ -0,0 +1 @@ +{"id":1,"code":"brute","name":"Brute","description":null,"path":"brute","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Owner","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:56Z"} diff --git a/lib/gitlab-cli/spec/fixtures/project_fork_link.json b/lib/gitlab-cli/spec/fixtures/project_fork_link.json new file mode 100644 index 000000000..f1490dfa7 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_fork_link.json @@ -0,0 +1 @@ +{"created_at":"2013-07-03T13:51:48Z","forked_from_project_id":24,"forked_to_project_id":42,"id":1,"updated_at":"2013-07-03T13:51:48Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_hook.json b/lib/gitlab-cli/spec/fixtures/project_hook.json new file mode 100644 index 000000000..180dd4555 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_hook.json @@ -0,0 +1 @@ +{"id":1,"url":"https://api.example.net/v1/webhooks/ci"} diff --git a/lib/gitlab-cli/spec/fixtures/project_hooks.json b/lib/gitlab-cli/spec/fixtures/project_hooks.json new file mode 100644 index 000000000..e70d4122c --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_hooks.json @@ -0,0 +1 @@ +[{"id":1,"url":"https://api.example.net/v1/webhooks/ci"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_issues.json b/lib/gitlab-cli/spec/fixtures/project_issues.json new file mode 100644 index 000000000..87fb2fb18 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_issues.json @@ -0,0 +1 @@ +[{"id":36,"project_id":3,"title":"Eos ut modi et laudantium quasi porro voluptas sed.","description":null,"labels":[],"milestone":null,"assignee":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":35,"project_id":3,"title":"Ducimus illo in iure voluptatem dolores labore.","description":null,"labels":[],"milestone":null,"assignee":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":34,"project_id":3,"title":"Rem tempora voluptatum atque eum sit nihil neque.","description":null,"labels":[],"milestone":null,"assignee":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":33,"project_id":3,"title":"Beatae possimus nostrum nihil reiciendis laboriosam nihil delectus alias accusantium dolor unde.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":32,"project_id":3,"title":"Deserunt tenetur impedit est beatae voluptas voluptas quaerat quisquam.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":16,"project_id":3,"title":"Numquam earum aut laudantium reprehenderit voluptatem aut.","description":null,"labels":[],"milestone":null,"assignee":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":15,"project_id":3,"title":"Qui veritatis voluptas fuga voluptate voluptas cupiditate.","description":null,"labels":[],"milestone":null,"assignee":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":14,"project_id":3,"title":"In assumenda et ipsa qui debitis voluptatem incidunt.","description":null,"labels":[],"milestone":null,"assignee":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":13,"project_id":3,"title":"Illo eveniet consequatur enim iste provident facilis rerum voluptatem et architecto aut.","description":null,"labels":[],"milestone":null,"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"author":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"},{"id":12,"project_id":3,"title":"Veniam et tempore quidem eum reprehenderit cupiditate non aut velit eaque.","description":null,"labels":[],"milestone":null,"assignee":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"closed":false,"updated_at":"2012-09-17T09:42:20Z","created_at":"2012-09-17T09:42:20Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_key.json b/lib/gitlab-cli/spec/fixtures/project_key.json new file mode 100644 index 000000000..d917f9466 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_key.json @@ -0,0 +1,6 @@ +{ + "id": 2, + "title": "Key Title", + "key": "ssh-rsa ...", + "created_at": "2013-09-22T18:34:32Z" +} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_keys.json b/lib/gitlab-cli/spec/fixtures/project_keys.json new file mode 100644 index 000000000..dd22f9668 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_keys.json @@ -0,0 +1,6 @@ +[{ + "id": 2, + "title": "Key Title", + "key": "ssh-rsa ...", + "created_at": "2013-09-22T18:34:32Z" +}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/project_tags.json b/lib/gitlab-cli/spec/fixtures/project_tags.json new file mode 100644 index 000000000..1e2fb96cb --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/project_tags.json @@ -0,0 +1 @@ +[{"name":"v2.8.2","commit":{"id":"a502f67c0b358cc6b391df0c5dca48375c21fcad","parents":[{"id":"4381084af341684240b1a671d368511afcf5774a"}],"tree":"1612068bdd20de5d14b3096cfa4c621e2051ed4c","message":"Up to 2.8.2","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-24T02:03:48-07:00","committed_date":"2012-08-24T02:03:48-07:00"}},{"name":"v2.8.1","commit":{"id":"ed2b53cd1c34c421b23208eeb502a141a6829f9d","parents":[{"id":"7ab587a47791e371f5c109c14097a5d1d7776ea5"}],"tree":"b7393b0b33b777583b285e85b423c4e5ab7f859f","message":"Up to 2.8.1","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-22T23:17:18-07:00","committed_date":"2012-08-22T23:17:18-07:00"}},{"name":"v2.8.0pre","commit":{"id":"b2c6ba97a25d299e83c51493d7bc770c13b8ed1a","parents":[{"id":"05da3801f53f06fdc529b4f3820af1380039f245"},{"id":"66399d558da45fb9cd3ea972a47a4f7bb12bfc8d"}],"tree":"36ad53f35bce1fe3f2a4a5f840e7b1bdbfed9c82","message":"Merge pull request #1230 from tsigo/hooray_apostrophes\n\nCorrect usage of \"Can't\"","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-16T14:11:08-07:00","committed_date":"2012-08-16T14:11:08-07:00"}},{"name":"v2.8.0","commit":{"id":"5c7ed6fa26b47ac71ff6ba04720d85df6d74b200","parents":[{"id":"d1daeba1736ba145fe525ce08a91f29495a3abf1"}],"tree":"4fc230ff2dbc0e75f27321eac2976aba5a6d323d","message":"Up to 2.8","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-08-21T15:15:26-07:00","committed_date":"2012-08-21T15:15:26-07:00"}},{"name":"v2.7.0pre","commit":{"id":"72a571724d84d112f98a5543c971e9b3b9da1383","parents":[{"id":"3ac840ff06e0ee5b349c52b5a8c02e803a17eec3"},{"id":"990b9217d9a55e26a53d4143d4a3c89123384327"}],"tree":"64b104df5d956e21e0749dc8e70849d1989de36f","message":"Merge pull request #1096 from moregeek/show-flash-note-when-destroying-a-project\n\nshow flash notice after deletion of a project","author":{"name":"Valeriy Sizov","email":"vsv2711@gmail.com"},"committer":{"name":"Valeriy Sizov","email":"vsv2711@gmail.com"},"authored_date":"2012-07-18T05:35:42-07:00","committed_date":"2012-07-18T05:35:42-07:00"}},{"name":"v2.7.0","commit":{"id":"8b7e404b5b6944e9c92cc270b2e5d0005781d49d","parents":[{"id":"11721b0dbe82c35789be3e4fa8e14663934b2ff5"}],"tree":"89fe8c5ff58daaedea07a910cffb14b04ebcc828","message":"Up to 2.7.0","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-07-21T00:53:55-07:00","committed_date":"2012-07-21T00:53:55-07:00"}},{"name":"v2.6.3","commit":{"id":"666cdb22792dd955a286b9993d6235b4cdd68b4b","parents":[{"id":"d92446df1fdba87101c92c90b1c34eb2f1eebef4"}],"tree":"888173aa4c12a4920d318c35b950095d3505673d","message":"up to 2.6.3","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-26T09:20:47-07:00","committed_date":"2012-06-26T09:21:28-07:00"}},{"name":"v2.6.2","commit":{"id":"39fecb554f172a0c8ea00316e612e1d37efc7200","parents":[{"id":"68389588d664100590b1a6ca7eedd50860b7e9bc"}],"tree":"53accb25e0b9d038d550cf387753bde15fe4ad19","message":"Up to 2.6.2","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-22T13:50:58-07:00","committed_date":"2012-06-22T13:50:58-07:00"}},{"name":"v2.6.1","commit":{"id":"d92a22c9e627268eca697bbd9b660d8c335df953","parents":[{"id":"193804516b8b0783c850981456e947f888ff51bb"}],"tree":"4ac1b5225f597ab55372cb5e950b121d6f55e386","message":"Up to 2.6.1","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-22T12:49:03-07:00","committed_date":"2012-06-22T12:49:03-07:00"}},{"name":"v2.6.0","commit":{"id":"b32465712becfbcf83d63b1e6eff7d1483fdabea","parents":[{"id":"1903f6ade027df0f10ef96b9439495eeda07482c"}],"tree":"ffbc05fd0f1771c1602c956df9556260048c7167","message":"Up to 2.6","author":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"randx","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-06-21T10:25:23-07:00","committed_date":"2012-06-21T10:25:23-07:00"}},{"name":"v2.5.0","commit":{"id":"cc8369144db2147d2956e8dd7d314e9a7dfd4fbb","parents":[{"id":"1b2068eaa91e5002d01a220c65da21dad8ccb071"}],"tree":"666a442e00689911169e8cc336c5ce60d014854c","message":"Prevent app crash in case if encoding failed","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-05-22T04:57:04-07:00","committed_date":"2012-05-22T04:57:04-07:00"}},{"name":"v2.4.2","commit":{"id":"f18339c26d673c5f8b4c19776036fd42a0de30aa","parents":[{"id":"c937d06c3c98e9ffce8ec1132203eaff6bf7b231"},{"id":"35e602f19c83585d64aa2043ed26eeb8cd7b40e2"}],"tree":"5101f0cd8e395fee1996764298a202437757e85b","message":"Merge branch 'master' of github.com:gitlabhq/gitlabhq","author":{"name":"Zevs","email":"vsv2711@gmail.com"},"committer":{"name":"Zevs","email":"vsv2711@gmail.com"},"authored_date":"2012-04-29T14:24:59-07:00","committed_date":"2012-04-29T14:24:59-07:00"}},{"name":"v2.4.1","commit":{"id":"d97a9aa4a44ff9f452144fad348fd9d7e3b48260","parents":[{"id":"21f3da23589d50038728393f0badc6255b5762ca"}],"tree":"905c33874b064778199f806749d5688e33d64be3","message":"fixed email markdown","author":{"name":"gitlabhq","email":"m@gitlabhq.com"},"committer":{"name":"gitlabhq","email":"m@gitlabhq.com"},"authored_date":"2012-04-23T05:32:56-07:00","committed_date":"2012-04-23T05:32:56-07:00"}},{"name":"v2.4.0pre","commit":{"id":"1845429268364e75bffdeb1075de8f1606e157ec","parents":[{"id":"45b18365d5f409f196a02a4e6e2b77b8ebef909b"}],"tree":"423c70246fa7ffd8804b26628fea34bdb2b22846","message":"Use try for commit prev_commit_id detection","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-04-19T13:35:35-07:00","committed_date":"2012-04-19T13:35:35-07:00"}},{"name":"v2.4.0","commit":{"id":"204c66461ed519eb0078be7e8ac8a6cb56834753","parents":[{"id":"511d07c47c9bf3a18bfa276d452c899369432a22"}],"tree":"9416c777cccf87d348f5705078e82f3f97485e19","message":"corrected exception for automerge","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-04-22T06:49:45-07:00","committed_date":"2012-04-22T06:49:45-07:00"}},{"name":"v2.3.1","commit":{"id":"fa8219e0a753e642a6f1dbdfc010d01ae8a949ee","parents":[{"id":"81da8e46f24913ccf42d3e2644962cbcbc0f9c2e"}],"tree":"5debfcd6d17f9d582aace6ac9b80db27d5c1fe36","message":"better MR list, dashboard pollished","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-22T13:57:04-07:00","committed_date":"2012-03-22T13:57:04-07:00"}},{"name":"v2.3.0pre","commit":{"id":"cadf12c60cc27c5b0b8273c1de4b190a0e88bd7d","parents":[{"id":"724ea16c348bc61cf7cb3dbe362c6f30cff1b2c7"}],"tree":"6f4c22761fd2dee405d3fbf38f9dd835bb3c8694","message":"Merged activities & projects pages","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-19T15:05:35-07:00","committed_date":"2012-03-19T15:05:35-07:00"}},{"name":"v2.3.0","commit":{"id":"b57faf9282d7df6cdd62953d474652a0ae2e6896","parents":[{"id":"cadf12c60cc27c5b0b8273c1de4b190a0e88bd7d"}],"tree":"f0d5b826df373191b4681452fc2ae4c5970cef4a","message":"Push events polished","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-03-20T14:59:35-07:00","committed_date":"2012-03-20T14:59:35-07:00"}},{"name":"v2.2.0pre","commit":{"id":"6a445b42003007cbb6c06f477c4d7a0b175688c1","parents":[{"id":"22f4c1908d0fc2dbce02e74ed03bf65f028d78d6"}],"tree":"9c60577833f6ca717acdebfa66140124c88e8471","message":"fixed forgot password form","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-02-20T10:37:37-08:00","committed_date":"2012-02-20T10:37:37-08:00"}},{"name":"v2.2.0","commit":{"id":"9e6d0710e927aa8ea834b8a9ae9f277be617ac7d","parents":[{"id":"8c40aab120dbc5507ab9cc8d7ad8e2519d6e9f25"},{"id":"6ea87c47f0f8a24ae031c3fff17bc913889ecd00"}],"tree":"86c831ab21236f21ffa5b97c752369612ce41b39","message":"Merge pull request #443 from CedricGatay/fix/incorrectLineNumberingInDiff\n\nIncorrect line numbering in diff","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-02-22T07:14:54-08:00","committed_date":"2012-02-22T07:14:54-08:00"}},{"name":"v2.1.0","commit":{"id":"98d6492582d232ed86525aa31ccbf280f4cbdaef","parents":[{"id":"611c5a87ab0c083a43785323b09cc47f554c3ba4"}],"tree":"1689b3cad580a18fd9b429ee0b33dac21c9f5a48","message":"removed broken migration","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2012-01-22T10:52:06-08:00","committed_date":"2012-01-22T10:52:06-08:00"}},{"name":"v2.0.0","commit":{"id":"9a2a8612769d472503b367fa35e99f6fb2876704","parents":[{"id":"2f7b67161952fc9ab322eba6878511b5f2dd5cf1"}],"tree":"26cdb4e66b5e664fe4bcd57d011c54c9c9c26ded","message":"Design tab for profile. Colorscheme as db value","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2011-12-20T12:47:09-08:00","committed_date":"2011-12-20T12:47:09-08:00"}},{"name":"v1.2.2","commit":{"id":"139a332293b9d8c4e5436619036e093483d8347f","parents":[{"id":"ade12da9488bea19d12505c371ead35686a1436e"}],"tree":"365d57f4df5c5dcac69b666cf6d2bfd8ef058008","message":"updated readme","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-25T14:30:51-08:00","committed_date":"2011-11-25T14:30:51-08:00"}},{"name":"v1.2.1","commit":{"id":"7ebba27db21719c0035bab65fea92a4780051c73","parents":[{"id":"b56024100d40457a998f83adae3cdc830c997cda"},{"id":"a4fbe13fce87cb6ff2a27a2574ae25bf1dad145c"}],"tree":"b121a7576af1503a96954ce9a94598a68579e053","message":"Merge branch 'master' of dev.gitlabhq.com:gitlabhq","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-22T13:15:09-08:00","committed_date":"2011-11-22T13:15:09-08:00"}},{"name":"v1.2.0pre","commit":{"id":"86829cae50857b5edf74b935380c6f68a19c2282","parents":[{"id":"a6b99319381c2d62ec4b92d64805e8de8965859e"}],"tree":"6aab9d13000584fa96fb3cb34d94f3b122bd1143","message":"fixed min height for menu","author":{"name":"gitlabhq","email":"m@gitlabhq.com"},"committer":{"name":"gitlabhq","email":"m@gitlabhq.com"},"authored_date":"2011-11-22T06:03:27-08:00","committed_date":"2011-11-22T06:03:27-08:00"}},{"name":"v1.2.0","commit":{"id":"b56024100d40457a998f83adae3cdc830c997cda","parents":[{"id":"4451b8df8ad6d4b6d79fbce77687c6c2fd37d0a9"}],"tree":"f402cbb6d54526a32b30968c98410bae97b27c8d","message":"lil style fixes","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-11-22T09:57:25-08:00","committed_date":"2011-11-22T09:57:25-08:00"}},{"name":"v1.1.0pre","commit":{"id":"6b030fd41d697e327d2935b406cba70b6a460504","parents":[{"id":"3a2b273316fb29d63b489906f85d9b5329377258"}],"tree":"63b1fdb2a0f135f7074f6a94da14543b8450dd71","message":"1.1pre1","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-21T10:04:41-07:00","committed_date":"2011-10-21T10:04:41-07:00"}},{"name":"v1.1.0","commit":{"id":"ba8048d71019b5aaa1f92ee5c3415bfddaa9babb","parents":[{"id":"6b030fd41d697e327d2935b406cba70b6a460504"}],"tree":"4db2b5f4f9b374dd1be3579459bc5947c225c9ba","message":"v1.1.0","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-22T06:07:26-07:00","committed_date":"2011-10-22T06:07:26-07:00"}},{"name":"v1.0.2","commit":{"id":"3a2b273316fb29d63b489906f85d9b5329377258","parents":[{"id":"757ea634665e475bf69c1ec962040a0511ee8aeb"},{"id":"c374eb80ff9fb71d37faffc15714bf98b632d3e5"}],"tree":"e0d8170e61a9468a7bb5d4e63305171ec1efa6bf","message":"Merge pull request #40 from vslinko/patch-1\n\nIncrease max key length. Some keys has comment after key string.","author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"authored_date":"2011-10-18T23:30:06-07:00","committed_date":"2011-10-18T23:30:06-07:00"}},{"name":"v1.0.1","commit":{"id":"7b5799a97998b68416f1b6233ce427135c99165a","parents":[{"id":"0541b3f3c5dcd291d144c83d9731c75ee811b4e0"},{"id":"7b67480c76db8b9a9ccdc80015cc500dc6d26892"}],"tree":"e052185e9dd72a1b1a04d59a5f9efbf3c0369601","message":"Merge branch '1x' of github.com:gitlabhq/gitlabhq into 1x","author":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dzaporozhets@sphereconsultinginc.com"},"authored_date":"2011-10-14T15:16:44-07:00","committed_date":"2011-10-14T15:16:44-07:00"}}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/projects.json b/lib/gitlab-cli/spec/fixtures/projects.json new file mode 100644 index 000000000..deab4c5f3 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/projects.json @@ -0,0 +1 @@ +[{"id":1,"code":"brute","name":"Brute","description":null,"path":"brute","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:56Z"},{"id":2,"code":"mozart","name":"Mozart","description":null,"path":"mozart","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:57Z"},{"id":3,"code":"gitlab","name":"Gitlab","description":null,"path":"gitlab","default_branch":null,"owner":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"private":true,"issues_enabled":true,"merge_requests_enabled":true,"wall_enabled":true,"wiki_enabled":true,"created_at":"2012-09-17T09:41:58Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/protect_branch.json b/lib/gitlab-cli/spec/fixtures/protect_branch.json new file mode 100644 index 000000000..752bc2389 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/protect_branch.json @@ -0,0 +1 @@ +{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected":true} diff --git a/lib/gitlab-cli/spec/fixtures/session.json b/lib/gitlab-cli/spec/fixtures/session.json new file mode 100644 index 000000000..e4f5ba35f --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/session.json @@ -0,0 +1 @@ +{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","private_token":"qEsq1pt6HJPaNciie3MG"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/snippet.json b/lib/gitlab-cli/spec/fixtures/snippet.json new file mode 100644 index 000000000..34e9d994d --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/snippet.json @@ -0,0 +1 @@ +{"id":1,"title":"Rails Console ActionMailer","file_name":"mailer_test.rb","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"expires_at":"2012-09-24T00:00:00Z","updated_at":"2012-09-17T09:51:42Z","created_at":"2012-09-17T09:51:42Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/snippets.json b/lib/gitlab-cli/spec/fixtures/snippets.json new file mode 100644 index 000000000..26457995c --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/snippets.json @@ -0,0 +1 @@ +[{"id":1,"title":"Rails Console ActionMailer","file_name":"mailer_test.rb","author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z"},"expires_at":"2012-09-24T00:00:00Z","updated_at":"2012-09-17T09:51:42Z","created_at":"2012-09-17T09:51:42Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/system_hook.json b/lib/gitlab-cli/spec/fixtures/system_hook.json new file mode 100644 index 000000000..0028b7a52 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/system_hook.json @@ -0,0 +1 @@ +{"id": 3, "url": "http://example.com/hook", "created_at": "2013-10-02T10:15:31Z"} diff --git a/lib/gitlab-cli/spec/fixtures/system_hook_test.json b/lib/gitlab-cli/spec/fixtures/system_hook_test.json new file mode 100644 index 000000000..cc79044ff --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/system_hook_test.json @@ -0,0 +1 @@ +{ "event_name": "project_create", "name": "Ruby", "path": "ruby", "project_id": 1, "owner_name": "Someone", "owner_email": "example@gitlabhq.com" } diff --git a/lib/gitlab-cli/spec/fixtures/system_hooks.json b/lib/gitlab-cli/spec/fixtures/system_hooks.json new file mode 100644 index 000000000..2b58791c3 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/system_hooks.json @@ -0,0 +1 @@ +[{"id": 3, "url": "http://example.com/hook", "created_at": "2013-10-02T10:15:31Z"}] diff --git a/lib/gitlab-cli/spec/fixtures/tag.json b/lib/gitlab-cli/spec/fixtures/tag.json new file mode 100644 index 000000000..a56a09262 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/tag.json @@ -0,0 +1 @@ +{"name": "v1.0.0","commit": {"id": "2695effb5807a22ff3d138d593fd856244e155e7","parents": [],"message": "Initial commit","authored_date": "2012-05-28T04:42:42-07:00","author_name": "John Smith","author email": "john@example.com","committer_name": "Jack Smith","committed_date": "2012-05-28T04:42:42-07:00","committer_email": "jack@example.com"},"protected": false} diff --git a/lib/gitlab-cli/spec/fixtures/team_member.json b/lib/gitlab-cli/spec/fixtures/team_member.json new file mode 100644 index 000000000..fd3ac3852 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/team_member.json @@ -0,0 +1 @@ +{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","access_level":40} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/team_members.json b/lib/gitlab-cli/spec/fixtures/team_members.json new file mode 100644 index 000000000..a2fe19e3b --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/team_members.json @@ -0,0 +1 @@ +[{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-09-17T09:41:56Z","access_level":40},{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":20},{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":6,"email":"faye.watsica@rohanwalter.com","name":"Ambrose Hansen","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":40},{"id":7,"email":"maida@walshtorp.name","name":"Alana Hahn","blocked":false,"created_at":"2012-09-17T09:42:03Z","access_level":20}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/unprotect_branch.json b/lib/gitlab-cli/spec/fixtures/unprotect_branch.json new file mode 100644 index 000000000..854c8274a --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/unprotect_branch.json @@ -0,0 +1 @@ +{"name":"api","commit":{"id":"f7dd067490fe57505f7226c3b54d3127d2f7fd46","parents":[{"id":"949b1df930bedace1dbd755aaa4a82e8c451a616"}],"tree":"f8c4b21c036339f92fcc5482aa28a41250553b27","message":"API: expose issues project id","author":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"committer":{"name":"Nihad Abbasov","email":"narkoz.2008@gmail.com"},"authored_date":"2012-07-25T04:22:21-07:00","committed_date":"2012-07-25T04:22:21-07:00"},"protected":false} diff --git a/lib/gitlab-cli/spec/fixtures/update_merge_request.json b/lib/gitlab-cli/spec/fixtures/update_merge_request.json new file mode 100644 index 000000000..735819ff3 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/update_merge_request.json @@ -0,0 +1 @@ +{"id":1,"target_branch":"master","source_branch":"api","project_id":3,"title":"A different new feature","closed":false,"merged":false,"author":{"id":1,"email":"john@example.com","name":"John Smith","blocked":false,"created_at":"2012-10-19T05:56:05Z"},"assignee":{"id":2,"email":"jack@example.com","name":"Jack Smith","blocked":false,"created_at":"2012-10-19T05:56:14Z"}} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/user.json b/lib/gitlab-cli/spec/fixtures/user.json new file mode 100644 index 000000000..4e0daca50 --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/user.json @@ -0,0 +1 @@ +{"id":1,"email":"john@example.com","name":"John Smith","bio":null,"skype":"","linkedin":"","twitter":"john","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:41:56Z"} \ No newline at end of file diff --git a/lib/gitlab-cli/spec/fixtures/users.json b/lib/gitlab-cli/spec/fixtures/users.json new file mode 100644 index 000000000..14c6388bf --- /dev/null +++ b/lib/gitlab-cli/spec/fixtures/users.json @@ -0,0 +1 @@ +[{"id":1,"email":"john@example.com","name":"John Smith","bio":null,"skype":"","linkedin":"","twitter":"john","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:41:56Z"},{"id":2,"email":"jack@example.com","name":"Jack Smith","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":3,"email":"wilma@mayerblanda.ca","name":"Beatrice Jewess","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":4,"email":"nicole@mertz.com","name":"Felipe Davis","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":5,"email":"aliza_stark@schmeler.info","name":"Michale Von","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":6,"email":"faye.watsica@rohanwalter.com","name":"Ambrose Hansen","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"},{"id":7,"email":"maida@walshtorp.name","name":"Alana Hahn","bio":null,"skype":"","linkedin":"","twitter":"","dark_scheme":false,"theme_id":1,"blocked":false,"created_at":"2012-09-17T09:42:03Z"}] \ No newline at end of file diff --git a/lib/gitlab-cli/spec/gitlab/cli_spec.rb b/lib/gitlab-cli/spec/gitlab/cli_spec.rb new file mode 100644 index 000000000..8b002ec64 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/cli_spec.rb @@ -0,0 +1,80 @@ +require 'spec_helper' + +describe Gitlab::CLI do + describe ".run" do + context "when command is version" do + it "should show gem version" do + output = capture_output { Gitlab::CLI.run('-v') } + expect(output).to eq("Gitlab Ruby Gem #{Gitlab::VERSION}\n") + end + end + + context "when command is info" do + it "should show environment info" do + output = capture_output { Gitlab::CLI.run('info') } + expect(output).to include("Gitlab endpoint is") + expect(output).to include("Gitlab private token is") + expect(output).to include("Ruby Version is") + expect(output).to include("Gitlab Ruby Gem") + end + end + + context "when command is help" do + it "should show available actions" do + output = capture_output { Gitlab::CLI.run('help') } + expect(output).to include('Available commands') + expect(output).to include('MergeRequests') + expect(output).to include('team_members') + end + end + + context "when command is user" do + before do + stub_get("/user", "user") + @output = capture_output { Gitlab::CLI.run('user') } + end + + it "should show executed command" do + expect(@output).to include('Gitlab.user') + end + + it "should show user data" do + expect(@output).to include('name') + expect(@output).to include('John Smith') + end + end + end + + describe ".start" do + context "when command with excluded fields" do + before do + stub_get("/user", "user") + args = ['user', '--except=id,email,name'] + @output = capture_output { Gitlab::CLI.start(args) } + end + + it "should show user data with excluded fields" do + expect(@output).to_not include('John Smith') + expect(@output).to include('bio') + expect(@output).to include('created_at') + end + end + + context "when command with required fields" do + before do + stub_get("/user", "user") + args = ['user', '--only=id,email,name'] + @output = capture_output { Gitlab::CLI.start(args) } + end + + it "should show user data with required fields" do + expect(@output).to include('id') + expect(@output).to include('name') + expect(@output).to include('email') + expect(@output).to include('John Smith') + expect(@output).to_not include('bio') + expect(@output).to_not include('created_at') + end + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/branches_spec.rb b/lib/gitlab-cli/spec/gitlab/client/branches_spec.rb new file mode 100644 index 000000000..80c18ccb5 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/branches_spec.rb @@ -0,0 +1,103 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :repo_branches } + it { should respond_to :repo_branch } + it { should respond_to :repo_protect_branch } + it { should respond_to :repo_unprotect_branch } + + describe ".branches" do + before do + stub_get("/projects/3/repository/branches", "branches") + @branches = Gitlab.branches(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/branches")).to have_been_made + end + + it "should return an array of repository branches" do + expect(@branches).to be_an Array + expect(@branches.first.name).to eq("api") + end + end + + describe ".branch" do + before do + stub_get("/projects/3/repository/branches/api", "branch") + @branch = Gitlab.branch(3, "api") + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/branches/api")).to have_been_made + end + + it "should return information about a repository branch" do + expect(@branch.name).to eq("api") + end + end + + describe ".protect_branch" do + before do + stub_put("/projects/3/repository/branches/api/protect", "protect_branch") + @branch = Gitlab.protect_branch(3, "api") + end + + it "should get the correct resource" do + expect(a_put("/projects/3/repository/branches/api/protect")).to have_been_made + end + + it "should return information about a protected repository branch" do + expect(@branch.name).to eq("api") + expect(@branch.protected).to eq(true) + end + end + + describe ".unprotect_branch" do + before do + stub_put("/projects/3/repository/branches/api/unprotect", "unprotect_branch") + @branch = Gitlab.unprotect_branch(3, "api") + end + + it "should get the correct resource" do + expect(a_put("/projects/3/repository/branches/api/unprotect")).to have_been_made + end + + it "should return information about an unprotected repository branch" do + expect(@branch.name).to eq("api") + expect(@branch.protected).to eq(false) + end + end + + describe ".create_branch" do + context "with branch name" do + before do + stub_post("/projects/3/repository/branches", "create_branch") + @branch = Gitlab.create_branch(3, "api","master") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/branches")).to have_been_made + end + + it "should return information about a new repository branch" do + expect(@branch.name).to eq("api") + end + end + context "with commit hash" do + before do + stub_post("/projects/3/repository/branches", "create_branch") + @branch = Gitlab.create_branch(3, "api","949b1df930bedace1dbd755aaa4a82e8c451a616") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/branches")).to have_been_made + end + + it "should return information about a new repository branch" do + expect(@branch.name).to eq("api") + end + end + end + +end diff --git a/lib/gitlab-cli/spec/gitlab/client/groups_spec.rb b/lib/gitlab-cli/spec/gitlab/client/groups_spec.rb new file mode 100644 index 000000000..ad17aedaa --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/groups_spec.rb @@ -0,0 +1,111 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".groups" do + before do + stub_get("/groups", "groups") + stub_get("/groups/3", "group") + @group = Gitlab.group(3) + @groups = Gitlab.groups + end + + it "should get the correct resource" do + expect(a_get("/groups")).to have_been_made + expect(a_get("/groups/3")).to have_been_made + end + + it "should return an array of Groups" do + expect(@groups).to be_an Array + expect(@groups.first.path).to eq("threegroup") + end + end + + describe ".create_group" do + before do + stub_post("/groups", "group_create") + @group = Gitlab.create_group('GitLab-Group', 'gitlab-path') + end + + it "should get the correct resource" do + expect(a_post("/groups"). + with(:body => {:path => 'gitlab-path', :name => 'GitLab-Group'})).to have_been_made + end + + it "should return information about a created group" do + expect(@group.name).to eq("Gitlab-Group") + expect(@group.path).to eq("gitlab-group") + end + end + + describe ".transfer_project_to_group" do + before do + stub_post("/projects", "project") + @project = Gitlab.create_project('Gitlab') + stub_post("/groups", "group_create") + @group = Gitlab.create_group('GitLab-Group', 'gitlab-path') + + stub_post("/groups/#{@group.id}/projects/#{@project.id}", "group_create") + @group_transfer = Gitlab.transfer_project_to_group(@group.id,@project.id) + end + + it "should post to the correct resource" do + expect(a_post("/groups/#{@group.id}/projects/#{@project.id}").with(:body => {:id => @group.id.to_s, :project_id => @project.id.to_s})).to have_been_made + end + + it "should return information about the group" do + expect(@group_transfer.name).to eq(@group.name) + expect(@group_transfer.path).to eq(@group.path) + expect(@group_transfer.id).to eq(@group.id) + end + end + + describe ".group_members" do + before do + stub_get("/groups/3/members", "group_members") + @members = Gitlab.group_members(3) + end + + it "should get the correct resource" do + expect(a_get("/groups/3/members")).to have_been_made + end + + it "should return information about a group members" do + expect(@members).to be_an Array + expect(@members.size).to eq(2) + expect(@members[1].name).to eq("John Smith") + end + end + + describe ".add_group_member" do + before do + stub_post("/groups/3/members", "group_member") + @member = Gitlab.add_group_member(3, 1, 40) + end + + it "should get the correct resource" do + expect(a_post("/groups/3/members"). + with(:body => {:user_id => '1', :access_level => '40'})).to have_been_made + end + + it "should return information about an added member" do + expect(@member.name).to eq("John Smith") + end + end + + describe ".remove_group_member" do + before do + stub_delete("/groups/3/members/1", "group_member_delete") + @group = Gitlab.remove_group_member(3, 1) + end + + it "should get the correct resource" do + expect(a_delete("/groups/3/members/1")).to have_been_made + end + + it "should return information about the group the member was removed from" do + expect(@group.group_id).to eq(3) + end + end + + +end diff --git a/lib/gitlab-cli/spec/gitlab/client/issues_spec.rb b/lib/gitlab-cli/spec/gitlab/client/issues_spec.rb new file mode 100644 index 000000000..e5a506b94 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/issues_spec.rb @@ -0,0 +1,122 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".issues" do + context "with project ID passed" do + before do + stub_get("/projects/3/issues", "project_issues") + @issues = Gitlab.issues(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues")).to have_been_made + end + + it "should return an array of project's issues" do + expect(@issues).to be_an Array + expect(@issues.first.project_id).to eq(3) + end + end + + context "without project ID passed" do + before do + stub_get("/issues", "issues") + @issues = Gitlab.issues + end + + it "should get the correct resource" do + expect(a_get("/issues")).to have_been_made + end + + it "should return an array of user's issues" do + expect(@issues).to be_an Array + expect(@issues.first.closed).to be_falsey + expect(@issues.first.author.name).to eq("John Smith") + end + end + end + + describe ".issue" do + before do + stub_get("/projects/3/issues/33", "issue") + @issue = Gitlab.issue(3, 33) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues/33")).to have_been_made + end + + it "should return information about an issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".create_issue" do + before do + stub_post("/projects/3/issues", "issue") + @issue = Gitlab.create_issue(3, 'title') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/issues"). + with(:body => {:title => 'title'})).to have_been_made + end + + it "should return information about a created issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".edit_issue" do + before do + stub_put("/projects/3/issues/33", "issue") + @issue = Gitlab.edit_issue(3, 33, :title => 'title') + end + + it "should get the correct resource" do + expect(a_put("/projects/3/issues/33"). + with(:body => {:title => 'title'})).to have_been_made + end + + it "should return information about an edited issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".close_issue" do + before do + stub_put("/projects/3/issues/33", "issue") + @issue = Gitlab.close_issue(3, 33) + end + + it "should get the correct resource" do + expect(a_put("/projects/3/issues/33"). + with(:body => {:state_event => 'close'})).to have_been_made + end + + it "should return information about an closed issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end + + describe ".reopen_issue" do + before do + stub_put("/projects/3/issues/33", "issue") + @issue = Gitlab.reopen_issue(3, 33) + end + + it "should get the correct resource" do + expect(a_put("/projects/3/issues/33"). + with(:body => {:state_event => 'reopen'})).to have_been_made + end + + it "should return information about an reopened issue" do + expect(@issue.project_id).to eq(3) + expect(@issue.assignee.name).to eq("Jack Smith") + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/merge_requests_spec.rb b/lib/gitlab-cli/spec/gitlab/client/merge_requests_spec.rb new file mode 100644 index 000000000..a336da9f5 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/merge_requests_spec.rb @@ -0,0 +1,124 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".merge_requests" do + before do + stub_get("/projects/3/merge_requests", "merge_requests") + @merge_requests = Gitlab.merge_requests(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_requests")).to have_been_made + end + + it "should return an array of project's merge requests" do + expect(@merge_requests).to be_an Array + expect(@merge_requests.first.project_id).to eq(3) + end + end + + describe ".merge_request" do + before do + stub_get("/projects/3/merge_request/1", "merge_request") + @merge_request = Gitlab.merge_request(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/merge_request/1")).to have_been_made + end + + it "should return information about a merge request" do + expect(@merge_request.project_id).to eq(3) + expect(@merge_request.assignee.name).to eq("Jack Smith") + end + end + + describe ".create_merge_request" do + before do + stub_post("/projects/3/merge_requests", "create_merge_request") + end + + it "should fail if it doesn't have a source_branch" do + expect { + Gitlab.create_merge_request(3, 'New merge request', :target_branch => 'master') + }.to raise_error Gitlab::Error::MissingAttributes + end + + it "should fail if it doesn't have a target_branch" do + expect { + Gitlab.create_merge_request(3, 'New merge request', :source_branch => 'dev') + }.to raise_error Gitlab::Error::MissingAttributes + end + + it "should return information about a merge request" do + @merge_request = Gitlab.create_merge_request(3, 'New feature', + :source_branch => 'api', + :target_branch => 'master' + ) + expect(@merge_request.project_id).to eq(3) + expect(@merge_request.assignee.name).to eq("Jack Smith") + expect(@merge_request.title).to eq('New feature') + end + end + + describe ".update_merge_request" do + before do + stub_put("/projects/3/merge_request/2", "update_merge_request") + @merge_request = Gitlab.update_merge_request(3, 2, + :assignee_id => '1', + :target_branch => 'master', + :title => 'A different new feature' + ) + end + + it "should return information about a merge request" do + expect(@merge_request.project_id).to eq(3) + expect(@merge_request.assignee.name).to eq("Jack Smith") + expect(@merge_request.title).to eq('A different new feature') + end + end + + describe ".merge_request_comments" do + before do + stub_get("/projects/3/merge_request/2/comments", "merge_request_comments") + @merge_request = Gitlab.merge_request_comments(3, 2) + end + + it "should return merge request's comments" do + expect(@merge_request).to be_an Array + expect(@merge_request.length).to eq(2) + expect(@merge_request[0].note).to eq("this is the 1st comment on the 2merge merge request") + expect(@merge_request[0].author.id).to eq(11) + expect(@merge_request[1].note).to eq("another discussion point on the 2merge request") + expect(@merge_request[1].author.id).to eq(12) + end + end + + describe ".merge_request_comments" do + before do + stub_get("/projects/3/merge_request/2/comments", "merge_request_comments") + @merge_request = Gitlab.merge_request_comments(3, 2) + end + + it "should return merge request's comments" do + expect(@merge_request).to be_an Array + expect(@merge_request.length).to eq(2) + expect(@merge_request[0].note).to eq("this is the 1st comment on the 2merge merge request") + expect(@merge_request[0].author.id).to eq(11) + expect(@merge_request[1].note).to eq("another discussion point on the 2merge request") + expect(@merge_request[1].author.id).to eq(12) + end + end + + describe ".create_merge_request_comment" do + before do + stub_post("/projects/3/merge_request/2/comments", "comment_merge_request") + end + + it "should return information about a merge request" do + @merge_request = Gitlab.create_merge_request_comment(3, 2, 'Cool Merge Request!') + expect(@merge_request.note).to eq('Cool Merge Request!') + @merge_request.author.id == 1 + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/milestones_spec.rb b/lib/gitlab-cli/spec/gitlab/client/milestones_spec.rb new file mode 100644 index 000000000..aa1e66b14 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/milestones_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".milestones" do + before do + stub_get("/projects/3/milestones", "milestones") + @milestones = Gitlab.milestones(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/milestones")).to have_been_made + end + + it "should return an array of project's milestones" do + expect(@milestones).to be_an Array + expect(@milestones.first.project_id).to eq(3) + end + end + + describe ".milestone" do + before do + stub_get("/projects/3/milestones/1", "milestone") + @milestone = Gitlab.milestone(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/milestones/1")).to have_been_made + end + + it "should return information about a milestone" do + expect(@milestone.project_id).to eq(3) + end + end + + describe ".create_milestone" do + before do + stub_post("/projects/3/milestones", "milestone") + @milestone = Gitlab.create_milestone(3, 'title') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/milestones"). + with(:body => {:title => 'title'})).to have_been_made + end + + it "should return information about a created milestone" do + expect(@milestone.project_id).to eq(3) + end + end + + describe ".edit_milestone" do + before do + stub_put("/projects/3/milestones/33", "milestone") + @milestone = Gitlab.edit_milestone(3, 33, :title => 'title') + end + + it "should get the correct resource" do + expect(a_put("/projects/3/milestones/33"). + with(:body => {:title => 'title'})).to have_been_made + end + + it "should return information about an edited milestone" do + expect(@milestone.project_id).to eq(3) + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/notes_spec.rb b/lib/gitlab-cli/spec/gitlab/client/notes_spec.rb new file mode 100644 index 000000000..d80cad476 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/notes_spec.rb @@ -0,0 +1,156 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe "notes" do + context "when wall notes" do + before do + stub_get("/projects/3/notes", "notes") + @notes = Gitlab.notes(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/notes")).to have_been_made + end + + it "should return an array of notes" do + expect(@notes).to be_an Array + expect(@notes.first.author.name).to eq("John Smith") + end + end + + context "when issue notes" do + before do + stub_get("/projects/3/issues/7/notes", "notes") + @notes = Gitlab.issue_notes(3, 7) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues/7/notes")).to have_been_made + end + + it "should return an array of notes" do + expect(@notes).to be_an Array + expect(@notes.first.author.name).to eq("John Smith") + end + end + + context "when snippet notes" do + before do + stub_get("/projects/3/snippets/7/notes", "notes") + @notes = Gitlab.snippet_notes(3, 7) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets/7/notes")).to have_been_made + end + + it "should return an array of notes" do + expect(@notes).to be_an Array + expect(@notes.first.author.name).to eq("John Smith") + end + end + end + + describe "note" do + context "when wall note" do + before do + stub_get("/projects/3/notes/1201", "note") + @note = Gitlab.note(3, 1201) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/notes/1201")).to have_been_made + end + + it "should return information about a note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when issue note" do + before do + stub_get("/projects/3/issues/7/notes/1201", "note") + @note = Gitlab.issue_note(3, 7, 1201) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/issues/7/notes/1201")).to have_been_made + end + + it "should return information about a note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when snippet note" do + before do + stub_get("/projects/3/snippets/7/notes/1201", "note") + @note = Gitlab.snippet_note(3, 7, 1201) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets/7/notes/1201")).to have_been_made + end + + it "should return information about a note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + end + + describe "create note" do + context "when wall note" do + before do + stub_post("/projects/3/notes", "note") + @note = Gitlab.create_note(3, "The solution is rather tricky") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/notes"). + with(:body => {:body => 'The solution is rather tricky'})).to have_been_made + end + + it "should return information about a created note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when issue note" do + before do + stub_post("/projects/3/issues/7/notes", "note") + @note = Gitlab.create_issue_note(3, 7, "The solution is rather tricky") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/issues/7/notes"). + with(:body => {:body => 'The solution is rather tricky'})).to have_been_made + end + + it "should return information about a created note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + + context "when snippet note" do + before do + stub_post("/projects/3/snippets/7/notes", "note") + @note = Gitlab.create_snippet_note(3, 7, "The solution is rather tricky") + end + + it "should get the correct resource" do + expect(a_post("/projects/3/snippets/7/notes"). + with(:body => {:body => 'The solution is rather tricky'})).to have_been_made + end + + it "should return information about a created note" do + expect(@note.body).to eq("The solution is rather tricky") + expect(@note.author.name).to eq("John Smith") + end + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/projects_spec.rb b/lib/gitlab-cli/spec/gitlab/client/projects_spec.rb new file mode 100644 index 000000000..5096f8f66 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/projects_spec.rb @@ -0,0 +1,357 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".projects" do + before do + stub_get("/projects", "projects") + @projects = Gitlab.projects + end + + it "should get the correct resource" do + expect(a_get("/projects")).to have_been_made + end + + it "should return an array of projects" do + expect(@projects).to be_an Array + expect(@projects.first.name).to eq("Brute") + expect(@projects.first.owner.name).to eq("John Smith") + end + end + + describe ".project" do + before do + stub_get("/projects/3", "project") + @project = Gitlab.project(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3")).to have_been_made + end + + it "should return information about a project" do + expect(@project.name).to eq("Gitlab") + expect(@project.owner.name).to eq("John Smith") + end + end + + describe ".project_events" do + before do + stub_get("/projects/2/events", "project_events") + @events = Gitlab.project_events(2) + end + + it "should get the correct resource" do + expect(a_get("/projects/2/events")).to have_been_made + end + + it "should return an array of events" do + expect(@events).to be_an Array + expect(@events.size).to eq(2) + end + + it "should return the action name of the event" do + expect(@events.first.action_name).to eq("opened") + end + end + + describe ".create_project" do + before do + stub_post("/projects", "project") + @project = Gitlab.create_project('Gitlab') + end + + it "should get the correct resource" do + expect(a_post("/projects")).to have_been_made + end + + it "should return information about a created project" do + expect(@project.name).to eq("Gitlab") + expect(@project.owner.name).to eq("John Smith") + end + end + + describe ".create_project for user" do + before do + stub_post("/users", "user") + @owner = Gitlab.create_user("john@example.com", "pass", {name: 'John Owner'}) + stub_post("/projects/user/#{@owner.id}", "project_for_user") + @project = Gitlab.create_project('Brute', {:user_id => @owner.id}) + end + + it "should return information about a created project" do + expect(@project.name).to eq("Brute") + expect(@project.owner.name).to eq("John Owner") + end + end + + describe ".delete_project" do + before do + stub_delete("/projects/Gitlab", "project") + @project = Gitlab.delete_project('Gitlab') + end + + it "should get the correct resource" do + expect(a_delete("/projects/Gitlab")).to have_been_made + end + + it "should return information about a deleted project" do + expect(@project.name).to eq("Gitlab") + expect(@project.owner.name).to eq("John Smith") + end + end + + describe ".team_members" do + before do + stub_get("/projects/3/members", "team_members") + @team_members = Gitlab.team_members(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/members")).to have_been_made + end + + it "should return an array of team members" do + expect(@team_members).to be_an Array + expect(@team_members.first.name).to eq("John Smith") + end + end + + describe ".team_member" do + before do + stub_get("/projects/3/members/1", "team_member") + @team_member = Gitlab.team_member(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/members/1")).to have_been_made + end + + it "should return information about a team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".add_team_member" do + before do + stub_post("/projects/3/members", "team_member") + @team_member = Gitlab.add_team_member(3, 1, 40) + end + + it "should get the correct resource" do + expect(a_post("/projects/3/members"). + with(:body => {:user_id => '1', :access_level => '40'})).to have_been_made + end + + it "should return information about an added team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".edit_team_member" do + before do + stub_put("/projects/3/members/1", "team_member") + @team_member = Gitlab.edit_team_member(3, 1, 40) + end + + it "should get the correct resource" do + expect(a_put("/projects/3/members/1"). + with(:body => {:access_level => '40'})).to have_been_made + end + + it "should return information about an edited team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".remove_team_member" do + before do + stub_delete("/projects/3/members/1", "team_member") + @team_member = Gitlab.remove_team_member(3, 1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/members/1")).to have_been_made + end + + it "should return information about a removed team member" do + expect(@team_member.name).to eq("John Smith") + end + end + + describe ".project_hooks" do + before do + stub_get("/projects/1/hooks", "project_hooks") + @hooks = Gitlab.project_hooks(1) + end + + it "should get the correct resource" do + expect(a_get("/projects/1/hooks")).to have_been_made + end + + it "should return an array of hooks" do + expect(@hooks).to be_an Array + expect(@hooks.first.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".project_hook" do + before do + stub_get("/projects/1/hooks/1", "project_hook") + @hook = Gitlab.project_hook(1, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/1/hooks/1")).to have_been_made + end + + it "should return information about a hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".add_project_hook" do + context "without specified events" do + before do + stub_post("/projects/1/hooks", "project_hook") + @hook = Gitlab.add_project_hook(1, "https://api.example.net/v1/webhooks/ci") + end + + it "should get the correct resource" do + body = {:url => "https://api.example.net/v1/webhooks/ci"} + expect(a_post("/projects/1/hooks").with(:body => body)).to have_been_made + end + + it "should return information about an added hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + context "with specified events" do + before do + stub_post("/projects/1/hooks", "project_hook") + @hook = Gitlab.add_project_hook(1, "https://api.example.net/v1/webhooks/ci", push_events: true, merge_requests_events: true) + end + + it "should get the correct resource" do + body = {:url => "https://api.example.net/v1/webhooks/ci", push_events: "true", merge_requests_events: "true"} + expect(a_post("/projects/1/hooks").with(:body => body)).to have_been_made + end + + it "should return information about an added hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + end + + describe ".edit_project_hook" do + before do + stub_put("/projects/1/hooks/1", "project_hook") + @hook = Gitlab.edit_project_hook(1, 1, "https://api.example.net/v1/webhooks/ci") + end + + it "should get the correct resource" do + body = {:url => "https://api.example.net/v1/webhooks/ci"} + expect(a_put("/projects/1/hooks/1").with(:body => body)).to have_been_made + end + + it "should return information about an edited hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".delete_project_hook" do + before do + stub_delete("/projects/1/hooks/1", "project_hook") + @hook = Gitlab.delete_project_hook(1, 1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/1/hooks/1")).to have_been_made + end + + it "should return information about a deleted hook" do + expect(@hook.url).to eq("https://api.example.net/v1/webhooks/ci") + end + end + + describe ".make_forked_from" do + before do + stub_post("/projects/42/fork/24", "project_fork_link") + @forked_project_link = Gitlab.make_forked_from(42, 24) + end + + it "should get the correct resource" do + expect(a_post("/projects/42/fork/24")).to have_been_made + end + + it "should return information about a forked project" do + expect(@forked_project_link.forked_from_project_id).to eq(24) + expect(@forked_project_link.forked_to_project_id).to eq(42) + end + end + + describe ".remove_forked" do + before do + stub_delete("/projects/42/fork", "project_fork_link") + @forked_project_link = Gitlab.remove_forked(42) + end + + it "should be sent to correct resource" do + expect(a_delete("/projects/42/fork")).to have_been_made + end + + it "should return information about an unforked project" do + expect(@forked_project_link.forked_to_project_id).to eq(42) + end + end + + describe ".deploy_keys" do + before do + stub_get("/projects/42/keys", "project_keys") + @deploy_keys = Gitlab.deploy_keys(42) + end + + it "should get the correct resource" do + expect(a_get("/projects/42/keys")).to have_been_made + end + + it "should return project deploy keys" do + expect(@deploy_keys).to be_an Array + expect(@deploy_keys.first.id).to eq 2 + expect(@deploy_keys.first.title).to eq "Key Title" + expect(@deploy_keys.first.key).to match(/ssh-rsa/) + end + end + + describe ".deploy_key" do + before do + stub_get("/projects/42/keys/2", "project_key") + @deploy_key = Gitlab.deploy_key(42, 2) + end + + it "should get the correct resource" do + expect(a_get("/projects/42/keys/2")).to have_been_made + end + + it "should return project deploy key" do + expect(@deploy_key.id).to eq 2 + expect(@deploy_key.title).to eq "Key Title" + expect(@deploy_key.key).to match(/ssh-rsa/) + end + end + + describe ".delete_deploy_key" do + before do + stub_delete("/projects/42/keys/2", "project_delete_key") + @deploy_key = Gitlab.delete_deploy_key(42, 2) + end + + it "should get the correct resource" do + expect(a_delete("/projects/42/keys/2")).to have_been_made + end + + it "should return information about a deleted key" do + expect(@deploy_key.id).to eq(2) + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/repositories_spec.rb b/lib/gitlab-cli/spec/gitlab/client/repositories_spec.rb new file mode 100644 index 000000000..f58e315d0 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/repositories_spec.rb @@ -0,0 +1,92 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :repo_tags } + it { should respond_to :repo_create_tag } + it { should respond_to :repo_branches } + it { should respond_to :repo_branch } + it { should respond_to :repo_commits } + it { should respond_to :repo_commit } + it { should respond_to :repo_commit_diff } + + describe ".tags" do + before do + stub_get("/projects/3/repository/tags", "project_tags") + @tags = Gitlab.tags(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/tags")).to have_been_made + end + + it "should return an array of repository tags" do + expect(@tags).to be_an Array + expect(@tags.first.name).to eq("v2.8.2") + end + end + + describe ".create_tag" do + before do + stub_post("/projects/3/repository/tags", "tag") + @tag = Gitlab.create_tag(3, 'v1.0.0', '2695effb5807a22ff3d138d593fd856244e155e7') + end + + it "should get the correct resource" do + expect(a_post("/projects/3/repository/tags")).to have_been_made + end + + it "should return information about a new repository tag" do + expect(@tag.name).to eq("v1.0.0") + end + end + + describe ".commits" do + before do + stub_get("/projects/3/repository/commits", "project_commits"). + with(:query => {:ref_name => "api"}) + @commits = Gitlab.commits(3, :ref_name => "api") + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits"). + with(:query => {:ref_name => "api"})).to have_been_made + end + + it "should return an array of repository commits" do + expect(@commits).to be_an Array + expect(@commits.first.id).to eq("f7dd067490fe57505f7226c3b54d3127d2f7fd46") + end + end + + describe ".commit" do + before do + stub_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6", "project_commit") + @commit = Gitlab.commit(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6")) + .to have_been_made + end + + it "should return a repository commit" do + expect(@commit.id).to eq("6104942438c14ec7bd21c6cd5bd995272b3faff6") + end + end + + describe ".commit_diff" do + before do + stub_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/diff", "project_commit_diff") + @diff = Gitlab.commit_diff(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6') + end + + it "should get the correct resource" do + expect(a_get("/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/diff")) + .to have_been_made + end + + it "should return a diff of a commit" do + expect(@diff.new_path).to eq("doc/update/5.4-to-6.0.md") + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/snippets_spec.rb b/lib/gitlab-cli/spec/gitlab/client/snippets_spec.rb new file mode 100644 index 000000000..b6ceecc0d --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/snippets_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".snippets" do + before do + stub_get("/projects/3/snippets", "snippets") + @snippets = Gitlab.snippets(3) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets")).to have_been_made + end + + it "should return an array of project's snippets" do + expect(@snippets).to be_an Array + expect(@snippets.first.file_name).to eq("mailer_test.rb") + end + end + + describe ".snippet" do + before do + stub_get("/projects/3/snippets/1", "snippet") + @snippet = Gitlab.snippet(3, 1) + end + + it "should get the correct resource" do + expect(a_get("/projects/3/snippets/1")).to have_been_made + end + + it "should return information about a snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end + + describe ".create_snippet" do + before do + stub_post("/projects/3/snippets", "snippet") + @snippet = Gitlab.create_snippet(3, {:title => 'API', :file_name => 'api.rb', :code => 'code'}) + end + + it "should get the correct resource" do + body = {:title => 'API', :file_name => 'api.rb', :code => 'code'} + expect(a_post("/projects/3/snippets").with(:body => body)).to have_been_made + end + + it "should return information about a new snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end + + describe ".edit_snippet" do + before do + stub_put("/projects/3/snippets/1", "snippet") + @snippet = Gitlab.edit_snippet(3, 1, :file_name => 'mailer_test.rb') + end + + it "should get the correct resource" do + expect(a_put("/projects/3/snippets/1"). + with(:body => {:file_name => 'mailer_test.rb'})).to have_been_made + end + + it "should return information about an edited snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end + + describe ".delete_snippet" do + before do + stub_delete("/projects/3/snippets/1", "snippet") + @snippet = Gitlab.delete_snippet(3, 1) + end + + it "should get the correct resource" do + expect(a_delete("/projects/3/snippets/1")).to have_been_made + end + + it "should return information about a deleted snippet" do + expect(@snippet.file_name).to eq("mailer_test.rb") + expect(@snippet.author.name).to eq("John Smith") + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/system_hooks_spec.rb b/lib/gitlab-cli/spec/gitlab/client/system_hooks_spec.rb new file mode 100644 index 000000000..7410c3655 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/system_hooks_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' + +describe Gitlab::Client do + it { should respond_to :system_hooks } + it { should respond_to :add_system_hook } + it { should respond_to :system_hook } + it { should respond_to :delete_system_hook } + + describe ".hooks" do + before do + stub_get("/hooks", "system_hooks") + @hooks = Gitlab.hooks + end + + it "should get the correct resource" do + expect(a_get("/hooks")).to have_been_made + end + + it "should return an array of system hooks" do + expect(@hooks).to be_an Array + expect(@hooks.first.url).to eq("http://example.com/hook") + end + end + + describe ".add_hook" do + before do + stub_post("/hooks", "system_hook") + @hook = Gitlab.add_hook("http://example.com/hook") + end + + it "should get the correct resource" do + expect(a_post("/hooks")).to have_been_made + end + + it "should return information about a added system hook" do + expect(@hook.url).to eq("http://example.com/hook") + end + end + + describe ".hook" do + before do + stub_get("/hooks/3", "system_hook_test") + @hook = Gitlab.hook(3) + end + it "should get the correct resource" do + expect(a_get("/hooks/3")).to have_been_made + end + + it "should return information about a added system hook" do + expect(@hook.event_name).to eq("project_create") + expect(@hook.project_id).to eq(1) + end + end + + describe ".delete_hook" do + before do + stub_delete("/hooks/3", "system_hook") + @hook = Gitlab.delete_hook(3) + end + + it "should get the correct resource" do + expect(a_delete("/hooks/3")).to have_been_made + end + + it "should return information about a deleted system hook" do + expect(@hook.url).to eq("http://example.com/hook") + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/client/users_spec.rb b/lib/gitlab-cli/spec/gitlab/client/users_spec.rb new file mode 100644 index 000000000..ead205b47 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/client/users_spec.rb @@ -0,0 +1,192 @@ +require 'spec_helper' + +describe Gitlab::Client do + describe ".users" do + before do + stub_get("/users", "users") + @users = Gitlab.users + end + + it "should get the correct resource" do + expect(a_get("/users")).to have_been_made + end + + it "should return an array of users" do + expect(@users).to be_an Array + expect(@users.first.email).to eq("john@example.com") + end + end + + describe ".user" do + context "with user ID passed" do + before do + stub_get("/users/1", "user") + @user = Gitlab.user(1) + end + + it "should get the correct resource" do + expect(a_get("/users/1")).to have_been_made + end + + it "should return information about a user" do + expect(@user.email).to eq("john@example.com") + end + end + + context "without user ID passed" do + before do + stub_get("/user", "user") + @user = Gitlab.user + end + + it "should get the correct resource" do + expect(a_get("/user")).to have_been_made + end + + it "should return information about an authorized user" do + expect(@user.email).to eq("john@example.com") + end + end + end + + describe ".create_user" do + context "when successful request" do + before do + stub_post("/users", "user") + @user = Gitlab.create_user("email", "pass") + end + + it "should get the correct resource" do + body = {:email => "email", :password => "pass", :name => "email"} + expect(a_post("/users").with(:body => body)).to have_been_made + end + + it "should return information about a created user" do + expect(@user.email).to eq("john@example.com") + end + end + + context "when bad request" do + it "should throw an exception" do + stub_post("/users", "error_already_exists", 409) + expect { + Gitlab.create_user("email", "pass") + }.to raise_error(Gitlab::Error::Conflict, "Server responded with code 409, message: 409 Already exists. Request URI: #{Gitlab.endpoint}/users") + end + end + end + + describe ".edit_user" do + before do + @options = { :name => "Roberto" } + stub_put("/users/1", "user").with(:body => @options) + @user = Gitlab.edit_user(1, @options) + end + + it "should get the correct resource" do + expect(a_put("/users/1").with(:body => @options)).to have_been_made + end + end + + describe ".session" do + after do + Gitlab.endpoint = 'https://api.example.com' + Gitlab.private_token = 'secret' + end + + before do + stub_request(:post, "#{Gitlab.endpoint}/session"). + to_return(:body => load_fixture('session'), :status => 200) + @session = Gitlab.session("email", "pass") + end + + context "when endpoint is not set" do + it "should raise Error::MissingCredentials" do + Gitlab.endpoint = nil + expect { + Gitlab.session("email", "pass") + }.to raise_error(Gitlab::Error::MissingCredentials, 'Please set an endpoint to API') + end + end + + context "when private_token is not set" do + it "should not raise Error::MissingCredentials" do + Gitlab.private_token = nil + expect { Gitlab.session("email", "pass") }.to_not raise_error + end + end + + context "when endpoint is set" do + it "should get the correct resource" do + expect(a_request(:post, "#{Gitlab.endpoint}/session")).to have_been_made + end + + it "should return information about a created session" do + expect(@session.email).to eq("john@example.com") + expect(@session.private_token).to eq("qEsq1pt6HJPaNciie3MG") + end + end + end + + describe ".ssh_keys" do + before do + stub_get("/user/keys", "keys") + @keys = Gitlab.ssh_keys + end + + it "should get the correct resource" do + expect(a_get("/user/keys")).to have_been_made + end + + it "should return an array of SSH keys" do + expect(@keys).to be_an Array + expect(@keys.first.title).to eq("narkoz@helium") + end + end + + describe ".ssh_key" do + before do + stub_get("/user/keys/1", "key") + @key = Gitlab.ssh_key(1) + end + + it "should get the correct resource" do + expect(a_get("/user/keys/1")).to have_been_made + end + + it "should return information about an SSH key" do + expect(@key.title).to eq("narkoz@helium") + end + end + + describe ".create_ssh_key" do + before do + stub_post("/user/keys", "key") + @key = Gitlab.create_ssh_key("title", "body") + end + + it "should get the correct resource" do + body = {:title => "title", :key => "body"} + expect(a_post("/user/keys").with(:body => body)).to have_been_made + end + + it "should return information about a created SSH key" do + expect(@key.title).to eq("narkoz@helium") + end + end + + describe ".delete_ssh_key" do + before do + stub_delete("/user/keys/1", "key") + @key = Gitlab.delete_ssh_key(1) + end + + it "should get the correct resource" do + expect(a_delete("/user/keys/1")).to have_been_made + end + + it "should return information about a deleted SSH key" do + expect(@key.title).to eq("narkoz@helium") + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/objectified_hash_spec.rb b/lib/gitlab-cli/spec/gitlab/objectified_hash_spec.rb new file mode 100644 index 000000000..db45711df --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/objectified_hash_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe Gitlab::ObjectifiedHash do + before do + @hash = {a: 1, b: 2} + @oh = Gitlab::ObjectifiedHash.new @hash + end + + it "should objectify hash" do + expect(@oh.a).to eq(@hash[:a]) + expect(@oh.b).to eq(@hash[:b]) + end + + describe "#to_hash" do + it "should return an original hash" do + expect(@oh.to_hash).to eq(@hash) + end + + it "should have an alias #to_h" do + expect(@oh.respond_to?(:to_h)).to be_truthy + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab/request_spec.rb b/lib/gitlab-cli/spec/gitlab/request_spec.rb new file mode 100644 index 000000000..869c2e964 --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab/request_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe Gitlab::Request do + it { should respond_to :get } + it { should respond_to :post } + it { should respond_to :put } + it { should respond_to :delete } + + describe ".default_options" do + it "should have default values" do + default_options = Gitlab::Request.default_options + expect(default_options).to be_a Hash + expect(default_options[:parser]).to be_a Proc + expect(default_options[:format]).to eq(:json) + expect(default_options[:headers]).to eq({'Accept' => 'application/json'}) + expect(default_options[:default_params]).to be_nil + end + end + + describe ".parse" do + it "should return ObjectifiedHash" do + body = JSON.unparse({a: 1, b: 2}) + expect(Gitlab::Request.parse(body)).to be_an Gitlab::ObjectifiedHash + end + end + + describe "#set_request_defaults" do + context "when endpoint is not set" do + it "should raise Error::MissingCredentials" do + expect { + Gitlab::Request.new.set_request_defaults(nil, 1234000) + }.to raise_error(Gitlab::Error::MissingCredentials, 'Please set an endpoint to API') + end + end + + context "when endpoint is set" do + it "should set base_uri" do + Gitlab::Request.new.set_request_defaults('http://rabbit-hole.example.org', 1234000) + expect(Gitlab::Request.base_uri).to eq("http://rabbit-hole.example.org") + end + + it "should set default_params" do + Gitlab::Request.new.set_request_defaults('http://rabbit-hole.example.org', 1234000, 'sudoer') + expect(Gitlab::Request.default_params).to eq({:sudo => 'sudoer'}) + end + end + end +end diff --git a/lib/gitlab-cli/spec/gitlab_spec.rb b/lib/gitlab-cli/spec/gitlab_spec.rb new file mode 100644 index 000000000..f037e70aa --- /dev/null +++ b/lib/gitlab-cli/spec/gitlab_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe Gitlab do + after { Gitlab.reset } + + describe ".client" do + it "should be a Gitlab::Client" do + expect(Gitlab.client).to be_a Gitlab::Client + end + end + + describe ".actions" do + it "should return an array of client methods" do + actions = Gitlab.actions + expect(actions).to be_an Array + expect(actions.first).to be_a Symbol + expect(actions.sort.first).to match(/add_/) + end + end + + describe ".endpoint=" do + it "should set endpoint" do + Gitlab.endpoint = 'https://api.example.com' + expect(Gitlab.endpoint).to eq('https://api.example.com') + end + end + + describe ".private_token=" do + it "should set private_token" do + Gitlab.private_token = 'secret' + expect(Gitlab.private_token).to eq('secret') + end + end + + describe ".sudo=" do + it "should set sudo" do + Gitlab.sudo = 'user' + expect(Gitlab.sudo).to eq('user') + end + end + + describe ".user_agent" do + it "should return default user_agent" do + expect(Gitlab.user_agent).to eq(Gitlab::Configuration::DEFAULT_USER_AGENT) + end + end + + describe ".user_agent=" do + it "should set user_agent" do + Gitlab.user_agent = 'Custom User Agent' + expect(Gitlab.user_agent).to eq('Custom User Agent') + end + end + + describe ".configure" do + Gitlab::Configuration::VALID_OPTIONS_KEYS.each do |key| + it "should set #{key}" do + Gitlab.configure do |config| + config.send("#{key}=", key) + expect(Gitlab.send(key)).to eq(key) + end + end + end + end +end diff --git a/lib/gitlab-cli/spec/spec_helper.rb b/lib/gitlab-cli/spec/spec_helper.rb new file mode 100644 index 000000000..28df28be2 --- /dev/null +++ b/lib/gitlab-cli/spec/spec_helper.rb @@ -0,0 +1,74 @@ +require 'rspec' +require 'webmock/rspec' + +require File.expand_path('../../lib/gitlab', __FILE__) +require File.expand_path('../../lib/gitlab/cli', __FILE__) + +def capture_output + out = StringIO.new + $stdout = out + $stderr = out + yield + $stdout = STDOUT + $stderr = STDERR + out.string +end + +def load_fixture(name) + File.new(File.dirname(__FILE__) + "/fixtures/#{name}.json") +end + +RSpec.configure do |config| + config.before(:all) do + Gitlab.endpoint = 'https://api.example.com' + Gitlab.private_token = 'secret' + end +end + +# GET +def stub_get(path, fixture) + stub_request(:get, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). + to_return(:body => load_fixture(fixture)) +end + +def a_get(path) + a_request(:get, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) +end + +# POST +def stub_post(path, fixture, status_code=200) + stub_request(:post, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). + to_return(:body => load_fixture(fixture), :status => status_code) +end + +def a_post(path) + a_request(:post, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) +end + +# PUT +def stub_put(path, fixture) + stub_request(:put, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). + to_return(:body => load_fixture(fixture)) +end + +def a_put(path) + a_request(:put, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) +end + +# DELETE +def stub_delete(path, fixture) + stub_request(:delete, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}). + to_return(:body => load_fixture(fixture)) +end + +def a_delete(path) + a_request(:delete, "#{Gitlab.endpoint}#{path}"). + with(:headers => {'PRIVATE-TOKEN' => Gitlab.private_token}) +end diff --git a/lib/redmine/scm/adapters/gitlab_adapter.rb b/lib/redmine/scm/adapters/gitlab_adapter.rb new file mode 100644 index 000000000..cad6583f6 --- /dev/null +++ b/lib/redmine/scm/adapters/gitlab_adapter.rb @@ -0,0 +1,287 @@ +#coding=utf-8 +# +require 'redmine/scm/adapters/abstract_adapter' +require 'base64' + +module Redmine + module Scm + module Adapters + + class GitlabAdapter < AbstractAdapter + + class GitBranch < Branch + attr_accessor :is_default + end + + def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil) + super + @g = Gitlab.client + @project = 11 + @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding + end + + def path_encoding + @path_encoding + end + + def info + begin + Info.new(:root_url => url, :lastrev => lastrev('',nil)) + rescue + nil + end + end + + def branches + return @branches if @branches + @branches = [] + branches = @g.branches(@project) + branches.each do |line| + name = line.name + scmid = line.commit.id + bran = GitBranch.new(name) + bran.revision = scmid + bran.scmid = name + bran.is_default = true #TODO + @branches << bran + end + @branches.sort! + rescue ScmCommandAborted + nil + end + + def tags + return @tags if @tags + tags = @g.tags(@project) + @tags = [] + tags.each do |tag| + @tags << tag.name + end + rescue ScmCommandAborted + nil + end + + def default_branch + bras = self.branches + return nil if bras.nil? + default_bras = bras.select{|x| x.is_default == true} + return default_bras.first.to_s if ! default_bras.empty? + master_bras = bras.select{|x| x.to_s == 'master'} + master_bras.empty? ? bras.first.to_s : 'master' + end + + def entry(path=nil, identifier=nil) + parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?} + search_path = parts[0..-2].join('/') + search_name = parts[-1] + if search_path.blank? && search_name.blank? + # Root entry + Entry.new(:path => '', :kind => 'dir') + else + # Search for the entry in the parent directory + es = entries(search_path, identifier, + options = {:report_last_commit => false}) + es ? es.detect {|e| e.name == search_name} : nil + end + end + + def entries(path=nil, identifier=nil, options={}) + entries = Entries.new + trees = @g.trees(@project, path: path, ref_name: identifier) + trees.each do |tree| + entries << Entry.new({ + :name => tree.name, + :path => File.join(path,tree.name), + :kind => tree.type == 'tree' ? 'dir' : 'file', + :size => nil, + :lastrev => nil + }) + end + entries.sort_by_name + rescue ScmCommandAborted + nil + end + + def lastrev(path, rev) + return nil if path.nil? + cmd_args = %w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1| + cmd_args << rev if rev + cmd_args << "--" << path unless path.empty? + lines = [] + git_cmd(cmd_args) { |io| lines = io.readlines } + begin + id = lines[0].split[1] + author = lines[1].match('Author:\s+(.*)$')[1] + time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1]) + + Revision.new({ + :identifier => id, + :scmid => id, + :author => author, + :time => time, + :message => nil, + :paths => nil + }) + rescue NoMethodError => e + logger.error("The revision '#{path}' has a wrong format") + return nil + end + rescue ScmCommandAborted + nil + end + + def revisions(path, identifier_from, identifier_to, options={}) + revs = Revisions.new + cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents --stdin| + cmd_args << "--reverse" if options[:reverse] + cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit] + cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) if path && !path.empty? + revisions = [] + if identifier_from || identifier_to + revisions << "" + revisions[0] << "#{identifier_from}.." if identifier_from + revisions[0] << "#{identifier_to}" if identifier_to + else + unless options[:includes].blank? + revisions += options[:includes] + end + unless options[:excludes].blank? + revisions += options[:excludes].map{|r| "^#{r}"} + end + end + + + commits = @g.commits(@project, {ref_name: identifier_to}) + commits.each do |commit| + revision = Revision.new({ + :identifier => commit.id, + :scmid => commit.id, + :author => commit.author_name, + :time => Time.parse(commit.created_at), + :message => commit.message, + :paths => nil, + :parents => nil + }) + revs << revision + end + + revs + rescue ScmCommandAborted => e + err_msg = "git log error: #{e.message}" + logger.error(err_msg) + if block_given? + raise CommandFailed, err_msg + else + revs + end + end + + def diff(path, identifier_from, identifier_to=nil) + path ||= '' + cmd_args = [] + if identifier_to + cmd_args << "diff" << "--no-color" << identifier_to << identifier_from + else + cmd_args << "show" << "--no-color" << identifier_from + end + cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) unless path.empty? + diff = [] + git_cmd(cmd_args) do |io| + io.each_line do |line| + diff << line + end + end + diff + rescue ScmCommandAborted + nil + end + + def annotate(path, identifier=nil) + identifier = 'HEAD' if identifier.blank? + cmd_args = %w|blame| + cmd_args << "-p" << identifier << "--" << scm_iconv(@path_encoding, 'UTF-8', path) + blame = Annotate.new + content = nil + git_cmd(cmd_args) { |io| io.binmode; content = io.read } + # git annotates binary files + return nil if content.is_binary_data? + identifier = '' + # git shows commit author on the first occurrence only + authors_by_commit = {} + content.split("\n").each do |line| + if line =~ /^([0-9a-f]{39,40})\s.*/ + identifier = $1 + elsif line =~ /^author (.+)/ + authors_by_commit[identifier] = $1.strip + elsif line =~ /^\t(.*)/ + blame.add_line($1, Revision.new( + :identifier => identifier, + :revision => identifier, + :scmid => identifier, + :author => authors_by_commit[identifier] + )) + identifier = '' + author = '' + end + end + blame + rescue ScmCommandAborted + nil + end + + def cat(path, identifier=nil) + if identifier.nil? + identifier = 'HEAD' + end + file = @g.files(@project, path, identifier) + cat = Base64.decode64 file.content + rescue ScmCommandAborted + nil + end + + def parse_commit(commits) + sum = {file: 0, insertion: 0, deletion: 0} + commits.split("\n").each do |commit| + if /(\d+)\s+?file/ =~ commit + sum[:file] += $1 .to_i + end + if /(\d+)\s+?insertion/ =~ commit + sum[:insertion] += $1.to_i + end + if /(\d+)\s+?deletion/ =~ commit + sum[:deletion] += $1.to_i + end + end + sum[:insertion] + sum[:deletion] + end + + def commits(authors, start_date, end_date, branch='master') + rs = [] + authors.each do |author| + cmd_args = %W|log #{branch} --pretty=tformat: --shortstat --author=#{author} --since=#{start_date} --until=#{end_date}| + commits = '' + git_cmd(cmd_args) do |io| + commits = io.read + end + logger.info "git log output for #{author} #{commits}" + rs << {author: author, num: parse_commit(commits)} + end + rs + end + + class Revision < Redmine::Scm::Adapters::Revision + # Returns the readable identifier + def format_identifier + identifier[0,8] + end + end + + def git_cmd(args, options = {}, &block) + logger.info "git cmd: #{args.join(' ')}" + end + private :git_cmd + end + + end + end +end diff --git a/lib/trustie.rb b/lib/trustie.rb index b6cec3c86..4f1f68fe1 100644 --- a/lib/trustie.rb +++ b/lib/trustie.rb @@ -1,2 +1,3 @@ require 'trustie/utils' require 'trustie/utils/image' +require 'trustie/gitlab/api' diff --git a/lib/trustie/gitlab/api.rb b/lib/trustie/gitlab/api.rb new file mode 100644 index 000000000..6c1993721 --- /dev/null +++ b/lib/trustie/gitlab/api.rb @@ -0,0 +1,35 @@ +#coding=utf-8 +# +# +module Trustie + module Gitlab + class Api + # attr_accessor :g + + def initialize(client=nil) + @g = client || ::Gitlab.client + end + + def trees(project_id) + @g.trees(project_id) + end + + def entries(project) + entries = [] + api = Trustie::Gitlab::Api.new + trees = api.trees(11) + trees.each do |tree| + entries << Redmine::Scm::Adapters::Entry.new({ + :name => tree.name, + :path => tree.id, + :kind => tree.type == 'tree' ? 'dir' : 'file', + :size => nil, + :lastrev => nil + }) + end + entries + end + + end + end +end diff --git a/lib/trustie/gitlab/helper.rb b/lib/trustie/gitlab/helper.rb new file mode 100644 index 000000000..e69de29bb diff --git a/spec/requests/gitlab_request_spec.rb b/spec/requests/gitlab_request_spec.rb new file mode 100644 index 000000000..05a94568b --- /dev/null +++ b/spec/requests/gitlab_request_spec.rb @@ -0,0 +1,13 @@ +require 'rails_helper' + +RSpec.describe "Gitlab request", :type => :request do + + describe "get repository files" do + it "参数正确,可以获取正确列表 " do + api = Trustie::Gitlab::Api.new + trees = api.trees(11) + expect(trees).to be_instance_of(Array) + end + end +end +