Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
b9e08d97
Commit
b9e08d97
authored
Feb 19, 2018
by
James Edwards-Jones
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
GitHub Service sends status update on pipeline events
parent
7d45cd88
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
537 additions
and
1 deletion
+537
-1
doc/user/project/integrations/github.md
doc/user/project/integrations/github.md
+30
-0
doc/user/project/integrations/img/github_configuration.png
doc/user/project/integrations/img/github_configuration.png
+0
-0
doc/user/project/integrations/img/github_status_check_pipeline_update.png
.../integrations/img/github_status_check_pipeline_update.png
+0
-0
doc/user/project/integrations/project_services.md
doc/user/project/integrations/project_services.md
+1
-1
ee/app/models/project_services/github_service.rb
ee/app/models/project_services/github_service.rb
+52
-0
ee/app/models/project_services/github_service/status_message.rb
.../models/project_services/github_service/status_message.rb
+57
-0
ee/app/models/project_services/github_service/status_notifier.rb
...models/project_services/github_service/status_notifier.rb
+20
-0
ee/changelogs/unreleased/jej-github-project-service-for-ci.yml
...angelogs/unreleased/jej-github-project-service-for-ci.yml
+5
-0
ee/spec/models/project_services/github_service/status_message_spec.rb
...ls/project_services/github_service/status_message_spec.rb
+102
-0
ee/spec/models/project_services/github_service/status_notifier_spec.rb
...s/project_services/github_service/status_notifier_spec.rb
+67
-0
ee/spec/models/project_services/github_service_spec.rb
ee/spec/models/project_services/github_service_spec.rb
+200
-0
lib/gitlab/data_builder/pipeline.rb
lib/gitlab/data_builder/pipeline.rb
+1
-0
spec/lib/gitlab/data_builder/pipeline_spec.rb
spec/lib/gitlab/data_builder/pipeline_spec.rb
+1
-0
spec/lib/gitlab/import_export/all_models.yml
spec/lib/gitlab/import_export/all_models.yml
+1
-0
No files found.
doc/user/project/integrations/github.md
0 → 100644
View file @
b9e08d97
# GitHub Project Integration
GitLab provides integration for updating pipeline statuses on GitHub. This is especially useful if using GitLab for CI/CD only.
![
Pipeline status update on GitHub
](
img/github_status_check_pipeline_update.png
)
## Configuration
### Complete these steps on GitHub
This integration requires a
[
GitHub API token
](
https://github.com/settings/tokens
)
with
`repo:status`
access granted:
1.
Go to your "Personal access tokens" page at https://github.com/settings/tokens
1.
Click "Generate New Token"
1.
Ensure that
`repo:status`
is checked and click "Generate token"
1.
Copy the generated token to use on GitLab
### Complete these steps on GitLab
1.
Navigate to the project you want to configure.
1.
Navigate to the
[
Integrations page
](
project_services.md#accessing-the-project-services
)
1.
Click "GitHub".
1.
Select the "Active" checkbox.
1.
Paste the token you've generated on GitHub
1.
Enter the path to your project on GitHub, such as "https://github.com/your-name/YourProject/"
1.
Save or optionally click "Test Settings".
![
Configure GitHub Project Integration
](
img/github_configuration.png
)
doc/user/project/integrations/img/github_configuration.png
0 → 100644
View file @
b9e08d97
119 KB
doc/user/project/integrations/img/github_status_check_pipeline_update.png
0 → 100644
View file @
b9e08d97
75.6 KB
doc/user/project/integrations/project_services.md
View file @
b9e08d97
...
...
@@ -35,7 +35,7 @@ Click on the service links to see further configuration instructions and details
| External Wiki | Replaces the link to the internal wiki with a link to an external wiki |
| Flowdock | Flowdock is a collaboration web app for technical teams |
| Gemnasium | Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities |
|
GitHub
| Sends pipeline notifications to GitHub |
|
[
GitHub
](
github.md
)
| Sends pipeline notifications to GitHub |
|
[
HipChat
](
hipchat.md
)
| Private group chat and IM |
|
[
Irker (IRC gateway)
](
irker.md
)
| Send IRC messages, on update, to a list of recipients through an Irker gateway |
|
[
JIRA
](
jira.md
)
| JIRA issue tracker |
...
...
ee/app/models/project_services/github_service.rb
View file @
b9e08d97
...
...
@@ -41,4 +41,56 @@ class GithubService < Service
def
self
.
supported_events
%w(pipeline)
end
def
can_test?
project
.
pipelines
.
any?
end
def
disabled_title
'Please setup a pipeline on your repository.'
end
def
execute
(
data
)
status_message
=
StatusMessage
.
from_pipeline_data
(
project
,
data
)
update_status
(
status_message
)
end
def
test_data
(
project
,
user
)
pipeline
=
project
.
pipelines
.
newest_first
.
first
raise
disabled_title
unless
pipeline
Gitlab
::
DataBuilder
::
Pipeline
.
build
(
pipeline
)
end
def
test
(
data
)
begin
result
=
execute
(
data
)
context
=
result
[
:context
]
by_user
=
result
.
dig
(
:creator
,
:login
)
result
=
"Status for
#{
context
}
updated by
#{
by_user
}
"
if
context
&&
by_user
rescue
StandardError
=>
error
return
{
success:
false
,
result:
error
}
end
{
success:
true
,
result:
result
}
end
private
def
update_status
(
status_message
)
notifier
.
notify
(
status_message
.
sha
,
status_message
.
status
,
status_message
.
status_options
)
end
def
notifier
StatusNotifier
.
new
(
token
,
remote_repo_path
,
api_endpoint:
api_url
)
end
def
remote_repo_path
"
#{
owner
}
/
#{
repository_name
}
"
end
end
ee/app/models/project_services/github_service/status_message.rb
0 → 100644
View file @
b9e08d97
class
GithubService
class
StatusMessage
include
Gitlab
::
Routing
attr_reader
:sha
def
initialize
(
project
,
params
)
@project
=
project
@gitlab_status
=
params
[
:status
]
@detailed_status
=
params
[
:detailed_status
]
@pipeline_id
=
params
[
:id
]
@sha
=
params
[
:sha
]
@ref_name
=
params
[
:ref
]
end
def
context
"ci/gitlab/
#{
@ref_name
}
"
.
truncate
(
255
)
end
def
description
"Pipeline
#{
@detailed_status
}
on GitLab"
.
truncate
(
140
)
end
def
target_url
project_pipeline_url
(
@project
,
@pipeline_id
)
end
def
status
case
@gitlab_status
.
to_s
when
'created'
,
'pending'
,
'running'
,
'manual'
:pending
when
'success'
,
'skipped'
:success
when
'failed'
:failure
when
'canceled'
:error
end
end
def
status_options
{
context:
context
,
description:
description
,
target_url:
target_url
}
end
def
self
.
from_pipeline_data
(
project
,
data
)
new
(
project
,
data
[
:object_attributes
])
end
end
end
ee/app/models/project_services/github_service/status_notifier.rb
0 → 100644
View file @
b9e08d97
class
GithubService
class
StatusNotifier
def
initialize
(
access_token
,
repo_path
,
api_endpoint:
nil
)
@access_token
=
access_token
@repo_path
=
repo_path
@api_endpoint
=
api_endpoint
.
presence
end
def
notify
(
ref
,
state
,
params
=
{})
client
.
create_status
(
@repo_path
,
ref
,
state
,
params
)
end
private
def
client
@client
||=
Octokit
::
Client
.
new
(
access_token:
@access_token
,
api_endpoint:
@api_endpoint
)
end
end
end
ee/changelogs/unreleased/jej-github-project-service-for-ci.yml
0 → 100644
View file @
b9e08d97
---
title
:
Adds GitHub Service to send status updates for pipelines
merge_request
:
4591
author
:
type
:
added
ee/spec/models/project_services/github_service/status_message_spec.rb
0 → 100644
View file @
b9e08d97
require
'spec_helper'
describe
GithubService
::
StatusMessage
do
include
Rails
.
application
.
routes
.
url_helpers
let
(
:project
)
{
double
(
:project
,
namespace:
"me"
,
to_s:
'example_project'
)
}
describe
'#description'
do
it
'includes human readable gitlab status'
do
subject
=
described_class
.
new
(
project
,
detailed_status:
'passed'
)
expect
(
subject
.
description
).
to
eq
"Pipeline passed on GitLab"
end
it
'gets truncated to 140 chars'
do
dummy_text
=
'a'
*
500
subject
=
described_class
.
new
(
project
,
detailed_status:
dummy_text
)
expect
(
subject
.
description
.
length
).
to
eq
140
end
end
describe
'#status'
do
using
RSpec
::
Parameterized
::
TableSyntax
where
(
:gitlab_status
,
:github_status
)
do
'pending'
|
:pending
'created'
|
:pending
'running'
|
:pending
'manual'
|
:pending
'success'
|
:success
'skipped'
|
:success
'failed'
|
:failure
'canceled'
|
:error
end
with_them
do
it
'transforms status'
do
subject
=
described_class
.
new
(
project
,
status:
gitlab_status
)
expect
(
subject
.
status
).
to
eq
github_status
end
end
end
describe
'#status_options'
do
let
(
:subject
)
{
described_class
.
new
(
project
,
id:
1
)
}
it
'includes context'
do
expect
(
subject
.
status_options
[
:context
]).
to
be_a
String
end
it
'includes target_url'
do
expect
(
subject
.
status_options
[
:target_url
]).
to
be_a
String
end
it
'includes description'
do
expect
(
subject
.
status_options
[
:description
]).
to
be_a
String
end
end
describe
'.from_pipeline_data'
do
let
(
:pipeline
)
{
create
(
:ci_pipeline
)
}
let
(
:project
)
{
pipeline
.
project
}
let
(
:sample_data
)
{
Gitlab
::
DataBuilder
::
Pipeline
.
build
(
pipeline
)
}
let
(
:subject
)
{
described_class
.
from_pipeline_data
(
project
,
sample_data
)
}
it
'builds an instance of GithubService::StatusMessage'
do
expect
(
subject
).
to
be_a
described_class
end
describe
'builds an object with'
do
specify
'sha'
do
expect
(
subject
.
sha
).
to
eq
pipeline
.
sha
end
specify
'status'
do
expect
(
subject
.
status
).
to
eq
:pending
end
specify
'target_url'
do
expect
(
subject
.
target_url
).
to
end_with
pipeline_path
(
pipeline
)
end
specify
'description'
do
expect
(
subject
.
description
).
to
eq
"Pipeline pending on GitLab"
end
specify
'context'
do
expect
(
subject
.
context
).
to
eq
"ci/gitlab/
#{
pipeline
.
ref
}
"
end
context
'blocked pipeline'
do
let
(
:pipeline
)
{
create
(
:ci_pipeline
,
:blocked
)
}
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'
end
end
end
end
end
ee/spec/models/project_services/github_service/status_notifier_spec.rb
0 → 100644
View file @
b9e08d97
require
'spec_helper'
describe
GithubService
::
StatusNotifier
do
let
(
:access_token
)
{
'aaaaa'
}
let
(
:repo_path
)
{
'myself/my-project'
}
subject
{
described_class
.
new
(
access_token
,
repo_path
)
}
describe
'#notify'
do
let
(
:ref
)
{
'master'
}
let
(
:state
)
{
'pending'
}
let
(
:params
)
{
{
context:
'Gitlab'
}
}
let
(
:github_status_api
)
{
"https://api.github.com/repos/
#{
repo_path
}
/statuses/
#{
ref
}
"
}
it
'uses GitHub API to update status'
do
stub_request
(
:post
,
github_status_api
)
subject
.
notify
(
ref
,
state
)
expect
(
a_request
(
:post
,
github_status_api
)).
to
have_been_made
.
once
end
context
'with blank api_endpoint'
do
let
(
:api_endpoint
)
{
''
}
subject
{
described_class
.
new
(
access_token
,
repo_path
,
api_endpoint:
api_endpoint
)
}
it
'defaults to using GitHub.com API'
do
github_status_api
=
"https://api.github.com/repos/
#{
repo_path
}
/statuses/
#{
ref
}
"
stub_request
(
:post
,
github_status_api
)
subject
.
notify
(
ref
,
state
)
expect
(
a_request
(
:post
,
github_status_api
)).
to
have_been_made
.
once
end
end
context
'with custom api_endpoint'
do
let
(
:api_endpoint
)
{
'https://my.code.repo'
}
subject
{
described_class
.
new
(
access_token
,
repo_path
,
api_endpoint:
api_endpoint
)
}
it
'uses provided API for requests'
do
custom_status_api
=
"https://my.code.repo/repos/
#{
repo_path
}
/statuses/
#{
ref
}
"
stub_request
(
:post
,
custom_status_api
)
subject
.
notify
(
ref
,
state
)
expect
(
a_request
(
:post
,
custom_status_api
)).
to
have_been_made
.
once
end
end
it
'passes optional params'
do
expect_context
=
hash_including
(
context:
'My Context'
)
stub_request
(
:post
,
github_status_api
).
with
(
body:
expect_context
)
subject
.
notify
(
ref
,
state
,
context:
'My Context'
)
end
it
'uses access token'
do
auth_header
=
{
'Authorization'
=>
'token aaaaa'
}
stub_request
(
:post
,
github_status_api
).
with
(
headers:
auth_header
)
subject
.
notify
(
ref
,
state
)
end
end
end
ee/spec/models/project_services/github_service_spec.rb
0 → 100644
View file @
b9e08d97
require
'spec_helper'
describe
GithubService
do
let
(
:project
)
{
create
(
:project
)
}
let
(
:pipeline
)
{
create
(
:ci_pipeline
,
project:
project
)
}
let
(
:pipeline_sample_data
)
{
Gitlab
::
DataBuilder
::
Pipeline
.
build
(
pipeline
)
}
let
(
:api_url
)
{
''
}
let
(
:owner
)
{
'my-user'
}
let
(
:token
)
{
'aaaaaaaaa'
}
let
(
:repository_name
)
{
'my-project'
}
let
(
:service_params
)
do
{
active:
true
,
project:
project
,
properties:
{
token:
token
,
api_url:
api_url
,
owner:
owner
,
repository_name:
repository_name
}
}
end
subject
{
described_class
.
create
(
service_params
)
}
describe
"Associations"
do
it
{
is_expected
.
to
belong_to
:project
}
end
describe
"#owner"
do
it
'is determined from the repo URL'
do
expect
(
subject
.
owner
).
to
eq
owner
end
end
describe
"#repository_name"
do
it
'is determined from the repo URL'
do
expect
(
subject
.
repository_name
).
to
eq
repository_name
end
end
describe
"#api_url"
do
it
'uses github.com by default'
do
expect
(
subject
.
api_url
).
to
eq
"https://api.github.com"
end
context
"with GitHub Enterprise repo URL"
do
let
(
:base_url
)
{
'https://my.code-repo.com'
}
it
'is set to the Enterprise API URL'
do
expect
(
subject
.
api_url
).
to
eq
"https://my.code-repo.com/api/v3"
end
end
end
describe
'#detailed_description'
do
it
'links to mirroring settings'
do
expect
(
subject
.
detailed_description
).
to
match
(
/href=.*mirroring/
)
end
end
describe
'#execute'
do
let
(
:remote_repo_path
)
{
"
#{
owner
}
/
#{
repository_name
}
"
}
let
(
:sha
)
{
pipeline
.
sha
}
let
(
:status_options
)
{
{
context:
'security'
,
target_url:
'https://localhost.pipeline.example.com'
,
description:
"SAST passed"
}
}
let
(
:status_message
)
{
double
(
sha:
sha
,
status: :success
,
status_options:
status_options
)
}
let
(
:notifier
)
{
instance_double
(
GithubService
::
StatusNotifier
)
}
it
'notifies GitHub of a status change'
do
expect
(
notifier
).
to
receive
(
:notify
)
expect
(
GithubService
::
StatusNotifier
).
to
receive
(
:new
).
with
(
token
,
remote_repo_path
,
anything
)
.
and_return
(
notifier
)
subject
.
execute
(
pipeline_sample_data
)
end
it
'uses StatusMessage to build message'
do
allow
(
subject
).
to
receive
(
:update_status
)
expect
(
GithubService
::
StatusMessage
).
to
receive
(
:from_pipeline_data
).
with
(
project
,
pipeline_sample_data
).
and_return
(
status_message
)
subject
.
execute
(
pipeline_sample_data
)
end
describe
'passes StatusMessage values to StatusNotifier'
do
before
do
allow
(
GithubService
::
StatusNotifier
).
to
receive
(
:new
).
and_return
(
notifier
)
allow
(
GithubService
::
StatusMessage
).
to
receive
(
:from_pipeline_data
).
and_return
(
status_message
)
end
specify
'sha'
do
expect
(
notifier
).
to
receive
(
:notify
).
with
(
sha
,
anything
,
anything
)
subject
.
execute
(
pipeline_sample_data
)
end
specify
'status'
do
expected_status
=
status_message
.
status
expect
(
notifier
).
to
receive
(
:notify
).
with
(
anything
,
expected_status
,
anything
)
subject
.
execute
(
pipeline_sample_data
)
end
specify
'context'
do
expected_context
=
status_options
[
:context
]
expect
(
notifier
).
to
receive
(
:notify
).
with
(
anything
,
anything
,
hash_including
(
context:
expected_context
))
subject
.
execute
(
pipeline_sample_data
)
end
specify
'target_url'
do
expected_target_url
=
status_options
[
:target_url
]
expect
(
notifier
).
to
receive
(
:notify
).
with
(
anything
,
anything
,
hash_including
(
target_url:
expected_target_url
))
subject
.
execute
(
pipeline_sample_data
)
end
specify
'description'
do
expected_description
=
status_options
[
:description
]
expect
(
notifier
).
to
receive
(
:notify
).
with
(
anything
,
anything
,
hash_including
(
description:
expected_description
))
subject
.
execute
(
pipeline_sample_data
)
end
end
it
'uses GitHub API to update status'
do
github_status_api
=
"https://api.github.com/repos/
#{
owner
}
/
#{
repository_name
}
/statuses/
#{
sha
}
"
stub_request
(
:post
,
github_status_api
)
subject
.
execute
(
pipeline_sample_data
)
expect
(
a_request
(
:post
,
github_status_api
)).
to
have_been_made
.
once
end
context
'with custom api endpoint'
do
let
(
:api_url
)
{
'https://my.code.repo'
}
it
'hands custom api url to StatusNotifier'
do
allow
(
notifier
).
to
receive
(
:notify
)
expect
(
GithubService
::
StatusNotifier
).
to
receive
(
:new
).
with
(
anything
,
anything
,
api_endpoint:
api_url
)
.
and_return
(
notifier
)
subject
.
execute
(
pipeline_sample_data
)
end
end
end
describe
'#can_test?'
do
it
'is false if there are no pipelines'
do
project
.
pipelines
.
delete_all
expect
(
subject
.
can_test?
).
to
eq
false
end
it
'is true if the project has a pipeline'
do
pipeline
expect
(
subject
.
can_test?
).
to
eq
true
end
end
describe
'#test_data'
do
let
(
:user
)
{
project
.
owner
}
let
(
:test_data
)
{
subject
.
test_data
(
project
,
user
)
}
it
'raises error if no pipeline found'
do
project
.
pipelines
.
delete_all
expect
{
test_data
}.
to
raise_error
'Please setup a pipeline on your repository.'
end
it
'generates data for latest pipeline'
do
pipeline
expect
(
test_data
[
:object_kind
]).
to
eq
'pipeline'
end
end
describe
'#test'
do
it
'mentions creator in success message'
do
dummy_response
=
{
context:
"default"
,
creator:
{
login:
"YourUser"
}
}
allow
(
subject
).
to
receive
(
:update_status
).
and_return
(
dummy_response
)
result
=
subject
.
test
(
pipeline_sample_data
)
expect
(
result
[
:success
]).
to
eq
true
expect
(
result
[
:result
].
to_s
).
to
eq
(
'Status for default updated by YourUser'
)
end
it
'forwards failure message on error'
do
error_response
=
{
method: :post
,
status:
401
,
url:
'https://api.github.com/repos/my-user/my-project/statuses/master'
,
body:
'Bad credentials'
}
allow
(
subject
).
to
receive
(
:update_status
).
and_raise
(
Octokit
::
Unauthorized
,
error_response
)
result
=
subject
.
test
(
pipeline_sample_data
)
expect
(
result
[
:success
]).
to
eq
false
expect
(
result
[
:result
].
to_s
).
to
end_with
(
'401 - Bad credentials'
)
end
end
end
lib/gitlab/data_builder/pipeline.rb
View file @
b9e08d97
...
...
@@ -22,6 +22,7 @@ module Gitlab
sha:
pipeline
.
sha
,
before_sha:
pipeline
.
before_sha
,
status:
pipeline
.
status
,
detailed_status:
pipeline
.
detailed_status
(
nil
).
label
,
stages:
pipeline
.
stages_names
,
created_at:
pipeline
.
created_at
,
finished_at:
pipeline
.
finished_at
,
...
...
spec/lib/gitlab/data_builder/pipeline_spec.rb
View file @
b9e08d97
...
...
@@ -26,6 +26,7 @@ describe Gitlab::DataBuilder::Pipeline do
it
{
expect
(
attributes
[
:tag
]).
to
eq
(
pipeline
.
tag
)
}
it
{
expect
(
attributes
[
:id
]).
to
eq
(
pipeline
.
id
)
}
it
{
expect
(
attributes
[
:status
]).
to
eq
(
pipeline
.
status
)
}
it
{
expect
(
attributes
[
:detailed_status
]).
to
eq
(
'passed'
)
}
it
{
expect
(
build_data
).
to
be_a
(
Hash
)
}
it
{
expect
(
build_data
[
:id
]).
to
eq
(
build
.
id
)
}
...
...
spec/lib/gitlab/import_export/all_models.yml
View file @
b9e08d97
...
...
@@ -209,6 +209,7 @@ project:
-
mattermost_slash_commands_service
-
slack_slash_commands_service
-
gitlab_slack_application_service
-
github_service
-
irker_service
-
packagist_service
-
pivotaltracker_service
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment