Commit 58ebd1f8 authored by Shinya Maeda's avatar Shinya Maeda

Merge branch '31197-webhook-payload-to-pipelines' into 'master'

Implement passing trigger payload into pipeline variable [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!53837
parents 59e2befe 7b89f625
...@@ -17,6 +17,9 @@ module Ci ...@@ -17,6 +17,9 @@ module Ci
private private
PAYLOAD_VARIABLE_KEY = 'TRIGGER_PAYLOAD'
PAYLOAD_VARIABLE_HIDDEN_PARAMS = %i(token).freeze
def create_pipeline_from_trigger(trigger) def create_pipeline_from_trigger(trigger)
# this check is to not leak the presence of the project if user cannot read it # this check is to not leak the presence of the project if user cannot read it
return unless trigger.project == project return unless trigger.project == project
...@@ -70,9 +73,23 @@ module Ci ...@@ -70,9 +73,23 @@ module Ci
end end
def variables def variables
if ::Feature.enabled?(:ci_trigger_payload_into_pipeline, project, default_enabled: :yaml)
param_variables + [payload_variable]
else
param_variables
end
end
def param_variables
params[:variables].to_h.map do |key, value| params[:variables].to_h.map do |key, value|
{ key: key, value: value } { key: key, value: value }
end end
end end
def payload_variable
{ key: PAYLOAD_VARIABLE_KEY,
value: params.except(*PAYLOAD_VARIABLE_HIDDEN_PARAMS).to_json,
variable_type: :file }
end
end end
end end
---
name: ci_trigger_payload_into_pipeline
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/53837
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/321027
milestone: '13.9'
type: development
group: group::pipeline authoring
default_enabled: false
...@@ -185,6 +185,41 @@ You should pass `ref` as part of the URL, to take precedence over `ref` from ...@@ -185,6 +185,41 @@ You should pass `ref` as part of the URL, to take precedence over `ref` from
the webhook body that designates the branch ref that fired the trigger in the the webhook body that designates the branch ref that fired the trigger in the
source repository. Be sure to URL-encode `ref` if it contains slashes. source repository. Be sure to URL-encode `ref` if it contains slashes.
### Using webhook payload in the triggered pipeline
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31197) in GitLab 13.9.
> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
> - It's disabled on GitLab.com.
> - It's not recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-the-trigger_payload-variable). **(FREE SELF)**
WARNING:
This feature might not be available to you. Check the **version history** note above for details.
If you trigger a pipeline by using a webhook, you can access the webhook payload with
the `TRIGGER_PAYLOAD` [predefined CI/CD variable](../variables/predefined_variables.md).
The payload is exposed as a [file-type variable](../variables/README.md#custom-cicd-variables-of-type-file),
so you can access the data with `cat $TRIGGER_PAYLOAD` or a similar command.
#### Enable or disable the `TRIGGER_PAYLOAD` variable
The `TRIGGER_PAYLOAD` CI/CD variable is under development and not ready for production use. It is
deployed behind a feature flag that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
can enable it.
To enable it:
```ruby
Feature.enable(:ci_trigger_payload_into_pipeline)
```
To disable it:
```ruby
Feature.disable(:ci_trigger_payload_into_pipeline)
```
## Making use of trigger variables ## Making use of trigger variables
You can pass any number of arbitrary variables in the trigger API call and they You can pass any number of arbitrary variables in the trigger API call and they
......
...@@ -145,3 +145,4 @@ Kubernetes-specific variables are detailed in the ...@@ -145,3 +145,4 @@ Kubernetes-specific variables are detailed in the
| `GITLAB_USER_ID` | 8.12 | all | The ID of the user who started the job. | | `GITLAB_USER_ID` | 8.12 | all | The ID of the user who started the job. |
| `GITLAB_USER_LOGIN` | 10.0 | all | The login username of the user who started the job. | | `GITLAB_USER_LOGIN` | 10.0 | all | The login username of the user who started the job. |
| `GITLAB_USER_NAME` | 10.0 | all | The real name of the user who started the job. | | `GITLAB_USER_NAME` | 10.0 | all | The real name of the user who started the job. |
| `TRIGGER_PAYLOAD` | 13.9 | all | This variable is available when a pipeline is [triggered with a webhook](../triggers/README.md#using-webhook-payload-in-the-triggered-pipeline) |
...@@ -96,7 +96,7 @@ RSpec.describe API::Triggers do ...@@ -96,7 +96,7 @@ RSpec.describe API::Triggers do
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(Ci::Pipeline.last.source).to eq('pipeline') expect(Ci::Pipeline.last.source).to eq('pipeline')
expect(Ci::Pipeline.last.triggered_by_pipeline).not_to be_nil expect(Ci::Pipeline.last.triggered_by_pipeline).not_to be_nil
expect(Ci::Pipeline.last.variables.map { |v| { v.key => v.value } }.last).to eq(params[:variables]) expect(Ci::Pipeline.last.variables.find { |v| v.key == 'KEY' }.value).to eq('VALUE')
end end
end end
end end
......
...@@ -54,6 +54,15 @@ RSpec.describe API::Triggers do ...@@ -54,6 +54,15 @@ RSpec.describe API::Triggers do
expect(pipeline.builds.size).to eq(5) expect(pipeline.builds.size).to eq(5)
end end
it 'stores payload as a variable' do
post api("/projects/#{project.id}/trigger/pipeline"), params: options.merge(ref: 'master')
expect(response).to have_gitlab_http_status(:created)
expect(pipeline.variables.find { |v| v.key == 'TRIGGER_PAYLOAD' }.value).to eq(
"{\"ref\":\"master\",\"id\":\"#{project.id}\",\"variables\":{}}"
)
end
it 'returns bad request with no pipeline created if there\'s no commit for that ref' do it 'returns bad request with no pipeline created if there\'s no commit for that ref' do
post api("/projects/#{project.id}/trigger/pipeline"), params: options.merge(ref: 'other-branch') post api("/projects/#{project.id}/trigger/pipeline"), params: options.merge(ref: 'other-branch')
...@@ -84,7 +93,7 @@ RSpec.describe API::Triggers do ...@@ -84,7 +93,7 @@ RSpec.describe API::Triggers do
post api("/projects/#{project.id}/trigger/pipeline"), params: options.merge(variables: variables, ref: 'master') post api("/projects/#{project.id}/trigger/pipeline"), params: options.merge(variables: variables, ref: 'master')
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(pipeline.variables.map { |v| { v.key => v.value } }.last).to eq(variables) expect(pipeline.variables.find { |v| v.key == 'TRIGGER_KEY' }.value).to eq('TRIGGER_VALUE')
end end
end end
end end
......
...@@ -45,6 +45,27 @@ RSpec.describe Ci::PipelineTriggerService do ...@@ -45,6 +45,27 @@ RSpec.describe Ci::PipelineTriggerService do
expect(result[:status]).to eq(:success) expect(result[:status]).to eq(:success)
end end
it 'stores the payload as a variable' do
expect { result }.to change { Ci::PipelineVariable.count }.by(1)
var = result[:pipeline].variables.first
expect(var.key).to eq('TRIGGER_PAYLOAD')
expect(var.value).to eq('{"ref":"master","variables":null}')
expect(var.variable_type).to eq('file')
end
context 'when FF ci_trigger_payload_into_pipeline is disabled' do
before do
stub_feature_flags(ci_trigger_payload_into_pipeline: false)
end
it 'does not store the payload as a variable' do
expect { result }.not_to change { Ci::PipelineVariable.count }
expect(result[:pipeline].variables).to be_empty
end
end
context 'when commit message has [ci skip]' do context 'when commit message has [ci skip]' do
before do before do
allow_next(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' } allow_next(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' }
...@@ -60,8 +81,8 @@ RSpec.describe Ci::PipelineTriggerService do ...@@ -60,8 +81,8 @@ RSpec.describe Ci::PipelineTriggerService do
let(:params) { { token: trigger.token, ref: 'master', variables: variables } } let(:params) { { token: trigger.token, ref: 'master', variables: variables } }
let(:variables) { { 'AAA' => 'AAA123' } } let(:variables) { { 'AAA' => 'AAA123' } }
it 'has a variable' do it 'has variables' do
expect { result }.to change { Ci::PipelineVariable.count }.by(1) expect { result }.to change { Ci::PipelineVariable.count }.by(2)
.and change { Ci::TriggerRequest.count }.by(1) .and change { Ci::TriggerRequest.count }.by(1)
expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables) expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables)
expect(result[:pipeline].trigger_requests.last.variables).to be_nil expect(result[:pipeline].trigger_requests.last.variables).to be_nil
...@@ -155,8 +176,8 @@ RSpec.describe Ci::PipelineTriggerService do ...@@ -155,8 +176,8 @@ RSpec.describe Ci::PipelineTriggerService do
let(:params) { { token: job.token, ref: 'master', variables: variables } } let(:params) { { token: job.token, ref: 'master', variables: variables } }
let(:variables) { { 'AAA' => 'AAA123' } } let(:variables) { { 'AAA' => 'AAA123' } }
it 'has a variable' do it 'has variables' do
expect { result }.to change { Ci::PipelineVariable.count }.by(1) expect { result }.to change { Ci::PipelineVariable.count }.by(2)
.and change { Ci::Sources::Pipeline.count }.by(1) .and change { Ci::Sources::Pipeline.count }.by(1)
expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables) expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables)
expect(job.sourced_pipelines.last.pipeline_id).to eq(result[:pipeline].id) expect(job.sourced_pipelines.last.pipeline_id).to eq(result[:pipeline].id)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment