Commit 8d36e6a7 authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'feature/gb/configurable-github-status-name' into 'master'

Configurable GitHub static context for statuses integration

Closes #6696

See merge request gitlab-org/gitlab-ee!8235
parents 8c27b53d c328a756
...@@ -30,6 +30,19 @@ with `repo:status` access granted: ...@@ -30,6 +30,19 @@ with `repo:status` access granted:
1. Select the "Active" checkbox. 1. Select the "Active" checkbox.
1. Paste the token you've generated on GitHub 1. Paste the token you've generated on GitHub
1. Enter the path to your project on GitHub, such as `https://github.com/username/repository` 1. Enter the path to your project on GitHub, such as `https://github.com/username/repository`
1. Optionally check "Static status check names" checkbox to enable static status check names.
1. Save or optionally click "Test Settings". 1. Save or optionally click "Test Settings".
#### Static / dynamic status check names
Since GitLab 11.5 it is possible to opt-in to using static status check names.
This makes it possible to mark these status checks as _Required_ on GitHub.
If you check "Static status check names" checkbox on the integration page, your
GitLab instance host name is going to be appended to a status check name,
whereas in case of dynamic status check names, a branch name is going to be
appended.
Dynamic status check name is a default behavior.
![Configure GitHub Project Integration](img/github_configuration.png) ![Configure GitHub Project Integration](img/github_configuration.png)
...@@ -5,7 +5,8 @@ module EE ...@@ -5,7 +5,8 @@ module EE
:multiproject_enabled, :multiproject_enabled,
:pass_unstable, :pass_unstable,
:project_name, :project_name,
:repository_url :repository_url,
:static_context
].freeze ].freeze
def allowed_service_params def allowed_service_params
......
...@@ -3,6 +3,7 @@ class GithubService < Service ...@@ -3,6 +3,7 @@ class GithubService < Service
include ActionView::Helpers::UrlHelper include ActionView::Helpers::UrlHelper
prop_accessor :token, :repository_url prop_accessor :token, :repository_url
boolean_accessor :static_context
delegate :api_url, :owner, :repository_name, to: :remote_project delegate :api_url, :owner, :repository_name, to: :remote_project
...@@ -31,8 +32,20 @@ class GithubService < Service ...@@ -31,8 +32,20 @@ class GithubService < Service
def fields def fields
[ [
{ type: 'text', name: "token", required: true, placeholder: "e.g. 8d3f016698e...", help: 'Create a <a href="https://github.com/settings/tokens">personal access token</a> with <code>repo:status</code> access granted and paste it here.'.html_safe }, { type: 'text',
{ type: 'text', name: "repository_url", title: 'Repository URL', required: true, placeholder: 'e.g. https://github.com/owner/repository' } name: "token",
required: true,
placeholder: "e.g. 8d3f016698e...",
help: 'Create a <a href="https://github.com/settings/tokens">personal access token</a> with <code>repo:status</code> access granted and paste it here.'.html_safe },
{ type: 'text',
name: "repository_url",
title: 'Repository URL',
required: true,
placeholder: 'e.g. https://github.com/owner/repository' },
{ type: 'checkbox',
name: "static_context",
title: 'Static status check names',
help: 'GitHub status checks need static name in order to be marked as "required".' }
] ]
end end
...@@ -51,7 +64,7 @@ class GithubService < Service ...@@ -51,7 +64,7 @@ class GithubService < Service
def execute(data) def execute(data)
return if disabled? return if disabled?
status_message = StatusMessage.from_pipeline_data(project, data) status_message = StatusMessage.from_pipeline_data(project, self, data)
update_status(status_message) update_status(status_message)
end end
......
...@@ -4,8 +4,9 @@ class GithubService ...@@ -4,8 +4,9 @@ class GithubService
attr_reader :sha attr_reader :sha
def initialize(project, params) def initialize(project, service, params)
@project = project @project = project
@service = service
@gitlab_status = params[:status] @gitlab_status = params[:status]
@detailed_status = params[:detailed_status] @detailed_status = params[:detailed_status]
@pipeline_id = params[:id] @pipeline_id = params[:id]
...@@ -14,7 +15,7 @@ class GithubService ...@@ -14,7 +15,7 @@ class GithubService
end end
def context def context
"ci/gitlab/#{@ref_name}".truncate(255) context_name.truncate(255)
end end
def description def description
...@@ -50,8 +51,18 @@ class GithubService ...@@ -50,8 +51,18 @@ class GithubService
} }
end end
def self.from_pipeline_data(project, data) def self.from_pipeline_data(project, service, data)
new(project, data[:object_attributes]) new(project, service, data[:object_attributes])
end
private
def context_name
if @service.static_context?
"ci/gitlab/#{::Gitlab.config.gitlab.host}"
else
"ci/gitlab/#{@ref_name}"
end
end end
end end
end end
---
title: Configurable GitHub static context for statuses integration
merge_request: 8235
author:
type: added
...@@ -4,17 +4,22 @@ describe GithubService::StatusMessage do ...@@ -4,17 +4,22 @@ describe GithubService::StatusMessage do
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
let(:project) { double(:project, namespace: "me", to_s: 'example_project') } let(:project) { double(:project, namespace: "me", to_s: 'example_project') }
let(:service) { double(:service, static_context?: false) }
before do
stub_config_setting(host: 'instance-host')
end
describe '#description' do describe '#description' do
it 'includes human readable gitlab status' do it 'includes human readable gitlab status' do
subject = described_class.new(project, detailed_status: 'passed') subject = described_class.new(project, service, detailed_status: 'passed')
expect(subject.description).to eq "Pipeline passed on GitLab" expect(subject.description).to eq "Pipeline passed on GitLab"
end end
it 'gets truncated to 140 chars' do it 'gets truncated to 140 chars' do
dummy_text = 'a' * 500 dummy_text = 'a' * 500
subject = described_class.new(project, detailed_status: dummy_text) subject = described_class.new(project, service, detailed_status: dummy_text)
expect(subject.description.length).to eq 140 expect(subject.description.length).to eq 140
end end
...@@ -36,7 +41,7 @@ describe GithubService::StatusMessage do ...@@ -36,7 +41,7 @@ describe GithubService::StatusMessage do
with_them do with_them do
it 'transforms status' do it 'transforms status' do
subject = described_class.new(project, status: gitlab_status) subject = described_class.new(project, service, status: gitlab_status)
expect(subject.status).to eq github_status expect(subject.status).to eq github_status
end end
...@@ -44,7 +49,7 @@ describe GithubService::StatusMessage do ...@@ -44,7 +49,7 @@ describe GithubService::StatusMessage do
end end
describe '#status_options' do describe '#status_options' do
let(:subject) { described_class.new(project, id: 1) } let(:subject) { described_class.new(project, service, id: 1) }
it 'includes context' do it 'includes context' do
expect(subject.status_options[:context]).to be_a String expect(subject.status_options[:context]).to be_a String
...@@ -59,11 +64,40 @@ describe GithubService::StatusMessage do ...@@ -59,11 +64,40 @@ describe GithubService::StatusMessage do
end end
end end
describe '#context' do
subject do
described_class.new(project, service, ref: 'some-ref')
end
context 'when status context is supposed to be dynamic' do
before do
allow(service).to receive(:static_context?).and_return(false)
end
it 'appends pipeline reference to the status context' do
expect(subject.context).to eq 'ci/gitlab/some-ref'
end
end
context 'when status context is supposed to be static' do
before do
allow(service).to receive(:static_context?).and_return(true)
end
it 'appends instance hostname to the status context' do
expect(subject.context).to eq 'ci/gitlab/instance-host'
end
end
end
describe '.from_pipeline_data' do describe '.from_pipeline_data' do
let(:pipeline) { create(:ci_pipeline) } let(:project) { create(:project) }
let(:project) { pipeline.project } let(:pipeline) { create(:ci_pipeline, ref: 'some-ref', project: project) }
let(:sample_data) { Gitlab::DataBuilder::Pipeline.build(pipeline) } let(:sample_data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
let(:subject) { described_class.from_pipeline_data(project, sample_data) }
subject do
described_class.from_pipeline_data(project, service, sample_data)
end
it 'builds an instance of GithubService::StatusMessage' do it 'builds an instance of GithubService::StatusMessage' do
expect(subject).to be_a described_class expect(subject).to be_a described_class
...@@ -87,16 +121,30 @@ describe GithubService::StatusMessage do ...@@ -87,16 +121,30 @@ describe GithubService::StatusMessage do
end end
specify 'context' do specify 'context' do
expect(subject.context).to eq "ci/gitlab/#{pipeline.ref}" expect(subject.context).to eq "ci/gitlab/some-ref"
end end
context 'blocked pipeline' do context 'when pipeline is blocked' do
let(:pipeline) { create(:ci_pipeline, :blocked) } let(:pipeline) { create(:ci_pipeline, :blocked) }
it 'uses human readable status which can be used in a sentence' do it 'uses human readable status which can be used in a sentence' do
expect(subject.description). to eq 'Pipeline waiting for manual action on GitLab' expect(subject.description). to eq 'Pipeline waiting for manual action on GitLab'
end end
end end
context 'when static context has been configured' do
before do
allow(service).to receive(:static_context?).and_return(true)
end
subject do
described_class.from_pipeline_data(project, service, sample_data)
end
it 'appends instance name to the context name' do
expect(subject.context).to eq 'ci/gitlab/instance-host'
end
end
end end
end end
end end
...@@ -80,7 +80,10 @@ describe GithubService do ...@@ -80,7 +80,10 @@ describe GithubService do
it 'uses StatusMessage to build message' do it 'uses StatusMessage to build message' do
allow(subject).to receive(:update_status) allow(subject).to receive(:update_status)
expect(GithubService::StatusMessage).to receive(:from_pipeline_data).with(project, pipeline_sample_data).and_return(status_message) expect(GithubService::StatusMessage)
.to receive(:from_pipeline_data)
.with(project, subject, pipeline_sample_data)
.and_return(status_message)
subject.execute(pipeline_sample_data) subject.execute(pipeline_sample_data)
end end
......
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