diff options
author | Jonathon Reinhart <Jonathon.Reinhart@gmail.com> | 2017-11-28 22:50:29 -0500 |
---|---|---|
committer | Jonathon Reinhart <Jonathon.Reinhart@gmail.com> | 2018-12-31 13:57:53 -0500 |
commit | ba781484c7b1bea2829f3429990a7cf39bb37ff8 (patch) | |
tree | 4f09b375a23a4f96deff70138c7870aa9ffa47d5 | |
parent | 4d875a2bc365d1c5eb9c0965f91e688efae1e143 (diff) | |
download | gitlab-ce-ba781484c7b1bea2829f3429990a7cf39bb37ff8.tar.gz |
Add support for Git push options, specifically ci.skip
gitlab-org/gitlab-shell!166 added support for collecting push options
from the environment, and passing them along to the
/internal/post_receive API endpoint.
This change handles the new push_options JSON element in the payload,
and passes them on through to the GitPushService and GitTagPushService
services.
Futhermore, it adds support for the first push option, ci.skip. With
this change, one can use 'git push -o ci.skip' to skip CI pipe
execution. Note that the pipeline is still created, but in the "skipped"
state, just like with the 'ci skip' commit message text.
Implements #18667
-rw-r--r-- | app/services/ci/create_pipeline_service.rb | 3 | ||||
-rw-r--r-- | app/services/git_push_service.rb | 3 | ||||
-rw-r--r-- | app/services/git_tag_push_service.rb | 3 | ||||
-rw-r--r-- | app/workers/post_receive.rb | 20 | ||||
-rw-r--r-- | changelogs/unreleased/18667-handle-push-opts.yml | 5 | ||||
-rw-r--r-- | doc/ci/yaml/README.md | 7 | ||||
-rw-r--r-- | lib/api/internal.rb | 3 | ||||
-rw-r--r-- | lib/gitlab/ci/pipeline/chain/command.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/ci/pipeline/chain/skip.rb | 7 | ||||
-rw-r--r-- | lib/gitlab/data_builder/push.rb | 13 | ||||
-rw-r--r-- | lib/gitlab/git_post_receive.rb | 5 | ||||
-rw-r--r-- | spec/requests/api/internal_spec.rb | 10 | ||||
-rw-r--r-- | spec/services/ci/create_pipeline_service_spec.rb | 22 |
13 files changed, 84 insertions, 19 deletions
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 19b5552887f..f8d8ef04001 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -31,7 +31,8 @@ module Ci seeds_block: block, variables_attributes: params[:variables_attributes], project: project, - current_user: current_user) + current_user: current_user, + push_options: params[:push_options]) sequence = Gitlab::Ci::Pipeline::Chain::Sequence .new(pipeline, command, SEQUENCE) diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index f1883877d56..9ecee7c6156 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -174,7 +174,8 @@ class GitPushService < BaseService params[:newrev], params[:ref], @push_commits, - commits_count: commits_count) + commits_count: commits_count, + push_options: params[:push_options] || []) end def push_to_existing_branch? diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb index dbadafc0f52..03fcf614c64 100644 --- a/app/services/git_tag_push_service.rb +++ b/app/services/git_tag_push_service.rb @@ -45,7 +45,8 @@ class GitTagPushService < BaseService params[:newrev], params[:ref], commits, - message) + message, + push_options: params[:push_options] || []) end def build_system_push_data diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 72a1733a2a8..bbd4ab159e4 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -3,7 +3,7 @@ class PostReceive include ApplicationWorker - def perform(gl_repository, identifier, changes) + def perform(gl_repository, identifier, changes, push_options = []) project, is_wiki = Gitlab::GlRepository.parse(gl_repository) if project.nil? @@ -15,7 +15,7 @@ class PostReceive # Use Sidekiq.logger so arguments can be correlated with execution # time and thread ID's. Sidekiq.logger.info "changes: #{changes.inspect}" if ENV['SIDEKIQ_LOG_ARGUMENTS'] - post_received = Gitlab::GitPostReceive.new(project, identifier, changes) + post_received = Gitlab::GitPostReceive.new(project, identifier, changes, push_options) if is_wiki process_wiki_changes(post_received) @@ -38,9 +38,21 @@ class PostReceive post_received.changes_refs do |oldrev, newrev, ref| if Gitlab::Git.tag_ref?(ref) - GitTagPushService.new(post_received.project, @user, oldrev: oldrev, newrev: newrev, ref: ref).execute + GitTagPushService.new( + post_received.project, + @user, + oldrev: oldrev, + newrev: newrev, + ref: ref, + push_options: post_received.push_options).execute elsif Gitlab::Git.branch_ref?(ref) - GitPushService.new(post_received.project, @user, oldrev: oldrev, newrev: newrev, ref: ref).execute + GitPushService.new( + post_received.project, + @user, + oldrev: oldrev, + newrev: newrev, + ref: ref, + push_options: post_received.push_options).execute end changes << Gitlab::DataBuilder::Repository.single_change(oldrev, newrev, ref) diff --git a/changelogs/unreleased/18667-handle-push-opts.yml b/changelogs/unreleased/18667-handle-push-opts.yml new file mode 100644 index 00000000000..204293476f6 --- /dev/null +++ b/changelogs/unreleased/18667-handle-push-opts.yml @@ -0,0 +1,5 @@ +--- +title: Handle ci.skip push option +merge_request: 15643 +author: Jonathon Reinhart +type: added diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 440254e58bd..1227ea69d63 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -2200,6 +2200,12 @@ with an API call. If your commit message contains `[ci skip]` or `[skip ci]`, using any capitalization, the commit will be created but the pipeline will be skipped. +Alternatively, one can pass the `ci.skip` [Git push option][push-option] if +using Git 2.10 or newer: +``` +$ git push -o ci.skip +``` + ## Validate the .gitlab-ci.yml Each instance of GitLab CI has an embedded debug tool called Lint, which validates the @@ -2224,3 +2230,4 @@ GitLab CI/CD with various languages. [environment]: ../environments.md "CI/CD environments" [schedules]: ../../user/project/pipelines/schedules.md "Pipelines schedules" [variables]: ../variables/README.md "CI/CD variables" +[push-option]: https://git-scm.com/docs/git-push#git-push--oltoptiongt diff --git a/lib/api/internal.rb b/lib/api/internal.rb index ae40b5f7557..9488b3469d9 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -256,8 +256,9 @@ module API post '/post_receive' do status 200 + PostReceive.perform_async(params[:gl_repository], params[:identifier], - params[:changes]) + params[:changes], params[:push_options].to_a) broadcast_message = BroadcastMessage.current&.last&.message reference_counter_decreased = Gitlab::ReferenceCounter.new(params[:gl_repository]).decrease diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb index 100b9521412..b9fd46bccc2 100644 --- a/lib/gitlab/ci/pipeline/chain/command.rb +++ b/lib/gitlab/ci/pipeline/chain/command.rb @@ -10,7 +10,7 @@ module Gitlab :origin_ref, :checkout_sha, :after_sha, :before_sha, :trigger_request, :schedule, :merge_request, :ignore_skip_ci, :save_incompleted, - :seeds_block, :variables_attributes + :seeds_block, :variables_attributes, :push_options ) do include Gitlab::Utils::StrongMemoize diff --git a/lib/gitlab/ci/pipeline/chain/skip.rb b/lib/gitlab/ci/pipeline/chain/skip.rb index b9707d2f8f5..79bbcc1ed1e 100644 --- a/lib/gitlab/ci/pipeline/chain/skip.rb +++ b/lib/gitlab/ci/pipeline/chain/skip.rb @@ -8,6 +8,7 @@ module Gitlab include ::Gitlab::Utils::StrongMemoize SKIP_PATTERN = /\[(ci[ _-]skip|skip[ _-]ci)\]/i + SKIP_PUSH_OPTION = 'ci.skip' def perform! if skipped? @@ -16,7 +17,7 @@ module Gitlab end def skipped? - !@command.ignore_skip_ci && commit_message_skips_ci? + !@command.ignore_skip_ci && (commit_message_skips_ci? || push_option_skips_ci?) end def break? @@ -32,6 +33,10 @@ module Gitlab !!(@pipeline.git_commit_message =~ SKIP_PATTERN) end end + + def push_option_skips_ci? + !!(@command.push_options&.include?(SKIP_PUSH_OPTION)) + end end end end diff --git a/lib/gitlab/data_builder/push.rb b/lib/gitlab/data_builder/push.rb index 9bf2f9291a8..862127110b9 100644 --- a/lib/gitlab/data_builder/push.rb +++ b/lib/gitlab/data_builder/push.rb @@ -31,7 +31,11 @@ module Gitlab } } ], - total_commits_count: 1 + total_commits_count: 1, + push_options: [ + "ci.skip", + "custom option" + ] }.freeze # Produce a hash of post-receive data @@ -52,10 +56,12 @@ module Gitlab # homepage: String, # }, # commits: Array, - # total_commits_count: Fixnum + # total_commits_count: Fixnum, + # push_options: Array # } # - def build(project, user, oldrev, newrev, ref, commits = [], message = nil, commits_count: nil) + # rubocop:disable Metrics/ParameterLists + def build(project, user, oldrev, newrev, ref, commits = [], message = nil, commits_count: nil, push_options: []) commits = Array(commits) # Total commits count @@ -93,6 +99,7 @@ module Gitlab project: project.hook_attrs, commits: commit_attrs, total_commits_count: commits_count, + push_options: push_options, # DEPRECATED repository: project.hook_attrs.slice(:name, :url, :description, :homepage, :git_http_url, :git_ssh_url, :visibility_level) diff --git a/lib/gitlab/git_post_receive.rb b/lib/gitlab/git_post_receive.rb index cf2329e489d..426436c2164 100644 --- a/lib/gitlab/git_post_receive.rb +++ b/lib/gitlab/git_post_receive.rb @@ -3,12 +3,13 @@ module Gitlab class GitPostReceive include Gitlab::Identifier - attr_reader :project, :identifier, :changes + attr_reader :project, :identifier, :changes, :push_options - def initialize(project, identifier, changes) + def initialize(project, identifier, changes, push_options) @project = project @identifier = identifier @changes = deserialize_changes(changes) + @push_options = push_options end def identify diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index 589816b5d8f..0fe63e2e517 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -809,7 +809,8 @@ describe API::Internal do gl_repository: gl_repository, secret_token: secret_token, identifier: identifier, - changes: changes + changes: changes, + push_options: push_options } end @@ -817,6 +818,11 @@ describe API::Internal do "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch" end + let(:push_options) do + ['ci.skip', + 'another push option'] + end + before do project.add_developer(user) allow(described_class).to receive(:identify).and_return(user) @@ -825,7 +831,7 @@ describe API::Internal do it 'enqueues a PostReceive worker job' do expect(PostReceive).to receive(:perform_async) - .with(gl_repository, identifier, changes) + .with(gl_repository, identifier, changes, push_options) post api("/internal/post_receive"), params: valid_params end diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index ffa47d527f7..fa590a7eebf 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -19,12 +19,14 @@ describe Ci::CreatePipelineService do ref: ref_name, trigger_request: nil, variables_attributes: nil, - merge_request: nil) + merge_request: nil, + push_options: nil) params = { ref: ref, before: '00000000', after: after, commits: [{ message: message }], - variables_attributes: variables_attributes } + variables_attributes: variables_attributes, + push_options: push_options } described_class.new(project, user, params).execute( source, trigger_request: trigger_request, merge_request: merge_request) @@ -357,6 +359,22 @@ describe Ci::CreatePipelineService do end end + context 'when push options contain ci.skip' do + let(:push_options) do + ['ci.skip', + 'another push option'] + end + + it 'creates a pipline in the skipped state' do + pipeline = execute_service(push_options: push_options) + + # TODO: DRY these up with "skips builds creation if the commit message" + expect(pipeline).to be_persisted + expect(pipeline.builds.any?).to be false + expect(pipeline.status).to eq("skipped") + end + end + context 'when there are no jobs for this pipeline' do before do config = YAML.dump({ test: { script: 'ls', only: ['feature'] } }) |