From dc20dd275fb15217b04431fa7f05b283ea03621c Mon Sep 17 00:00:00 2001 From: David Date: Fri, 15 Apr 2016 02:18:46 +0000 Subject: aiionx_sidekiq_log_patch --- lib/gitlab/sidekiq_middleware/arguments_logger.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/sidekiq_middleware/arguments_logger.rb b/lib/gitlab/sidekiq_middleware/arguments_logger.rb index 7813091ec7b..82a59a7a87e 100644 --- a/lib/gitlab/sidekiq_middleware/arguments_logger.rb +++ b/lib/gitlab/sidekiq_middleware/arguments_logger.rb @@ -2,7 +2,7 @@ module Gitlab module SidekiqMiddleware class ArgumentsLogger def call(worker, job, queue) - Sidekiq.logger.info "arguments: #{job['args']}" + Sidekiq.logger.info "arguments: #{JSON.dump(job['args'])}" yield end end -- cgit v1.2.1 From be414d4829463708e23b639fea9e6fe88863b1c5 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 1 Sep 2016 02:21:16 +0800 Subject: We don't need them --- lib/tasks/.gitkeep | 0 lib/tasks/ci/.gitkeep | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/tasks/.gitkeep delete mode 100644 lib/tasks/ci/.gitkeep (limited to 'lib') diff --git a/lib/tasks/.gitkeep b/lib/tasks/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/lib/tasks/ci/.gitkeep b/lib/tasks/ci/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 -- cgit v1.2.1 From 63e03dada7e754a92ca088c683f4189424ab34b1 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 21 Sep 2016 16:12:32 +0800 Subject: Make various trace methods take last_lines argument: So that we could read last few lines rather than read the entire file which could be huge. --- lib/gitlab/ci/trace_reader.rb | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 lib/gitlab/ci/trace_reader.rb (limited to 'lib') diff --git a/lib/gitlab/ci/trace_reader.rb b/lib/gitlab/ci/trace_reader.rb new file mode 100644 index 00000000000..37e51536e8f --- /dev/null +++ b/lib/gitlab/ci/trace_reader.rb @@ -0,0 +1,49 @@ +module Gitlab + module Ci + # This was inspired from: http://stackoverflow.com/a/10219411/1520132 + class TraceReader + BUFFER_SIZE = 4096 + + attr_accessor :path, :buffer_size + + def initialize(new_path, buffer_size: BUFFER_SIZE) + self.path = new_path + self.buffer_size = Integer(buffer_size) + end + + def read(last_lines: nil) + if last_lines + read_last_lines(last_lines) + else + File.read(path) + end + end + + def read_last_lines(max_lines) + File.open(path) do |file| + chunks = [] + pos = lines = 0 + max = file.size + + # We want an extra line to make sure fist line has full contents + while lines <= max_lines && pos < max + pos += buffer_size + + buf = if pos <= max + file.seek(-pos, IO::SEEK_END) + file.read(buffer_size) + else # Reached the head, read only left + file.seek(0) + file.read(buffer_size - (pos - max)) + end + + lines += buf.count("\n") + chunks.unshift(buf) + end + + chunks.join.lines.last(max_lines).join + end + end + end + end +end -- cgit v1.2.1 From fd51f19c978023160ad759676a0363c12aea3fc8 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Thu, 22 Sep 2016 13:56:43 +0100 Subject: API: disable rails session auth for non-GET/HEAD requests --- lib/api/helpers.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 714d4ea3dc6..8b8c4eb4d46 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -21,8 +21,11 @@ module API end # Check the Rails session for valid authentication details + # + # Until CSRF protection is added to the API, disallow this method for + # state-changing endpoints def find_user_from_warden - warden ? warden.authenticate : nil + warden.try(:authenticate) if request.get? || request.head? end def find_user_by_private_token -- cgit v1.2.1 From dffd33252f029901e33883935b20f6b0368d819b Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Sun, 25 Sep 2016 11:55:14 +0200 Subject: Move reply by email docs to a new location [ci skip] --- lib/tasks/gitlab/check.rake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 5f4a6bbfa35..2ae48a970ce 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -671,7 +671,7 @@ namespace :gitlab do "Enable mail_room in the init.d configuration." ) for_more_information( - "doc/incoming_email/README.md" + "doc/administration/reply_by_email.md" ) fix_and_rerun end @@ -690,7 +690,7 @@ namespace :gitlab do "Enable mail_room in your Procfile." ) for_more_information( - "doc/incoming_email/README.md" + "doc/administration/reply_by_email.md" ) fix_and_rerun end @@ -747,7 +747,7 @@ namespace :gitlab do "Check that the information in config/gitlab.yml is correct" ) for_more_information( - "doc/incoming_email/README.md" + "doc/administration/reply_by_email.md" ) fix_and_rerun end -- cgit v1.2.1 From 05745737c659098d3cc1e9ae0f8eedddac7b3603 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 26 Sep 2016 14:21:39 +0200 Subject: Explain the extra chmod --- lib/gitlab/workhorse.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index 5d33f98e89e..594439a5d4b 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -111,7 +111,7 @@ module Gitlab def write_secret bytes = SecureRandom.random_bytes(SECRET_LENGTH) File.open(secret_path, 'w:BINARY', 0600) do |f| - f.chmod(0600) + f.chmod(0600) # If the file already existed, the '0600' passed to 'open' above was a no-op. f.write(Base64.strict_encode64(bytes)) end end -- cgit v1.2.1 From 4c480be39b0862f41043e94a6dc5b943b6f8e8f0 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 12 Aug 2016 12:04:33 +0200 Subject: Prevent claiming associated model IDs via import and added relevant specs --- lib/gitlab/import_export/attribute_cleaner.rb | 13 +++++++++++++ lib/gitlab/import_export/project_tree_restorer.rb | 5 +++-- lib/gitlab/import_export/relation_factory.rb | 12 +++++++++--- 3 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 lib/gitlab/import_export/attribute_cleaner.rb (limited to 'lib') diff --git a/lib/gitlab/import_export/attribute_cleaner.rb b/lib/gitlab/import_export/attribute_cleaner.rb new file mode 100644 index 00000000000..c12b898a665 --- /dev/null +++ b/lib/gitlab/import_export/attribute_cleaner.rb @@ -0,0 +1,13 @@ +module Gitlab + module ImportExport + class AttributeCleaner + IGNORED_REFERENCES = Gitlab::ImportExport::RelationFactory::PROJECT_REFERENCES + Gitlab::ImportExport::RelationFactory::USER_REFERENCES + + def self.clean!(relation_hash:) + relation_hash.select! do |key, _value| + IGNORED_REFERENCES.include?(key) || !key.end_with?('_id') + end + end + end + end +end diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb index c7b3551b84c..35adcd8f0da 100644 --- a/lib/gitlab/import_export/project_tree_restorer.rb +++ b/lib/gitlab/import_export/project_tree_restorer.rb @@ -104,9 +104,10 @@ module Gitlab def create_relation(relation, relation_hash_list) relation_array = [relation_hash_list].flatten.map do |relation_hash| Gitlab::ImportExport::RelationFactory.create(relation_sym: relation.to_sym, - relation_hash: relation_hash.merge('project_id' => restored_project.id), + relation_hash: relation_hash, members_mapper: members_mapper, - user: @user) + user: @user, + project_id: restored_project.id) end relation_hash_list.is_a?(Array) ? relation_array : relation_array.first diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 354ccd64696..9300f789e1b 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -13,6 +13,8 @@ module Gitlab USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id].freeze + PROJECT_REFERENCES = %w[project_id source_project_id gl_project_id target_project_id].freeze + BUILD_MODELS = %w[Ci::Build commit_status].freeze IMPORTED_OBJECT_MAX_RETRIES = 5.freeze @@ -25,9 +27,9 @@ module Gitlab new(*args).create end - def initialize(relation_sym:, relation_hash:, members_mapper:, user:) + def initialize(relation_sym:, relation_hash:, members_mapper:, user:, project_id:) @relation_name = OVERRIDES[relation_sym] || relation_sym - @relation_hash = relation_hash.except('id', 'noteable_id') + @relation_hash = relation_hash.except('id', 'noteable_id').merge('project_id' => project_id) @members_mapper = members_mapper @user = user @imported_object_retries = 0 @@ -153,7 +155,11 @@ module Gitlab end def parsed_relation_hash - @parsed_relation_hash ||= @relation_hash.reject { |k, _v| !relation_class.attribute_method?(k) } + @parsed_relation_hash ||= begin + Gitlab::ImportExport::AttributeCleaner.clean!(relation_hash: @relation_hash) + + @relation_hash.reject { |k, _v| !relation_class.attribute_method?(k) } + end end def set_st_diffs -- cgit v1.2.1 From 9e0b7c630f2fc64805062d0c7e02fd6092631071 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 27 Sep 2016 16:12:08 +0200 Subject: updated attribute cleaner to use allowed keyword and reject attributes --- lib/gitlab/import_export/attribute_cleaner.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/import_export/attribute_cleaner.rb b/lib/gitlab/import_export/attribute_cleaner.rb index c12b898a665..b9e4042220a 100644 --- a/lib/gitlab/import_export/attribute_cleaner.rb +++ b/lib/gitlab/import_export/attribute_cleaner.rb @@ -1,11 +1,11 @@ module Gitlab module ImportExport class AttributeCleaner - IGNORED_REFERENCES = Gitlab::ImportExport::RelationFactory::PROJECT_REFERENCES + Gitlab::ImportExport::RelationFactory::USER_REFERENCES + ALLOWED_REFERENCES = RelationFactory::PROJECT_REFERENCES + RelationFactory::USER_REFERENCES def self.clean!(relation_hash:) - relation_hash.select! do |key, _value| - IGNORED_REFERENCES.include?(key) || !key.end_with?('_id') + relation_hash.reject! do |key, _value| + key.end_with?('_id') && !ALLOWED_REFERENCES.include?(key) end end end -- cgit v1.2.1 From 924a6b7d33a245845071894de8d46d77bd44b52e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 28 Jul 2016 19:38:32 +0200 Subject: New AccessRequestsFinder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/access_requests.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb index 9d1d9058996..7b9de7c9598 100644 --- a/lib/api/access_requests.rb +++ b/lib/api/access_requests.rb @@ -16,9 +16,9 @@ module API # GET /projects/:id/access_requests get ":id/access_requests" do source = find_source(source_type, params[:id]) - authorize_admin_source!(source_type, source) - access_requesters = paginate(source.requesters.includes(:user)) + access_requesters = AccessRequestsFinder.new(source).execute!(current_user) + access_requesters = paginate(access_requesters.includes(:user)) present access_requesters.map(&:user), with: Entities::AccessRequester, source: source end -- cgit v1.2.1 From ec0061a95cbba02286b2c143048c93d8f26ff5f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 16 Sep 2016 17:54:21 +0200 Subject: Allow Member.add_user to handle access requesters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes include: - Ensure Member.add_user is not called directly when not necessary - New GroupMember.add_users_to_group to have the same abstraction level as for Project - Refactor Member.add_user to take a source instead of an array of members - Fix Rubocop offenses - Always use Project#add_user instead of project.team.add_user - Factorize users addition as members in Member.add_users_to_source - Make access_level a keyword argument in GroupMember.add_users_to_group and ProjectMember.add_users_to_projects - Destroy any requester before adding them as a member - Improve the way we handle access requesters in Member.add_user Instead of removing the requester and creating a new member, we now simply accepts their access request. This way, they will receive a "access request granted" email. - Fix error that was previously silently ignored - Stop raising when access level is invalid in Member, let Rails validation do their work Signed-off-by: Rémy Coutable --- lib/api/members.rb | 17 ++--------------- lib/gitlab/access.rb | 4 ++++ 2 files changed, 6 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/api/members.rb b/lib/api/members.rb index 37f0a6512f4..a18ce769e29 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -59,13 +59,6 @@ module API authorize_admin_source!(source_type, source) required_attributes! [:user_id, :access_level] - access_requester = source.requesters.find_by(user_id: params[:user_id]) - if access_requester - # We pass current_user = access_requester so that the requester doesn't - # receive a "access denied" email - ::Members::DestroyService.new(access_requester, access_requester.user).execute - end - member = source.members.find_by(user_id: params[:user_id]) # This is to ensure back-compatibility but 409 behavior should be used @@ -73,18 +66,12 @@ module API conflict!('Member already exists') if source_type == 'group' && member unless member - source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at]) - member = source.members.find_by(user_id: params[:user_id]) + member = source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at]) end - if member + if member.persisted? && member.valid? present member.user, with: Entities::Member, member: member else - # Since `source.add_user` doesn't return a member object, we have to - # build a new one and populate its errors in order to render them. - member = source.members.build(attributes_for_keys([:user_id, :access_level, :expires_at])) - member.valid? # populate the errors - # This is to ensure back-compatibility but 400 behavior should be used # for all validation errors in 9.0! render_api_error!('Access level is not known', 422) if member.errors.key?(:access_level) diff --git a/lib/gitlab/access.rb b/lib/gitlab/access.rb index a533bac2692..9b484a2ecfd 100644 --- a/lib/gitlab/access.rb +++ b/lib/gitlab/access.rb @@ -53,6 +53,10 @@ module Gitlab } end + def sym_options_with_owner + sym_options.merge(owner: OWNER) + end + def protection_options { "Not protected: Both developers and masters can push new commits, force push, or delete the branch." => PROTECTION_NONE, -- cgit v1.2.1 From 93d849beaebb00dc4dcb6cb5ffa4721883e0da51 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Thu, 22 Sep 2016 17:31:18 -0300 Subject: Expose project share expiration_date field on API --- lib/api/entities.rb | 2 +- lib/api/projects.rb | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 92a6f29adb0..29ad9f3565a 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -343,7 +343,7 @@ module API end class ProjectGroupLink < Grape::Entity - expose :id, :project_id, :group_id, :group_access + expose :id, :project_id, :group_id, :group_access, :expires_at end class Todo < Grape::Entity diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 6d99617b56f..680055c95eb 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -393,23 +393,24 @@ module API # Share project with group # # Parameters: - # id (required) - The ID of a project - # group_id (required) - The ID of a group + # id (required) - The ID of a project + # group_id (required) - The ID of a group # group_access (required) - Level of permissions for sharing + # expires_at (optional) - Share expiration date # # Example Request: # POST /projects/:id/share post ":id/share" do authorize! :admin_project, user_project required_attributes! [:group_id, :group_access] + attrs = attributes_for_keys [:group_id, :group_access, :expires_at] unless user_project.allowed_to_share_with_group? return render_api_error!("The project sharing with group is disabled", 400) end - link = user_project.project_group_links.new - link.group_id = params[:group_id] - link.group_access = params[:group_access] + link = user_project.project_group_links.new(attrs) + if link.save present link, with: Entities::ProjectGroupLink else -- cgit v1.2.1 From e3f12e975d59b0606b8f1365e21814b34ea83767 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Wed, 28 Sep 2016 19:38:43 -0600 Subject: Remove Flog as we use a Rubocop that does its job. --- lib/tasks/flog.rake | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 lib/tasks/flog.rake (limited to 'lib') diff --git a/lib/tasks/flog.rake b/lib/tasks/flog.rake deleted file mode 100644 index 3bfe999ae74..00000000000 --- a/lib/tasks/flog.rake +++ /dev/null @@ -1,25 +0,0 @@ -desc 'Code complexity analyze via flog' -task :flog do - output = %x(bundle exec flog -m app/ lib/gitlab) - exit_code = 0 - minimum_score = 70 - output = output.lines - - # Skip total complexity score - output.shift - - # Skip some trash info - output.shift - - output.each do |line| - score, method = line.split(" ") - score = score.to_i - - if score > minimum_score - exit_code = 1 - puts "High complexity in #{method}. Score: #{score}" - end - end - - exit exit_code -end -- cgit v1.2.1 From e80e4cb8b97a3865b7e3c551a856a53d98cccf75 Mon Sep 17 00:00:00 2001 From: Guilherme Salazar Date: Fri, 23 Sep 2016 20:43:57 -0300 Subject: expose pipeline data in builds API add pipeline ref, sha, and status to the build API response add tests of build API (pipeline data) change API documentation for builds API log change to builds API in CHANGELOG CHANGELOG: add reference to pull request and contributor's name --- lib/api/entities.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 0adc118ba27..409a4c7cc07 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -545,6 +545,10 @@ module API expose :filename, :size end + class PipelineBasic < Grape::Entity + expose :id, :sha, :ref, :status + end + class Build < Grape::Entity expose :id, :status, :stage, :name, :ref, :tag, :coverage expose :created_at, :started_at, :finished_at @@ -552,6 +556,7 @@ module API expose :artifacts_file, using: BuildArtifactFile, if: -> (build, opts) { build.artifacts? } expose :commit, with: RepoCommit expose :runner, with: Runner + expose :pipeline, with: PipelineBasic end class Trigger < Grape::Entity @@ -562,8 +567,8 @@ module API expose :key, :value end - class Pipeline < Grape::Entity - expose :id, :status, :ref, :sha, :before_sha, :tag, :yaml_errors + class Pipeline < PipelineBasic + expose :before_sha, :tag, :yaml_errors expose :user, with: Entities::UserBasic expose :created_at, :updated_at, :started_at, :finished_at, :committed_at -- cgit v1.2.1 From eb4d3eef90770aa14c804f9d186afc0bcc55c0a0 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 29 Sep 2016 10:48:24 +0200 Subject: Remove duplicate VersionInfo class This was brought over during the CI merge and already exists at `lib/gitlab/version_info.rb`. --- lib/ci/version_info.rb | 52 -------------------------------------------------- 1 file changed, 52 deletions(-) delete mode 100644 lib/ci/version_info.rb (limited to 'lib') diff --git a/lib/ci/version_info.rb b/lib/ci/version_info.rb deleted file mode 100644 index 2a87c91db5e..00000000000 --- a/lib/ci/version_info.rb +++ /dev/null @@ -1,52 +0,0 @@ -class VersionInfo - include Comparable - - attr_reader :major, :minor, :patch - - def self.parse(str) - if str && m = str.match(/(\d+)\.(\d+)\.(\d+)/) - VersionInfo.new(m[1].to_i, m[2].to_i, m[3].to_i) - else - VersionInfo.new - end - end - - def initialize(major = 0, minor = 0, patch = 0) - @major = major - @minor = minor - @patch = patch - end - - def <=>(other) - return unless other.is_a? VersionInfo - return unless valid? && other.valid? - - if other.major < @major - 1 - elsif @major < other.major - -1 - elsif other.minor < @minor - 1 - elsif @minor < other.minor - -1 - elsif other.patch < @patch - 1 - elsif @patch < other.patch - -1 - else - 0 - end - end - - def to_s - if valid? - "%d.%d.%d" % [@major, @minor, @patch] - else - "Unknown" - end - end - - def valid? - @major >= 0 && @minor >= 0 && @patch >= 0 && @major + @minor + @patch > 0 - end -end -- cgit v1.2.1 From 26678d8ea3f05b5508c0ebc80cb2bc40e0a66556 Mon Sep 17 00:00:00 2001 From: Patricio Cano Date: Thu, 29 Sep 2016 08:18:15 -0500 Subject: Fix race condition that can be triggered if the token expires right after we retrieve it, but before we can set the new expiry time. --- lib/gitlab/lfs_token.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/lfs_token.rb b/lib/gitlab/lfs_token.rb index 7b3bbcf6a32..5f67e97fa2a 100644 --- a/lib/gitlab/lfs_token.rb +++ b/lib/gitlab/lfs_token.rb @@ -20,13 +20,8 @@ module Gitlab def token Gitlab::Redis.with do |redis| token = redis.get(redis_key) - - if token - redis.expire(redis_key, EXPIRY_TIME) - else - token = Devise.friendly_token(TOKEN_LENGTH) - redis.set(redis_key, token, ex: EXPIRY_TIME) - end + token ||= Devise.friendly_token(TOKEN_LENGTH) + redis.set(redis_key, token, ex: EXPIRY_TIME) token end -- cgit v1.2.1 From 59157c0423d34c1f20c446548df540d103bda939 Mon Sep 17 00:00:00 2001 From: DJ Mountney Date: Tue, 27 Sep 2016 17:56:02 -0700 Subject: Expose the Koding application settings in the API This will allow the Koding app to enable the integration itself once is has authorized an admin user using the application secrets. --- lib/api/entities.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index c5dc8b22f60..04437322ec1 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -494,6 +494,8 @@ module API expose :after_sign_out_path expose :container_registry_token_expire_delay expose :repository_storage + expose :koding_enabled + expose :koding_url end class Release < Grape::Entity -- cgit v1.2.1 From 56259155d5a0ecfbbafb7319651495582504cfb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 29 Sep 2016 16:55:55 +0200 Subject: Small improvements thanks to Robert's feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/milestones.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 7a0cb7c99f3..9b73f6826cf 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -108,8 +108,7 @@ module API finder_params = { project_id: user_project.id, - milestone_title: @milestone.title, - state: 'all' + milestone_title: @milestone.title } issues = IssuesFinder.new(current_user, finder_params).execute -- cgit v1.2.1 From 5dbf1f487188e73bc5eb556c7b955088ff4676e5 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 21 Sep 2016 09:46:13 -0300 Subject: Use `Module#prepend` instead of `alias_method_chain` --- lib/banzai/filter/task_list_filter.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/task_list_filter.rb b/lib/banzai/filter/task_list_filter.rb index 66608c9859c..4efbcaf5c7f 100644 --- a/lib/banzai/filter/task_list_filter.rb +++ b/lib/banzai/filter/task_list_filter.rb @@ -10,19 +10,21 @@ module Banzai # task_list gem. # # See https://github.com/github/task_list/pull/60 - class TaskListFilter < TaskList::Filter - def add_css_class_with_fix(node, *new_class_names) + module ClassNamesFilter + def add_css_class(node, *new_class_names) if new_class_names.include?('task-list') # Don't add class to all lists return elsif new_class_names.include?('task-list-item') - add_css_class_without_fix(node.parent, 'task-list') + super(node.parent, 'task-list') end - add_css_class_without_fix(node, *new_class_names) + super(node, *new_class_names) end + end - alias_method_chain :add_css_class, :fix + class TaskListFilter < TaskList::Filter + prepend ClassNamesFilter end end end -- cgit v1.2.1 From 375072aa279f8e89a095b957005ae03ee1b0a7ff Mon Sep 17 00:00:00 2001 From: Katarzyna Kobierska Date: Fri, 9 Sep 2016 10:51:44 +0200 Subject: Add missing values to linter --- lib/ci/gitlab_ci_yaml_processor.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 0369e80312a..b61388d6ea7 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -59,6 +59,8 @@ module Ci tag_list: job[:tags] || [], name: job[:name].to_s, allow_failure: job[:allow_failure] || false, + only: job[:only], + except: job[:except], when: job[:when] || 'on_success', environment: job[:environment_name], yaml_variables: yaml_variables(name), -- cgit v1.2.1 From 7dfb204ef9d343888e2fd8327c5a5348b98a76ce Mon Sep 17 00:00:00 2001 From: Katarzyna Kobierska Date: Tue, 20 Sep 2016 15:19:55 +0200 Subject: Expose jobs to view --- lib/ci/gitlab_ci_yaml_processor.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index b61388d6ea7..2fd1fced65c 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -4,7 +4,7 @@ module Ci include Gitlab::Ci::Config::Node::LegacyValidationHelpers - attr_reader :path, :cache, :stages + attr_reader :path, :cache, :stages, :jobs def initialize(config, path = nil) @ci_config = Gitlab::Ci::Config.new(config) @@ -59,8 +59,6 @@ module Ci tag_list: job[:tags] || [], name: job[:name].to_s, allow_failure: job[:allow_failure] || false, - only: job[:only], - except: job[:except], when: job[:when] || 'on_success', environment: job[:environment_name], yaml_variables: yaml_variables(name), -- cgit v1.2.1 From 52ee85e7bf35d372285d70cc93016854774839b1 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 30 Sep 2016 12:27:43 +0200 Subject: Initialize Redis pool in single-threaded context This side-steps the need for mutexes and whatnot. --- lib/gitlab/redis.rb | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/redis.rb b/lib/gitlab/redis.rb index 69c4ef721d5..3faab937726 100644 --- a/lib/gitlab/redis.rb +++ b/lib/gitlab/redis.rb @@ -11,13 +11,6 @@ module Gitlab DEFAULT_REDIS_URL = 'redis://localhost:6379' CONFIG_FILE = File.expand_path('../../config/resque.yml', __dir__) - # To be thread-safe we must be careful when writing the class instance - # variables @_raw_config and @pool. Because @pool depends on @_raw_config we need two - # mutexes to prevent deadlock. - RAW_CONFIG_MUTEX = Mutex.new - POOL_MUTEX = Mutex.new - private_constant :RAW_CONFIG_MUTEX, :POOL_MUTEX - class << self # Do NOT cache in an instance variable. Result may be mutated by caller. def params @@ -31,24 +24,19 @@ module Gitlab end def with - if @pool.nil? - POOL_MUTEX.synchronize do - @pool = ConnectionPool.new { ::Redis.new(params) } - end - end + @pool ||= ConnectionPool.new { ::Redis.new(params) } @pool.with { |redis| yield redis } end def _raw_config return @_raw_config if defined?(@_raw_config) - RAW_CONFIG_MUTEX.synchronize do - begin - @_raw_config = File.read(CONFIG_FILE).freeze - rescue Errno::ENOENT - @_raw_config = false - end + begin + @_raw_config = File.read(CONFIG_FILE).freeze + rescue Errno::ENOENT + @_raw_config = false end + @_raw_config end end -- cgit v1.2.1 From 958d9f11e80633f7120a782900fe1f78b3dbebea Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 29 Sep 2016 17:17:22 +0200 Subject: fix export project file permissions issue --- lib/gitlab/import_export/command_line_util.rb | 9 ++++++++- lib/gitlab/import_export/file_importer.rb | 2 +- lib/gitlab/import_export/project_tree_saver.rb | 4 +++- lib/gitlab/import_export/repo_restorer.rb | 2 +- lib/gitlab/import_export/repo_saver.rb | 2 +- lib/gitlab/import_export/version_saver.rb | 4 +++- lib/gitlab/import_export/wiki_repo_saver.rb | 2 +- 7 files changed, 18 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb index e522a0fc8f6..f00c7460e82 100644 --- a/lib/gitlab/import_export/command_line_util.rb +++ b/lib/gitlab/import_export/command_line_util.rb @@ -1,6 +1,8 @@ module Gitlab module ImportExport module CommandLineUtil + DEFAULT_MODE = 0700 + def tar_czf(archive:, dir:) tar_with_options(archive: archive, dir: dir, options: 'czf') end @@ -21,6 +23,11 @@ module Gitlab execute(%W(#{Gitlab.config.gitlab_shell.path}/bin/create-hooks) + repository_storage_paths_args) end + def mkdir_p(path) + FileUtils.mkdir_p(path, mode: DEFAULT_MODE) + FileUtils.chmod(DEFAULT_MODE, path) + end + private def tar_with_options(archive:, dir:, options:) @@ -45,7 +52,7 @@ module Gitlab # if we are copying files, create the destination folder destination_folder = File.file?(source) ? File.dirname(destination) : destination - FileUtils.mkdir_p(destination_folder) + mkdir_p(destination_folder) FileUtils.copy_entry(source, destination) true end diff --git a/lib/gitlab/import_export/file_importer.rb b/lib/gitlab/import_export/file_importer.rb index eca6e5b6d51..113895ba22c 100644 --- a/lib/gitlab/import_export/file_importer.rb +++ b/lib/gitlab/import_export/file_importer.rb @@ -15,7 +15,7 @@ module Gitlab end def import - FileUtils.mkdir_p(@shared.export_path) + mkdir_p(@shared.export_path) wait_for_archived_file do decompress_archive diff --git a/lib/gitlab/import_export/project_tree_saver.rb b/lib/gitlab/import_export/project_tree_saver.rb index 9153088e966..2fbf437ec26 100644 --- a/lib/gitlab/import_export/project_tree_saver.rb +++ b/lib/gitlab/import_export/project_tree_saver.rb @@ -1,6 +1,8 @@ module Gitlab module ImportExport class ProjectTreeSaver + include Gitlab::ImportExport::CommandLineUtil + attr_reader :full_path def initialize(project:, shared:) @@ -10,7 +12,7 @@ module Gitlab end def save - FileUtils.mkdir_p(@shared.export_path) + mkdir_p(@shared.export_path) File.write(full_path, project_json_tree) true diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb index d1e33ea8678..48a9a6fa5e2 100644 --- a/lib/gitlab/import_export/repo_restorer.rb +++ b/lib/gitlab/import_export/repo_restorer.rb @@ -12,7 +12,7 @@ module Gitlab def restore return true unless File.exist?(@path_to_bundle) - FileUtils.mkdir_p(path_to_repo) + mkdir_p(path_to_repo) git_unbundle(repo_path: path_to_repo, bundle_path: @path_to_bundle) && repo_restore_hooks rescue => e diff --git a/lib/gitlab/import_export/repo_saver.rb b/lib/gitlab/import_export/repo_saver.rb index 331e14021e6..a7028a32570 100644 --- a/lib/gitlab/import_export/repo_saver.rb +++ b/lib/gitlab/import_export/repo_saver.rb @@ -20,7 +20,7 @@ module Gitlab private def bundle_to_disk - FileUtils.mkdir_p(@shared.export_path) + mkdir_p(@shared.export_path) git_bundle(repo_path: path_to_repo, bundle_path: @full_path) rescue => e @shared.error(e) diff --git a/lib/gitlab/import_export/version_saver.rb b/lib/gitlab/import_export/version_saver.rb index 9b642d740b7..7cf88298642 100644 --- a/lib/gitlab/import_export/version_saver.rb +++ b/lib/gitlab/import_export/version_saver.rb @@ -1,12 +1,14 @@ module Gitlab module ImportExport class VersionSaver + include Gitlab::ImportExport::CommandLineUtil + def initialize(shared:) @shared = shared end def save - FileUtils.mkdir_p(@shared.export_path) + mkdir_p(@shared.export_path) File.write(version_file, Gitlab::ImportExport.version, mode: 'w') rescue => e diff --git a/lib/gitlab/import_export/wiki_repo_saver.rb b/lib/gitlab/import_export/wiki_repo_saver.rb index 6107420e4dd..1e6722a7bba 100644 --- a/lib/gitlab/import_export/wiki_repo_saver.rb +++ b/lib/gitlab/import_export/wiki_repo_saver.rb @@ -9,7 +9,7 @@ module Gitlab end def bundle_to_disk(full_path) - FileUtils.mkdir_p(@shared.export_path) + mkdir_p(@shared.export_path) git_bundle(repo_path: path_to_repo, bundle_path: full_path) rescue => e @shared.error(e) -- cgit v1.2.1 From 88c1db4a2b365a75a43c46a0bed58ca1f8069408 Mon Sep 17 00:00:00 2001 From: Jared Deckard Date: Fri, 30 Sep 2016 16:38:02 -0500 Subject: Replace talk_list patch with a patched fork --- lib/banzai/filter/task_list_filter.rb | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/task_list_filter.rb b/lib/banzai/filter/task_list_filter.rb index 4efbcaf5c7f..9fa5f589f3e 100644 --- a/lib/banzai/filter/task_list_filter.rb +++ b/lib/banzai/filter/task_list_filter.rb @@ -2,29 +2,7 @@ require 'task_list/filter' module Banzai module Filter - # Work around a bug in the default TaskList::Filter that adds a `task-list` - # class to every list element, regardless of whether or not it contains a - # task list. - # - # This is a (hopefully) temporary fix, pending a new release of the - # task_list gem. - # - # See https://github.com/github/task_list/pull/60 - module ClassNamesFilter - def add_css_class(node, *new_class_names) - if new_class_names.include?('task-list') - # Don't add class to all lists - return - elsif new_class_names.include?('task-list-item') - super(node.parent, 'task-list') - end - - super(node, *new_class_names) - end - end - class TaskListFilter < TaskList::Filter - prepend ClassNamesFilter end end end -- cgit v1.2.1 From dd088d14bb51e9c0baee013b9d3b21a12a768051 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Tue, 13 Sep 2016 20:55:00 +0200 Subject: GrapeDSL for Keys endpoint --- lib/api/keys.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/api/keys.rb b/lib/api/keys.rb index 2b723b79504..767f27ef334 100644 --- a/lib/api/keys.rb +++ b/lib/api/keys.rb @@ -4,10 +4,9 @@ module API before { authenticate! } resource :keys do - # Get single ssh key by id. Only available to admin users. - # - # Example Request: - # GET /keys/:id + desc 'Get single ssh key by id. Only available to admin users' do + success Entities::SSHKeyWithUser + end get ":id" do authenticated_as_admin! -- cgit v1.2.1 From d291ea97e0e944610c36469757a10b342ab0e05c Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Fri, 12 Aug 2016 09:27:52 +0200 Subject: GrapeDSL for Award Emoji endpoints --- lib/api/award_emoji.rb | 64 ++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) (limited to 'lib') diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb index 2461a783ea8..e9ccba3b465 100644 --- a/lib/api/award_emoji.rb +++ b/lib/api/award_emoji.rb @@ -8,16 +8,19 @@ module API awardable_string = awardable_type.pluralize awardable_id_string = "#{awardable_type}_id" + params do + requires :id, type: String, desc: 'The ID of a project' + requires :"#{awardable_id_string}", type: Integer, desc: "The ID of an Issue, Merge Request or Snippet" + end + [ ":id/#{awardable_string}/:#{awardable_id_string}/award_emoji", ":id/#{awardable_string}/:#{awardable_id_string}/notes/:note_id/award_emoji" ].each do |endpoint| - # Get a list of project +awardable+ award emoji - # - # Parameters: - # id (required) - The ID of a project - # awardable_id (required) - The ID of an issue or MR - # Example Request: - # GET /projects/:id/issues/:awardable_id/award_emoji + + desc 'Get a list of project +awardable+ award emoji' do + detail 'This feature was introduced in 8.9' + success Entities::AwardEmoji + end get endpoint do if can_read_awardable? awards = paginate(awardable.award_emoji) @@ -27,14 +30,13 @@ module API end end - # Get a specific award emoji - # - # Parameters: - # id (required) - The ID of a project - # awardable_id (required) - The ID of an issue or MR - # award_id (required) - The ID of the award - # Example Request: - # GET /projects/:id/issues/:awardable_id/award_emoji/:award_id + desc 'Get a specific award emoji' do + detail 'This feature was introduced in 8.9' + success Entities::AwardEmoji + end + params do + requires :award_id, type: Integer, desc: 'The ID of the award' + end get "#{endpoint}/:award_id" do if can_read_awardable? present awardable.award_emoji.find(params[:award_id]), with: Entities::AwardEmoji @@ -43,17 +45,14 @@ module API end end - # Award a new Emoji - # - # Parameters: - # id (required) - The ID of a project - # awardable_id (required) - The ID of an issue or mr - # name (required) - The name of a award_emoji (without colons) - # Example Request: - # POST /projects/:id/issues/:awardable_id/award_emoji + desc 'Award a new Emoji' do + detail 'This feature was introduced in 8.9' + success Entities::AwardEmoji + end + params do + requires :name, type: String, desc: 'The name of a award_emoji (without colons)' + end post endpoint do - required_attributes! [:name] - not_found!('Award Emoji') unless can_read_awardable? && can_award_awardable? award = awardable.create_award_emoji(params[:name], current_user) @@ -65,14 +64,13 @@ module API end end - # Delete a +awardables+ award emoji - # - # Parameters: - # id (required) - The ID of a project - # awardable_id (required) - The ID of an issue or MR - # award_emoji_id (required) - The ID of an award emoji - # Example Request: - # DELETE /projects/:id/issues/:issue_id/notes/:note_id/award_emoji/:award_id + desc 'Delete a +awardables+ award emoji' do + detail 'This feature was introduced in 8.9' + success Entities::AwardEmoji + end + params do + requires :award_id, type: Integer, desc: 'The ID of an award emoji' + end delete "#{endpoint}/:award_id" do award = awardable.award_emoji.find(params[:award_id]) -- cgit v1.2.1 From f5e43f0788438758e4b1404da19fb4255245aead Mon Sep 17 00:00:00 2001 From: Katarzyna Kobierska Date: Fri, 30 Sep 2016 11:14:42 +0200 Subject: Prevent rendering the link when the author has no access --- lib/banzai/filter/user_reference_filter.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/user_reference_filter.rb b/lib/banzai/filter/user_reference_filter.rb index e1ca7f4d24b..b3c8e565c27 100644 --- a/lib/banzai/filter/user_reference_filter.rb +++ b/lib/banzai/filter/user_reference_filter.rb @@ -106,13 +106,17 @@ module Banzai project = context[:project] author = context[:author] - url = urls.namespace_project_url(project.namespace, project, - only_path: context[:only_path]) + if author && !project.team.member?(author) + '@all' + else + url = urls.namespace_project_url(project.namespace, project, + only_path: context[:only_path]) - data = data_attribute(project: project.id, author: author.try(:id)) - text = link_text || User.reference_prefix + 'all' + data = data_attribute(project: project.id, author: author.try(:id)) + text = link_text || User.reference_prefix + 'all' - link_tag(url, data, text, 'All Project and Group Members') + link_tag(url, data, text, 'All Project and Group Members') + end end def link_to_namespace(namespace, link_text: nil) -- cgit v1.2.1 From bf3b8d1c1d3d854311a638ebeaf87991367e4052 Mon Sep 17 00:00:00 2001 From: Katarzyna Kobierska Date: Fri, 30 Sep 2016 14:53:37 +0200 Subject: Fix test, add author attribute to all tests --- lib/banzai/filter/user_reference_filter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/user_reference_filter.rb b/lib/banzai/filter/user_reference_filter.rb index b3c8e565c27..c6302b586d3 100644 --- a/lib/banzai/filter/user_reference_filter.rb +++ b/lib/banzai/filter/user_reference_filter.rb @@ -106,8 +106,8 @@ module Banzai project = context[:project] author = context[:author] - if author && !project.team.member?(author) - '@all' + if author && !project.team.member?(author) + link_text else url = urls.namespace_project_url(project.namespace, project, only_path: context[:only_path]) -- cgit v1.2.1 From 08e31875c2d345c0755707ab73c1fd71b1fd9b05 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 27 Sep 2016 11:46:13 +0200 Subject: Update runner version only when updating contacted_at --- lib/ci/api/builds.rb | 6 +++--- lib/ci/api/helpers.rb | 18 +++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index 59f85416ee5..ed87a2603e8 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -12,10 +12,9 @@ module Ci # POST /builds/register post "register" do authenticate_runner! - update_runner_last_contact(save: false) - update_runner_info required_attributes! [:token] not_found! unless current_runner.active? + update_runner_info build = Ci::RegisterBuildService.new.execute(current_runner) @@ -41,10 +40,11 @@ module Ci # PUT /builds/:id put ":id" do authenticate_runner! - update_runner_last_contact build = Ci::Build.where(runner_id: current_runner.id).running.find(params[:id]) forbidden!('Build has been erased!') if build.erased? + update_runner_info + build.update_attributes(trace: params[:trace]) if params[:trace] Gitlab::Metrics.add_event(:update_build, diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb index 23353c62885..c6a83682e32 100644 --- a/lib/ci/api/helpers.rb +++ b/lib/ci/api/helpers.rb @@ -3,7 +3,7 @@ module Ci module Helpers BUILD_TOKEN_HEADER = "HTTP_BUILD_TOKEN" BUILD_TOKEN_PARAM = :token - UPDATE_RUNNER_EVERY = 40 * 60 + UPDATE_RUNNER_EVERY = 10 * 60 def authenticate_runners! forbidden! unless runner_registration_token_valid? @@ -30,14 +30,15 @@ module Ci token && (build.valid_token?(token) || build.project.valid_runners_token?(token)) end - def update_runner_last_contact(save: true) + def update_runner_info # Use a random threshold to prevent beating DB updates # it generates a distribution between: [40m, 80m] contacted_at_max_age = UPDATE_RUNNER_EVERY + Random.rand(UPDATE_RUNNER_EVERY) - if current_runner.contacted_at.nil? || Time.now - current_runner.contacted_at >= contacted_at_max_age - current_runner.contacted_at = Time.now - current_runner.save if current_runner.changed? && save - end + return unless current_runner.contacted_at.nil? || Time.now - current_runner.contacted_at >= contacted_at_max_age + + current_runner.contacted_at = Time.now + current_runner.assign_attributes(get_runner_version_from_params) + current_runner.save if current_runner.changed? end def build_not_found! @@ -57,11 +58,6 @@ module Ci attributes_for_keys(["name", "version", "revision", "platform", "architecture"], params["info"]) end - def update_runner_info - current_runner.assign_attributes(get_runner_version_from_params) - current_runner.save if current_runner.changed? - end - def max_artifacts_size current_application_settings.max_artifacts_size.megabytes.to_i end -- cgit v1.2.1 From 9a8e486307550aa1a590c769d9e71621c5ce8c62 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 3 Oct 2016 10:47:37 +0200 Subject: Extract method that checks if ci runner needs update --- lib/ci/api/helpers.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb index c6a83682e32..e608f5f6cad 100644 --- a/lib/ci/api/helpers.rb +++ b/lib/ci/api/helpers.rb @@ -31,16 +31,23 @@ module Ci end def update_runner_info - # Use a random threshold to prevent beating DB updates - # it generates a distribution between: [40m, 80m] - contacted_at_max_age = UPDATE_RUNNER_EVERY + Random.rand(UPDATE_RUNNER_EVERY) - return unless current_runner.contacted_at.nil? || Time.now - current_runner.contacted_at >= contacted_at_max_age + return unless update_runner? current_runner.contacted_at = Time.now current_runner.assign_attributes(get_runner_version_from_params) current_runner.save if current_runner.changed? end + def update_runner? + # Use a random threshold to prevent beating DB updates. + # It generates a distribution between [40m, 80m]. + # + contacted_at_max_age = UPDATE_RUNNER_EVERY + Random.rand(UPDATE_RUNNER_EVERY) + + current_runner.contacted_at.nil? || + (Time.now - current_runner.contacted_at) >= contacted_at_max_age + end + def build_not_found! if headers['User-Agent'].match(/gitlab-ci-multi-runner \d+\.\d+\.\d+(~beta\.\d+\.g[0-9a-f]+)? /) no_content! -- cgit v1.2.1 From 3158f57dba6dcef3e586ae8fced7deb6fdbd6dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 28 Jul 2016 19:31:17 +0200 Subject: Improve Members::DestroyService MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/access_requests.rb | 4 +--- lib/api/members.rb | 10 +++++++++- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb index 7b9de7c9598..75be24efd59 100644 --- a/lib/api/access_requests.rb +++ b/lib/api/access_requests.rb @@ -75,9 +75,7 @@ module API required_attributes! [:user_id] source = find_source(source_type, params[:id]) - access_requester = source.requesters.find_by!(user_id: params[:user_id]) - - ::Members::DestroyService.new(access_requester, current_user).execute + ::Members::DestroyService.new(source, current_user, declared(params)).execute(:requesters) end end end diff --git a/lib/api/members.rb b/lib/api/members.rb index a18ce769e29..03dbf4eabb8 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -65,6 +65,14 @@ module API # for both project and group members in 9.0! conflict!('Member already exists') if source_type == 'group' && member + access_requester = source.requesters.find_by(user_id: params[:user_id]) + if access_requester + # We delete a potential access requester before creating the new member. + # We pass current_user = access_requester so that the requester doesn't + # receive a "access denied" email. + ::Members::DestroyService.new(source, access_requester.user, params).execute(:requesters) + end + unless member member = source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at]) end @@ -134,7 +142,7 @@ module API if member.nil? { message: "Access revoked", id: params[:user_id].to_i } else - ::Members::DestroyService.new(member, current_user).execute + ::Members::DestroyService.new(source, current_user, params).execute present member.user, with: Entities::Member, member: member end -- cgit v1.2.1 From c8b1311934935c7ac7fd901558e19ac496fbad2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 9 Sep 2016 18:51:31 +0200 Subject: Fix a few things after the initial improvment to Members::DestroyService MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/access_requests.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb index 75be24efd59..d3db7740830 100644 --- a/lib/api/access_requests.rb +++ b/lib/api/access_requests.rb @@ -75,7 +75,8 @@ module API required_attributes! [:user_id] source = find_source(source_type, params[:id]) - ::Members::DestroyService.new(source, current_user, declared(params)).execute(:requesters) + ::Members::DestroyService.new(source, current_user, params). + execute(:requesters) end end end -- cgit v1.2.1 From 1592d57c18ba905d7bd1643ab6af56c902d709c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 3 Oct 2016 18:43:33 +0200 Subject: Remove useless code now that Member#add_user handles it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/members.rb | 8 -------- 1 file changed, 8 deletions(-) (limited to 'lib') diff --git a/lib/api/members.rb b/lib/api/members.rb index 03dbf4eabb8..34df55fe192 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -65,14 +65,6 @@ module API # for both project and group members in 9.0! conflict!('Member already exists') if source_type == 'group' && member - access_requester = source.requesters.find_by(user_id: params[:user_id]) - if access_requester - # We delete a potential access requester before creating the new member. - # We pass current_user = access_requester so that the requester doesn't - # receive a "access denied" email. - ::Members::DestroyService.new(source, access_requester.user, params).execute(:requesters) - end - unless member member = source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at]) end -- cgit v1.2.1 From d6e42e0ca1ab9962b7d43517c6f6beab5f1ade1c Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Tue, 13 Sep 2016 20:55:26 +0200 Subject: GrapeDSL for Namespace endpoint --- lib/api/namespaces.rb | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/api/namespaces.rb b/lib/api/namespaces.rb index 50d3729449e..fe981d7b9fa 100644 --- a/lib/api/namespaces.rb +++ b/lib/api/namespaces.rb @@ -4,20 +4,18 @@ module API before { authenticate! } resource :namespaces do - # Get a namespaces list - # - # Example Request: - # GET /namespaces + desc 'Get a namespaces list' do + success Entities::Namespace + end + params do + optional :search, type: String, desc: "Search query for namespaces" + end get do - @namespaces = if current_user.admin - Namespace.all - else - current_user.namespaces - end - @namespaces = @namespaces.search(params[:search]) if params[:search].present? - @namespaces = paginate @namespaces + namespaces = current_user.admin ? Namespace.all : current_user.namespaces + + namespaces = namespaces.search(params[:search]) if params[:search].present? - present @namespaces, with: Entities::Namespace + present paginate(namespaces), with: Entities::Namespace end end end -- cgit v1.2.1 From 138e26b1fad6730aa048b8cc91f92a597e323162 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 4 Oct 2016 14:06:44 +0100 Subject: Adds v-pre to code blocks in comments Closes #22911 --- lib/banzai/filter/sanitization_filter.rb | 2 +- lib/banzai/filter/syntax_highlight_filter.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/sanitization_filter.rb b/lib/banzai/filter/sanitization_filter.rb index 2470362e019..af1e575fc89 100644 --- a/lib/banzai/filter/sanitization_filter.rb +++ b/lib/banzai/filter/sanitization_filter.rb @@ -25,7 +25,7 @@ module Banzai return if customized?(whitelist[:transformers]) # Allow code highlighting - whitelist[:attributes]['pre'] = %w(class) + whitelist[:attributes]['pre'] = %w(class v-pre) whitelist[:attributes]['span'] = %w(class) # Allow table alignment diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb index fcdb496aed2..bb6b4582e4f 100644 --- a/lib/banzai/filter/syntax_highlight_filter.rb +++ b/lib/banzai/filter/syntax_highlight_filter.rb @@ -30,7 +30,8 @@ module Banzai # users can still access an issue/comment/etc. end - highlighted = %(
#{code}
) + highlighted = %(
#{code}
) + puts highlighted # Extracted to a method to measure it replace_parent_pre_element(node, highlighted) -- cgit v1.2.1 From cd2556e73792f018af71e8910b4f556e29de1985 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 4 Oct 2016 14:28:57 +0100 Subject: Removed puts code :see_no_evil: --- lib/banzai/filter/syntax_highlight_filter.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb index bb6b4582e4f..026b81ac175 100644 --- a/lib/banzai/filter/syntax_highlight_filter.rb +++ b/lib/banzai/filter/syntax_highlight_filter.rb @@ -31,7 +31,6 @@ module Banzai end highlighted = %(
#{code}
) - puts highlighted # Extracted to a method to measure it replace_parent_pre_element(node, highlighted) -- cgit v1.2.1 From b5f954177825fbea9245149805541cffb2e0de05 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 4 Oct 2016 02:40:03 -0300 Subject: Skip wiki creation when GitHub project has wiki enabled If the GitHub project repository has wiki, we should not create the default wiki. Otherwise the GitHub importer will fail because the wiki repository already exist. This bug was introduced here https://gitlab.com/gitlab-org/gitlab-ce/commit/892dea67717c0efbd6a28f763 9f34535ec0a8747 --- lib/gitlab/github_import/importer.rb | 3 +-- lib/gitlab/github_import/project_creator.rb | 35 ++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index b8321244473..4b70f33a851 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -170,10 +170,9 @@ module Gitlab end def import_wiki - unless project.wiki_enabled? + unless project.wiki.repository_exists? wiki = WikiFormatter.new(project) gitlab_shell.import_repository(project.repository_storage_path, wiki.path_with_namespace, wiki.import_url) - project.project.update_attribute(:wiki_access_level, ProjectFeature::ENABLED) end rescue Gitlab::Shell::Error => e # GitHub error message when the wiki repo has not been created, diff --git a/lib/gitlab/github_import/project_creator.rb b/lib/gitlab/github_import/project_creator.rb index 605abfabdab..a2410068845 100644 --- a/lib/gitlab/github_import/project_creator.rb +++ b/lib/gitlab/github_import/project_creator.rb @@ -1,7 +1,7 @@ module Gitlab module GithubImport class ProjectCreator - attr_reader :repo, :namespace, :current_user, :session_data + attr_reader :repo, :name, :namespace, :current_user, :session_data def initialize(repo, name, namespace, current_user, session_data) @repo = repo @@ -12,24 +12,37 @@ module Gitlab end def execute - project = ::Projects::CreateService.new( + ::Projects::CreateService.new( current_user, - name: @name, - path: @name, + name: name, + path: name, description: repo.description, namespace_id: namespace.id, - visibility_level: repo.private ? Gitlab::VisibilityLevel::PRIVATE : ApplicationSetting.current.default_project_visibility, + visibility_level: visibility_level, import_type: "github", import_source: repo.full_name, - import_url: repo.clone_url.sub("https://", "https://#{@session_data[:github_access_token]}@") + import_url: import_url, + skip_wiki: skip_wiki ).execute + end + + private - # If repo has wiki we'll import it later - if repo.has_wiki? && project - project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED) - end + def import_url + repo.clone_url.sub('https://', "https://#{session_data[:github_access_token]}@") + end + + def visibility_level + repo.private ? Gitlab::VisibilityLevel::PRIVATE : ApplicationSetting.current.default_project_visibility + end - project + # + # If the GitHub project repository has wiki, we should not create the + # default wiki. Otherwise the GitHub importer will fail because the wiki + # repository already exist. + # + def skip_wiki + repo.has_wiki? end end end -- cgit v1.2.1 From e956a24dfd45baaafe93a520df61015bba40a4da Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 23 Aug 2016 15:23:56 -0400 Subject: api: add /projects/visible API endpoint FIxes #19361, #3119. --- lib/api/projects.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'lib') diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 680055c95eb..52afbb4eef3 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -32,6 +32,21 @@ module API end end + # Get a list of visible projects for authenticated user + # + # Example Request: + # GET /projects/visible + get '/visible' do + @projects = ProjectsFinder.new.execute(current_user) + @projects = filter_projects(@projects) + @projects = paginate @projects + if params[:simple] + present @projects, with: Entities::BasicProjectDetails, user: current_user + else + present @projects, with: Entities::ProjectWithAccess, user: current_user + end + end + # Get an owned projects list for authenticated user # # Example Request: -- cgit v1.2.1 From 35ced4dae480d61ddc4d73eb4695626ecc419e9c Mon Sep 17 00:00:00 2001 From: barthc Date: Thu, 1 Sep 2016 18:23:39 +0100 Subject: fix group links 404 --- lib/api/groups.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 953fa474e88..bfb89475025 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -6,6 +6,8 @@ module API resource :groups do # Get a groups list # + # Parameters: + # skip_groups (optional) - Array of group ids to exclude from list # Example Request: # GET /groups get do @@ -16,6 +18,7 @@ module API end @groups = @groups.search(params[:search]) if params[:search].present? + @groups = @groups.where.not(id: params[:skip_groups]) if params[:skip_groups].present? @groups = paginate @groups present @groups, with: Entities::Group end -- cgit v1.2.1 From 84b7dd763bd6a9a55b2a59039c57af588cc2519f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 29 Jul 2016 16:02:35 +0200 Subject: Use Grape DSL to document methods and their params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/access_requests.rb | 64 +++++++++++++------------------ lib/api/members.rb | 96 ++++++++++++++++++++-------------------------- 2 files changed, 67 insertions(+), 93 deletions(-) (limited to 'lib') diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb index d3db7740830..87915b19480 100644 --- a/lib/api/access_requests.rb +++ b/lib/api/access_requests.rb @@ -5,15 +5,14 @@ module API helpers ::API::Helpers::MembersHelpers %w[group project].each do |source_type| + params do + requires :id, type: String, desc: "The #{source_type} ID" + end resource source_type.pluralize do - # Get a list of group/project access requests viewable by the authenticated user. - # - # Parameters: - # id (required) - The group/project ID - # - # Example Request: - # GET /groups/:id/access_requests - # GET /projects/:id/access_requests + desc "Gets a list of access requests for a #{source_type}." do + detail 'This feature was introduced in GitLab 8.11.' + success Entities::AccessRequester + end get ":id/access_requests" do source = find_source(source_type, params[:id]) @@ -23,14 +22,10 @@ module API present access_requesters.map(&:user), with: Entities::AccessRequester, source: source end - # Request access to the group/project - # - # Parameters: - # id (required) - The group/project ID - # - # Example Request: - # POST /groups/:id/access_requests - # POST /projects/:id/access_requests + desc "Requests access for the authenticated user to a #{source_type}." do + detail 'This feature was introduced in GitLab 8.11.' + success Entities::AccessRequester + end post ":id/access_requests" do source = find_source(source_type, params[:id]) access_requester = source.request_access(current_user) @@ -42,37 +37,30 @@ module API end end - # Approve a group/project access request - # - # Parameters: - # id (required) - The group/project ID - # user_id (required) - The user ID of the access requester - # access_level (optional) - Access level - # - # Example Request: - # PUT /groups/:id/access_requests/:user_id/approve - # PUT /projects/:id/access_requests/:user_id/approve + desc 'Approves an access request for the given user.' do + detail 'This feature was introduced in GitLab 8.11.' + success Entities::Member + end + params do + requires :user_id, type: Integer, desc: 'The user ID of the access requester' + optional :access_level, type: Integer, desc: 'A valid access level (defaults: `30`, developer access level)' + end put ':id/access_requests/:user_id/approve' do - required_attributes! [:user_id] source = find_source(source_type, params[:id]) - member = ::Members::ApproveAccessRequestService.new(source, current_user, params).execute + member = ::Members::ApproveAccessRequestService.new(source, current_user, declared(params)).execute status :created present member.user, with: Entities::Member, member: member end - # Deny a group/project access request - # - # Parameters: - # id (required) - The group/project ID - # user_id (required) - The user ID of the access requester - # - # Example Request: - # DELETE /groups/:id/access_requests/:user_id - # DELETE /projects/:id/access_requests/:user_id + desc 'Denies an access request for the given user.' do + detail 'This feature was introduced in GitLab 8.11.' + end + params do + requires :user_id, type: Integer, desc: 'The user ID of the access requester' + end delete ":id/access_requests/:user_id" do - required_attributes! [:user_id] source = find_source(source_type, params[:id]) ::Members::DestroyService.new(source, current_user, params). diff --git a/lib/api/members.rb b/lib/api/members.rb index 34df55fe192..b80818f0eb6 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -5,16 +5,16 @@ module API helpers ::API::Helpers::MembersHelpers %w[group project].each do |source_type| + params do + requires :id, type: String, desc: "The #{source_type} ID" + end resource source_type.pluralize do - # Get a list of group/project members viewable by the authenticated user. - # - # Parameters: - # id (required) - The group/project ID - # query - Query string - # - # Example Request: - # GET /groups/:id/members - # GET /projects/:id/members + desc 'Gets a list of group or project members viewable by the authenticated user.' do + success Entities::Member + end + params do + optional :query, type: String, desc: 'A query string to search for members' + end get ":id/members" do source = find_source(source_type, params[:id]) @@ -25,15 +25,12 @@ module API present users, with: Entities::Member, source: source end - # Get a group/project member - # - # Parameters: - # id (required) - The group/project ID - # user_id (required) - The user ID of the member - # - # Example Request: - # GET /groups/:id/members/:user_id - # GET /projects/:id/members/:user_id + desc 'Gets a member of a group or project.' do + success Entities::Member + end + params do + requires :user_id, type: Integer, desc: 'The user ID of the member' + end get ":id/members/:user_id" do source = find_source(source_type, params[:id]) @@ -43,26 +40,25 @@ module API present member.user, with: Entities::Member, member: member end - # Add a new group/project member - # - # Parameters: - # id (required) - The group/project ID - # user_id (required) - The user ID of the new member - # access_level (required) - A valid access level - # expires_at (optional) - Date string in the format YEAR-MONTH-DAY - # - # Example Request: - # POST /groups/:id/members - # POST /projects/:id/members + desc 'Adds a member to a group or project.' do + success Entities::Member + end + params do + requires :user_id, type: Integer, desc: 'The user ID of the new member' + requires :access_level, type: Integer, desc: 'A valid access level (defaults: `30`, developer access level)' + optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY' + end post ":id/members" do source = find_source(source_type, params[:id]) authorize_admin_source!(source_type, source) - required_attributes! [:user_id, :access_level] member = source.members.find_by(user_id: params[:user_id]) - # This is to ensure back-compatibility but 409 behavior should be used - # for both project and group members in 9.0! + # We need this explicit check because `source.add_user` doesn't + # currently return the member created so it would return 201 even if + # the member already existed... + # The `source_type == 'group'` check is to ensure back-compatibility + # but 409 behavior should be used for both project and group members in 9.0! conflict!('Member already exists') if source_type == 'group' && member unless member @@ -79,21 +75,17 @@ module API end end - # Update a group/project member - # - # Parameters: - # id (required) - The group/project ID - # user_id (required) - The user ID of the member - # access_level (required) - A valid access level - # expires_at (optional) - Date string in the format YEAR-MONTH-DAY - # - # Example Request: - # PUT /groups/:id/members/:user_id - # PUT /projects/:id/members/:user_id + desc 'Updates a member of a group or project.' do + success Entities::Member + end + params do + requires :user_id, type: Integer, desc: 'The user ID of the new member' + requires :access_level, type: Integer, desc: 'A valid access level' + optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY' + end put ":id/members/:user_id" do source = find_source(source_type, params[:id]) authorize_admin_source!(source_type, source) - required_attributes! [:user_id, :access_level] member = source.members.find_by!(user_id: params[:user_id]) attrs = attributes_for_keys [:access_level, :expires_at] @@ -108,18 +100,12 @@ module API end end - # Remove a group/project member - # - # Parameters: - # id (required) - The group/project ID - # user_id (required) - The user ID of the member - # - # Example Request: - # DELETE /groups/:id/members/:user_id - # DELETE /projects/:id/members/:user_id + desc 'Removes a user from a group or project.' + params do + requires :user_id, type: Integer, desc: 'The user ID of the member' + end delete ":id/members/:user_id" do source = find_source(source_type, params[:id]) - required_attributes! [:user_id] # This is to ensure back-compatibility but find_by! should be used # in that casse in 9.0! @@ -134,7 +120,7 @@ module API if member.nil? { message: "Access revoked", id: params[:user_id].to_i } else - ::Members::DestroyService.new(source, current_user, params).execute + ::Members::DestroyService.new(source, current_user, declared(params)).execute present member.user, with: Entities::Member, member: member end -- cgit v1.2.1 From 16ed9b6129daf51a296d4576580c5f232d043db6 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 4 Oct 2016 18:03:10 +0200 Subject: Refactor Gitlab::Identifier This refactors Gitlab::Identifier so it uses fewer queries and is actually tested. Queries are reduced by caching the output as well as using 1 query (instead of 2) to find a user using an SSH key. --- lib/gitlab/identifier.rb | 58 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/identifier.rb b/lib/gitlab/identifier.rb index 3e5d728f3bc..f8809db21aa 100644 --- a/lib/gitlab/identifier.rb +++ b/lib/gitlab/identifier.rb @@ -5,19 +5,61 @@ module Gitlab def identify(identifier, project, newrev) if identifier.blank? # Local push from gitlab - email = project.commit(newrev).author_email rescue nil - User.find_by(email: email) if email - + identify_using_commit(project, newrev) elsif identifier =~ /\Auser-\d+\Z/ # git push over http - user_id = identifier.gsub("user-", "") - User.find_by(id: user_id) - + identify_using_user(identifier) elsif identifier =~ /\Akey-\d+\Z/ # git push over ssh - key_id = identifier.gsub("key-", "") - Key.find_by(id: key_id).try(:user) + identify_using_ssh_key(identifier) + end + end + + # Tries to identify a user based on a commit SHA. + def identify_using_commit(project, ref) + commit = project.commit(ref) + + return if !commit || !commit.author_email + + email = commit.author_email + + identify_with_cache(:email, email) do + User.find_by(email: email) end end + + # Tries to identify a user based on a user identifier (e.g. "user-123"). + def identify_using_user(identifier) + user_id = identifier.gsub("user-", "") + + identify_with_cache(:user, user_id) do + User.find_by(id: user_id) + end + end + + # Tries to identify a user based on an SSH key identifier (e.g. "key-123"). + def identify_using_ssh_key(identifier) + key_id = identifier.gsub("key-", "") + + identify_with_cache(:ssh_key, key_id) do + User.find_by_ssh_key_id(key_id) + end + end + + def identify_with_cache(category, key) + if identification_cache[category].key?(key) + identification_cache[category][key] + else + identification_cache[category][key] = yield + end + end + + def identification_cache + @identification_cache ||= { + email: {}, + user: {}, + ssh_key: {} + } + end end end -- cgit v1.2.1 From 0a1baaa80f017ebf068a0a83d7efda45fbe2ef6c Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 5 Oct 2016 12:13:58 +0100 Subject: Tidy up project list actions --- lib/api/projects.rb | 52 ++++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 52afbb4eef3..c24e8e8bd9b 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -22,14 +22,12 @@ module API # Example Request: # GET /projects get do - @projects = current_user.authorized_projects - @projects = filter_projects(@projects) - @projects = paginate @projects - if params[:simple] - present @projects, with: Entities::BasicProjectDetails, user: current_user - else - present @projects, with: Entities::ProjectWithAccess, user: current_user - end + projects = current_user.authorized_projects + projects = filter_projects(projects) + projects = paginate projects + entity = params[:simple] ? Entities::BasicProjectDetails : Entities::ProjectWithAccess + + present projects, with: entity, user: current_user end # Get a list of visible projects for authenticated user @@ -37,14 +35,12 @@ module API # Example Request: # GET /projects/visible get '/visible' do - @projects = ProjectsFinder.new.execute(current_user) - @projects = filter_projects(@projects) - @projects = paginate @projects - if params[:simple] - present @projects, with: Entities::BasicProjectDetails, user: current_user - else - present @projects, with: Entities::ProjectWithAccess, user: current_user - end + projects = ProjectsFinder.new.execute(current_user) + projects = filter_projects(projects) + projects = paginate projects + entity = params[:simple] ? Entities::BasicProjectDetails : Entities::ProjectWithAccess + + present projects, with: entity, user: current_user end # Get an owned projects list for authenticated user @@ -52,10 +48,10 @@ module API # Example Request: # GET /projects/owned get '/owned' do - @projects = current_user.owned_projects - @projects = filter_projects(@projects) - @projects = paginate @projects - present @projects, with: Entities::ProjectWithAccess, user: current_user + projects = current_user.owned_projects + projects = filter_projects(projects) + projects = paginate projects + present projects, with: Entities::ProjectWithAccess, user: current_user end # Gets starred project for the authenticated user @@ -63,10 +59,10 @@ module API # Example Request: # GET /projects/starred get '/starred' do - @projects = current_user.viewable_starred_projects - @projects = filter_projects(@projects) - @projects = paginate @projects - present @projects, with: Entities::Project, user: current_user + projects = current_user.viewable_starred_projects + projects = filter_projects(projects) + projects = paginate projects + present projects, with: Entities::Project, user: current_user end # Get all projects for admin user @@ -75,10 +71,10 @@ module API # GET /projects/all get '/all' do authenticated_as_admin! - @projects = Project.all - @projects = filter_projects(@projects) - @projects = paginate @projects - present @projects, with: Entities::ProjectWithAccess, user: current_user + projects = Project.all + projects = filter_projects(projects) + projects = paginate projects + present projects, with: Entities::ProjectWithAccess, user: current_user end # Get a single project -- cgit v1.2.1 From 41d70ea300efb73a05f4753ddd3e0c3730e96e0a Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Mon, 3 Oct 2016 00:12:59 -0300 Subject: Added Issue Board API support - Includes documentation and tests --- lib/api/api.rb | 1 + lib/api/boards.rb | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/api/entities.rb | 18 +++++++- 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 lib/api/boards.rb (limited to 'lib') diff --git a/lib/api/api.rb b/lib/api/api.rb index cb47ec8f33f..0bbf73a1b63 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -43,6 +43,7 @@ module API mount ::API::Groups mount ::API::Internal mount ::API::Issues + mount ::API::Boards mount ::API::Keys mount ::API::Labels mount ::API::LicenseTemplates diff --git a/lib/api/boards.rb b/lib/api/boards.rb new file mode 100644 index 00000000000..4d5d144a02e --- /dev/null +++ b/lib/api/boards.rb @@ -0,0 +1,115 @@ +module API + # Boards API + class Boards < Grape::API + before { authenticate! } + + resource :projects do + # Get the project board + get ':id/boards' do + authorize!(:read_board, user_project) + present [user_project.board], with: Entities::Board + end + + segment ':id/boards/:board_id' do + helpers do + def project_board + board = user_project.board + if params[:board_id].to_i == board.id + board + else + not_found!('Board') + end + end + + def board_lists + project_board.lists.destroyable + end + end + + # Get the lists of a project board + # Does not include `backlog` and `done` lists + get '/lists' do + authorize!(:read_board, user_project) + present board_lists, with: Entities::List + end + + # Get a list of a project board + get '/lists/:list_id' do + authorize!(:read_board, user_project) + present board_lists.find(params[:list_id]), with: Entities::List + end + + # Create a new board list + # + # Parameters: + # id (required) - The ID of a project + # label_id (required) - The ID of an existing label + # Example Request: + # POST /projects/:id/boards/:board_id/lists + post '/lists' do + required_attributes! [:label_id] + + unless user_project.labels.exists?(params[:label_id]) + render_api_error!({ error: "Label not found!" }, 400) + end + + authorize!(:admin_list, user_project) + + list = ::Boards::Lists::CreateService.new(user_project, current_user, + { label_id: params[:label_id] }).execute + + if list.valid? + present list, with: Entities::List + else + render_validation_error!(list) + end + end + + # Moves a board list to a new position + # + # Parameters: + # id (required) - The ID of a project + # board_id (required) - The ID of a board + # position (required) - The position of the list + # Example Request: + # PUT /projects/:id/boards/:board_id/lists/:list_id + put '/lists/:list_id' do + list = project_board.lists.movable.find(params[:list_id]) + + authorize!(:admin_list, user_project) + + moved = ::Boards::Lists::MoveService.new(user_project, current_user, + { position: params[:position].to_i }).execute(list) + + if moved + present list, with: Entities::List + else + render_api_error!({ error: "List could not be moved!" }, 400) + end + end + + # Delete a board list + # + # Parameters: + # id (required) - The ID of a project + # board_id (required) - The ID of a board + # list_id (required) - The ID of a board list + # Example Request: + # DELETE /projects/:id/boards/:board_id/lists/:list_id + delete "/lists/:list_id" do + list = board_lists.find_by(id: params[:list_id]) + + authorize!(:admin_list, user_project) + + if list + destroyed_list = ::Boards::Lists::DestroyService.new( + user_project, current_user).execute(list) + present destroyed_list, with: Entities::List + else + not_found!('List') + end + end + end + end + end +end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 04437322ec1..feaa0c213bf 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -432,8 +432,11 @@ module API end end - class Label < Grape::Entity + class LabelBasic < Grape::Entity expose :name, :color, :description + end + + class Label < LabelBasic expose :open_issues_count, :closed_issues_count, :open_merge_requests_count expose :subscribed do |label, options| @@ -441,6 +444,19 @@ module API end end + class List < Grape::Entity + expose :id + expose :label, using: Entities::LabelBasic + expose :position + end + + class Board < Grape::Entity + expose :id + expose :lists, using: Entities::List do |board| + board.lists.destroyable + end + end + class Compare < Grape::Entity expose :commit, using: Entities::RepoCommit do |compare, options| Commit.decorate(compare.commits, nil).last -- cgit v1.2.1 From a1ee8cf5ad07256807f15590bdb5f56152d55553 Mon Sep 17 00:00:00 2001 From: Marc Siegfriedt Date: Mon, 29 Aug 2016 23:58:32 +0000 Subject: multi-file commit add docs and tests - add additional validation allow move without content updated response --- lib/api/commits.rb | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index b4eaf1813d4..14ddc8c9a62 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -29,6 +29,42 @@ module API present commits, with: Entities::RepoCommit end + desc 'Commit multiple file changes as one commit' do + detail 'This feature was introduced in GitLab 8.13' + end + + params do + requires :id, type: Integer, desc: 'The project ID' + requires :branch_name, type: String, desc: 'The name of branch' + requires :commit_message, type: String, desc: 'Commit message' + requires :actions, type: Array, desc: 'Actions to perform in commit' + optional :author_email, type: String, desc: 'Author email for commit' + optional :author_name, type: String, desc: 'Author name for commit' + end + + post ":id/repository/commits" do + authorize! :push_code, user_project + + attrs = declared(params) + attrs[:source_branch] = attrs[:branch_name] + attrs[:target_branch] = attrs[:branch_name] + attrs[:actions].map! do |action| + action[:action] = action[:action].to_sym + action[:file_path].slice!(0) if action[:file_path] && action[:file_path].start_with?('/') + action[:previous_path].slice!(0) if action[:previous_path] && action[:previous_path].start_with?('/') + action + end + + result = ::Files::MultiService.new(user_project, current_user, attrs).execute + + if result[:status] == :success + commit_detail = user_project.repository.commits(result[:result], limit: 1).first + present commit_detail, with: Entities::RepoCommitDetail + else + render_api_error!(result[:message], 400) + end + end + # Get a specific commit of a project # # Parameters: -- cgit v1.2.1 From b4d614bdbcb50f506c56eaa180d7b3f3055884a8 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Mon, 29 Aug 2016 12:09:33 -0500 Subject: Fix inconsistent highlighting of already selected activity nav-links --- lib/event_filter.rb | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/event_filter.rb b/lib/event_filter.rb index 668d2fa41b3..96e70e37e8f 100644 --- a/lib/event_filter.rb +++ b/lib/event_filter.rb @@ -2,8 +2,8 @@ class EventFilter attr_accessor :params class << self - def default_filter - %w{ push issues merge_requests team} + def all + 'all' end def push @@ -35,18 +35,21 @@ class EventFilter return events unless params.present? filter = params.dup - actions = [] - actions << Event::PUSHED if filter.include? 'push' - actions << Event::MERGED if filter.include? 'merged' - if filter.include? 'team' - actions << Event::JOINED - actions << Event::LEFT + case filter + when EventFilter.push + actions = [Event::PUSHED] + when EventFilter.merged + actions = [Event::MERGED] + when EventFilter.comments + actions = [Event::COMMENTED] + when EventFilter.team + actions = [Event::JOINED, Event::LEFT] + when EventFilter.all + actions = [Event::PUSHED, Event::MERGED, Event::COMMENTED, Event::JOINED, Event::LEFT] end - actions << Event::COMMENTED if filter.include? 'comments' - events.where(action: actions) end -- cgit v1.2.1 From 640a4c88341f790ede78f845d29a37634030581f Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Mon, 3 Oct 2016 16:42:02 +0200 Subject: Use higher size on Gitlab::Redis connection pool on Sidekiq servers --- lib/gitlab/redis.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/redis.rb b/lib/gitlab/redis.rb index 3faab937726..c649da8c426 100644 --- a/lib/gitlab/redis.rb +++ b/lib/gitlab/redis.rb @@ -24,10 +24,20 @@ module Gitlab end def with - @pool ||= ConnectionPool.new { ::Redis.new(params) } + @pool ||= ConnectionPool.new(size: pool_size) { ::Redis.new(params) } @pool.with { |redis| yield redis } end + def pool_size + if Sidekiq.server? + # the pool will be used in a multi-threaded context + Sidekiq.options[:concurrency] + 5 + else + # probably this is a Unicorn process, so single threaded + 5 + end + end + def _raw_config return @_raw_config if defined?(@_raw_config) -- cgit v1.2.1 From 333c02a8c822dfab1b98c55db8fb8daa4c53bd51 Mon Sep 17 00:00:00 2001 From: Ahmad Sherif Date: Wed, 5 Oct 2016 21:20:00 +0200 Subject: Fix broken handling of certain calls in GitHub importer client Closes #22998 --- lib/gitlab/github_import/client.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index e33ac61f5ae..7f424b74efb 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -102,9 +102,19 @@ module Gitlab def request(method, *args, &block) sleep rate_limit_sleep_time if rate_limit_exceed? - data = api.send(method, *args, &block) - yield data + data = api.send(method, *args) + return data unless data.is_a?(Array) + if block_given? + yield data + each_response_page(&block) + else + each_response_page { |page| data.concat(page) } + data + end + end + + def each_response_page last_response = api.last_response while last_response.rels[:next] -- cgit v1.2.1 From 3f85c3ef1629870e22f6a676585e8de80e5120c3 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 6 Oct 2016 13:10:50 +0200 Subject: Initial support for closing environments --- lib/gitlab/ci/config/node/environment.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/ci/config/node/environment.rb b/lib/gitlab/ci/config/node/environment.rb index d388ab6b879..daa115f9017 100644 --- a/lib/gitlab/ci/config/node/environment.rb +++ b/lib/gitlab/ci/config/node/environment.rb @@ -8,7 +8,7 @@ module Gitlab class Environment < Entry include Validatable - ALLOWED_KEYS = %i[name url] + ALLOWED_KEYS = %i[name url close] validations do validate do @@ -35,6 +35,8 @@ module Gitlab length: { maximum: 255 }, addressable_url: true, allow_nil: true + + validates :close, boolean: true, allow_nil: true end end -- cgit v1.2.1 From 86c0c0869dd4b9de301822a7d598bc4528604e5a Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Fri, 30 Sep 2016 12:21:05 +0100 Subject: Switch from request to env in ::API::Helpers Per https://gitlab.com/gitlab-org/gitlab-ce/issues/22820, this helper is mixed in to classes that lack a `request` method. They do include `env`, so use it instead. --- lib/api/helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 8b8c4eb4d46..281a8f13531 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -25,7 +25,7 @@ module API # Until CSRF protection is added to the API, disallow this method for # state-changing endpoints def find_user_from_warden - warden.try(:authenticate) if request.get? || request.head? + warden.try(:authenticate) if %w[GET HEAD].include?(env['REQUEST_METHOD']) end def find_user_by_private_token -- cgit v1.2.1 From fe46e4eb35dd6728a8a5ebcee9cc05a4613effbf Mon Sep 17 00:00:00 2001 From: Justin DiPierro Date: Thu, 29 Sep 2016 12:46:54 -0400 Subject: Load Github::Shell's secret token from file on initialization instead of every request. --- lib/api/helpers.rb | 2 +- lib/gitlab/backend/shell.rb | 46 ++++++++++++++++++++++++++++++--------------- lib/tasks/gitlab/shell.rake | 2 +- 3 files changed, 33 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 8b8c4eb4d46..e3b947adcc3 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -433,7 +433,7 @@ module API end def secret_token - File.read(Gitlab.config.gitlab_shell.secret_file).chomp + Gitlab::Shell.secret_token end def send_git_blob(repository, blob) diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 79eac66b364..d0060fbaca1 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -17,6 +17,18 @@ module Gitlab end class << self + def secret_token + @secret_token ||= begin + File.read(Gitlab.config.gitlab_shell.secret_file).chomp + end + end + + def ensure_secret_token! + return if File.exist?(File.join(Gitlab.config.gitlab_shell.path, '.gitlab_shell_secret')) + + generate_and_link_secret_token + end + def version_required @version_required ||= File.read(Rails.root. join('GITLAB_SHELL_VERSION')).strip @@ -25,6 +37,25 @@ module Gitlab def strip_key(key) key.split(/ /)[0, 2].join(' ') end + + private + + # Create (if necessary) and link the secret token file + def generate_and_link_secret_token + secret_file = Gitlab.config.gitlab_shell.secret_file + shell_path = Gitlab.config.gitlab_shell.path + + unless File.size?(secret_file) + # Generate a new token of 16 random hexadecimal characters and store it in secret_file. + token = SecureRandom.hex(16) + File.write(secret_file, token) + end + + link_path = File.join(shell_path, '.gitlab_shell_secret') + if File.exist?(shell_path) && !File.exist?(link_path) + FileUtils.symlink(secret_file, link_path) + end + end end # Init new repository @@ -201,21 +232,6 @@ module Gitlab File.exist?(full_path(storage, dir_name)) end - # Create (if necessary) and link the secret token file - def generate_and_link_secret_token - secret_file = Gitlab.config.gitlab_shell.secret_file - unless File.size?(secret_file) - # Generate a new token of 16 random hexadecimal characters and store it in secret_file. - token = SecureRandom.hex(16) - File.write(secret_file, token) - end - - link_path = File.join(gitlab_shell_path, '.gitlab_shell_secret') - if File.exist?(gitlab_shell_path) && !File.exist?(link_path) - FileUtils.symlink(secret_file, link_path) - end - end - protected def gitlab_shell_path diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index bb7eb852f1b..210899882b4 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -78,7 +78,7 @@ namespace :gitlab do f.puts "PATH=#{ENV['PATH']}" end - Gitlab::Shell.new.generate_and_link_secret_token + Gitlab::Shell.ensure_secret_token! end desc "GitLab | Setup gitlab-shell" -- cgit v1.2.1 From 6b90ccb9fd57401912e1978cbad28cc693a2e0a1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 6 Oct 2016 15:14:24 +0300 Subject: Change user & group landing page routing from /u/:name & /groups/:name to /:name Signed-off-by: Dmitriy Zaporozhets --- lib/constraints/group_url_constrainer.rb | 7 +++++++ lib/constraints/namespace_url_constrainer.rb | 13 +++++++++++++ lib/constraints/user_url_constrainer.rb | 7 +++++++ 3 files changed, 27 insertions(+) create mode 100644 lib/constraints/group_url_constrainer.rb create mode 100644 lib/constraints/namespace_url_constrainer.rb create mode 100644 lib/constraints/user_url_constrainer.rb (limited to 'lib') diff --git a/lib/constraints/group_url_constrainer.rb b/lib/constraints/group_url_constrainer.rb new file mode 100644 index 00000000000..ca39b1961ae --- /dev/null +++ b/lib/constraints/group_url_constrainer.rb @@ -0,0 +1,7 @@ +require 'constraints/namespace_url_constrainer' + +class GroupUrlConstrainer < NamespaceUrlConstrainer + def find_resource(id) + Group.find_by_path(id) + end +end diff --git a/lib/constraints/namespace_url_constrainer.rb b/lib/constraints/namespace_url_constrainer.rb new file mode 100644 index 00000000000..23920193743 --- /dev/null +++ b/lib/constraints/namespace_url_constrainer.rb @@ -0,0 +1,13 @@ +class NamespaceUrlConstrainer + def matches?(request) + id = request.path.sub(/\A\/+/, '').split('/').first.sub(/.atom\z/, '') + + if id =~ Gitlab::Regex.namespace_regex + find_resource(id) + end + end + + def find_resource(id) + Namespace.find_by_path(id) + end +end diff --git a/lib/constraints/user_url_constrainer.rb b/lib/constraints/user_url_constrainer.rb new file mode 100644 index 00000000000..ef38d47d5c6 --- /dev/null +++ b/lib/constraints/user_url_constrainer.rb @@ -0,0 +1,7 @@ +require 'constraints/namespace_url_constrainer' + +class UserUrlConstrainer < NamespaceUrlConstrainer + def find_resource(id) + User.find_by_username(id) + end +end -- cgit v1.2.1 From 42c6555bab47eb042749be1f24d486797eb8d8ee Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 6 Oct 2016 16:59:22 +0300 Subject: Make user constrainer lookup same as controller and add more constrainer tests Signed-off-by: Dmitriy Zaporozhets --- lib/constraints/user_url_constrainer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/constraints/user_url_constrainer.rb b/lib/constraints/user_url_constrainer.rb index ef38d47d5c6..504a0f5d93e 100644 --- a/lib/constraints/user_url_constrainer.rb +++ b/lib/constraints/user_url_constrainer.rb @@ -2,6 +2,6 @@ require 'constraints/namespace_url_constrainer' class UserUrlConstrainer < NamespaceUrlConstrainer def find_resource(id) - User.find_by_username(id) + User.find_by('lower(username) = ?', id.downcase) end end -- cgit v1.2.1 From e94cd6fdfe43d9128d37a539cf84f4388c5cf970 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Thu, 6 Oct 2016 22:17:11 +0100 Subject: Add markdown cache columns to the database, but don't use them yet This commit adds a number of _html columns and, with the exception of Note, starts updating them whenever the content of their partner fields changes. Note has a collision with the note_html attr_accessor; that will be fixed later A background worker for clearing these cache columns is also introduced - use `rake cache:clear` to set it off. You can clear the database or Redis caches separately by running `rake cache:clear:db` or `rake cache:clear:redis`, respectively. --- lib/banzai.rb | 4 ++++ lib/banzai/renderer.rb | 28 ++++++++++++++++++++++++++++ lib/tasks/cache.rake | 43 +++++++++++++++++++++++++++---------------- 3 files changed, 59 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/banzai.rb b/lib/banzai.rb index 9ebe379f454..35ca234c1ba 100644 --- a/lib/banzai.rb +++ b/lib/banzai.rb @@ -3,6 +3,10 @@ module Banzai Renderer.render(text, context) end + def self.render_field(object, field) + Renderer.render_field(object, field) + end + def self.cache_collection_render(texts_and_contexts) Renderer.cache_collection_render(texts_and_contexts) end diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb index a4ae27eefd8..6924a293da8 100644 --- a/lib/banzai/renderer.rb +++ b/lib/banzai/renderer.rb @@ -31,6 +31,34 @@ module Banzai end end + # Convert a Markdown-containing field on an object into an HTML-safe String + # of HTML. This method is analogous to calling render(object.field), but it + # can cache the rendered HTML in the object, rather than Redis. + # + # The context to use is learned from the passed-in object by calling + # #banzai_render_context(field), and cannot be changed. Use #render, passing + # it the field text, if a custom rendering is needed. The generated context + # is returned along with the HTML. + def render_field(object, field) + html_field = object.markdown_cache_field_for(field) + + html = object.__send__(html_field) + return html if html.present? + + html = cacheless_render_field(object, field) + object.update_column(html_field, html) unless object.new_record? || object.destroyed? + + html + end + + # Same as +render_field+, but without consulting or updating the cache field + def cacheless_render_field(object, field) + text = object.__send__(field) + context = object.banzai_render_context(field) + + cacheless_render(text, context) + end + # Perform multiple render from an Array of Markdown String into an # Array of HTML-safe String of HTML. # diff --git a/lib/tasks/cache.rake b/lib/tasks/cache.rake index 2214f855200..a95a3455a4a 100644 --- a/lib/tasks/cache.rake +++ b/lib/tasks/cache.rake @@ -1,22 +1,33 @@ namespace :cache do - CLEAR_BATCH_SIZE = 1000 # There seems to be no speedup when pushing beyond 1,000 - REDIS_SCAN_START_STOP = '0' # Magic value, see http://redis.io/commands/scan + namespace :clear do + REDIS_CLEAR_BATCH_SIZE = 1000 # There seems to be no speedup when pushing beyond 1,000 + REDIS_SCAN_START_STOP = '0' # Magic value, see http://redis.io/commands/scan - desc "GitLab | Clear redis cache" - task :clear => :environment do - Gitlab::Redis.with do |redis| - cursor = REDIS_SCAN_START_STOP - loop do - cursor, keys = redis.scan( - cursor, - match: "#{Gitlab::Redis::CACHE_NAMESPACE}*", - count: CLEAR_BATCH_SIZE - ) - - redis.del(*keys) if keys.any? - - break if cursor == REDIS_SCAN_START_STOP + desc "GitLab | Clear redis cache" + task redis: :environment do + Gitlab::Redis.with do |redis| + cursor = REDIS_SCAN_START_STOP + loop do + cursor, keys = redis.scan( + cursor, + match: "#{Gitlab::Redis::CACHE_NAMESPACE}*", + count: REDIS_CLEAR_BATCH_SIZE + ) + + redis.del(*keys) if keys.any? + + break if cursor == REDIS_SCAN_START_STOP + end end end + + desc "GitLab | Clear database cache (in the background)" + task db: :environment do + ClearDatabaseCacheWorker.perform_async + end + + task all: [:db, :redis] end + + task clear: 'cache:clear:all' end -- cgit v1.2.1 From 109816c42fbe44fca108b52308a5fa4366876216 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Thu, 6 Oct 2016 22:52:44 +0100 Subject: Use CacheMarkdownField for notes --- lib/banzai/note_renderer.rb | 5 ++-- lib/banzai/object_renderer.rb | 53 ++++++++++++++++++++----------------------- 2 files changed, 26 insertions(+), 32 deletions(-) (limited to 'lib') diff --git a/lib/banzai/note_renderer.rb b/lib/banzai/note_renderer.rb index bab6a9934d1..2b7c10f1a0e 100644 --- a/lib/banzai/note_renderer.rb +++ b/lib/banzai/note_renderer.rb @@ -3,7 +3,7 @@ module Banzai # Renders a collection of Note instances. # # notes - The notes to render. - # project - The project to use for rendering/redacting. + # project - The project to use for redacting. # user - The user viewing the notes. # path - The request path. # wiki - The project's wiki. @@ -13,8 +13,7 @@ module Banzai user, requested_path: path, project_wiki: wiki, - ref: git_ref, - pipeline: :note) + ref: git_ref) renderer.render(notes, :note) end diff --git a/lib/banzai/object_renderer.rb b/lib/banzai/object_renderer.rb index 9aef807c152..9f8eb0931b8 100644 --- a/lib/banzai/object_renderer.rb +++ b/lib/banzai/object_renderer.rb @@ -1,28 +1,32 @@ module Banzai - # Class for rendering multiple objects (e.g. Note instances) in a single pass. + # Class for rendering multiple objects (e.g. Note instances) in a single pass, + # using +render_field+ to benefit from caching in the database. Rendering and + # redaction are both performed. # - # Rendered Markdown is stored in an attribute in every object based on the - # name of the attribute containing the Markdown. For example, when the - # attribute `note` is rendered the HTML is stored in `note_html`. + # The unredacted HTML is generated according to the usual +render_field+ + # policy, so specify the pipeline and any other context options on the model. + # + # The *redacted* (i.e., suitable for use) HTML is placed in an attribute + # named "redacted_", where is the name of the cache field for the + # chosen attribute. + # + # As an example, rendering the attribute `note` would place the unredacted + # HTML into `note_html` and the redacted HTML into `redacted_note_html`. class ObjectRenderer attr_reader :project, :user - # Make sure to set the appropriate pipeline in the `raw_context` attribute - # (e.g. `:note` for Note instances). - # - # project - A Project to use for rendering and redacting Markdown. + # project - A Project to use for redacting Markdown. # user - The user viewing the Markdown/HTML documents, if any. - # context - A Hash containing extra attributes to use in the rendering - # pipeline. - def initialize(project, user = nil, raw_context = {}) + # context - A Hash containing extra attributes to use during redaction + def initialize(project, user = nil, redaction_context = {}) @project = project @user = user - @raw_context = raw_context + @redaction_context = redaction_context end # Renders and redacts an Array of objects. # - # objects - The objects to render + # objects - The objects to render. # attribute - The attribute containing the raw Markdown to render. # # Returns the same input objects. @@ -32,7 +36,7 @@ module Banzai objects.each_with_index do |object, index| redacted_data = redacted[index] - object.__send__("#{attribute}_html=", redacted_data[:document].to_html.html_safe) + object.__send__("redacted_#{attribute}_html=", redacted_data[:document].to_html.html_safe) object.user_visible_reference_count = redacted_data[:visible_reference_count] end end @@ -53,12 +57,8 @@ module Banzai # Returns a Banzai context for the given object and attribute. def context_for(object, attribute) - context = base_context.merge(cache_key: [object, attribute]) - - if object.respond_to?(:author) - context[:author] = object.author - end - + context = base_context.dup + context = context.merge(object.banzai_render_context(attribute)) context end @@ -66,21 +66,16 @@ module Banzai # # Returns an Array of `Nokogiri::HTML::Document`. def render_attributes(objects, attribute) - strings_and_contexts = objects.map do |object| + objects.map do |object| + string = Banzai.render_field(object, attribute) context = context_for(object, attribute) - string = object.__send__(attribute) - - { text: string, context: context } - end - - Banzai.cache_collection_render(strings_and_contexts).each_with_index.map do |html, index| - Banzai::Pipeline[:relative_link].to_document(html, strings_and_contexts[index][:context]) + Banzai::Pipeline[:relative_link].to_document(string, context) end end def base_context - @base_context ||= @raw_context.merge(current_user: user, project: project) + @base_context ||= @redaction_context.merge(current_user: user, project: project) end end end -- cgit v1.2.1 From 9920551536bb4f78dffeaaf3a194b92f54c34a47 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Thu, 6 Oct 2016 23:01:42 +0100 Subject: Enable CacheMarkdownField for the remaining models This commit alters views for the following models to use the markdown cache if present: * AbuseReport * Appearance * ApplicationSetting * BroadcastMessage * Group * Issue * Label * MergeRequest * Milestone * Project At the same time, calls to `escape_once` have been moved into the `single_line` Banzai pipeline, so they can't be missed out by accident and the work is done at save, rather than render, time. --- lib/banzai/filter/html_entity_filter.rb | 12 ++++++++++++ lib/banzai/pipeline/single_line_pipeline.rb | 1 + 2 files changed, 13 insertions(+) create mode 100644 lib/banzai/filter/html_entity_filter.rb (limited to 'lib') diff --git a/lib/banzai/filter/html_entity_filter.rb b/lib/banzai/filter/html_entity_filter.rb new file mode 100644 index 00000000000..4ef8b3b6dcf --- /dev/null +++ b/lib/banzai/filter/html_entity_filter.rb @@ -0,0 +1,12 @@ +require 'erb' + +module Banzai + module Filter + # Text filter that escapes these HTML entities: & " < > + class HTMLEntityFilter < HTML::Pipeline::TextFilter + def call + ERB::Util.html_escape(text) + end + end + end +end diff --git a/lib/banzai/pipeline/single_line_pipeline.rb b/lib/banzai/pipeline/single_line_pipeline.rb index ba2555df98d..30bc035d085 100644 --- a/lib/banzai/pipeline/single_line_pipeline.rb +++ b/lib/banzai/pipeline/single_line_pipeline.rb @@ -3,6 +3,7 @@ module Banzai class SingleLinePipeline < GfmPipeline def self.filters @filters ||= FilterArray[ + Filter::HTMLEntityFilter, Filter::SanitizationFilter, Filter::EmojiFilter, -- cgit v1.2.1 From 4f1de5faacb6824bad2624b75537e9f4ddbb1207 Mon Sep 17 00:00:00 2001 From: Will Starms Date: Thu, 25 Aug 2016 11:48:08 -0500 Subject: Correct namespace validation to forbid bad names #21077 Adds .git and .atom to the master namespace regex Updates existing group tests and adds two new ones Updates path cleaning to also forbid .atom --- lib/gitlab/regex.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index 776bbcbb5d0..0d30e1bb92e 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -2,7 +2,7 @@ module Gitlab module Regex extend self - NAMESPACE_REGEX_STR = '(?:[a-zA-Z0-9_\.][a-zA-Z0-9_\-\.]*[a-zA-Z0-9_\-]|[a-zA-Z0-9_])'.freeze + NAMESPACE_REGEX_STR = '(?:[a-zA-Z0-9_\.][a-zA-Z0-9_\-\.]*[a-zA-Z0-9_\-]|[a-zA-Z0-9_])(? Date: Mon, 10 Oct 2016 13:35:26 +0200 Subject: API: New /users/:id/events endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/users.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'lib') diff --git a/lib/api/users.rb b/lib/api/users.rb index 18c4cad09ae..e868f628404 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -321,6 +321,26 @@ module API user.activate end end + + desc 'Get contribution events of a specified user' do + detail 'This feature was introduced in GitLab 8.13.' + success Entities::Event + end + params do + requires :id, type: String, desc: 'The user ID' + end + get ':id/events' do + user = User.find_by(id: declared(params).id) + not_found!('User') unless user + + events = user.recent_events. + merge(ProjectsFinder.new.execute(current_user)). + references(:project). + with_associations. + page(params[:page]) + + present paginate(events), with: Entities::Event + end end resource :user do -- cgit v1.2.1 From d6cfc0042ed2ce9a33f31a6c44661c136e861b98 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 7 Oct 2016 16:39:57 +0300 Subject: Catch any undefined API routing and return 400 Bad Request Signed-off-by: Dmitriy Zaporozhets --- lib/api/api.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/api/api.rb b/lib/api/api.rb index 0bbf73a1b63..95a64f14ac7 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -73,5 +73,9 @@ module API mount ::API::Triggers mount ::API::Users mount ::API::Variables + + route :any, '*path' do + error!('400 Bad Request', 400) + end end end -- cgit v1.2.1 From 137ebcfb3cb013174f2885776a47264cffd193a6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 7 Oct 2016 20:18:02 +0300 Subject: Replace undefined Grape routing code from 400 to 404 Signed-off-by: Dmitriy Zaporozhets --- lib/api/api.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/api.rb b/lib/api/api.rb index 95a64f14ac7..99722a0a65c 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -75,7 +75,7 @@ module API mount ::API::Variables route :any, '*path' do - error!('400 Bad Request', 400) + error!('404 Not Found', 404) end end end -- cgit v1.2.1 From aac2af5bc42fbca355d7d5f5ab03ef662b876219 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Mon, 10 Oct 2016 15:46:26 +0100 Subject: HTMLEntityFilter -> HtmlEntityFilter --- lib/banzai/filter/html_entity_filter.rb | 2 +- lib/banzai/pipeline/single_line_pipeline.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/html_entity_filter.rb b/lib/banzai/filter/html_entity_filter.rb index 4ef8b3b6dcf..e008fd428b0 100644 --- a/lib/banzai/filter/html_entity_filter.rb +++ b/lib/banzai/filter/html_entity_filter.rb @@ -3,7 +3,7 @@ require 'erb' module Banzai module Filter # Text filter that escapes these HTML entities: & " < > - class HTMLEntityFilter < HTML::Pipeline::TextFilter + class HtmlEntityFilter < HTML::Pipeline::TextFilter def call ERB::Util.html_escape(text) end diff --git a/lib/banzai/pipeline/single_line_pipeline.rb b/lib/banzai/pipeline/single_line_pipeline.rb index 30bc035d085..1929099931b 100644 --- a/lib/banzai/pipeline/single_line_pipeline.rb +++ b/lib/banzai/pipeline/single_line_pipeline.rb @@ -3,7 +3,7 @@ module Banzai class SingleLinePipeline < GfmPipeline def self.filters @filters ||= FilterArray[ - Filter::HTMLEntityFilter, + Filter::HtmlEntityFilter, Filter::SanitizationFilter, Filter::EmojiFilter, -- cgit v1.2.1 From ebba49149395ba6fb0f14c3aa9c46a496b234dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 7 Oct 2016 18:35:36 +0200 Subject: Add a new gitlab:users:clear_all_authentication_tokens task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/tasks/gitlab/users.rake | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 lib/tasks/gitlab/users.rake (limited to 'lib') diff --git a/lib/tasks/gitlab/users.rake b/lib/tasks/gitlab/users.rake new file mode 100644 index 00000000000..3a16ace60bd --- /dev/null +++ b/lib/tasks/gitlab/users.rake @@ -0,0 +1,11 @@ +namespace :gitlab do + namespace :users do + desc "GitLab | Clear the authentication token for all users" + task clear_all_authentication_tokens: :environment do |t, args| + # Do small batched updates because these updates will be slow and locking + User.select(:id).find_in_batches(batch_size: 100) do |batch| + User.where(id: batch.map(&:id)).update_all(authentication_token: nil) + end + end + end +end -- cgit v1.2.1 From 1022456bb15d18b05c14fe344950fb75c7c69f48 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Fri, 7 Oct 2016 16:49:48 +0100 Subject: Allow browsing branches that end with '.atom' We need to do two things to support this: 1. Simplify the regex capture in the routing for the CommitsController to not exclude the '.atom' suffix. That's a perfectly valid git branch name, so we shouldn't blow up if we get it. 2. Because Rails now can't automatically detect the request format, add some code to do so in `ExtractPath` when there is no path. This means that, given branches 'foo' and 'foo.atom', the Atom feed for the former is unroutable. To fix this: don't do that! Give the branches different names! --- lib/extracts_path.rb | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index a4558d157c0..e4d996a3fb6 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -52,8 +52,7 @@ module ExtractsPath # Append a trailing slash if we only get a ref and no file path id += '/' unless id.ends_with?('/') - valid_refs = @project.repository.ref_names - valid_refs.select! { |v| id.start_with?("#{v}/") } + valid_refs = ref_names.select { |v| id.start_with?("#{v}/") } if valid_refs.length == 0 # No exact ref match, so just try our best @@ -74,6 +73,19 @@ module ExtractsPath pair end + # If we have an ID of 'foo.atom', and the controller provides Atom and HTML + # formats, then we have to check if the request was for the Atom version of + # the ID without the '.atom' suffix, or the HTML version of the ID including + # the suffix. We only check this if the version including the suffix doesn't + # match, so it is possible to create a branch which has an unroutable Atom + # feed. + def extract_ref_without_atom(id) + id_without_atom = id.sub(/\.atom$/, '') + valid_refs = ref_names.select { |v| "#{id_without_atom}/".start_with?("#{v}/") } + + valid_refs.max_by(&:length) + end + # Assigns common instance variables for views working with Git tree-ish objects # # Assignments are: @@ -86,6 +98,10 @@ module ExtractsPath # If the :id parameter appears to be requesting a specific response format, # that will be handled as well. # + # If there is no path and the ref doesn't exist in the repo, try to resolve + # the ref without an '.atom' suffix. If _that_ ref is found, set the request's + # format to Atom manually. + # # Automatically renders `not_found!` if a valid tree path could not be # resolved (e.g., when a user inserts an invalid path or ref). def assign_ref_vars @@ -103,6 +119,13 @@ module ExtractsPath @commit = @repo.commit(@options[:extended_sha1]) end + if @path.empty? && !@commit + @id = @ref = extract_ref_without_atom(@id) + @commit = @repo.commit(@ref) + + request.format = :atom if @commit + end + raise InvalidPathError unless @commit @hex_path = Digest::SHA1.hexdigest(@path) @@ -125,4 +148,10 @@ module ExtractsPath id += "/" + params[:path] unless params[:path].blank? id end + + def ref_names + return [] unless @project + + @ref_names ||= @project.repository.ref_names + end end -- cgit v1.2.1 From 8caf097a162cc43cea59162600bbb1fbc981f0bc Mon Sep 17 00:00:00 2001 From: henrik Date: Tue, 11 Oct 2016 15:41:10 +0200 Subject: Convert unicode emojis to images. --- lib/banzai/filter/emoji_filter.rb | 54 +++++++++++++++++++++++++++++++++------ lib/gitlab/emoji.rb | 7 ++++- 2 files changed, 52 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/emoji_filter.rb b/lib/banzai/filter/emoji_filter.rb index 2492b5213ac..23ae6dfc79a 100644 --- a/lib/banzai/filter/emoji_filter.rb +++ b/lib/banzai/filter/emoji_filter.rb @@ -1,6 +1,6 @@ module Banzai module Filter - # HTML filter that replaces :emoji: with images. + # HTML filter that replaces :emoji: and unicode with images. # # Based on HTML::Pipeline::EmojiFilter # @@ -13,14 +13,14 @@ module Banzai def call search_text_nodes(doc).each do |node| content = node.to_html - next unless content.include?(':') next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS) + if content.include?(':') || node.text.match(emoji_unicode_pattern) + html = emoji_name_image_filter(content) + html = emoji_unicode_image_filter(html) + next if html == content + node.replace(html) + end - html = emoji_image_filter(content) - - next if html == content - - node.replace(html) end doc @@ -31,18 +31,34 @@ module Banzai # text - String text to replace :emoji: in. # # Returns a String with :emoji: replaced with images. - def emoji_image_filter(text) + def emoji_name_image_filter(text) text.gsub(emoji_pattern) do |match| name = $1 ":#{name}:" end end + + # Replace unicode emojis with corresponding images if they exist. + # + # text - String text to replace unicode emojis in. + # + # Returns a String with unicode emojis replaced with images. + + def emoji_unicode_image_filter(text) + text.gsub(emoji_unicode_pattern) do |moji| + ":#{Gitlab::Emoji.emojis_by_moji[moji][" + end + end # Build a regexp that matches all valid :emoji: names. def self.emoji_pattern @emoji_pattern ||= /:(#{Gitlab::Emoji.emojis_names.map { |name| Regexp.escape(name) }.join('|')}):/ end + # Build a regexp that matches all valid unicode emojis names. + def self.emoji_unicode_pattern + @emoji_unicode_pattern ||= /(#{Gitlab::Emoji.emojis_unicodes.map { |moji| Regexp.escape(moji) }.join('|')})/ + end private def emoji_url(name) @@ -60,6 +76,21 @@ module Banzai end end + def emoji_unicode_url(moji) + emoji_unicode_path = emoji_unicode_filename(moji) + + if context[:asset_host] + # Asset host is specified. + url_to_image(emoji_unicode_path) + elsif context[:asset_root] + # Gitlab url is specified + File.join(context[:asset_root], url_to_image(emoji_unicode_path)) + else + # All other cases + url_to_image(emoji_unicode_path) + end + end + def url_to_image(image) ActionController::Base.helpers.url_to_image(image) end @@ -71,6 +102,13 @@ module Banzai def emoji_filename(name) "#{Gitlab::Emoji.emoji_filename(name)}.png" end + def emoji_unicode_pattern + self.class.emoji_unicode_pattern + end + + def emoji_unicode_filename(name) + "#{Gitlab::Emoji.emoji_unicode_filename(name)}.png" + end end end end diff --git a/lib/gitlab/emoji.rb b/lib/gitlab/emoji.rb index b63213ae208..803b0c2d057 100644 --- a/lib/gitlab/emoji.rb +++ b/lib/gitlab/emoji.rb @@ -9,7 +9,9 @@ module Gitlab def emojis_by_moji Gemojione.index.instance_variable_get(:@emoji_by_moji) end - + def emojis_unicodes + emojis_by_moji.keys.sort + end def emojis_names emojis.keys.sort end @@ -17,5 +19,8 @@ module Gitlab def emoji_filename(name) emojis[name]["unicode"] end + def emoji_unicode_filename(moji) + emojis_by_moji[moji]["unicode"] + end end end -- cgit v1.2.1 From e171c1d80debd88d1aa3a3c74d1937b68a7f0f18 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 6 Oct 2016 17:36:46 -0300 Subject: Update Issue Board API to handle with has_many association --- lib/api/boards.rb | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/api/boards.rb b/lib/api/boards.rb index 4d5d144a02e..9b71d335128 100644 --- a/lib/api/boards.rb +++ b/lib/api/boards.rb @@ -7,13 +7,14 @@ module API # Get the project board get ':id/boards' do authorize!(:read_board, user_project) - present [user_project.board], with: Entities::Board + present user_project.boards, with: Entities::Board end segment ':id/boards/:board_id' do helpers do def project_board - board = user_project.board + board = user_project.boards.first + if params[:board_id].to_i == board.id board else @@ -55,8 +56,10 @@ module API authorize!(:admin_list, user_project) - list = ::Boards::Lists::CreateService.new(user_project, current_user, - { label_id: params[:label_id] }).execute + service = ::Boards::Lists::CreateService.new(user_project, current_user, + { label_id: params[:label_id] }) + + list = service.execute(project_board) if list.valid? present list, with: Entities::List @@ -78,10 +81,10 @@ module API authorize!(:admin_list, user_project) - moved = ::Boards::Lists::MoveService.new(user_project, current_user, - { position: params[:position].to_i }).execute(list) + service = ::Boards::Lists::MoveService.new(user_project, current_user, + { position: params[:position].to_i }) - if moved + if service.execute(list) present list, with: Entities::List else render_api_error!({ error: "List could not be moved!" }, 400) @@ -97,16 +100,16 @@ module API # Example Request: # DELETE /projects/:id/boards/:board_id/lists/:list_id delete "/lists/:list_id" do - list = board_lists.find_by(id: params[:list_id]) - authorize!(:admin_list, user_project) - if list - destroyed_list = ::Boards::Lists::DestroyService.new( - user_project, current_user).execute(list) - present destroyed_list, with: Entities::List + list = board_lists.find(params[:list_id]) + + service = ::Boards::Lists::DestroyService.new(user_project, current_user) + + if service.execute(list) + present list, with: Entities::List else - not_found!('List') + render_api_error!({ error: 'List could not be deleted!' }, 400) end end end -- cgit v1.2.1 From 670b2eb5c05a721f810a5b248612cadde0eaf2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 11 Oct 2016 10:20:35 +0000 Subject: Merge branch 'api-fix-project-group-sharing' into 'security' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit API: Share projects only with groups current_user can access Aims to address the issues here: https://gitlab.com/gitlab-org/gitlab-ce/issues/23004 * Projects can be shared with non-existent groups * Projects can be shared with groups that the current user does not have access to read Concerns: The new implementation of the API endpoint allows projects to be shared with a larger range of groups than can be done via the web UI. The form for sharing a project with a group uses the following API endpoint to index the available groups: https://gitlab.com/gitlab-org/gitlab-ce/blob/494269fc92f61098ee6bd635a0426129ce2c5456/lib/api/groups.rb#L17. The groups indexed in the web form will only be those groups that the user is currently a member of. The new implementation allows projects to be shared with any group that the authenticated user has access to view. This widens the range of groups to those that are public and internal. See merge request !2005 Signed-off-by: Rémy Coutable --- lib/api/projects.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib') diff --git a/lib/api/projects.rb b/lib/api/projects.rb index c24e8e8bd9b..da16e24d7ea 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -416,6 +416,12 @@ module API required_attributes! [:group_id, :group_access] attrs = attributes_for_keys [:group_id, :group_access, :expires_at] + group = Group.find_by_id(attrs[:group_id]) + + unless group && can?(current_user, :read_group, group) + not_found!('Group') + end + unless user_project.allowed_to_share_with_group? return render_api_error!("The project sharing with group is disabled", 400) end -- cgit v1.2.1 From b9b13ea8016077e186374e4ee45dfc8a59ea5a78 Mon Sep 17 00:00:00 2001 From: Thomas Balthazar Date: Mon, 8 Aug 2016 13:42:24 +0200 Subject: Create a new /templates API namespace The /licenses, /gitignores and /gitlab_ci_ymls endpoints are now also available under a new /templates namespace. Old endpoints will be deprecated when GitLab 9.0.0 is released. --- lib/api/api.rb | 1 - lib/api/license_templates.rb | 58 -------------------- lib/api/templates.rb | 124 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 100 insertions(+), 83 deletions(-) delete mode 100644 lib/api/license_templates.rb (limited to 'lib') diff --git a/lib/api/api.rb b/lib/api/api.rb index 99722a0a65c..c64d444842d 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -46,7 +46,6 @@ module API mount ::API::Boards mount ::API::Keys mount ::API::Labels - mount ::API::LicenseTemplates mount ::API::Lint mount ::API::Members mount ::API::MergeRequests diff --git a/lib/api/license_templates.rb b/lib/api/license_templates.rb deleted file mode 100644 index d0552299ed0..00000000000 --- a/lib/api/license_templates.rb +++ /dev/null @@ -1,58 +0,0 @@ -module API - # License Templates API - class LicenseTemplates < Grape::API - PROJECT_TEMPLATE_REGEX = - /[\<\{\[] - (project|description| - one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here - [\>\}\]]/xi.freeze - YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze - FULLNAME_TEMPLATE_REGEX = - /[\<\{\[] - (fullname|name\sof\s(author|copyright\sowner)) - [\>\}\]]/xi.freeze - - # Get the list of the available license templates - # - # Parameters: - # popular - Filter licenses to only the popular ones - # - # Example Request: - # GET /licenses - # GET /licenses?popular=1 - get 'licenses' do - options = { - featured: params[:popular].present? ? true : nil - } - present Licensee::License.all(options), with: Entities::RepoLicense - end - - # Get text for specific license - # - # Parameters: - # key (required) - The key of a license - # project - Copyrighted project name - # fullname - Full name of copyright holder - # - # Example Request: - # GET /licenses/mit - # - get 'licenses/:key', requirements: { key: /[\w\.-]+/ } do - required_attributes! [:key] - - not_found!('License') unless Licensee::License.find(params[:key]) - - # We create a fresh Licensee::License object since we'll modify its - # content in place below. - license = Licensee::License.new(params[:key]) - - license.content.gsub!(YEAR_TEMPLATE_REGEX, Time.now.year.to_s) - license.content.gsub!(PROJECT_TEMPLATE_REGEX, params[:project]) if params[:project].present? - - fullname = params[:fullname].presence || current_user.try(:name) - license.content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname - - present license, with: Entities::RepoLicense - end - end -end diff --git a/lib/api/templates.rb b/lib/api/templates.rb index b9e718147e1..8a53d9c0095 100644 --- a/lib/api/templates.rb +++ b/lib/api/templates.rb @@ -1,39 +1,115 @@ module API class Templates < Grape::API GLOBAL_TEMPLATE_TYPES = { - gitignores: Gitlab::Template::GitignoreTemplate, - gitlab_ci_ymls: Gitlab::Template::GitlabCiYmlTemplate + gitignores: { + klass: Gitlab::Template::GitignoreTemplate, + gitlab_version: 8.8 + }, + gitlab_ci_ymls: { + klass: Gitlab::Template::GitlabCiYmlTemplate, + gitlab_version: 8.9 + } }.freeze + PROJECT_TEMPLATE_REGEX = + /[\<\{\[] + (project|description| + one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here + [\>\}\]]/xi.freeze + YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze + FULLNAME_TEMPLATE_REGEX = + /[\<\{\[] + (fullname|name\sof\s(author|copyright\sowner)) + [\>\}\]]/xi.freeze + DEPRECATION_MESSAGE = ' This endpoint is deprecated and will be removed in GitLab 9.0.'.freeze helpers do + def parsed_license_template + # We create a fresh Licensee::License object since we'll modify its + # content in place below. + template = Licensee::License.new(params[:name]) + + template.content.gsub!(YEAR_TEMPLATE_REGEX, Time.now.year.to_s) + template.content.gsub!(PROJECT_TEMPLATE_REGEX, params[:project]) if params[:project].present? + + fullname = params[:fullname].presence || current_user.try(:name) + template.content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname + template + end + def render_response(template_type, template) not_found!(template_type.to_s.singularize) unless template present template, with: Entities::Template end end - GLOBAL_TEMPLATE_TYPES.each do |template_type, klass| - # Get the list of the available template - # - # Example Request: - # GET /gitignores - # GET /gitlab_ci_ymls - get template_type.to_s do - present klass.all, with: Entities::TemplatesList - end - - # Get the text for a specific template present in local filesystem - # - # Parameters: - # name (required) - The name of a template - # - # Example Request: - # GET /gitignores/Elixir - # GET /gitlab_ci_ymls/Ruby - get "#{template_type}/:name" do - required_attributes! [:name] - new_template = klass.find(params[:name]) - render_response(template_type, new_template) + { "licenses" => :deprecated, "templates/licenses" => :ok }.each do |route, status| + desc 'Get the list of the available license template' do + detailed_desc = 'This feature was introduced in GitLab 8.7.' + detailed_desc << DEPRECATION_MESSAGE unless status == :ok + detail detailed_desc + success Entities::RepoLicense + end + params do + optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses' + end + get route do + options = { + featured: declared(params).popular.present? ? true : nil + } + present Licensee::License.all(options), with: Entities::RepoLicense + end + end + + { "licenses/:name" => :deprecated, "templates/licenses/:name" => :ok }.each do |route, status| + desc 'Get the text for a specific license' do + detailed_desc = 'This feature was introduced in GitLab 8.7.' + detailed_desc << DEPRECATION_MESSAGE unless status == :ok + detail detailed_desc + success Entities::RepoLicense + end + params do + requires :name, type: String, desc: 'The name of the template' + end + get route, requirements: { name: /[\w\.-]+/ } do + not_found!('License') unless Licensee::License.find(declared(params).name) + + template = parsed_license_template + + present template, with: Entities::RepoLicense + end + end + + GLOBAL_TEMPLATE_TYPES.each do |template_type, properties| + klass = properties[:klass] + gitlab_version = properties[:gitlab_version] + + { template_type => :deprecated, "templates/#{template_type}" => :ok }.each do |route, status| + desc 'Get the list of the available template' do + detailed_desc = "This feature was introduced in GitLab #{gitlab_version}." + detailed_desc << DEPRECATION_MESSAGE unless status == :ok + detail detailed_desc + success Entities::TemplatesList + end + get route do + present klass.all, with: Entities::TemplatesList + end + end + + { "#{template_type}/:name" => :deprecated, "templates/#{template_type}/:name" => :ok }.each do |route, status| + desc 'Get the text for a specific template present in local filesystem' do + detailed_desc = "This feature was introduced in GitLab #{gitlab_version}." + detailed_desc << DEPRECATION_MESSAGE unless status == :ok + detail detailed_desc + success Entities::Template + end + params do + requires :name, type: String, desc: 'The name of the template' + end + get route do + new_template = klass.find(declared(params).name) + + render_response(template_type, new_template) + end end end end -- cgit v1.2.1 From b998479c81512b7c9a2cff28e7aabff3c4be0424 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Wed, 12 Oct 2016 13:32:48 +0200 Subject: API: Version information --- lib/api/api.rb | 1 + lib/api/version.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 lib/api/version.rb (limited to 'lib') diff --git a/lib/api/api.rb b/lib/api/api.rb index 99722a0a65c..eb4e1fc504f 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -73,6 +73,7 @@ module API mount ::API::Triggers mount ::API::Users mount ::API::Variables + mount ::API::Version route :any, '*path' do error!('404 Not Found', 404) diff --git a/lib/api/version.rb b/lib/api/version.rb new file mode 100644 index 00000000000..9ba576bd828 --- /dev/null +++ b/lib/api/version.rb @@ -0,0 +1,12 @@ +module API + class Version < Grape::API + before { authenticate! } + + desc 'Get the version information of the GitLab instance.' do + detail 'This feature was introduced in GitLab 8.13.' + end + get '/version' do + { version: Gitlab::VERSION, revision: Gitlab::REVISION } + end + end +end -- cgit v1.2.1 From 3d6f18cec57fc6c7776bd05558e0d03dd3b141e1 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Wed, 12 Oct 2016 20:38:33 +0200 Subject: GrapeDSL for variables --- lib/api/variables.rb | 89 +++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 47 deletions(-) (limited to 'lib') diff --git a/lib/api/variables.rb b/lib/api/variables.rb index f6495071a11..b9fb3c21dbb 100644 --- a/lib/api/variables.rb +++ b/lib/api/variables.rb @@ -4,27 +4,29 @@ module API before { authenticate! } before { authorize! :admin_build, user_project } + params do + requires :id, type: String, desc: 'The ID of a project' + end + resource :projects do - # Get project variables - # - # Parameters: - # id (required) - The ID of a project - # page (optional) - The page number for pagination - # per_page (optional) - The value of items per page to show - # Example Request: - # GET /projects/:id/variables + desc 'Get project variables' do + success Entities::Variable + end + params do + optional :page, type: Integer, desc: 'The page number for pagination' + optional :per_page, type: Integer, desc: 'The value of items per page to show' + end get ':id/variables' do variables = user_project.variables present paginate(variables), with: Entities::Variable end - # Get specific variable of a project - # - # Parameters: - # id (required) - The ID of a project - # key (required) - The `key` of variable - # Example Request: - # GET /projects/:id/variables/:key + desc 'Get a specific variable from a project' do + success Entities::Variable + end + params do + requires :key, type: String, desc: 'The key of the variable' + end get ':id/variables/:key' do key = params[:key] variable = user_project.variables.find_by(key: key.to_s) @@ -34,18 +36,15 @@ module API present variable, with: Entities::Variable end - # Create a new variable in project - # - # Parameters: - # id (required) - The ID of a project - # key (required) - The key of variable - # value (required) - The value of variable - # Example Request: - # POST /projects/:id/variables + desc 'Create a new variable in a project' do + success Entities::Variable + end + params do + requires :key, type: String, desc: 'The key of the variable' + requires :value, type: String, desc: 'The value of the variable' + end post ':id/variables' do - required_attributes! [:key, :value] - - variable = user_project.variables.create(key: params[:key], value: params[:value]) + variable = user_project.variables.create(declared(params, include_parent_namespaces: false).to_h) if variable.valid? present variable, with: Entities::Variable @@ -54,41 +53,37 @@ module API end end - # Update existing variable of a project - # - # Parameters: - # id (required) - The ID of a project - # key (optional) - The `key` of variable - # value (optional) - New value for `value` field of variable - # Example Request: - # PUT /projects/:id/variables/:key + desc 'Update an existing variable from a project' do + success Entities::Variable + end + params do + optional :key, type: String, desc: 'The key of the variable' + optional :value, type: String, desc: 'The value of the variable' + end put ':id/variables/:key' do - variable = user_project.variables.find_by(key: params[:key].to_s) + variable = user_project.variables.find_by(key: params[:key]) return not_found!('Variable') unless variable - attrs = attributes_for_keys [:value] - if variable.update(attrs) + if variable.update(value: params[:value]) present variable, with: Entities::Variable else render_validation_error!(variable) end end - # Delete existing variable of a project - # - # Parameters: - # id (required) - The ID of a project - # key (required) - The ID of a variable - # Example Request: - # DELETE /projects/:id/variables/:key + desc 'Delete an existing variable from a project' do + success Entities::Variable + end + params do + requires :key, type: String, desc: 'The key of the variable' + end delete ':id/variables/:key' do - variable = user_project.variables.find_by(key: params[:key].to_s) + variable = user_project.variables.find_by(key: params[:key]) return not_found!('Variable') unless variable - variable.destroy - present variable, with: Entities::Variable + present variable.destroy, with: Entities::Variable end end end -- cgit v1.2.1 From cfd0d66c8308c0f259e39322193c8ddb34ec28f9 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 13 Oct 2016 10:04:58 +0200 Subject: Reassign secret token when regenerating one --- lib/gitlab/backend/shell.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index d0060fbaca1..9cec71a3222 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -47,8 +47,8 @@ module Gitlab unless File.size?(secret_file) # Generate a new token of 16 random hexadecimal characters and store it in secret_file. - token = SecureRandom.hex(16) - File.write(secret_file, token) + @secret_token = SecureRandom.hex(16) + File.write(secret_file, @secret_token) end link_path = File.join(shell_path, '.gitlab_shell_secret') -- cgit v1.2.1 From 2273b5d6d6f64a14d41bc8d25287d615502d2622 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Thu, 13 Oct 2016 12:52:51 +0200 Subject: Sort API mounts --- lib/api/api.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/api/api.rb b/lib/api/api.rb index 99722a0a65c..a6f32a9fc04 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -31,11 +31,12 @@ module API # Keep in alphabetical order mount ::API::AccessRequests mount ::API::AwardEmoji + mount ::API::Boards mount ::API::Branches mount ::API::BroadcastMessages mount ::API::Builds - mount ::API::CommitStatuses mount ::API::Commits + mount ::API::CommitStatuses mount ::API::DeployKeys mount ::API::Deployments mount ::API::Environments @@ -43,22 +44,21 @@ module API mount ::API::Groups mount ::API::Internal mount ::API::Issues - mount ::API::Boards mount ::API::Keys mount ::API::Labels mount ::API::LicenseTemplates mount ::API::Lint mount ::API::Members - mount ::API::MergeRequests mount ::API::MergeRequestDiffs + mount ::API::MergeRequests mount ::API::Milestones mount ::API::Namespaces mount ::API::Notes mount ::API::NotificationSettings mount ::API::Pipelines mount ::API::ProjectHooks - mount ::API::ProjectSnippets mount ::API::Projects + mount ::API::ProjectSnippets mount ::API::Repositories mount ::API::Runners mount ::API::Services -- cgit v1.2.1 From ae95118a4ff3242a210d93e57370f6ef400db886 Mon Sep 17 00:00:00 2001 From: Johan H Date: Tue, 11 Oct 2016 16:27:09 +0200 Subject: Convert UTF-8 Emoji to Gitlab emoji --- lib/banzai/filter/emoji_filter.rb | 39 +++++++++++++++++++++------------------ lib/gitlab/emoji.rb | 7 +++++-- 2 files changed, 26 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/emoji_filter.rb b/lib/banzai/filter/emoji_filter.rb index 23ae6dfc79a..a8c1ca0c60a 100644 --- a/lib/banzai/filter/emoji_filter.rb +++ b/lib/banzai/filter/emoji_filter.rb @@ -14,15 +14,16 @@ module Banzai search_text_nodes(doc).each do |node| content = node.to_html next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS) - if content.include?(':') || node.text.match(emoji_unicode_pattern) - html = emoji_name_image_filter(content) - html = emoji_unicode_image_filter(html) - next if html == content - node.replace(html) - end - end + next unless content.include?(':') || node.text.match(emoji_unicode_pattern) + + html = emoji_name_image_filter(content) + html = emoji_unicode_image_filter(html) + next if html == content + + node.replace(html) + end doc end @@ -34,31 +35,35 @@ module Banzai def emoji_name_image_filter(text) text.gsub(emoji_pattern) do |match| name = $1 - ":#{name}:" + emoji_image_tag(name, emoji_url(name)) end end - - # Replace unicode emojis with corresponding images if they exist. + # Replace unicode emoji with corresponding images if they exist. # - # text - String text to replace unicode emojis in. + # text - String text to replace unicode emoji in. # - # Returns a String with unicode emojis replaced with images. - + # Returns a String with unicode emoji replaced with images. def emoji_unicode_image_filter(text) text.gsub(emoji_unicode_pattern) do |moji| - ":#{Gitlab::Emoji.emojis_by_moji[moji][" + emoji_image_tag(Gitlab::Emoji.emojis_by_moji[moji]['name'], emoji_unicode_url(moji)) end end + + def emoji_image_tag(emoji_name, emoji_url) + ":#{emoji_name}:" + end + # Build a regexp that matches all valid :emoji: names. def self.emoji_pattern @emoji_pattern ||= /:(#{Gitlab::Emoji.emojis_names.map { |name| Regexp.escape(name) }.join('|')}):/ end + # Build a regexp that matches all valid unicode emojis names. def self.emoji_unicode_pattern @emoji_unicode_pattern ||= /(#{Gitlab::Emoji.emojis_unicodes.map { |moji| Regexp.escape(moji) }.join('|')})/ - end + private def emoji_url(name) @@ -80,13 +85,10 @@ module Banzai emoji_unicode_path = emoji_unicode_filename(moji) if context[:asset_host] - # Asset host is specified. url_to_image(emoji_unicode_path) elsif context[:asset_root] - # Gitlab url is specified File.join(context[:asset_root], url_to_image(emoji_unicode_path)) else - # All other cases url_to_image(emoji_unicode_path) end end @@ -102,6 +104,7 @@ module Banzai def emoji_filename(name) "#{Gitlab::Emoji.emoji_filename(name)}.png" end + def emoji_unicode_pattern self.class.emoji_unicode_pattern end diff --git a/lib/gitlab/emoji.rb b/lib/gitlab/emoji.rb index 803b0c2d057..bbbca8acc40 100644 --- a/lib/gitlab/emoji.rb +++ b/lib/gitlab/emoji.rb @@ -9,16 +9,19 @@ module Gitlab def emojis_by_moji Gemojione.index.instance_variable_get(:@emoji_by_moji) end + def emojis_unicodes - emojis_by_moji.keys.sort + emojis_by_moji.keys end + def emojis_names - emojis.keys.sort + emojis.keys end def emoji_filename(name) emojis[name]["unicode"] end + def emoji_unicode_filename(moji) emojis_by_moji[moji]["unicode"] end -- cgit v1.2.1 From 069f2d347585a0f79ab8e3ddfb194ebbc86176c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 29 Sep 2016 19:31:14 +0200 Subject: Draft a quick CE->EE merge check rake task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/tasks/ce_to_ee_merge_check.rake | 6 +++ lib/tasks/gitlab/dev.rake | 96 +++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 lib/tasks/ce_to_ee_merge_check.rake create mode 100644 lib/tasks/gitlab/dev.rake (limited to 'lib') diff --git a/lib/tasks/ce_to_ee_merge_check.rake b/lib/tasks/ce_to_ee_merge_check.rake new file mode 100644 index 00000000000..bb87f85cd9c --- /dev/null +++ b/lib/tasks/ce_to_ee_merge_check.rake @@ -0,0 +1,6 @@ +desc 'Checks if the branch would apply cleanly to EE' +task ce_to_ee_merge_check: :environment do + return if defined?(Gitlab::License) + + Rake::Task['gitlab:dev:ce_to_ee_merge_check'].invoke +end diff --git a/lib/tasks/gitlab/dev.rake b/lib/tasks/gitlab/dev.rake new file mode 100644 index 00000000000..bf17ba499bc --- /dev/null +++ b/lib/tasks/gitlab/dev.rake @@ -0,0 +1,96 @@ +namespace :gitlab do + namespace :dev do + desc 'Checks if the branch would apply cleanly to EE' + task ce_to_ee_merge_check: :environment do + ce_repo = ENV['CI_BUILD_REPO'] + ce_branch = ENV['CI_BUILD_REF_NAME'] + + ee_repo = 'https://gitlab.com/gitlab-org/gitlab-ee.git' + ee_branch = "#{ce_branch}-ee" + ee_dir = 'gitlab-ee-merge-check' + + puts "\n=> Cloning #{ee_repo} into #{ee_dir}\n" + `git clone #{ee_repo} #{ee_dir} --depth 1` + Dir.chdir(ee_dir) do + puts "\n => Fetching #{ce_repo}/#{ce_branch}\n" + `git fetch #{ce_repo} #{ce_branch} --depth 1` + + # Try to merge the current tested branch to EE/master... + puts "\n => Merging #{ce_repo}/#{ce_branch} into #{ee_repo}/master\n" + `git merge --ff-only FETCH_HEAD` + + exit 0 if $?.success? + + # Try to merge a possible -ee branch to EE/master... + puts "\n => Merging #{ee_repo}/#{ee_branch} into #{ee_repo}/master\n" + `git merge --ff-only #{ee_branch}` + + # The -ee doesn't exist + if $?.exitstatus == 1 + puts <<-MSG.strip_heredoc + \n================================================================= + The #{ce_branch} branch cannot be merged without conflicts to the + current EE/master, and no #{ee_branch} branch was detected in + the EE repository. + + Please create a #{ee_branch} branch that includes changes + #{ce_branch} but also specific changes than can be applied cleanly + to EE/master. + + You can create this branch as follow: + + 1. In the EE repo: + $ git fetch origin + $ git fetch #{ce_repo} #{ce_branch} + $ git checkout -b #{ee_branch} FETCH_HEAD + $ git rebase origin/master + 2. At this point you will likely have conflicts, solve them, and + continue/finish the rebase. + 3. You can squash all the original #{ce_branch} commits into a + single "Port of #{ce_branch} to EE". + 4. Push your branch to #{ee_repo}: + $ git push origin #{ee_branch} + =================================================================\n + MSG + + exit 1 + end + + # The -ee cannot be merged cleanly to EE/master... + unless $?.success? + puts <<-MSG.strip_heredoc + \n================================================================= + The #{ce_branch} branch cannot be merged without conflicts to + EE/master, and even though the #{ee_branch} branch exists in the EE + repository, it cannot be merged without conflicts to EE/master. + + Please update the #{ee_branch}, push it again to #{ee_repo}, and + retry this job. + =================================================================\n + MSG + + exit 2 + end + + puts "\n => Merging #{ce_repo}/#{ce_branch} into #{ee_repo}/master\n" + `git merge --ff-only FETCH_HEAD` + exit 0 if $?.success? + + # The -ee can be merged cleanly to EE/master, but still + # cannot be merged cleanly to EE/master... + puts <<-MSG.strip_heredoc + \n================================================================= + The #{ce_branch} branch cannot be merged without conflicts to EE, and + even though the #{ee_branch} branch exists in the EE repository and + applies cleanly to EE/master, it doesn't prevent conflicts when + merging #{ce_branch} into EE. + + We may be in a complex situation here. + =================================================================\n + MSG + + exit 3 + end + end + end +end -- cgit v1.2.1 From 2650d5f895c6f7e56f7ba76e5fa448d38fd15d7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 7 Oct 2016 17:21:51 +0200 Subject: Improve the branch existence and merge checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also add a safeguard for non-CI env. Signed-off-by: Rémy Coutable --- lib/tasks/ce_to_ee_merge_check.rake | 2 -- lib/tasks/gitlab/dev.rake | 35 +++++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/tasks/ce_to_ee_merge_check.rake b/lib/tasks/ce_to_ee_merge_check.rake index bb87f85cd9c..424e7883060 100644 --- a/lib/tasks/ce_to_ee_merge_check.rake +++ b/lib/tasks/ce_to_ee_merge_check.rake @@ -1,6 +1,4 @@ desc 'Checks if the branch would apply cleanly to EE' task ce_to_ee_merge_check: :environment do - return if defined?(Gitlab::License) - Rake::Task['gitlab:dev:ce_to_ee_merge_check'].invoke end diff --git a/lib/tasks/gitlab/dev.rake b/lib/tasks/gitlab/dev.rake index bf17ba499bc..47bdb2d32d2 100644 --- a/lib/tasks/gitlab/dev.rake +++ b/lib/tasks/gitlab/dev.rake @@ -2,6 +2,9 @@ namespace :gitlab do namespace :dev do desc 'Checks if the branch would apply cleanly to EE' task ce_to_ee_merge_check: :environment do + return if defined?(Gitlab::License) + return unless ENV['CI'] + ce_repo = ENV['CI_BUILD_REPO'] ce_branch = ENV['CI_BUILD_REF_NAME'] @@ -17,27 +20,28 @@ namespace :gitlab do # Try to merge the current tested branch to EE/master... puts "\n => Merging #{ce_repo}/#{ce_branch} into #{ee_repo}/master\n" - `git merge --ff-only FETCH_HEAD` + `git merge FETCH_HEAD` exit 0 if $?.success? - # Try to merge a possible -ee branch to EE/master... - puts "\n => Merging #{ee_repo}/#{ee_branch} into #{ee_repo}/master\n" - `git merge --ff-only #{ee_branch}` + # Check if the -ee branch exists... + puts "\n => Check if #{ee_repo}/#{ee_branch} exists\n" + `git rev-parse --verify #{ee_branch}` # The -ee doesn't exist - if $?.exitstatus == 1 + unless $?.success? + puts puts <<-MSG.strip_heredoc - \n================================================================= + ================================================================= The #{ce_branch} branch cannot be merged without conflicts to the current EE/master, and no #{ee_branch} branch was detected in the EE repository. - Please create a #{ee_branch} branch that includes changes + Please create a #{ee_branch} branch that includes changes from #{ce_branch} but also specific changes than can be applied cleanly to EE/master. - You can create this branch as follow: + You can create this branch as follows: 1. In the EE repo: $ git fetch origin @@ -45,7 +49,8 @@ namespace :gitlab do $ git checkout -b #{ee_branch} FETCH_HEAD $ git rebase origin/master 2. At this point you will likely have conflicts, solve them, and - continue/finish the rebase. + continue/finish the rebase. Note: You can squash the CE commits + before rebasing. 3. You can squash all the original #{ce_branch} commits into a single "Port of #{ce_branch} to EE". 4. Push your branch to #{ee_repo}: @@ -56,10 +61,15 @@ namespace :gitlab do exit 1 end + # Try to merge the -ee branch to EE/master... + puts "\n => Merging #{ee_repo}/#{ee_branch} into #{ee_repo}/master\n" + `git merge #{ee_branch} master` + # The -ee cannot be merged cleanly to EE/master... unless $?.success? + puts puts <<-MSG.strip_heredoc - \n================================================================= + ================================================================= The #{ce_branch} branch cannot be merged without conflicts to EE/master, and even though the #{ee_branch} branch exists in the EE repository, it cannot be merged without conflicts to EE/master. @@ -73,13 +83,14 @@ namespace :gitlab do end puts "\n => Merging #{ce_repo}/#{ce_branch} into #{ee_repo}/master\n" - `git merge --ff-only FETCH_HEAD` + `git merge FETCH_HEAD` exit 0 if $?.success? # The -ee can be merged cleanly to EE/master, but still # cannot be merged cleanly to EE/master... + puts puts <<-MSG.strip_heredoc - \n================================================================= + ================================================================= The #{ce_branch} branch cannot be merged without conflicts to EE, and even though the #{ee_branch} branch exists in the EE repository and applies cleanly to EE/master, it doesn't prevent conflicts when -- cgit v1.2.1 From e836b904b77e857ad2e1a0bc65129380d5f0e6dc Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Thu, 13 Oct 2016 17:52:21 +0200 Subject: Grapify system hooks API --- lib/api/system_hooks.rb | 60 ++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 31 deletions(-) (limited to 'lib') diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb index 22b8f90dc5c..2e76b91051f 100644 --- a/lib/api/system_hooks.rb +++ b/lib/api/system_hooks.rb @@ -7,38 +7,36 @@ module API end resource :hooks do - # Get the list of system hooks - # - # Example Request: - # GET /hooks + desc 'Get the list of system hooks' do + success Entities::Hook + end get do - @hooks = SystemHook.all - present @hooks, with: Entities::Hook + hooks = SystemHook.all + present hooks, with: Entities::Hook end - # Create new system hook - # - # Parameters: - # url (required) - url for system hook - # Example Request - # POST /hooks + desc 'Create a new system hook' do + success Entities::Hook + end + params do + requires :url, type: String, desc: 'The URL for the system hook' + end post do - attrs = attributes_for_keys [:url] - required_attributes! [:url] - @hook = SystemHook.new attrs - if @hook.save - present @hook, with: Entities::Hook + hook = SystemHook.new declared(params).to_h + + if hook.save + present hook, with: Entities::Hook else not_found! end end - # Test a hook - # - # Example Request - # GET /hooks/:id + desc 'Test a hook' + params do + requires :id, type: Integer, desc: 'The ID of the system hook' + end get ":id" do - @hook = SystemHook.find(params[:id]) + hook = SystemHook.find(params[:id]) data = { event_name: "project_create", name: "Ruby", @@ -47,20 +45,20 @@ module API owner_name: "Someone", owner_email: "example@gitlabhq.com" } - @hook.execute(data, 'system_hooks') + hook.execute(data, 'system_hooks') data end - # Delete a hook. This is an idempotent function. - # - # Parameters: - # id (required) - ID of the hook - # Example Request: - # DELETE /hooks/:id + desc 'Delete a hook' do + success Entities::Hook + end + params do + requires :id, type: Integer, desc: 'The ID of the system hook' + end delete ":id" do begin - @hook = SystemHook.find(params[:id]) - @hook.destroy + hook = SystemHook.find(params[:id]) + present hook.destroy, with: Entities::Hook rescue # SystemHook raises an Error if no hook with id found end -- cgit v1.2.1 From 3f71c43e88c56bb5310c8814cd9f95cafb4f53ef Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 1 Sep 2016 13:59:10 +0100 Subject: Allow setting content for resolutions When reading conflicts: 1. Add a `type` field. `text` works as before, and has `sections`; `text-editor` is a file with ambiguous conflict markers that can only be resolved in an editor. 2. Add a `content_path` field pointing to a JSON representation of the file's content for a single file. 3. Hitting `content_path` returns a similar datastructure to the `file`, but without the `content_path` and `sections` fields, and with a `content` field containing the full contents of the file (with conflict markers). When writing conflicts: 1. Instead of `sections` being at the top level, they are now in a `files` array. This matches the read format better. 2. The `files` array contains file hashes, each of which must contain: a. `new_path` b. `old_path` c. EITHER `sections` (which works as before) or `content` (with the full content of the resolved file). --- lib/gitlab/conflict/file.rb | 51 +++++++++++++++++++++++++++------ lib/gitlab/conflict/file_collection.rb | 4 +++ lib/gitlab/conflict/parser.rb | 15 ++++++---- lib/gitlab/conflict/resolution_error.rb | 6 ++++ 4 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 lib/gitlab/conflict/resolution_error.rb (limited to 'lib') diff --git a/lib/gitlab/conflict/file.rb b/lib/gitlab/conflict/file.rb index dff9e29c6a5..26a9f170298 100644 --- a/lib/gitlab/conflict/file.rb +++ b/lib/gitlab/conflict/file.rb @@ -4,12 +4,12 @@ module Gitlab include Gitlab::Routing.url_helpers include IconsHelper - class MissingResolution < StandardError + class MissingResolution < ResolutionError end CONTEXT_LINES = 3 - attr_reader :merge_file_result, :their_path, :our_path, :our_mode, :merge_request, :repository + attr_reader :merge_file_result, :their_path, :our_path, :our_mode, :merge_request, :repository, :type def initialize(merge_file_result, conflict, merge_request:) @merge_file_result = merge_file_result @@ -21,12 +21,24 @@ module Gitlab @match_line_headers = {} end + def content + merge_file_result[:data] + end + # Array of Gitlab::Diff::Line objects def lines - @lines ||= Gitlab::Conflict::Parser.new.parse(merge_file_result[:data], + return @lines if defined?(@lines) + + begin + @type = 'text' + @lines = Gitlab::Conflict::Parser.new.parse(content, our_path: our_path, their_path: their_path, parent_file: self) + rescue Gitlab::Conflict::Parser::ParserError + @type = 'text-editor' + @lines = nil + end end def resolve_lines(resolution) @@ -53,6 +65,14 @@ module Gitlab end.compact end + def resolve_content(resolution) + if resolution == content + raise MissingResolution, "Resolved content has no changes for file #{our_path}" + end + + resolution + end + def highlight_lines! their_file = lines.reject { |line| line.type == 'new' }.map(&:text).join("\n") our_file = lines.reject { |line| line.type == 'old' }.map(&:text).join("\n") @@ -170,21 +190,36 @@ module Gitlab match_line.text = "@@ -#{match_line.old_pos},#{line.old_pos} +#{match_line.new_pos},#{line.new_pos} @@#{header}" end - def as_json(opts = nil) - { + def as_json(opts = {}) + json_hash = { old_path: their_path, new_path: our_path, blob_icon: file_type_icon_class('file', our_mode, our_path), blob_path: namespace_project_blob_path(merge_request.project.namespace, merge_request.project, - ::File.join(merge_request.diff_refs.head_sha, our_path)), - sections: sections + ::File.join(merge_request.diff_refs.head_sha, our_path)) } + + if opts[:full_content] + json_hash.merge(content: content) + else + json_hash.merge!(sections: sections) if type == 'text' + + json_hash.merge(type: type, content_path: content_path) + end + end + + def content_path + conflict_for_path_namespace_project_merge_request_path(merge_request.project.namespace, + merge_request.project, + merge_request, + old_path: their_path, + new_path: our_path) end # Don't try to print merge_request or repository. def inspect - instance_variables = [:merge_file_result, :their_path, :our_path, :our_mode].map do |instance_variable| + instance_variables = [:merge_file_result, :their_path, :our_path, :our_mode, :type].map do |instance_variable| value = instance_variable_get("@#{instance_variable}") "#{instance_variable}=\"#{value}\"" diff --git a/lib/gitlab/conflict/file_collection.rb b/lib/gitlab/conflict/file_collection.rb index bbd0427a2c8..fa5bd4649d4 100644 --- a/lib/gitlab/conflict/file_collection.rb +++ b/lib/gitlab/conflict/file_collection.rb @@ -30,6 +30,10 @@ module Gitlab end end + def file_for_path(old_path, new_path) + files.find { |file| file.their_path == old_path && file.our_path == new_path } + end + def as_json(opts = nil) { target_branch: merge_request.target_branch, diff --git a/lib/gitlab/conflict/parser.rb b/lib/gitlab/conflict/parser.rb index 98e842cded3..ddd657903fb 100644 --- a/lib/gitlab/conflict/parser.rb +++ b/lib/gitlab/conflict/parser.rb @@ -1,19 +1,24 @@ module Gitlab module Conflict class Parser - class ParserError < StandardError + class UnresolvableError < StandardError end - class UnexpectedDelimiter < ParserError + class UnmergeableFile < UnresolvableError end - class MissingEndDelimiter < ParserError + class UnsupportedEncoding < UnresolvableError + end + + # Recoverable errors - the conflict can be resolved in an editor, but not with + # sections. + class ParserError < StandardError end - class UnmergeableFile < ParserError + class UnexpectedDelimiter < ParserError end - class UnsupportedEncoding < ParserError + class MissingEndDelimiter < ParserError end def parse(text, our_path:, their_path:, parent_file: nil) diff --git a/lib/gitlab/conflict/resolution_error.rb b/lib/gitlab/conflict/resolution_error.rb new file mode 100644 index 00000000000..a0f2006bc24 --- /dev/null +++ b/lib/gitlab/conflict/resolution_error.rb @@ -0,0 +1,6 @@ +module Gitlab + module Conflict + class ResolutionError < StandardError + end + end +end -- cgit v1.2.1 From 4743d19463e7aef965665e43238af73820d18d7f Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 7 Sep 2016 12:28:13 +0100 Subject: Simplify conflict file JSON creation --- lib/gitlab/conflict/file.rb | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/conflict/file.rb b/lib/gitlab/conflict/file.rb index 26a9f170298..661e43d3fa9 100644 --- a/lib/gitlab/conflict/file.rb +++ b/lib/gitlab/conflict/file.rb @@ -9,7 +9,7 @@ module Gitlab CONTEXT_LINES = 3 - attr_reader :merge_file_result, :their_path, :our_path, :our_mode, :merge_request, :repository, :type + attr_reader :merge_file_result, :their_path, :our_path, :our_mode, :merge_request, :repository def initialize(merge_file_result, conflict, merge_request:) @merge_file_result = merge_file_result @@ -25,6 +25,12 @@ module Gitlab merge_file_result[:data] end + def type + lines unless @type + + @type.inquiry + end + # Array of Gitlab::Diff::Line objects def lines return @lines if defined?(@lines) @@ -200,12 +206,14 @@ module Gitlab ::File.join(merge_request.diff_refs.head_sha, our_path)) } - if opts[:full_content] - json_hash.merge(content: content) - else - json_hash.merge!(sections: sections) if type == 'text' - - json_hash.merge(type: type, content_path: content_path) + json_hash.tap do |json_hash| + if opts[:full_content] + json_hash[:content] = content + else + json_hash[:sections] = sections if type.text? + json_hash[:type] = type + json_hash[:content_path] = content_path + end end end -- cgit v1.2.1 From 3764fd4b4166bdf869cc04e4e82558d6b80b4ca5 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 13 Oct 2016 10:34:15 +0100 Subject: Add blob_ace_mode to conflict content response --- lib/gitlab/conflict/file.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/gitlab/conflict/file.rb b/lib/gitlab/conflict/file.rb index 661e43d3fa9..c843315782d 100644 --- a/lib/gitlab/conflict/file.rb +++ b/lib/gitlab/conflict/file.rb @@ -25,6 +25,10 @@ module Gitlab merge_file_result[:data] end + def our_blob + @our_blob ||= repository.blob_at(merge_request.diff_refs.head_sha, our_path) + end + def type lines unless @type @@ -209,6 +213,7 @@ module Gitlab json_hash.tap do |json_hash| if opts[:full_content] json_hash[:content] = content + json_hash[:blob_ace_mode] = our_blob && our_blob.language.try(:ace_mode) else json_hash[:sections] = sections if type.text? json_hash[:type] = type -- cgit v1.2.1 From b927473c45e42e99adbbe69b71653f1b2981df01 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 14 Oct 2016 09:16:55 +0200 Subject: Grapify todos API --- lib/api/todos.rb | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/api/todos.rb b/lib/api/todos.rb index 19df13d8aac..832b04a3bb1 100644 --- a/lib/api/todos.rb +++ b/lib/api/todos.rb @@ -8,18 +8,19 @@ module API 'issues' => ->(id) { find_project_issue(id) } } + params do + requires :id, type: String, desc: 'The ID of a project' + end resource :projects do ISSUABLE_TYPES.each do |type, finder| type_id_str = "#{type.singularize}_id".to_sym - # Create a todo on an issuable - # - # Parameters: - # id (required) - The ID of a project - # issuable_id (required) - The ID of an issuable - # Example Request: - # POST /projects/:id/issues/:issuable_id/todo - # POST /projects/:id/merge_requests/:issuable_id/todo + desc 'Create a todo on an issuable' do + success Entities::Todo + end + params do + requires type_id_str, type: Integer, desc: 'The ID of an issuable' + end post ":id/#{type}/:#{type_id_str}/todo" do issuable = instance_exec(params[type_id_str], &finder) todo = TodoService.new.mark_todo(issuable, current_user).first @@ -40,25 +41,21 @@ module API end end - # Get a todo list - # - # Example Request: - # GET /todos - # + desc 'Get a todo list' do + success Entities::Todo + end get do todos = find_todos present paginate(todos), with: Entities::Todo, current_user: current_user end - # Mark a todo as done - # - # Parameters: - # id: (required) - The ID of the todo being marked as done - # - # Example Request: - # DELETE /todos/:id - # + desc 'Mark a todo as done' do + success Entities::Todo + end + params do + requires :id, type: Integer, desc: 'The ID of the todo being marked as done' + end delete ':id' do todo = current_user.todos.find(params[:id]) TodoService.new.mark_todos_as_done([todo], current_user) @@ -66,11 +63,7 @@ module API present todo.reload, with: Entities::Todo, current_user: current_user end - # Mark all todos as done - # - # Example Request: - # DELETE /todos - # + desc 'Mark all todos as done' delete do todos = find_todos TodoService.new.mark_todos_as_done(todos, current_user) -- cgit v1.2.1 From 4c46c9a9738cfa90dd450e70ccf85e470be1d789 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 14 Oct 2016 09:38:20 +0200 Subject: Grapify boards API --- lib/api/boards.rb | 76 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 31 deletions(-) (limited to 'lib') diff --git a/lib/api/boards.rb b/lib/api/boards.rb index 9b71d335128..b14dd4f6e83 100644 --- a/lib/api/boards.rb +++ b/lib/api/boards.rb @@ -3,19 +3,28 @@ module API class Boards < Grape::API before { authenticate! } + params do + requires :id, type: String, desc: 'The ID of a project' + end resource :projects do - # Get the project board + desc 'Get all project boards' do + detail 'This feature was introduced in 8.13' + success Entities::Board + end get ':id/boards' do authorize!(:read_board, user_project) present user_project.boards, with: Entities::Board end + params do + requires :board_id, type: Integer, desc: 'The ID of a board' + end segment ':id/boards/:board_id' do helpers do def project_board board = user_project.boards.first - if params[:board_id].to_i == board.id + if params[:board_id] == board.id board else not_found!('Board') @@ -27,29 +36,35 @@ module API end end - # Get the lists of a project board - # Does not include `backlog` and `done` lists + desc 'Get the lists of a project board' do + detail 'Does not include `backlog` and `done` lists. This feature was introduced in 8.13' + success Entities::List + end get '/lists' do authorize!(:read_board, user_project) present board_lists, with: Entities::List end - # Get a list of a project board + desc 'Get a list of a project board' do + detail 'This feature was introduced in 8.13' + success Entities::List + end + params do + requires :list_id, type: Integer, desc: 'The ID of a list' + end get '/lists/:list_id' do authorize!(:read_board, user_project) present board_lists.find(params[:list_id]), with: Entities::List end - # Create a new board list - # - # Parameters: - # id (required) - The ID of a project - # label_id (required) - The ID of an existing label - # Example Request: - # POST /projects/:id/boards/:board_id/lists + desc 'Create a new board list' do + detail 'This feature was introduced in 8.13' + success Entities::List + end + params do + requires :label_id, type: Integer, desc: 'The ID of an existing label' + end post '/lists' do - required_attributes! [:label_id] - unless user_project.labels.exists?(params[:label_id]) render_api_error!({ error: "Label not found!" }, 400) end @@ -68,21 +83,21 @@ module API end end - # Moves a board list to a new position - # - # Parameters: - # id (required) - The ID of a project - # board_id (required) - The ID of a board - # position (required) - The position of the list - # Example Request: - # PUT /projects/:id/boards/:board_id/lists/:list_id + desc 'Moves a board list to a new position' do + detail 'This feature was introduced in 8.13' + success Entities::List + end + params do + requires :list_id, type: Integer, desc: 'The ID of a list' + requires :position, type: Integer, desc: 'The position of the list' + end put '/lists/:list_id' do list = project_board.lists.movable.find(params[:list_id]) authorize!(:admin_list, user_project) service = ::Boards::Lists::MoveService.new(user_project, current_user, - { position: params[:position].to_i }) + { position: params[:position] }) if service.execute(list) present list, with: Entities::List @@ -91,14 +106,13 @@ module API end end - # Delete a board list - # - # Parameters: - # id (required) - The ID of a project - # board_id (required) - The ID of a board - # list_id (required) - The ID of a board list - # Example Request: - # DELETE /projects/:id/boards/:board_id/lists/:list_id + desc 'Delete a board list' do + detail 'This feature was introduced in 8.13' + success Entities::List + end + params do + requires :list_id, type: Integer, desc: 'The ID of a board list' + end delete "/lists/:list_id" do authorize!(:admin_list, user_project) -- cgit v1.2.1 From 04593581037bca7a7c3b00c719404e610c158cc1 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Thu, 13 Oct 2016 19:32:10 +0200 Subject: API: Fix Sytem hooks delete behavior --- lib/api/system_hooks.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb index 2e76b91051f..794e34874f4 100644 --- a/lib/api/system_hooks.rb +++ b/lib/api/system_hooks.rb @@ -56,12 +56,10 @@ module API requires :id, type: Integer, desc: 'The ID of the system hook' end delete ":id" do - begin - hook = SystemHook.find(params[:id]) - present hook.destroy, with: Entities::Hook - rescue - # SystemHook raises an Error if no hook with id found - end + hook = SystemHook.find_by(id: params[:id]) + not_found!('System hook') unless hook + + present hook.destroy, with: Entities::Hook end end end -- cgit v1.2.1 From c5bf8e362ce10e52428bda873eb14b41e15a1bd0 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 14 Oct 2016 14:34:31 +0200 Subject: Use module_function in Banzai::Renderer Using `extend self` prevents GitLab Performance Monitoring from being able to track class methods. Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/23347 --- lib/banzai/renderer.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb index 6924a293da8..ce048a36fa0 100644 --- a/lib/banzai/renderer.rb +++ b/lib/banzai/renderer.rb @@ -1,6 +1,6 @@ module Banzai module Renderer - extend self + module_function # Convert a Markdown String into an HTML-safe String of HTML # @@ -141,8 +141,6 @@ module Banzai end.html_safe end - private - def cacheless_render(text, context = {}) Gitlab::Metrics.measure(:banzai_cacheless_render) do result = render_result(text, context) -- cgit v1.2.1 From d60d5fe4e422ecd83437653bc5764c6269162125 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 15 Oct 2016 01:36:05 +0300 Subject: Improve ExtractsPath logic related to atom format * Don't set request format to atom if '.atom' suffix was not provided * Don't try '.atom' detection logic on request that uses extended_sha1 Signed-off-by: Dmitriy Zaporozhets --- lib/extracts_path.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index e4d996a3fb6..9b74364849e 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -113,17 +113,18 @@ module ExtractsPath @id = get_id @ref, @path = extract_ref(@id) @repo = @project.repository - if @options[:extended_sha1].blank? - @commit = @repo.commit(@ref) - else - @commit = @repo.commit(@options[:extended_sha1]) - end - if @path.empty? && !@commit - @id = @ref = extract_ref_without_atom(@id) + if @options[:extended_sha1].present? + @commit = @repo.commit(@options[:extended_sha1]) + else @commit = @repo.commit(@ref) - request.format = :atom if @commit + if @path.empty? && !@commit && @id.ends_with?('.atom') + @id = @ref = extract_ref_without_atom(@id) + @commit = @repo.commit(@ref) + + request.format = :atom if @commit + end end raise InvalidPathError unless @commit -- cgit v1.2.1 From 7e3ff1852340c33f5b8853190d6a24813d5920a2 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sun, 11 Sep 2016 20:38:09 +0430 Subject: Add RTL support to markdown renderer --- lib/banzai/filter/set_direction_filter.rb | 15 +++++++++++++++ lib/banzai/pipeline/gfm_pipeline.rb | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 lib/banzai/filter/set_direction_filter.rb (limited to 'lib') diff --git a/lib/banzai/filter/set_direction_filter.rb b/lib/banzai/filter/set_direction_filter.rb new file mode 100644 index 00000000000..c2976aeb7c6 --- /dev/null +++ b/lib/banzai/filter/set_direction_filter.rb @@ -0,0 +1,15 @@ +module Banzai + module Filter + # HTML filter that sets dir="auto" for RTL languages support + class SetDirectionFilter < HTML::Pipeline::Filter + def call + # select these elements just on top level of the document + doc.xpath('p|h1|h2|h3|h4|h5|h6|ol|ul[not(@class="section-nav")]|blockquote|table').each do |el| + el['dir'] = 'auto' + end + + doc + end + end + end +end diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb index 8d94b199c66..5da2d0b008c 100644 --- a/lib/banzai/pipeline/gfm_pipeline.rb +++ b/lib/banzai/pipeline/gfm_pipeline.rb @@ -25,7 +25,9 @@ module Banzai Filter::MilestoneReferenceFilter, Filter::TaskListFilter, - Filter::InlineDiffFilter + Filter::InlineDiffFilter, + + Filter::SetDirectionFilter ] end -- cgit v1.2.1 From 5f98d059396dc8c0faab4defd0414049c909b6c1 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 17 Oct 2016 12:46:00 +0200 Subject: Add `action` and `on_stop` to `environment` in .gitlab-ci.yml --- lib/gitlab/ci/config/node/environment.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/ci/config/node/environment.rb b/lib/gitlab/ci/config/node/environment.rb index daa115f9017..1c1d07843b1 100644 --- a/lib/gitlab/ci/config/node/environment.rb +++ b/lib/gitlab/ci/config/node/environment.rb @@ -8,7 +8,7 @@ module Gitlab class Environment < Entry include Validatable - ALLOWED_KEYS = %i[name url close] + ALLOWED_KEYS = %i[name url action on_stop] validations do validate do @@ -36,7 +36,11 @@ module Gitlab addressable_url: true, allow_nil: true - validates :close, boolean: true, allow_nil: true + validates :action, + inclusion: { in: %w[start stop], message: 'should be start or stop, ' }, + allow_nil: true + + validates :on_stop, string: true, allow_nil: true end end @@ -56,9 +60,13 @@ module Gitlab value[:url] end + def action + value[:action] || 'start' + end + def value case @config - when String then { name: @config } + when String then { name: @config, action: 'start' } when Hash then @config else {} end -- cgit v1.2.1 From 9b790f1cf97157240178601c62d2e557a404503e Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 17 Oct 2016 16:13:19 +0200 Subject: Improve after code review --- lib/gitlab/ci/config/node/environment.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/ci/config/node/environment.rb b/lib/gitlab/ci/config/node/environment.rb index 1c1d07843b1..b392f272bd6 100644 --- a/lib/gitlab/ci/config/node/environment.rb +++ b/lib/gitlab/ci/config/node/environment.rb @@ -37,10 +37,10 @@ module Gitlab allow_nil: true validates :action, - inclusion: { in: %w[start stop], message: 'should be start or stop, ' }, + inclusion: { in: %w[start stop], message: 'should be start or stop' }, allow_nil: true - validates :on_stop, string: true, allow_nil: true + validates :on_stop, type: String, allow_nil: true end end -- cgit v1.2.1 From 25dd1712ca01d017fd3b9c2d230a62e82444b5a1 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 17 Oct 2016 16:23:17 +0200 Subject: Add specs to test on_stop and action on environments --- lib/gitlab/ci/config/node/environment.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/gitlab/ci/config/node/environment.rb b/lib/gitlab/ci/config/node/environment.rb index b392f272bd6..9a95ef43628 100644 --- a/lib/gitlab/ci/config/node/environment.rb +++ b/lib/gitlab/ci/config/node/environment.rb @@ -64,6 +64,10 @@ module Gitlab value[:action] || 'start' end + def on_stop + value[:on_stop] + end + def value case @config when String then { name: @config, action: 'start' } -- cgit v1.2.1 From 317e48193fe5d75d6671c900a765ead719e6b4df Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Wed, 12 Oct 2016 15:34:47 +0200 Subject: Fix the diff in the merge request view when converting a symlink to a regular file. In this specific case using file_path as a cache key is not enough, because there are two entries with the same path. Closes #21610. --- lib/gitlab/diff/file.rb | 4 ++++ lib/gitlab/diff/file_collection/merge_request_diff.rb | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index e47df508ca2..ce85e5e0123 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -125,6 +125,10 @@ module Gitlab repository.blob_at(commit.id, file_path) end + + def cache_key + "#{file_path}-#{new_file}-#{deleted_file}-#{renamed_file}" + end end end end diff --git a/lib/gitlab/diff/file_collection/merge_request_diff.rb b/lib/gitlab/diff/file_collection/merge_request_diff.rb index 36348b33943..dc4d47c878b 100644 --- a/lib/gitlab/diff/file_collection/merge_request_diff.rb +++ b/lib/gitlab/diff/file_collection/merge_request_diff.rb @@ -35,16 +35,16 @@ module Gitlab # for the highlighted ones, so we just skip their execution. # If the highlighted diff files lines are not cached we calculate and cache them. # - # The content of the cache is a Hash where the key correspond to the file_path and the values are Arrays of + # The content of the cache is a Hash where the key identifies the file and the values are Arrays of # hashes that represent serialized diff lines. # def cache_highlight!(diff_file) - file_path = diff_file.file_path + item_key = diff_file.cache_key - if highlight_cache[file_path] - highlight_diff_file_from_cache!(diff_file, highlight_cache[file_path]) + if highlight_cache[item_key] + highlight_diff_file_from_cache!(diff_file, highlight_cache[item_key]) else - highlight_cache[file_path] = diff_file.highlighted_diff_lines.map(&:to_hash) + highlight_cache[item_key] = diff_file.highlighted_diff_lines.map(&:to_hash) end end -- cgit v1.2.1 From 4de883bc81d605d8cd0d138be5d0e2ff2a263d77 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Sat, 15 Oct 2016 12:09:02 +0200 Subject: Use GrapeDSL for commits --- lib/api/commits.rb | 129 ++++++++++++++++++++++++++++------------------------- 1 file changed, 69 insertions(+), 60 deletions(-) (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 14ddc8c9a62..617a240318a 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -6,33 +6,40 @@ module API before { authenticate! } before { authorize! :download_code, user_project } + params do + requires :id, type: String, desc: 'The ID of a project' + end resource :projects do - # Get a project repository commits - # - # Parameters: - # id (required) - The ID of a project - # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used - # since (optional) - Only commits after or in this date will be returned - # until (optional) - Only commits before or in this date will be returned - # Example Request: - # GET /projects/:id/repository/commits + desc 'Get a project repository commits' do + success Entities::RepoCommit + end + params do + optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used' + optional :since, type: String, desc: 'Only commits after or in this date will be returned' + optional :until, type: String, desc: 'Only commits before or in this date will be returned' + optional :page, type: Integer, default: 0, desc: 'The page for pagination' + optional :per_page, type: Integer, default: 20, desc: 'The number of results per page' + end get ":id/repository/commits" do + # TODO remove the next line for 9.0, use DateTime type in the params block datetime_attributes! :since, :until - page = (params[:page] || 0).to_i - per_page = (params[:per_page] || 20).to_i ref = params[:ref_name] || user_project.try(:default_branch) || 'master' - after = params[:since] - before = params[:until] + offset = params[:page] * params[:per_page] + + commits = user_project.repository.commits(ref, + limit: params[:per_page], + offset: offset, + after: params[:since], + before: params[:until]) - commits = user_project.repository.commits(ref, limit: per_page, offset: page * per_page, after: after, before: before) present commits, with: Entities::RepoCommit end desc 'Commit multiple file changes as one commit' do + success Entities::RepoCommitDetail detail 'This feature was introduced in GitLab 8.13' end - params do requires :id, type: Integer, desc: 'The project ID' requires :branch_name, type: String, desc: 'The name of branch' @@ -41,7 +48,6 @@ module API optional :author_email, type: String, desc: 'Author email for commit' optional :author_name, type: String, desc: 'Author name for commit' end - post ":id/repository/commits" do authorize! :push_code, user_project @@ -65,79 +71,82 @@ module API end end - # Get a specific commit of a project - # - # Parameters: - # id (required) - The ID of a project - # sha (required) - The commit hash or name of a repository branch or tag - # Example Request: - # GET /projects/:id/repository/commits/:sha + desc 'Get a specific commit of a project' do + success Entities::RepoCommitDetail + failure [[404, 'Not Found']] + end + params do + requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' + end get ":id/repository/commits/:sha" do - sha = params[:sha] - commit = user_project.commit(sha) + commit = user_project.commit(params[:sha]) + not_found! "Commit" unless commit + present commit, with: Entities::RepoCommitDetail end - # Get the diff for a specific commit of a project - # - # Parameters: - # id (required) - The ID of a project - # sha (required) - The commit or branch name - # Example Request: - # GET /projects/:id/repository/commits/:sha/diff + desc 'Get the diff for a specific commit of a project' do + failure [[404, 'Not Found']] + end + params do + requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' + end get ":id/repository/commits/:sha/diff" do - sha = params[:sha] - commit = user_project.commit(sha) + commit = user_project.commit(params[:sha]) + not_found! "Commit" unless commit + commit.raw_diffs.to_a end - # Get a commit's comments - # - # Parameters: - # id (required) - The ID of a project - # sha (required) - The commit hash - # Examples: - # GET /projects/:id/repository/commits/:sha/comments + desc "Get a commit's comments" do + success Entities::CommitNote + failure [[404, 'Not Found']] + end + params do + requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' + optional :per_page, type: Integer, desc: 'The amount of items per page for paginaion' + optional :page, type: Integer, desc: 'The page number for pagination' + end get ':id/repository/commits/:sha/comments' do - sha = params[:sha] - commit = user_project.commit(sha) + commit = user_project.commit(params[:sha]) + not_found! 'Commit' unless commit notes = Note.where(commit_id: commit.id).order(:created_at) + present paginate(notes), with: Entities::CommitNote end - # Post comment to commit - # - # Parameters: - # id (required) - The ID of a project - # sha (required) - The commit hash - # note (required) - Text of comment - # path (optional) - The file path - # line (optional) - The line number - # line_type (optional) - The type of line (new or old) - # Examples: - # POST /projects/:id/repository/commits/:sha/comments + desc 'Post comment to commit' do + success Entities::CommitNote + end + params do + requires :sha, type: String, regexp: /\A\h{6,40}\z/, desc: "The commit's SHA" + requires :note, type: String, desc: 'The text of the comment' + optional :path, type: String, desc: 'The file path' + given :path do + requires :line, type: Integer, desc: 'The line number' + requires :line_type, type: String, values: ['new', 'old'], default: 'new', desc: 'The type of the line' + end + end post ':id/repository/commits/:sha/comments' do - required_attributes! [:note] - - sha = params[:sha] - commit = user_project.commit(sha) + commit = user_project.commit(params[:sha]) not_found! 'Commit' unless commit + opts = { note: params[:note], noteable_type: 'Commit', commit_id: commit.id } - if params[:path] && params[:line] && params[:line_type] + if params[:path] commit.raw_diffs(all_diffs: true).each do |diff| next unless diff.new_path == params[:path] lines = Gitlab::Diff::Parser.new.parse(diff.diff.each_line) lines.each do |line| - next unless line.new_pos == params[:line].to_i && line.type == params[:line_type] + next unless line.new_pos == params[:line] && line.type == params[:line_type] break opts[:line_code] = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos) end -- cgit v1.2.1 From ad85928752ea6c41863c6b8225ff2279e3044bef Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 18 Oct 2016 12:22:51 +0200 Subject: Add logical validation to gitlab-ci.yml --- lib/ci/gitlab_ci_yaml_processor.rb | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'lib') diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 2fd1fced65c..3e33c9399e2 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -109,6 +109,7 @@ module Ci validate_job_stage!(name, job) validate_job_dependencies!(name, job) + validate_job_environment!(name, job) end end @@ -150,6 +151,35 @@ module Ci end end + def validate_job_environment!(name, job) + return unless job[:environment] + return unless job[:environment].is_a?(Hash) + + environment = job[:environment] + validate_on_stop_job!(name, environment, environment[:on_stop]) + end + + def validate_on_stop_job!(name, environment, on_stop) + return unless on_stop + + on_stop_job = @jobs[on_stop.to_sym] + unless on_stop_job + raise ValidationError, "#{name} job: on_stop job #{on_stop} is not defined" + end + + unless on_stop_job[:environment] + raise ValidationError, "#{name} job: on_stop job #{on_stop} does not have environment defined" + end + + unless on_stop_job[:environment][:name] == environment[:name] + raise ValidationError, "#{name} job: on_stop job #{on_stop} have different environment name" + end + + unless on_stop_job[:environment][:action] == 'stop' + raise ValidationError, "#{name} job: on_stop job #{on_stop} needs to have action stop defined" + end + end + def process?(only_params, except_params, ref, tag, trigger_request) if only_params.present? return false unless matching?(only_params, ref, tag, trigger_request) -- cgit v1.2.1 From 9c8c5e9dc050f32cec05f6903105ff34d726979b Mon Sep 17 00:00:00 2001 From: amaia Date: Mon, 17 Oct 2016 05:53:12 -0700 Subject: fix: commit messages being double-escaped in activies tab --- lib/banzai/filter/html_entity_filter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/banzai/filter/html_entity_filter.rb b/lib/banzai/filter/html_entity_filter.rb index e008fd428b0..f3bd587c28b 100644 --- a/lib/banzai/filter/html_entity_filter.rb +++ b/lib/banzai/filter/html_entity_filter.rb @@ -5,7 +5,7 @@ module Banzai # Text filter that escapes these HTML entities: & " < > class HtmlEntityFilter < HTML::Pipeline::TextFilter def call - ERB::Util.html_escape(text) + ERB::Util.html_escape_once(text) end end end -- cgit v1.2.1 From 3db585d27c005397aab3fa05cbe77853bc1019be Mon Sep 17 00:00:00 2001 From: the-undefined Date: Wed, 12 Oct 2016 06:12:31 +0100 Subject: Add Nofollow for uppercased scheme in external url Ensure that external URLs with non-lowercase protocols will be attributed with 'nofollow noreferrer' and open up in a new window. Covers the edge cases to skip: - HTTPS schemes - relative links Closes #22782 --- lib/banzai/filter/external_link_filter.rb | 34 +++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/external_link_filter.rb b/lib/banzai/filter/external_link_filter.rb index 0a29c547a4d..2f19b59e725 100644 --- a/lib/banzai/filter/external_link_filter.rb +++ b/lib/banzai/filter/external_link_filter.rb @@ -3,10 +3,17 @@ module Banzai # HTML Filter to modify the attributes of external links class ExternalLinkFilter < HTML::Pipeline::Filter def call - # Skip non-HTTP(S) links and internal links - doc.xpath("descendant-or-self::a[starts-with(@href, 'http') and not(starts-with(@href, '#{internal_url}'))]").each do |node| - node.set_attribute('rel', 'nofollow noreferrer') - node.set_attribute('target', '_blank') + links.each do |node| + href = href_to_lowercase_scheme(node["href"].to_s) + + unless node["href"].to_s == href + node.set_attribute('href', href) + end + + if href =~ /\Ahttp(s)?:\/\// && external_url?(href) + node.set_attribute('rel', 'nofollow noreferrer') + node.set_attribute('target', '_blank') + end end doc @@ -14,6 +21,25 @@ module Banzai private + def links + query = 'descendant-or-self::a[@href and not(@href = "")]' + doc.xpath(query) + end + + def href_to_lowercase_scheme(href) + scheme_match = href.match(/\A(\w+):\/\//) + + if scheme_match + scheme_match.to_s.downcase + scheme_match.post_match + else + href + end + end + + def external_url?(url) + !url.start_with?(internal_url) + end + def internal_url @internal_url ||= Gitlab.config.gitlab.url end -- cgit v1.2.1 From c7282f89596293423c61d6676db60a9a347d09ef Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 14 Oct 2016 10:45:23 +0200 Subject: Grapify the commit status API --- lib/api/commit_statuses.rb | 53 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb index dfbdd597d29..f282a3b9cd6 100644 --- a/lib/api/commit_statuses.rb +++ b/lib/api/commit_statuses.rb @@ -6,17 +6,17 @@ module API resource :projects do before { authenticate! } - # Get a commit's statuses - # - # Parameters: - # id (required) - The ID of a project - # sha (required) - The commit hash - # ref (optional) - The ref - # stage (optional) - The stage - # name (optional) - The name - # all (optional) - Show all statuses, default: false - # Examples: - # GET /projects/:id/repository/commits/:sha/statuses + desc "Get a commit's statuses" do + success Entities::CommitStatus + end + params do + requires :id, type: String, desc: 'The ID of a project' + requires :sha, type: String, desc: 'The commit hash' + optional :ref, type: String, desc: 'The ref' + optional :stage, type: String, desc: 'The stage' + optional :name, type: String, desc: 'The name' + optional :all, type: String, desc: 'Show all statuses, default: false' + end get ':id/repository/commits/:sha/statuses' do authorize!(:read_commit_status, user_project) @@ -31,22 +31,23 @@ module API present paginate(statuses), with: Entities::CommitStatus end - # Post status to commit - # - # Parameters: - # id (required) - The ID of a project - # sha (required) - The commit hash - # ref (optional) - The ref - # state (required) - The state of the status. Can be: pending, running, success, failed or canceled - # target_url (optional) - The target URL to associate with this status - # description (optional) - A short description of the status - # name or context (optional) - A string label to differentiate this status from the status of other systems. Default: "default" - # Examples: - # POST /projects/:id/statuses/:sha + desc 'Post status to a commit' do + success Entities::CommitStatus + end + params do + requires :id, type: String, desc: 'The ID of a project' + requires :sha, type: String, desc: 'The commit hash' + requires :state, type: String, desc: 'The state of the status', + values: ['pending', 'running', 'success', 'failed', 'canceled'] + optional :ref, type: String, desc: 'The ref' + optional :target_url, type: String, desc: 'The target URL to associate with this status' + optional :description, type: String, desc: 'A short description of the status' + optional :name, type: String, desc: 'A string label to differentiate this status from the status of other systems. Default: "default"' + optional :context, type: String, desc: 'A string label to differentiate this status from the status of other systems. Default: "default"' + end post ':id/statuses/:sha' do authorize! :create_commit_status, user_project - required_attributes! [:state] - attrs = attributes_for_keys [:target_url, :description] + commit = @project.commit(params[:sha]) not_found! 'Commit' unless commit @@ -68,7 +69,7 @@ module API status = GenericCommitStatus.running_or_pending.find_or_initialize_by( project: @project, pipeline: pipeline, user: current_user, name: name, ref: ref) - status.attributes = attrs + status.attributes = declared(params).slice(:target_url, :description) begin case params[:state].to_s -- cgit v1.2.1 From 8e4301d982ce28d80e711865ac294a98ddce3ec6 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Thu, 6 Oct 2016 19:05:27 -0300 Subject: Prevent wrong markdown on issue ids when project has Jira service activated --- lib/banzai/filter/abstract_reference_filter.rb | 16 ++++++++++-- .../filter/external_issue_reference_filter.rb | 29 ++++++++++++---------- lib/banzai/filter/issue_reference_filter.rb | 8 ++++++ 3 files changed, 38 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb index affe34394c2..cb213a76a05 100644 --- a/lib/banzai/filter/abstract_reference_filter.rb +++ b/lib/banzai/filter/abstract_reference_filter.rb @@ -208,8 +208,12 @@ module Banzai @references_per_project ||= begin refs = Hash.new { |hash, key| hash[key] = Set.new } - regex = Regexp.union(object_class.reference_pattern, - object_class.link_reference_pattern) + regex = + if uses_reference_pattern? + Regexp.union(object_class.reference_pattern, object_class.link_reference_pattern) + else + object_class.link_reference_pattern + end nodes.each do |node| node.to_html.scan(regex) do @@ -295,6 +299,14 @@ module Banzai value end end + + # There might be special cases like filters + # that should ignore reference pattern + # eg: IssueReferenceFilter when using a external issues tracker + # In those cases this method should be overridden on the filter subclass + def uses_reference_pattern? + true + end end end end diff --git a/lib/banzai/filter/external_issue_reference_filter.rb b/lib/banzai/filter/external_issue_reference_filter.rb index eaa702952cc..0d20be557a0 100644 --- a/lib/banzai/filter/external_issue_reference_filter.rb +++ b/lib/banzai/filter/external_issue_reference_filter.rb @@ -8,7 +8,7 @@ module Banzai # Public: Find `JIRA-123` issue references in text # - # ExternalIssueReferenceFilter.references_in(text) do |match, issue| + # ExternalIssueReferenceFilter.references_in(text, pattern) do |match, issue| # "##{issue}" # end # @@ -17,8 +17,8 @@ module Banzai # Yields the String match and the String issue reference. # # Returns a String replaced with the return of the block. - def self.references_in(text) - text.gsub(ExternalIssue.reference_pattern) do |match| + def self.references_in(text, pattern) + text.gsub(pattern) do |match| yield match, $~[:issue] end end @@ -27,7 +27,7 @@ module Banzai # Early return if the project isn't using an external tracker return doc if project.nil? || default_issues_tracker? - ref_pattern = ExternalIssue.reference_pattern + ref_pattern = issue_reference_pattern ref_start_pattern = /\A#{ref_pattern}\z/ each_node do |node| @@ -60,7 +60,7 @@ module Banzai def issue_link_filter(text, link_text: nil) project = context[:project] - self.class.references_in(text) do |match, id| + self.class.references_in(text, issue_reference_pattern) do |match, id| ExternalIssue.new(id, project) url = url_for_issue(id, project, only_path: context[:only_path]) @@ -82,18 +82,21 @@ module Banzai end def default_issues_tracker? - if RequestStore.active? - default_issues_tracker_cache[project.id] ||= - project.default_issues_tracker? - else - project.default_issues_tracker? - end + external_issues_cached(:default_issues_tracker?) + end + + def issue_reference_pattern + external_issues_cached(:issue_reference_pattern) end private - def default_issues_tracker_cache - RequestStore[:banzai_default_issues_tracker_cache] ||= {} + def external_issues_cached(attribute) + return project.public_send(attribute) unless RequestStore.active? + + cached_attributes = RequestStore[:banzai_external_issues_tracker_attributes] ||= Hash.new { |h, k| h[k] = {} } + cached_attributes[project.id][attribute] = project.public_send(attribute) if cached_attributes[project.id][attribute].nil? + cached_attributes[project.id][attribute] end end end diff --git a/lib/banzai/filter/issue_reference_filter.rb b/lib/banzai/filter/issue_reference_filter.rb index 54c5f9a71a4..4d1bc687696 100644 --- a/lib/banzai/filter/issue_reference_filter.rb +++ b/lib/banzai/filter/issue_reference_filter.rb @@ -4,6 +4,10 @@ module Banzai # issues that do not exist are ignored. # # This filter supports cross-project references. + # + # When external issues tracker like Jira is activated we should not + # use issue reference pattern, but we should still be able + # to reference issues from other GitLab projects. class IssueReferenceFilter < AbstractReferenceFilter self.reference_type = :issue @@ -11,6 +15,10 @@ module Banzai Issue end + def uses_reference_pattern? + context[:project].default_issues_tracker? + end + def find_object(project, iid) issues_per_project[project][iid] end -- cgit v1.2.1 From 476c26deb22a6e958dc3251e9771560b058a34a3 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 20 Sep 2016 00:59:26 -0300 Subject: Replace label references with links for group labels --- lib/banzai/filter/label_reference_filter.rb | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb index 8f262ef3d8d..3a09912f1be 100644 --- a/lib/banzai/filter/label_reference_filter.rb +++ b/lib/banzai/filter/label_reference_filter.rb @@ -9,7 +9,7 @@ module Banzai end def find_object(project, id) - project.labels.find(id) + find_labels(project).find(id) end def self.references_in(text, pattern = Label.reference_pattern) @@ -35,7 +35,17 @@ module Banzai return unless project label_params = label_params(label_id, label_name) - project.labels.find_by(label_params) + find_labels(project).find_by(label_params) + end + + def find_labels(project) + label_ids = [] + label_ids << project.group.labels.select(:id) if project.group.present? + label_ids << project.labels.select(:id) + + union = Gitlab::SQL::Union.new(label_ids) + + object_class.where("labels.id IN (#{union.to_sql})") end # Parameters to pass to `Label.find_by` based on the given arguments @@ -60,7 +70,7 @@ module Banzai end def object_link_text(object, matches) - if context[:project] == object.project + if object.project.nil? || object.project == context[:project] LabelsHelper.render_colored_label(object) else LabelsHelper.render_colored_cross_project_label(object) -- cgit v1.2.1 From cfedd42badc6b84457d1de35cb31988777462d5a Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 20 Sep 2016 17:07:56 -0300 Subject: Add ProjectLabel model --- lib/banzai/filter/label_reference_filter.rb | 2 +- lib/gitlab/google_code_import/importer.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb index 3a09912f1be..4c4784b0052 100644 --- a/lib/banzai/filter/label_reference_filter.rb +++ b/lib/banzai/filter/label_reference_filter.rb @@ -70,7 +70,7 @@ module Banzai end def object_link_text(object, matches) - if object.project.nil? || object.project == context[:project] + if object.is_a?(GroupLabel) || object.project == context[:project] LabelsHelper.render_colored_label(object) else LabelsHelper.render_colored_cross_project_label(object) diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb index 62da327931f..ef8c3e35619 100644 --- a/lib/gitlab/google_code_import/importer.rb +++ b/lib/gitlab/google_code_import/importer.rb @@ -237,7 +237,7 @@ module Gitlab def create_label(name) color = nice_label_color(name) - Label.create!(project_id: project.id, name: name, color: color) + project.labels.create!(name: name, color: color) end def format_content(raw_content) -- cgit v1.2.1 From e036a72dca49766df3ee455d6ac955c30846f3fb Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 28 Sep 2016 11:12:44 -0300 Subject: Add Lavel#type to methods in lib/gitlab/import_export/import_export.yml --- lib/gitlab/import_export/import_export.yml | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index bb9d1080330..4204a13dd63 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -71,6 +71,8 @@ excluded_attributes: - :awardable_id methods: + labels: + - :type statuses: - :type services: -- cgit v1.2.1 From 07709c5576a06179c5365b0d7fe154c5f67ca7e5 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 29 Sep 2016 00:21:47 -0300 Subject: Unfold references for group labels when moving issue to another project --- lib/banzai/filter/label_reference_filter.rb | 39 ++++++++++++++++++++++++++--- lib/gitlab/gfm/reference_rewriter.rb | 18 ++++++++++++- 2 files changed, 53 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb index 4c4784b0052..649c697b415 100644 --- a/lib/banzai/filter/label_reference_filter.rb +++ b/lib/banzai/filter/label_reference_filter.rb @@ -70,13 +70,46 @@ module Banzai end def object_link_text(object, matches) - if object.is_a?(GroupLabel) || object.project == context[:project] - LabelsHelper.render_colored_label(object) + if same_group?(object) && namespace_match?(matches) + render_same_project_label(object) + elsif same_project?(object) + render_same_project_label(object) else - LabelsHelper.render_colored_cross_project_label(object) + render_cross_project_label(object, matches) end end + def same_group?(object) + object.is_a?(GroupLabel) && object.group == project.group + end + + def namespace_match?(matches) + matches[:project].blank? || matches[:project] == project.path_with_namespace + end + + def same_project?(object) + object.is_a?(ProjectLabel) && object.project == project + end + + def project + context[:project] + end + + def render_same_project_label(object) + LabelsHelper.render_colored_label(object) + end + + def render_cross_project_label(object, matches) + source_project = + if matches[:project] + Project.find_with_namespace(matches[:project]) + else + object.project + end + + LabelsHelper.render_colored_cross_project_label(object, source_project) + end + def unescape_html_entities(text) CGI.unescapeHTML(text.to_s) end diff --git a/lib/gitlab/gfm/reference_rewriter.rb b/lib/gitlab/gfm/reference_rewriter.rb index 78d7a4f27cf..d0b8cd90e0e 100644 --- a/lib/gitlab/gfm/reference_rewriter.rb +++ b/lib/gitlab/gfm/reference_rewriter.rb @@ -58,7 +58,7 @@ module Gitlab referable = find_referable(reference) return reference unless referable - cross_reference = referable.to_reference(target_project) + cross_reference = build_cross_reference(referable, target_project) return reference if reference == cross_reference new_text = before + cross_reference + after @@ -72,6 +72,22 @@ module Gitlab extractor.all.first end + def build_cross_reference(referable, target_project) + if referable.respond_to?(:project) + referable.to_reference(target_project) + else + to_reference(referable, target_project) + end + end + + def to_reference(referable, target_project) + if @source_project != target_project + @source_project.to_reference + referable.to_reference + else + referable.to_reference + end + end + def substitution_valid?(substituted) @original_html == markdown(substituted) end -- cgit v1.2.1 From 848a146fc3bd34ec94a206f2ed6ef33d539bfce5 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 29 Sep 2016 09:51:12 +0200 Subject: Fix import test --- lib/gitlab/import_export/import_export.yml | 4 +++- lib/gitlab/import_export/relation_factory.rb | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index 4204a13dd63..59abca04b35 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -71,7 +71,9 @@ excluded_attributes: - :awardable_id methods: - labels: + project_labels: + - :type + label: - :type statuses: - :type diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 9300f789e1b..5a84bc97226 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -9,7 +9,8 @@ module Gitlab builds: 'Ci::Build', hooks: 'ProjectHook', merge_access_levels: 'ProtectedBranch::MergeAccessLevel', - push_access_levels: 'ProtectedBranch::PushAccessLevel' }.freeze + push_access_levels: 'ProtectedBranch::PushAccessLevel', + labels: :project_labels }.freeze USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id].freeze @@ -19,7 +20,7 @@ module Gitlab IMPORTED_OBJECT_MAX_RETRIES = 5.freeze - EXISTING_OBJECT_CHECK = %i[milestone milestones label labels].freeze + EXISTING_OBJECT_CHECK = %i[milestone milestones label labels project_label project_labels].freeze FINDER_ATTRIBUTES = %w[title project_id].freeze -- cgit v1.2.1 From 77b7bfd463bf57d38cb6aa30f277cd19ffbb6504 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 29 Sep 2016 13:15:18 +0200 Subject: Fix import/export labels to cope with project and group labels. Added relevant specs. --- lib/gitlab/import_export.rb | 2 +- lib/gitlab/import_export/import_export.yml | 2 +- lib/gitlab/import_export/project_tree_restorer.rb | 7 ++++++- lib/gitlab/import_export/relation_factory.rb | 20 ++++++++++++++++++-- 4 files changed, 26 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb index 181e288a014..eb667a85b78 100644 --- a/lib/gitlab/import_export.rb +++ b/lib/gitlab/import_export.rb @@ -3,7 +3,7 @@ module Gitlab extend self # For every version update, the version history in import_export.md has to be kept up to date. - VERSION = '0.1.4' + VERSION = '0.1.5' FILENAME_LIMIT = 50 def export_path(relative_path:) diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index 59abca04b35..8882f146632 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -71,7 +71,7 @@ excluded_attributes: - :awardable_id methods: - project_labels: + labels: - :type label: - :type diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb index 5a109f24f9f..accac5325f8 100644 --- a/lib/gitlab/import_export/project_tree_restorer.rb +++ b/lib/gitlab/import_export/project_tree_restorer.rb @@ -110,7 +110,7 @@ module Gitlab def create_relation(relation, relation_hash_list) relation_array = [relation_hash_list].flatten.map do |relation_hash| Gitlab::ImportExport::RelationFactory.create(relation_sym: relation.to_sym, - relation_hash: relation_hash, + relation_hash: parsed_relation_hash(relation_hash), members_mapper: members_mapper, user: @user, project_id: restored_project.id) @@ -118,6 +118,11 @@ module Gitlab relation_hash_list.is_a?(Array) ? relation_array : relation_array.first end + + def parsed_relation_hash(relation_hash) + group_id = restored_project.group ? restored_project.group.id : nil + relation_hash.merge!('group_id' => group_id, 'project_id' => restored_project.id) + end end end end diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 5a84bc97226..8bc4ab85c18 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -10,7 +10,8 @@ module Gitlab hooks: 'ProjectHook', merge_access_levels: 'ProtectedBranch::MergeAccessLevel', push_access_levels: 'ProtectedBranch::PushAccessLevel', - labels: :project_labels }.freeze + labels: :project_labels, + label: :project_label }.freeze USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id].freeze @@ -20,7 +21,7 @@ module Gitlab IMPORTED_OBJECT_MAX_RETRIES = 5.freeze - EXISTING_OBJECT_CHECK = %i[milestone milestones label labels project_label project_labels].freeze + EXISTING_OBJECT_CHECK = %i[milestone milestones label labels project_label project_labels project_label group_label].freeze FINDER_ATTRIBUTES = %w[title project_id].freeze @@ -57,6 +58,8 @@ module Gitlab update_user_references update_project_references + + handle_group_label if group_label? reset_ci_tokens if @relation_name == 'Ci::Trigger' @relation_hash['data'].deep_symbolize_keys! if @relation_name == :events && @relation_hash['data'] set_st_diffs if @relation_name == :merge_request_diff @@ -124,6 +127,19 @@ module Gitlab @relation_hash['target_project_id'] && @relation_hash['target_project_id'] == @relation_hash['source_project_id'] end + def group_label? + @relation_hash['type'] == 'GroupLabel' + end + + def handle_group_label + # If there's no group, move the label to a project label + if @relation_hash['group_id'] + @relation_name = :group_label + else + @relation_hash['type'] = 'ProjectLabel' + end + end + def reset_ci_tokens return unless Gitlab::ImportExport.reset_tokens? -- cgit v1.2.1 From 3db2261005c438faad8bf4a339d46eb7798f05b5 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 29 Sep 2016 15:50:14 -0300 Subject: Reuse LabelsFinder on Banzai::Filter::LabelReferenceFilter --- lib/banzai/filter/label_reference_filter.rb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb index 649c697b415..2ce33aa1d15 100644 --- a/lib/banzai/filter/label_reference_filter.rb +++ b/lib/banzai/filter/label_reference_filter.rb @@ -39,13 +39,7 @@ module Banzai end def find_labels(project) - label_ids = [] - label_ids << project.group.labels.select(:id) if project.group.present? - label_ids << project.labels.select(:id) - - union = Gitlab::SQL::Union.new(label_ids) - - object_class.where("labels.id IN (#{union.to_sql})") + LabelsFinder.new(user, project_id: project.id).execute end # Parameters to pass to `Label.find_by` based on the given arguments @@ -91,6 +85,10 @@ module Banzai object.is_a?(ProjectLabel) && object.project == project end + def user + context[:current_user] || context[:author] + end + def project context[:project] end -- cgit v1.2.1 From 7e11ca86fdb23c967c25b19735770f99f936b32c Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 3 Oct 2016 18:41:46 -0300 Subject: Reuse LabelsFinder on Issueable#add_labels_by_names --- lib/api/merge_requests.rb | 4 ++-- lib/gitlab/fogbugz_import/importer.rb | 2 +- lib/gitlab/google_code_import/importer.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 2b685621da9..67fdd0be927 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -91,7 +91,7 @@ module API if merge_request.valid? # Find or create labels and attach to issue if params[:labels].present? - merge_request.add_labels_by_names(params[:labels].split(",")) + merge_request.add_labels_by_names(params[:labels].split(","), current_user) end present merge_request, with: Entities::MergeRequest, current_user: current_user @@ -201,7 +201,7 @@ module API # Find or create labels and attach to issue unless params[:labels].nil? merge_request.remove_labels - merge_request.add_labels_by_names(params[:labels].split(",")) + merge_request.add_labels_by_names(params[:labels].split(","), current_user) end present merge_request, with: Entities::MergeRequest, current_user: current_user diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb index 501d5a95547..1d6f97b99c7 100644 --- a/lib/gitlab/fogbugz_import/importer.rb +++ b/lib/gitlab/fogbugz_import/importer.rb @@ -129,7 +129,7 @@ module Gitlab assignee_id: assignee_id, state: bug['fOpen'] == 'true' ? 'opened' : 'closed' ) - issue.add_labels_by_names(labels) + issue.add_labels_by_names(labels, project.creator) if issue.iid != bug['ixBug'] issue.update_attribute(:iid, bug['ixBug']) diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb index ef8c3e35619..8d757da2264 100644 --- a/lib/gitlab/google_code_import/importer.rb +++ b/lib/gitlab/google_code_import/importer.rb @@ -100,7 +100,7 @@ module Gitlab state: raw_issue["state"] == "closed" ? "closed" : "opened" ) - issue.add_labels_by_names(labels) + issue.add_labels_by_names(labels, project.creator) if issue.iid != raw_issue["id"] issue.update_attribute(:iid, raw_issue["id"]) -- cgit v1.2.1 From 11d786e7da9f767a877bbdd4fd482c0d0c4cd747 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 3 Oct 2016 18:59:04 -0300 Subject: Use try instead of ternary operator on Gitlab::ImportExport::ProjectTreeRestorer --- lib/gitlab/import_export/project_tree_restorer.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb index accac5325f8..7cdba880a93 100644 --- a/lib/gitlab/import_export/project_tree_restorer.rb +++ b/lib/gitlab/import_export/project_tree_restorer.rb @@ -120,8 +120,7 @@ module Gitlab end def parsed_relation_hash(relation_hash) - group_id = restored_project.group ? restored_project.group.id : nil - relation_hash.merge!('group_id' => group_id, 'project_id' => restored_project.id) + relation_hash.merge!('group_id' => restored_project.group.try(:id), 'project_id' => restored_project.id) end end end -- cgit v1.2.1 From 00e3c2e00f1c81aa2f7a76e4d93c8a1fb2074d6e Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 10 Oct 2016 23:37:07 -0300 Subject: Fix replace label references with links for group labels --- lib/banzai/filter/label_reference_filter.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb index 2ce33aa1d15..21085ae6d49 100644 --- a/lib/banzai/filter/label_reference_filter.rb +++ b/lib/banzai/filter/label_reference_filter.rb @@ -39,7 +39,13 @@ module Banzai end def find_labels(project) - LabelsFinder.new(user, project_id: project.id).execute + label_ids = [] + label_ids << project.group.labels.select(:id) if project.group.present? + label_ids << project.labels.select(:id) + + union = Gitlab::SQL::Union.new(label_ids) + + Label.where("labels.id IN (#{union.to_sql})") end # Parameters to pass to `Label.find_by` based on the given arguments -- cgit v1.2.1 From 1e6d136af31b0b91a03881a0c20b9bfa448201ee Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 11 Oct 2016 16:30:40 -0300 Subject: Keep cross project reference logic in GroupLabel#to_reference --- lib/gitlab/gfm/reference_rewriter.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/gfm/reference_rewriter.rb b/lib/gitlab/gfm/reference_rewriter.rb index d0b8cd90e0e..a7c596dced0 100644 --- a/lib/gitlab/gfm/reference_rewriter.rb +++ b/lib/gitlab/gfm/reference_rewriter.rb @@ -76,15 +76,7 @@ module Gitlab if referable.respond_to?(:project) referable.to_reference(target_project) else - to_reference(referable, target_project) - end - end - - def to_reference(referable, target_project) - if @source_project != target_project - @source_project.to_reference + referable.to_reference - else - referable.to_reference + referable.to_reference(@source_project, target_project) end end -- cgit v1.2.1 From 033ea9d1e80544df5236ca045c88f649e41afbc7 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 13 Oct 2016 18:04:55 -0300 Subject: Move label management to services on merge requests API --- lib/api/merge_requests.rb | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 67fdd0be927..bf8504e1101 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -86,14 +86,11 @@ module API render_api_error!({ labels: errors }, 400) end + attrs[:labels] = params[:labels] if params[:labels] + merge_request = ::MergeRequests::CreateService.new(user_project, current_user, attrs).execute if merge_request.valid? - # Find or create labels and attach to issue - if params[:labels].present? - merge_request.add_labels_by_names(params[:labels].split(","), current_user) - end - present merge_request, with: Entities::MergeRequest, current_user: current_user else handle_merge_request_errors! merge_request.errors @@ -195,15 +192,11 @@ module API render_api_error!({ labels: errors }, 400) end + attrs[:labels] = params[:labels] if params[:labels] + merge_request = ::MergeRequests::UpdateService.new(user_project, current_user, attrs).execute(merge_request) if merge_request.valid? - # Find or create labels and attach to issue - unless params[:labels].nil? - merge_request.remove_labels - merge_request.add_labels_by_names(params[:labels].split(","), current_user) - end - present merge_request, with: Entities::MergeRequest, current_user: current_user else handle_merge_request_errors! merge_request.errors -- cgit v1.2.1 From bf710b5119dce329a1ffd43b01b3a4dbb3e94b09 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 13 Oct 2016 18:34:44 -0300 Subject: Validate label params against all labels available to project on the API --- lib/api/helpers.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 67473f300c9..45120898b76 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -71,6 +71,10 @@ module API @project ||= find_project(params[:id]) end + def available_labels + @available_labels ||= LabelsFinder.new(current_user, project_id: user_project.id).execute + end + def find_project(id) project = Project.find_with_namespace(id) || Project.find_by(id: id) @@ -118,7 +122,7 @@ module API end def find_project_label(id) - label = user_project.labels.find_by_id(id) || user_project.labels.find_by_title(id) + label = available_labels.find_by_id(id) || available_labels.find_by_title(id) label || not_found!('Label') end @@ -197,16 +201,11 @@ module API def validate_label_params(params) errors = {} - if params[:labels].present? - params[:labels].split(',').each do |label_name| - label = user_project.labels.create_with( - color: Label::DEFAULT_COLOR).find_or_initialize_by( - title: label_name.strip) + params[:labels].to_s.split(',').each do |label_name| + label = available_labels.find_or_initialize_by(title: label_name.strip) + next if label.valid? - if label.invalid? - errors[label.title] = label.errors - end - end + errors[label.title] = label.errors end errors -- cgit v1.2.1 From 68f30b2fff362805568588f416709e7000d75ce3 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 13 Oct 2016 18:48:59 -0300 Subject: Add support to group labels on issues board API --- lib/api/boards.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/boards.rb b/lib/api/boards.rb index b14dd4f6e83..4ac491edc1b 100644 --- a/lib/api/boards.rb +++ b/lib/api/boards.rb @@ -65,8 +65,8 @@ module API requires :label_id, type: Integer, desc: 'The ID of an existing label' end post '/lists' do - unless user_project.labels.exists?(params[:label_id]) - render_api_error!({ error: "Label not found!" }, 400) + unless available_labels.exists?(params[:label_id]) + render_api_error!({ error: 'Label not found!' }, 400) end authorize!(:admin_list, user_project) -- cgit v1.2.1 From 9b288238549dac5b59fd467f6ee1fdc53b6c783e Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 13 Oct 2016 18:53:06 -0300 Subject: List all available labels to the project on the labels API --- lib/api/labels.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/labels.rb b/lib/api/labels.rb index c806829d69e..642e6345b9e 100644 --- a/lib/api/labels.rb +++ b/lib/api/labels.rb @@ -11,7 +11,7 @@ module API # Example Request: # GET /projects/:id/labels get ':id/labels' do - present user_project.labels, with: Entities::Label, current_user: current_user + present available_labels, with: Entities::Label, current_user: current_user end # Creates a new label -- cgit v1.2.1 From f008cdf218952556a0dc93962f55c0ff50733594 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 13 Oct 2016 19:30:02 -0300 Subject: Remove Issuable#add_labels_by_names --- lib/gitlab/fogbugz_import/importer.rb | 25 ++++++++++--------------- lib/gitlab/google_code_import/importer.rb | 19 ++++++++----------- 2 files changed, 18 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb index 1d6f97b99c7..9e926e2681a 100644 --- a/lib/gitlab/fogbugz_import/importer.rb +++ b/lib/gitlab/fogbugz_import/importer.rb @@ -122,25 +122,20 @@ module Gitlab author_id = user_info(bug['ixPersonOpenedBy'])[:gitlab_id] || project.creator_id issue = Issue.create!( - project_id: project.id, - title: bug['sTitle'], - description: body, - author_id: author_id, - assignee_id: assignee_id, - state: bug['fOpen'] == 'true' ? 'opened' : 'closed' + iid: bug['ixBug'], + project_id: project.id, + title: bug['sTitle'], + description: body, + author_id: author_id, + assignee_id: assignee_id, + state: bug['fOpen'] == 'true' ? 'opened' : 'closed', + created_at: date, + updated_at: DateTime.parse(bug['dtLastUpdated']) ) - issue.add_labels_by_names(labels, project.creator) - if issue.iid != bug['ixBug'] - issue.update_attribute(:iid, bug['ixBug']) - end + issue.update_attribute(:label_ids, project.labels.where(title: labels).pluck(:id)) import_issue_comments(issue, comments) - - issue.update_attribute(:created_at, date) - - last_update = DateTime.parse(bug['dtLastUpdated']) - issue.update_attribute(:updated_at, last_update) end end diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb index 8d757da2264..79a0eaba1e8 100644 --- a/lib/gitlab/google_code_import/importer.rb +++ b/lib/gitlab/google_code_import/importer.rb @@ -92,19 +92,16 @@ module Gitlab end issue = Issue.create!( - project_id: project.id, - title: raw_issue["title"], - description: body, - author_id: project.creator_id, - assignee_id: assignee_id, - state: raw_issue["state"] == "closed" ? "closed" : "opened" + iid: raw_issue['id'], + project_id: project.id, + title: raw_issue['title'], + description: body, + author_id: project.creator_id, + assignee_id: assignee_id, + state: raw_issue['state'] == 'closed' ? 'closed' : 'opened' ) - issue.add_labels_by_names(labels, project.creator) - - if issue.iid != raw_issue["id"] - issue.update_attribute(:iid, raw_issue["id"]) - end + issue.update_attribute(:label_ids, project.labels.where(title: labels).pluck(:id)) import_issue_comments(issue, comments) end -- cgit v1.2.1 From d3b76e832f0afc38e2d0ffdff540c708a74ac26c Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 17 Oct 2016 17:30:49 -0200 Subject: Reuse LabelsFinder on Banzai::Filter::LabelReferenceFilter --- lib/banzai/filter/label_reference_filter.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb index 21085ae6d49..c24831e68ee 100644 --- a/lib/banzai/filter/label_reference_filter.rb +++ b/lib/banzai/filter/label_reference_filter.rb @@ -39,13 +39,7 @@ module Banzai end def find_labels(project) - label_ids = [] - label_ids << project.group.labels.select(:id) if project.group.present? - label_ids << project.labels.select(:id) - - union = Gitlab::SQL::Union.new(label_ids) - - Label.where("labels.id IN (#{union.to_sql})") + LabelsFinder.new(nil, project_id: project.id).execute(authorized_only: false) end # Parameters to pass to `Label.find_by` based on the given arguments -- cgit v1.2.1 From d009d38ed6ab5459f596194ce808c304e6379161 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 18 Oct 2016 00:27:10 -0200 Subject: User Labes::CreateService to create labels --- lib/gitlab/fogbugz_import/importer.rb | 4 ++-- lib/gitlab/github_import/label_formatter.rb | 7 ++++--- lib/gitlab/google_code_import/importer.rb | 4 ++-- lib/gitlab/issues_labels.rb | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb index 9e926e2681a..f154ee689cf 100644 --- a/lib/gitlab/fogbugz_import/importer.rb +++ b/lib/gitlab/fogbugz_import/importer.rb @@ -74,8 +74,8 @@ module Gitlab end def create_label(name) - color = nice_label_color(name) - Label.create!(project_id: project.id, title: name, color: color) + params = { title: name, color: nice_label_color(name) } + ::Labels::CreateService.new(project.owner, project, params).execute end def user_info(person_id) diff --git a/lib/gitlab/github_import/label_formatter.rb b/lib/gitlab/github_import/label_formatter.rb index 2cad7fca88e..3101116a614 100644 --- a/lib/gitlab/github_import/label_formatter.rb +++ b/lib/gitlab/github_import/label_formatter.rb @@ -14,9 +14,10 @@ module Gitlab end def create! - project.labels.find_or_create_by!(title: title) do |label| - label.color = color - end + params = attributes.except(:project) + service = ::Labels::CreateService.new(project.owner, project, params) + + service.execute end private diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb index 79a0eaba1e8..904a228aeef 100644 --- a/lib/gitlab/google_code_import/importer.rb +++ b/lib/gitlab/google_code_import/importer.rb @@ -233,8 +233,8 @@ module Gitlab end def create_label(name) - color = nice_label_color(name) - project.labels.create!(name: name, color: color) + params = { name: name, color: nice_label_color(name) } + ::Labels::CreateService.new(project.owner, project, params).execute end def format_content(raw_content) diff --git a/lib/gitlab/issues_labels.rb b/lib/gitlab/issues_labels.rb index 1bec6088292..6788eca7146 100644 --- a/lib/gitlab/issues_labels.rb +++ b/lib/gitlab/issues_labels.rb @@ -18,8 +18,8 @@ module Gitlab { title: "enhancement", color: green } ] - labels.each do |label| - project.labels.create(label) + labels.each do |params| + ::Labels::CreateService.new(project.owner, project).execute(params) end end end -- cgit v1.2.1 From f0ad0ceff5236f3ee5babee47bfec217a54c3b07 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 18 Oct 2016 06:26:16 -0200 Subject: Fix GitHub importer spec --- lib/gitlab/github_import/label_formatter.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/github_import/label_formatter.rb b/lib/gitlab/github_import/label_formatter.rb index 3101116a614..8ed1574c4fc 100644 --- a/lib/gitlab/github_import/label_formatter.rb +++ b/lib/gitlab/github_import/label_formatter.rb @@ -16,8 +16,11 @@ module Gitlab def create! params = attributes.except(:project) service = ::Labels::CreateService.new(project.owner, project, params) + label = service.execute - service.execute + raise ActiveRecord::RecordInvalid.new(label) unless label.persisted? + + label end private -- cgit v1.2.1 From 891e5f4851c2067daba12a1750651170a1583481 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 18 Oct 2016 19:31:10 +0200 Subject: Update specs to cope with new label types and priorities Fixed all related specs and also changed the logic to handle edge cases. This includes exporting and exporting of group labels, which will get associated with the new group (if any) or they will become normal project labels otherwise. Found other issues to do with not being able to import all labels at once in the beginning of the JSON - code was much simpler when we import all labels and milestones associated to a project first, then the associations will find the already created labels instead of creating them from the associations themselves. --- lib/gitlab/import_export/attribute_cleaner.rb | 2 +- lib/gitlab/import_export/import_export.yml | 9 ++++++--- lib/gitlab/import_export/json_hash_builder.rb | 6 ++++++ lib/gitlab/import_export/relation_factory.rb | 22 ++++++++++++++-------- 4 files changed, 27 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/import_export/attribute_cleaner.rb b/lib/gitlab/import_export/attribute_cleaner.rb index b9e4042220a..f755a404693 100644 --- a/lib/gitlab/import_export/attribute_cleaner.rb +++ b/lib/gitlab/import_export/attribute_cleaner.rb @@ -1,7 +1,7 @@ module Gitlab module ImportExport class AttributeCleaner - ALLOWED_REFERENCES = RelationFactory::PROJECT_REFERENCES + RelationFactory::USER_REFERENCES + ALLOWED_REFERENCES = RelationFactory::PROJECT_REFERENCES + RelationFactory::USER_REFERENCES + ['group_id'] def self.clean!(relation_hash:) relation_hash.reject! do |key, _value| diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index 8882f146632..e6ecd118609 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -1,6 +1,7 @@ # Model relationships to be included in the project import/export project_tree: - - :labels + - labels: + :priorities - milestones: - :events - issues: @@ -9,7 +10,8 @@ project_tree: - :author - :events - label_links: - - :label + - label: + :priorities - milestone: - :events - snippets: @@ -26,7 +28,8 @@ project_tree: - :merge_request_diff - :events - label_links: - - :label + - label: + :priorities - milestone: - :events - pipelines: diff --git a/lib/gitlab/import_export/json_hash_builder.rb b/lib/gitlab/import_export/json_hash_builder.rb index 0cc10f40087..48c09dafcb6 100644 --- a/lib/gitlab/import_export/json_hash_builder.rb +++ b/lib/gitlab/import_export/json_hash_builder.rb @@ -65,11 +65,17 @@ module Gitlab # +value+ existing model to be included in the hash # +parsed_hash+ the original hash def parse_hash(value) + return nil if already_contains_methods?(value) + @attributes_finder.parse(value) do |hash| { include: hash_or_merge(value, hash) } end end + def already_contains_methods?(value) + value.is_a?(Hash) && value.values.detect { |val| val[:methods]} + end + # Adds new model configuration to an existing hash with key +current_key+ # It may include exceptions or other attribute detail configuration, parsed by +@attributes_finder+ # diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 8bc4ab85c18..dc630e76411 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -11,6 +11,7 @@ module Gitlab merge_access_levels: 'ProtectedBranch::MergeAccessLevel', push_access_levels: 'ProtectedBranch::PushAccessLevel', labels: :project_labels, + priorities: :label_priorities, label: :project_label }.freeze USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id].freeze @@ -23,8 +24,6 @@ module Gitlab EXISTING_OBJECT_CHECK = %i[milestone milestones label labels project_label project_labels project_label group_label].freeze - FINDER_ATTRIBUTES = %w[title project_id].freeze - def self.create(*args) new(*args).create end @@ -134,6 +133,7 @@ module Gitlab def handle_group_label # If there's no group, move the label to a project label if @relation_hash['group_id'] + @relation_hash['project_id'] = nil @relation_name = :group_label else @relation_hash['type'] = 'ProjectLabel' @@ -188,11 +188,9 @@ module Gitlab # Otherwise always create the record, skipping the extra SELECT clause. @existing_or_new_object ||= begin if EXISTING_OBJECT_CHECK.include?(@relation_name) - events = parsed_relation_hash.delete('events') + attribute_hash = attribute_hash_for(['events', 'priorities']) - unless events.blank? - existing_object.assign_attributes(events: events) - end + existing_object.assign_attributes(attribute_hash) if attribute_hash.any? existing_object else @@ -201,14 +199,22 @@ module Gitlab end end + def attribute_hash_for(attributes) + attributes.inject({}) do |hash, value| + hash[value] = parsed_relation_hash.delete(value) if parsed_relation_hash[value] + hash + end + end + def existing_object @existing_object ||= begin - finder_hash = parsed_relation_hash.slice(*FINDER_ATTRIBUTES) + finder_attributes = @relation_name == :group_label ? %w[title group_id] : %w[title project_id] + finder_hash = parsed_relation_hash.slice(*finder_attributes) existing_object = relation_class.find_or_create_by(finder_hash) # Done in two steps, as MySQL behaves differently than PostgreSQL using # the +find_or_create_by+ method and does not return the ID the second time. - existing_object.update(parsed_relation_hash) + existing_object.update!(parsed_relation_hash) existing_object end end -- cgit v1.2.1 From 4f6d1c1d70d744ff599ae9c51e1cbc3a3c23e13e Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 19 Oct 2016 11:53:31 -0200 Subject: Rename Labels::CreateService to Labels::FindOrCreateService --- lib/gitlab/fogbugz_import/importer.rb | 2 +- lib/gitlab/github_import/label_formatter.rb | 2 +- lib/gitlab/google_code_import/importer.rb | 2 +- lib/gitlab/issues_labels.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb index f154ee689cf..ce4d87a0741 100644 --- a/lib/gitlab/fogbugz_import/importer.rb +++ b/lib/gitlab/fogbugz_import/importer.rb @@ -75,7 +75,7 @@ module Gitlab def create_label(name) params = { title: name, color: nice_label_color(name) } - ::Labels::CreateService.new(project.owner, project, params).execute + ::Labels::FindOrCreateService.new(project.owner, project, params).execute end def user_info(person_id) diff --git a/lib/gitlab/github_import/label_formatter.rb b/lib/gitlab/github_import/label_formatter.rb index 8ed1574c4fc..942dfb3312b 100644 --- a/lib/gitlab/github_import/label_formatter.rb +++ b/lib/gitlab/github_import/label_formatter.rb @@ -15,7 +15,7 @@ module Gitlab def create! params = attributes.except(:project) - service = ::Labels::CreateService.new(project.owner, project, params) + service = ::Labels::FindOrCreateService.new(project.owner, project, params) label = service.execute raise ActiveRecord::RecordInvalid.new(label) unless label.persisted? diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb index 904a228aeef..b16a5654096 100644 --- a/lib/gitlab/google_code_import/importer.rb +++ b/lib/gitlab/google_code_import/importer.rb @@ -234,7 +234,7 @@ module Gitlab def create_label(name) params = { name: name, color: nice_label_color(name) } - ::Labels::CreateService.new(project.owner, project, params).execute + ::Labels::FindOrCreateService.new(project.owner, project, params).execute end def format_content(raw_content) diff --git a/lib/gitlab/issues_labels.rb b/lib/gitlab/issues_labels.rb index 6788eca7146..01a2c19ab23 100644 --- a/lib/gitlab/issues_labels.rb +++ b/lib/gitlab/issues_labels.rb @@ -19,7 +19,7 @@ module Gitlab ] labels.each do |params| - ::Labels::CreateService.new(project.owner, project).execute(params) + ::Labels::FindOrCreateService.new(project.owner, project).execute(params) end end end -- cgit v1.2.1 From 97762a5858864dd39aa744e19bc16b555832ebba Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 19 Oct 2016 17:27:58 -0200 Subject: Use LabelsFinder on Google Code importer --- lib/gitlab/google_code_import/importer.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/google_code_import/importer.rb b/lib/gitlab/google_code_import/importer.rb index b16a5654096..6a68e786b4f 100644 --- a/lib/gitlab/google_code_import/importer.rb +++ b/lib/gitlab/google_code_import/importer.rb @@ -101,7 +101,8 @@ module Gitlab state: raw_issue['state'] == 'closed' ? 'closed' : 'opened' ) - issue.update_attribute(:label_ids, project.labels.where(title: labels).pluck(:id)) + issue_labels = ::LabelsFinder.new(project.owner, project_id: project.id, title: labels).execute + issue.update_attribute(:label_ids, issue_labels.pluck(:id)) import_issue_comments(issue, comments) end -- cgit v1.2.1 From edef2d15f9f3b357074b73db3b26acc5b7ab2d5a Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 19 Oct 2016 17:28:14 -0200 Subject: Use LabelsFinder on Fogbuz importer --- lib/gitlab/fogbugz_import/importer.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb index ce4d87a0741..65ee85ca5a9 100644 --- a/lib/gitlab/fogbugz_import/importer.rb +++ b/lib/gitlab/fogbugz_import/importer.rb @@ -133,7 +133,8 @@ module Gitlab updated_at: DateTime.parse(bug['dtLastUpdated']) ) - issue.update_attribute(:label_ids, project.labels.where(title: labels).pluck(:id)) + issue_labels = ::LabelsFinder.new(project.owner, project_id: project.id, title: labels).execute + issue.update_attribute(:label_ids, issue_labels.pluck(:id)) import_issue_comments(issue, comments) end -- cgit v1.2.1 From 9124310f2871117acaac98781be84c9fc016e2ad Mon Sep 17 00:00:00 2001 From: Callum Dryden Date: Thu, 6 Oct 2016 15:19:27 +0000 Subject: Differentiate the expire from leave event At the moment we cannot see weather a user left a project due to their membership expiring of if they themselves opted to leave the project. This adds a new event type that allows us to make this differentiation. Note that is not really feasable to go back and reliably fix up the previous events. As a result the events for previous expire removals will remain the same however events of this nature going forward will be correctly represented. --- lib/event_filter.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/event_filter.rb b/lib/event_filter.rb index 96e70e37e8f..21f6a9a762b 100644 --- a/lib/event_filter.rb +++ b/lib/event_filter.rb @@ -45,9 +45,16 @@ class EventFilter when EventFilter.comments actions = [Event::COMMENTED] when EventFilter.team - actions = [Event::JOINED, Event::LEFT] + actions = [Event::JOINED, Event::LEFT, Event::EXPIRED] when EventFilter.all - actions = [Event::PUSHED, Event::MERGED, Event::COMMENTED, Event::JOINED, Event::LEFT] + actions = [ + Event::PUSHED, + Event::MERGED, + Event::COMMENTED, + Event::JOINED, + Event::LEFT, + Event::EXPIRED + ] end events.where(action: actions) -- cgit v1.2.1 From a4ef4244d4b9b54246f53bba5c02746542034da5 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 20 Oct 2016 16:16:57 +0800 Subject: Preserve note_type and position for notes from emails Closes #23208 --- lib/gitlab/email/handler/create_note_handler.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/email/handler/create_note_handler.rb b/lib/gitlab/email/handler/create_note_handler.rb index 06dae31cc27..447c7a6a6b9 100644 --- a/lib/gitlab/email/handler/create_note_handler.rb +++ b/lib/gitlab/email/handler/create_note_handler.rb @@ -46,7 +46,9 @@ module Gitlab noteable_type: sent_notification.noteable_type, noteable_id: sent_notification.noteable_id, commit_id: sent_notification.commit_id, - line_code: sent_notification.line_code + line_code: sent_notification.line_code, + position: sent_notification.position, + type: sent_notification.note_type ).execute end end -- cgit v1.2.1 From fd2c3a3da0302a474d7c1adbd409aedea2a41053 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Wed, 19 Oct 2016 19:43:04 +0300 Subject: Refactoring find_commits functionality --- lib/gitlab/project_search_results.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index 5b9cfaeb2f8..24733435a5a 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -73,11 +73,7 @@ module Gitlab end def commits - if project.empty_repo? || query.blank? - [] - else - project.repository.find_commits_by_message(query).compact - end + project.repository.find_commits_by_message(query) end def project_ids_relation -- cgit v1.2.1 From 0c0caede85b0ea6082799ae9fa6afd74a1186006 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Thu, 20 Oct 2016 17:33:12 +0300 Subject: Fix: Backup restore doesn't clear cache --- lib/tasks/gitlab/backup.rake | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index b43ee5b3383..a9f1255e8cf 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -51,6 +51,7 @@ namespace :gitlab do $progress.puts 'done'.color(:green) Rake::Task['gitlab:backup:db:restore'].invoke end + Rake::Task['gitlab:backup:repo:restore'].invoke unless backup.skipped?('repositories') Rake::Task['gitlab:backup:uploads:restore'].invoke unless backup.skipped?('uploads') Rake::Task['gitlab:backup:builds:restore'].invoke unless backup.skipped?('builds') @@ -58,6 +59,7 @@ namespace :gitlab do Rake::Task['gitlab:backup:lfs:restore'].invoke unless backup.skipped?('lfs') Rake::Task['gitlab:backup:registry:restore'].invoke unless backup.skipped?('registry') Rake::Task['gitlab:shell:setup'].invoke + Rake::Task['cache:clear'].invoke backup.cleanup end -- cgit v1.2.1 From b4359fb24e599c278edeae843bd6a25c980b1243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 20 Oct 2016 18:51:03 +0200 Subject: Don't use Hash#slice since it's not supported in Ruby 2.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/commit_statuses.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb index f282a3b9cd6..f54d4f06627 100644 --- a/lib/api/commit_statuses.rb +++ b/lib/api/commit_statuses.rb @@ -67,9 +67,14 @@ module API pipeline = @project.ensure_pipeline(ref, commit.sha, current_user) status = GenericCommitStatus.running_or_pending.find_or_initialize_by( - project: @project, pipeline: pipeline, - user: current_user, name: name, ref: ref) - status.attributes = declared(params).slice(:target_url, :description) + project: @project, + pipeline: pipeline, + user: current_user, + name: name, + ref: ref, + target_url: params[:target_url], + description: params[:description] + ) begin case params[:state].to_s -- cgit v1.2.1 From 3a29ea9da0abd6cfd0788f6d717a08862ed6b062 Mon Sep 17 00:00:00 2001 From: Lemures Lemniscati Date: Sat, 22 Oct 2016 03:07:26 +0900 Subject: Fix documents and comments on Build API `scope`. #23146 #19131 --- lib/api/builds.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 52bdbcae5a8..7b00c5037f1 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -8,7 +8,7 @@ module API # # Parameters: # id (required) - The ID of a project - # scope (optional) - The scope of builds to show (one or array of: pending, running, failed, success, canceled; + # scope (optional) - The scope of builds to show (one or array of: created, pending, running, failed, success, canceled, skipped; # if none provided showing all builds) # Example Request: # GET /projects/:id/builds @@ -25,7 +25,7 @@ module API # Parameters: # id (required) - The ID of a project # sha (required) - The SHA id of a commit - # scope (optional) - The scope of builds to show (one or array of: pending, running, failed, success, canceled; + # scope (optional) - The scope of builds to show (one or array of: created, pending, running, failed, success, canceled, skipped; # if none provided showing all builds) # Example Request: # GET /projects/:id/repository/commits/:sha/builds -- cgit v1.2.1 From 0890aeb61a5378ec3bb98511de236ee01eee8711 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sat, 22 Oct 2016 01:59:40 -0700 Subject: Fix error in generating labels Attempting to generate default set of labels would result in an error: ArgumentError: wrong number of arguments (given 1, expected 0) Closes #23649 --- lib/gitlab/issues_labels.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/issues_labels.rb b/lib/gitlab/issues_labels.rb index 01a2c19ab23..dbc759367eb 100644 --- a/lib/gitlab/issues_labels.rb +++ b/lib/gitlab/issues_labels.rb @@ -19,7 +19,7 @@ module Gitlab ] labels.each do |params| - ::Labels::FindOrCreateService.new(project.owner, project).execute(params) + ::Labels::FindOrCreateService.new(project.owner, project, params).execute end end end -- cgit v1.2.1 From c0eb2cbbb4b14e3abb843a65d685bee400b5fffe Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Sat, 22 Oct 2016 12:42:19 +0100 Subject: Stop clearing the database cache on rake cache:clear --- lib/tasks/cache.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/tasks/cache.rake b/lib/tasks/cache.rake index a95a3455a4a..78ae187817a 100644 --- a/lib/tasks/cache.rake +++ b/lib/tasks/cache.rake @@ -29,5 +29,5 @@ namespace :cache do task all: [:db, :redis] end - task clear: 'cache:clear:all' + task clear: 'cache:clear:redis' end -- cgit v1.2.1 From f79f3a1dd621362b0894eff0a54f220f8415a2e0 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Tue, 6 Sep 2016 10:35:34 +0530 Subject: Fix branch protection API. 1. Previously, we were not removing existing access levels before creating new ones. This is not a problem for EE, but _is_ for CE, since we restrict the number of access levels in CE to 1. 2. The correct approach is: CE -> delete all access levels before updating a protected branch EE -> delete developer access levels if "developers_can_{merge,push}" is switched off 3. The dispatch is performed by checking if a "length: 1" validation is present on the access levels or not. 4. Another source of problems was that we didn't put multiple queries in a transaction. If the `destroy_all` passes, but the `update` fails, we should have a rollback. 5. Modifying the API to provide users direct access to CRUD access levels will make things a lot simpler. 6. Create `create/update` services separately for this API, which perform the necessary data translation, before calling the regular `create/update` services. The translation code was getting too large for the API endpoint itself, so this move makes sense. --- lib/api/branches.rb | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) (limited to 'lib') diff --git a/lib/api/branches.rb b/lib/api/branches.rb index b615703df93..6941cc4aca6 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -57,40 +57,25 @@ module API developers_can_merge = to_boolean(params[:developers_can_merge]) developers_can_push = to_boolean(params[:developers_can_push]) - protected_branch_params = { - name: @branch.name + params = { + name: @branch.name, } - # If `developers_can_merge` is switched off, _all_ `DEVELOPER` - # merge_access_levels need to be deleted. - if developers_can_merge == false - protected_branch.merge_access_levels.where(access_level: Gitlab::Access::DEVELOPER).destroy_all - end + service_args = [user_project, current_user, params, + developers_can_push: developers_can_push, + developers_can_merge: developers_can_merge] - # If `developers_can_push` is switched off, _all_ `DEVELOPER` - # push_access_levels need to be deleted. - if developers_can_push == false - protected_branch.push_access_levels.where(access_level: Gitlab::Access::DEVELOPER).destroy_all - end + protected_branch = if protected_branch + ProtectedBranches::ApiUpdateService.new(*service_args).execute(protected_branch) + else + ProtectedBranches::ApiCreateService.new(*service_args).execute + end - protected_branch_params.merge!( - merge_access_levels_attributes: [{ - access_level: developers_can_merge ? Gitlab::Access::DEVELOPER : Gitlab::Access::MASTER - }], - push_access_levels_attributes: [{ - access_level: developers_can_push ? Gitlab::Access::DEVELOPER : Gitlab::Access::MASTER - }] - ) - - if protected_branch - service = ProtectedBranches::UpdateService.new(user_project, current_user, protected_branch_params) - service.execute(protected_branch) + if protected_branch.valid? + present @branch, with: Entities::RepoBranch, project: user_project else - service = ProtectedBranches::CreateService.new(user_project, current_user, protected_branch_params) - service.execute + render_api_error!(protected_branch.errors.full_messages, 422) end - - present @branch, with: Entities::RepoBranch, project: user_project end # Unprotect a single branch @@ -123,7 +108,7 @@ module API post ":id/repository/branches" do authorize_push_project result = CreateBranchService.new(user_project, current_user). - execute(params[:branch_name], params[:ref]) + execute(params[:branch_name], params[:ref]) if result[:status] == :success present result[:branch], @@ -142,10 +127,10 @@ module API # Example Request: # DELETE /projects/:id/repository/branches/:branch delete ":id/repository/branches/:branch", - requirements: { branch: /.+/ } do + requirements: { branch: /.+/ } do authorize_push_project result = DeleteBranchService.new(user_project, current_user). - execute(params[:branch]) + execute(params[:branch]) if result[:status] == :success { -- cgit v1.2.1 From b803bc7bb8ad481790d01848902e80602e77da67 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Thu, 22 Sep 2016 20:38:05 +0530 Subject: Implement review comments from @DouweM. --- lib/api/branches.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/branches.rb b/lib/api/branches.rb index 6941cc4aca6..7feb47784b7 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -57,11 +57,11 @@ module API developers_can_merge = to_boolean(params[:developers_can_merge]) developers_can_push = to_boolean(params[:developers_can_push]) - params = { + protected_branch_params = { name: @branch.name, } - service_args = [user_project, current_user, params, + service_args = [user_project, current_user, protected_branch_params, developers_can_push: developers_can_push, developers_can_merge: developers_can_merge] -- cgit v1.2.1 From 1051087ac4efc3dbf45bd075e36af647d2b66d62 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Fri, 30 Sep 2016 13:14:46 +0530 Subject: Implement second round of review comments from @DouweM. - Pass `developers_and_merge` and `developers_can_push` in `params` instead of using keyword arguments. - Refactor a slightly complex boolean check to a simple `nil?` check. --- lib/api/branches.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/api/branches.rb b/lib/api/branches.rb index 7feb47784b7..6d827448994 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -54,16 +54,13 @@ module API not_found!('Branch') unless @branch protected_branch = user_project.protected_branches.find_by(name: @branch.name) - developers_can_merge = to_boolean(params[:developers_can_merge]) - developers_can_push = to_boolean(params[:developers_can_push]) - protected_branch_params = { name: @branch.name, + developers_can_push: to_boolean(params[:developers_can_push]), + developers_can_merge: to_boolean(params[:developers_can_merge]) } - service_args = [user_project, current_user, protected_branch_params, - developers_can_push: developers_can_push, - developers_can_merge: developers_can_merge] + service_args = [user_project, current_user, protected_branch_params] protected_branch = if protected_branch ProtectedBranches::ApiUpdateService.new(*service_args).execute(protected_branch) -- cgit v1.2.1 From 672704f6389104b3d93c00a116dd4dc8ece19136 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 24 Oct 2016 13:51:17 +0300 Subject: Add relative url support to routing contrainers Signed-off-by: Dmitriy Zaporozhets --- lib/constraints/namespace_url_constrainer.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/constraints/namespace_url_constrainer.rb b/lib/constraints/namespace_url_constrainer.rb index 23920193743..91b70143f11 100644 --- a/lib/constraints/namespace_url_constrainer.rb +++ b/lib/constraints/namespace_url_constrainer.rb @@ -1,6 +1,9 @@ class NamespaceUrlConstrainer def matches?(request) - id = request.path.sub(/\A\/+/, '').split('/').first.sub(/.atom\z/, '') + id = request.path + id = id.sub(/\A#{relative_url_root}/, '') if relative_url_root + id = id.sub(/\A\/+/, '').split('/').first + id = id.sub(/.atom\z/, '') if id if id =~ Gitlab::Regex.namespace_regex find_resource(id) @@ -10,4 +13,12 @@ class NamespaceUrlConstrainer def find_resource(id) Namespace.find_by_path(id) end + + private + + def relative_url_root + if defined?(Gitlab::Application.config.relative_url_root) + Gitlab::Application.config.relative_url_root + end + end end -- cgit v1.2.1 From 8f527cbf06d31c084bdf71c7f882d73ff6591e29 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Mon, 24 Oct 2016 13:06:17 +0200 Subject: Grapify builds API --- lib/api/builds.rb | 162 ++++++++++++++++++++++++++---------------------------- 1 file changed, 79 insertions(+), 83 deletions(-) (limited to 'lib') diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 7b00c5037f1..67adca6605f 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -3,15 +3,32 @@ module API class Builds < Grape::API before { authenticate! } + params do + requires :id, type: String, desc: 'The ID of a project' + end resource :projects do - # Get a project builds - # - # Parameters: - # id (required) - The ID of a project - # scope (optional) - The scope of builds to show (one or array of: created, pending, running, failed, success, canceled, skipped; - # if none provided showing all builds) - # Example Request: - # GET /projects/:id/builds + helpers do + params :optional_scope do + optional :scope, types: [String, Array[String]], desc: 'The scope of builds to show', + values: ['pending', 'running', 'failed', 'success', 'canceled'], + coerce_with: ->(scope) { + if scope.is_a?(String) + [scope] + elsif scope.is_a?(Hashie::Mash) + scope.values + else + ['unknown'] + end + } + end + end + + desc 'Get a project builds' do + success Entities::Build + end + params do + use :optional_scope + end get ':id/builds' do builds = user_project.builds.order('id DESC') builds = filter_builds(builds, params[:scope]) @@ -20,15 +37,13 @@ module API user_can_download_artifacts: can?(current_user, :read_build, user_project) end - # Get builds for a specific commit of a project - # - # Parameters: - # id (required) - The ID of a project - # sha (required) - The SHA id of a commit - # scope (optional) - The scope of builds to show (one or array of: created, pending, running, failed, success, canceled, skipped; - # if none provided showing all builds) - # Example Request: - # GET /projects/:id/repository/commits/:sha/builds + desc 'Get builds for a specific commit of a project' do + success Entities::Build + end + params do + requires :sha, type: String, desc: 'The SHA id of a commit' + use :optional_scope + end get ':id/repository/commits/:sha/builds' do authorize_read_builds! @@ -42,13 +57,12 @@ module API user_can_download_artifacts: can?(current_user, :read_build, user_project) end - # Get a specific build of a project - # - # Parameters: - # id (required) - The ID of a project - # build_id (required) - The ID of a build - # Example Request: - # GET /projects/:id/builds/:build_id + desc 'Get a specific build of a project' do + success Entities::Build + end + params do + requires :build_id, type: Integer, desc: 'The ID of a build' + end get ':id/builds/:build_id' do authorize_read_builds! @@ -58,13 +72,12 @@ module API user_can_download_artifacts: can?(current_user, :read_build, user_project) end - # Download the artifacts file from build - # - # Parameters: - # id (required) - The ID of a build - # token (required) - The build authorization token - # Example Request: - # GET /projects/:id/builds/:build_id/artifacts + desc 'Download the artifacts file from build' do + detail 'This feature was introduced in GitLab 8.5' + end + params do + requires :build_id, type: Integer, desc: 'The ID of a build' + end get ':id/builds/:build_id/artifacts' do authorize_read_builds! @@ -73,14 +86,13 @@ module API present_artifacts!(build.artifacts_file) end - # Download the artifacts file from ref_name and job - # - # Parameters: - # id (required) - The ID of a project - # ref_name (required) - The ref from repository - # job (required) - The name for the build - # Example Request: - # GET /projects/:id/builds/artifacts/:ref_name/download?job=name + desc 'Download the artifacts file from build' do + detail 'This feature was introduced in GitLab 8.10' + end + params do + requires :ref_name, type: String, desc: 'The ref from repository' + requires :job, type: String, desc: 'The name for the build' + end get ':id/builds/artifacts/:ref_name/download', requirements: { ref_name: /.+/ } do authorize_read_builds! @@ -91,17 +103,13 @@ module API present_artifacts!(latest_build.artifacts_file) end - # Get a trace of a specific build of a project - # - # Parameters: - # id (required) - The ID of a project - # build_id (required) - The ID of a build - # Example Request: - # GET /projects/:id/build/:build_id/trace - # # TODO: We should use `present_file!` and leave this implementation for backward compatibility (when build trace # is saved in the DB instead of file). But before that, we need to consider how to replace the value of # `runners_token` with some mask (like `xxxxxx`) when sending trace file directly by workhorse. + desc 'Get a trace of a specific build of a project' + params do + requires :build_id, type: Integer, desc: 'The ID of a build' + end get ':id/builds/:build_id/trace' do authorize_read_builds! @@ -115,13 +123,12 @@ module API body trace end - # Cancel a specific build of a project - # - # parameters: - # id (required) - the id of a project - # build_id (required) - the id of a build - # example request: - # post /projects/:id/build/:build_id/cancel + desc 'Cancel a specific build of a project' do + success Entities::Build + end + params do + requires :build_id, type: Integer, desc: 'The ID of a build' + end post ':id/builds/:build_id/cancel' do authorize_update_builds! @@ -133,13 +140,12 @@ module API user_can_download_artifacts: can?(current_user, :read_build, user_project) end - # Retry a specific build of a project - # - # parameters: - # id (required) - the id of a project - # build_id (required) - the id of a build - # example request: - # post /projects/:id/build/:build_id/retry + desc 'Retry a specific build of a project' do + success Entities::Build + end + params do + requires :build_id, type: Integer, desc: 'The ID of a build' + end post ':id/builds/:build_id/retry' do authorize_update_builds! @@ -152,13 +158,12 @@ module API user_can_download_artifacts: can?(current_user, :read_build, user_project) end - # Erase build (remove artifacts and build trace) - # - # Parameters: - # id (required) - the id of a project - # build_id (required) - the id of a build - # example Request: - # post /projects/:id/build/:build_id/erase + desc 'Erase build (remove artifacts and build trace)' do + success Entities::Build + end + params do + requires :build_id, type: Integer, desc: 'The ID of a build' + end post ':id/builds/:build_id/erase' do authorize_update_builds! @@ -170,13 +175,12 @@ module API user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project) end - # Keep the artifacts to prevent them from being deleted - # - # Parameters: - # id (required) - the id of a project - # build_id (required) - The ID of a build - # Example Request: - # POST /projects/:id/builds/:build_id/artifacts/keep + desc 'Keep the artifacts to prevent them from being deleted' do + success Entities::Build + end + params do + requires :build_id, type: Integer, desc: 'The ID of a build' + end post ':id/builds/:build_id/artifacts/keep' do authorize_update_builds! @@ -235,14 +239,6 @@ module API return builds if scope.nil? || scope.empty? available_statuses = ::CommitStatus::AVAILABLE_STATUSES - scope = - if scope.is_a?(String) - [scope] - elsif scope.is_a?(Hashie::Mash) - scope.values - else - ['unknown'] - end unknown = scope - available_statuses render_api_error!('Scope contains invalid value(s)', 400) unless unknown.empty? -- cgit v1.2.1 From f73d83db76ae8386ad4db604efb40156593b7a7a Mon Sep 17 00:00:00 2001 From: Luis HGO Date: Mon, 20 Jun 2016 22:37:40 -0300 Subject: Added path parameter to Commits API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/commits.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 617a240318a..2f2cf769481 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -19,6 +19,7 @@ module API optional :until, type: String, desc: 'Only commits before or in this date will be returned' optional :page, type: Integer, default: 0, desc: 'The page for pagination' optional :per_page, type: Integer, default: 20, desc: 'The number of results per page' + optional :path, type: String, desc: 'The file path' end get ":id/repository/commits" do # TODO remove the next line for 9.0, use DateTime type in the params block @@ -28,6 +29,7 @@ module API offset = params[:page] * params[:per_page] commits = user_project.repository.commits(ref, + path: params[:path], limit: params[:per_page], offset: offset, after: params[:since], -- cgit v1.2.1 From 21666dbe119df7f2d86f0ac13c4addc814af4485 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Mon, 24 Oct 2016 14:05:33 +0200 Subject: Grapify the labels API --- lib/api/labels.rb | 91 +++++++++++++++++++++++-------------------------------- 1 file changed, 38 insertions(+), 53 deletions(-) (limited to 'lib') diff --git a/lib/api/labels.rb b/lib/api/labels.rb index 642e6345b9e..326e1e7ae00 100644 --- a/lib/api/labels.rb +++ b/lib/api/labels.rb @@ -3,37 +3,32 @@ module API class Labels < Grape::API before { authenticate! } + params do + requires :id, type: String, desc: 'The ID of a project' + end resource :projects do - # Get all labels of the project - # - # Parameters: - # id (required) - The ID of a project - # Example Request: - # GET /projects/:id/labels + desc 'Get all labels of the project' do + success Entities::Label + end get ':id/labels' do present available_labels, with: Entities::Label, current_user: current_user end - # Creates a new label - # - # Parameters: - # id (required) - The ID of a project - # name (required) - The name of the label to be created - # color (required) - Color of the label given in 6-digit hex - # notation with leading '#' sign (e.g. #FFAABB) - # description (optional) - The description of label to be created - # Example Request: - # POST /projects/:id/labels + desc 'Create a new label' do + success Entities::Label + end + params do + requires :name, type: String, desc: 'The name of the label to be created' + requires :color, type: String, desc: "The color of the label given in 6-digit hex notation with leading '#' sign (e.g. #FFAABB)" + optional :description, type: String, desc: 'The description of label to be created' + end post ':id/labels' do authorize! :admin_label, user_project - required_attributes! [:name, :color] - - attrs = attributes_for_keys [:name, :color, :description] - label = user_project.find_label(attrs[:name]) + label = user_project.find_label(params[:name]) conflict!('Label already exists') if label - label = user_project.labels.create(attrs) + label = user_project.labels.create(declared(params, include_parent_namespaces: false).to_h) if label.valid? present label, with: Entities::Label, current_user: current_user @@ -42,54 +37,44 @@ module API end end - # Deletes an existing label - # - # Parameters: - # id (required) - The ID of a project - # name (required) - The name of the label to be deleted - # - # Example Request: - # DELETE /projects/:id/labels + desc 'Delete an existing label' do + success Entities::Label + end + params do + requires :name, type: String, desc: 'The name of the label to be deleted' + end delete ':id/labels' do authorize! :admin_label, user_project - required_attributes! [:name] label = user_project.find_label(params[:name]) not_found!('Label') unless label - label.destroy + present label.destroy, with: Entities::Label, current_user: current_user end - # Updates an existing label. At least one optional parameter is required. - # - # Parameters: - # id (required) - The ID of a project - # name (required) - The name of the label to be deleted - # new_name (optional) - The new name of the label - # color (optional) - Color of the label given in 6-digit hex - # notation with leading '#' sign (e.g. #FFAABB) - # description (optional) - The description of label to be created - # Example Request: - # PUT /projects/:id/labels + desc 'Update an existing label. At least one optional parameter is required.' do + success Entities::Label + end + params do + requires :name, type: String, desc: 'The name of the label to be updated' + optional :new_name, type: String, desc: 'The new name of the label' + optional :color, type: String, desc: "The new color of the label given in 6-digit hex notation with leading '#' sign (e.g. #FFAABB)" + optional :description, type: String, desc: 'The new description of label' + at_least_one_of :new_name, :color, :description + end put ':id/labels' do authorize! :admin_label, user_project - required_attributes! [:name] label = user_project.find_label(params[:name]) not_found!('Label not found') unless label - attrs = attributes_for_keys [:new_name, :color, :description] - - if attrs.empty? - render_api_error!('Required parameters "new_name" or "color" ' \ - 'missing', - 400) - end - + update_params = declared(params, + include_parent_namespaces: false, + include_missing: false).to_h # Rename new name to the actual label attribute name - attrs[:name] = attrs.delete(:new_name) if attrs.key?(:new_name) + update_params['name'] = update_params.delete('new_name') if update_params.key?('new_name') - if label.update(attrs) + if label.update(update_params) present label, with: Entities::Label, current_user: current_user else render_validation_error!(label) -- cgit v1.2.1