From 56b8334190e02ad2185d9b961200a8277b958f31 Mon Sep 17 00:00:00 2001 From: Laura Montemayor Date: Tue, 4 Mar 2025 15:19:46 +0100 Subject: [PATCH 1/4] Add input push option --- app/services/git/base_hooks_service.rb | 24 +++++++-- .../services/ee/git/branch_hooks_service.rb | 2 +- lib/gitlab/push_options.rb | 3 +- spec/services/git/base_hooks_service_spec.rb | 54 +++++++++++++++++++ 4 files changed, 78 insertions(+), 5 deletions(-) diff --git a/app/services/git/base_hooks_service.rb b/app/services/git/base_hooks_service.rb index 6d76b7c6b0c3fe..6c7ca019577cf3 100644 --- a/app/services/git/base_hooks_service.rb +++ b/app/services/git/base_hooks_service.rb @@ -133,7 +133,7 @@ def generate_vars_from_push_options # Accept only valid format. We ignore the following formats # 1. "=123". In this case, `key` will be an empty string # 2. "FOO". In this case, `value` will be nil. - # However, the format "FOO=" will result in key beign `FOO` and value + # However, the format "FOO=" will result in key being `FOO` and value # being an empty string. This is acceptable. next if key.blank? || value.nil? @@ -170,9 +170,27 @@ def push_data @push_data.dup end - # to be overridden in EE + # merges with EE override def pipeline_options - {} + { + inputs: generate_ci_inputs_from_push_options || {} + } + end + + def ci_inputs_from_push_options + strong_memoize(:ci_inputs_from_push_options) do + push_options&.dig(:ci, :input) + end + end + + def generate_ci_inputs_from_push_options + return {} unless ci_inputs_from_push_options + + params = ci_inputs_from_push_options.map do |input, _| + input.to_s.split("=", 2) + end + + ::Ci::PipelineCreation::Inputs.parse_params(params.to_h) end def log_pipeline_errors(error_message) diff --git a/ee/app/services/ee/git/branch_hooks_service.rb b/ee/app/services/ee/git/branch_hooks_service.rb index ebdb521928e2a0..cf27a6bc88ea03 100644 --- a/ee/app/services/ee/git/branch_hooks_service.rb +++ b/ee/app/services/ee/git/branch_hooks_service.rb @@ -12,7 +12,7 @@ def pipeline_options mirror_update = project.mirror? && project.repository.up_to_date_with_upstream?(branch_name) - { mirror_update: mirror_update } + super.merge(mirror_update: mirror_update) end end end diff --git a/lib/gitlab/push_options.rb b/lib/gitlab/push_options.rb index 4df9c3d64abb20..17a37d3c4b4f11 100644 --- a/lib/gitlab/push_options.rb +++ b/lib/gitlab/push_options.rb @@ -22,7 +22,7 @@ class PushOptions ] }, ci: { - keys: [:skip, :variable] + keys: [:skip, :variable, :input] }, integrations: { keys: [:skip_ci] @@ -36,6 +36,7 @@ class PushOptions }).freeze MULTI_VALUE_OPTIONS = [ + %w[ci input], %w[ci variable], %w[merge_request label], %w[merge_request unlabel], diff --git a/spec/services/git/base_hooks_service_spec.rb b/spec/services/git/base_hooks_service_spec.rb index fd3dd2896fcc1d..dca2b4806e2b7c 100644 --- a/spec/services/git/base_hooks_service_spec.rb +++ b/spec/services/git/base_hooks_service_spec.rb @@ -152,6 +152,60 @@ def commits_count end end + describe 'Pipeline options' do + context 'when pipeline options contain inputs' do + let(:pipeline_params) do + { + after: newrev, + before: oldrev, + checkout_sha: checkout_sha, + push_options: push_options, + ref: ref, + variables_attributes: variables_attributes + } + end + + let(:push_options) do + { + ci: { + input: { + "security_scan=false": 1, + "level=20": 1 + } + } + } + end + + let(:pipeline_service) { double(execute: service_response) } + let(:service_response) { double(error?: false, payload: pipeline, message: 'message') } + let(:pipeline) { double(persisted?: true) } + let(:variables_attributes) { [] } + + let(:inputs) do + { + security_scan: false, + level: 20 + } + end + + before do + params[:push_options] = push_options + end + + it 'calls the create pipeline service' do + expect(Ci::CreatePipelineService) + .to receive(:new) + .with(project, user, pipeline_params) + .and_return(pipeline_service) + + expect(pipeline_service).to receive(:execute).with(:push, { inputs: inputs }) + expect(subject).not_to receive(:log_pipeline_errors) + + subject.execute + end + end + end + describe 'Generating CI variables from push options' do let(:pipeline_params) do { -- GitLab From f455bc172f813b0bfcb0aa6d15b5f774ea4507bf Mon Sep 17 00:00:00 2001 From: Laura Montemayor Date: Tue, 11 Mar 2025 18:22:13 +0100 Subject: [PATCH 2/4] Add docs --- doc/topics/git/commit.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/topics/git/commit.md b/doc/topics/git/commit.md index 21dd4deb0d3dbd..804880e3abfb0a 100644 --- a/doc/topics/git/commit.md +++ b/doc/topics/git/commit.md @@ -117,6 +117,7 @@ see [issue 373212](https://gitlab.com/gitlab-org/gitlab/-/issues/373212). | Push option | Description | Example | |--------------------------------|-------------|---------| +| `ci.input==` | Creates a pipeline with the specified inputs. | `git push -o ci.input="stage=test" -o ci.input="security_scan=false"` | | `ci.skip` | Do not create a CI/CD pipeline for the latest push. Skips only branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). This does not skip pipelines for CI/CD integrations, such as Jenkins. | `git push -o ci.skip` | | `ci.variable="="` | Provide [CI/CD variables](../../ci/variables/_index.md) to the CI/CD pipeline, if one is created due to the push. Passes variables only to branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). | `git push -o ci.variable="MAX_RETRIES=10" -o ci.variable="MAX_TIME=600"` | -- GitLab From 2475e3488cf436b0f2319759d20f0a31a4b8adbe Mon Sep 17 00:00:00 2001 From: Laura Montemayor Date: Thu, 13 Mar 2025 15:03:54 +0100 Subject: [PATCH 3/4] Add another type to spec, return empty hash --- app/services/git/base_hooks_service.rb | 2 ++ spec/services/git/base_hooks_service_spec.rb | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/services/git/base_hooks_service.rb b/app/services/git/base_hooks_service.rb index 6c7ca019577cf3..8144aec9e96d58 100644 --- a/app/services/git/base_hooks_service.rb +++ b/app/services/git/base_hooks_service.rb @@ -172,6 +172,8 @@ def push_data # merges with EE override def pipeline_options + return {} unless ci_inputs_from_push_options + { inputs: generate_ci_inputs_from_push_options || {} } diff --git a/spec/services/git/base_hooks_service_spec.rb b/spec/services/git/base_hooks_service_spec.rb index dca2b4806e2b7c..a460319be4969a 100644 --- a/spec/services/git/base_hooks_service_spec.rb +++ b/spec/services/git/base_hooks_service_spec.rb @@ -169,8 +169,11 @@ def commits_count { ci: { input: { - "security_scan=false": 1, - "level=20": 1 + 'security_scan=false': 1, + 'stage=test': 1, + 'level=20': 1, + 'enviornments=["staging", "production"]': 1, + 'rules=[{"if": "$CI_MERGE_REQUEST_ID"}, {"if": "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH"}]': 1 } } } @@ -184,7 +187,15 @@ def commits_count let(:inputs) do { security_scan: false, - level: 20 + stage: 'test', + level: 20, + enviornments: %w[ + staging production + ], + rules: [ + { if: "$CI_MERGE_REQUEST_ID" }, + { if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH" } + ] } end -- GitLab From 500f0e897daf389284f562412701f46a0b9f9eba Mon Sep 17 00:00:00 2001 From: Laura Montemayor Date: Mon, 17 Mar 2025 09:30:57 +0100 Subject: [PATCH 4/4] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: Marcel Amirault --- doc/topics/git/commit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/topics/git/commit.md b/doc/topics/git/commit.md index 804880e3abfb0a..6c1223bd96a1a4 100644 --- a/doc/topics/git/commit.md +++ b/doc/topics/git/commit.md @@ -117,7 +117,7 @@ see [issue 373212](https://gitlab.com/gitlab-org/gitlab/-/issues/373212). | Push option | Description | Example | |--------------------------------|-------------|---------| -| `ci.input==` | Creates a pipeline with the specified inputs. | `git push -o ci.input="stage=test" -o ci.input="security_scan=false"` | +| `ci.input==` | Creates a pipeline with the specified inputs. | For example: `git push -o ci.input='stage=test' -o ci.input='security_scan=false'`. Example with an array of strings: `ci.input='["string", "double", "quotes"]'` | | `ci.skip` | Do not create a CI/CD pipeline for the latest push. Skips only branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). This does not skip pipelines for CI/CD integrations, such as Jenkins. | `git push -o ci.skip` | | `ci.variable="="` | Provide [CI/CD variables](../../ci/variables/_index.md) to the CI/CD pipeline, if one is created due to the push. Passes variables only to branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). | `git push -o ci.variable="MAX_RETRIES=10" -o ci.variable="MAX_TIME=600"` | -- GitLab