Commit b123171d authored by Kirill Zaitsev's avatar Kirill Zaitsev Committed by Rémy Coutable
Browse files

Add new data to project in push, issue, merge-request and note webhooks data

- Add `avatar_url`, `description`, `git_ssh_url`, `git_http_url`,
  `path_with_namespace` and `default_branch` in `project` in push, issue,
  merge-request and note webhooks data
- Deprecate the `ssh_url` in favor of `git_ssh_url` and `http_url` in
  favor of `git_http_url` in `project` for push, issue, merge-request and
  note webhooks data
- Deprecate the `repository` key in push, issue, merge-request and
  note webhooks data, use `project` instead
parent 9b1dfd3e
......@@ -29,6 +29,11 @@ v 8.5.0 (unreleased)
- Update the ExternalIssue regex pattern (Blake Hitchcock)
- Remember user's inline/side-by-side diff view preference in a cookie (Kirill Katsnelson)
- Optimized performance of finding issues to be closed by a merge request
- Add `avatar_url`, `description`, `git_ssh_url`, `git_http_url`, `path_with_namespace`
and `default_branch` in `project` in push, issue, merge-request and note webhooks data (Kirill Zaitsev)
- Deprecate the `ssh_url` in favor of `git_ssh_url` and `http_url` in favor of `git_http_url`
in `project` for push, issue, merge-request and note webhooks data (Kirill Zaitsev)
- Deprecate the `repository` key in push, issue, merge-request and note webhooks data, use `project` instead (Kirill Zaitsev)
- API: Expose MergeRequest#merge_status (Andrei Dziahel)
- Revert "Add IP check against DNSBLs at account sign-up"
- Actually use the `skip_merges` option in Repository#commits (Tony Chu)
......
......@@ -129,13 +129,10 @@ def to_hook_data(user)
hook_data = {
object_kind: self.class.name.underscore,
user: user.hook_attrs,
repository: {
name: project.name,
url: project.url_to_repo,
description: project.description,
homepage: project.web_url
},
object_attributes: hook_attrs
project: project.hook_attrs,
object_attributes: hook_attrs,
# DEPRECATED
repository: project.hook_attrs.slice(:name, :url, :description, :homepage)
}
hook_data.merge!(assignee: assignee.hook_attrs) if assignee
......
......@@ -738,11 +738,20 @@ def rename_repo
def hook_attrs
{
name: name,
ssh_url: ssh_url_to_repo,
http_url: http_url_to_repo,
description: description,
web_url: web_url,
avatar_url: avatar_url,
git_ssh_url: ssh_url_to_repo,
git_http_url: http_url_to_repo,
namespace: namespace.name,
visibility_level: visibility_level
visibility_level: visibility_level,
path_with_namespace: path_with_namespace,
default_branch: default_branch,
# Backward compatibility
homepage: web_url,
url: url_to_repo,
ssh_url: ssh_url_to_repo,
http_url: http_url_to_repo
}
end
......
# Web hooks
_**Note:**
Starting from GitLab 8.5:_
- _the `repository` key is deprecated in favor of the `project` key_
- _the `project.ssh_url` key is deprecated in favor of the `project.git_ssh_url` key_
- _the `project.http_url` key is deprecated in favor of the `project.git_http_url` key_
Project web hooks allow you to trigger an URL if new code is pushed or a new issue is created.
You can configure web hooks to listen for specific events like pushes, issues or merge requests. GitLab will send a POST request with data to the web hook URL.
......@@ -37,8 +44,25 @@ X-Gitlab-Event: Push Hook
"user_id": 4,
"user_name": "John Smith",
"user_email": "john@example.com",
"user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80",
"project_id": 15,
"repository": {
"project":{
"name":"Diaspora",
"description":"",
"web_url":"http://example.com/mike/diaspora",
"avatar_url":null,
"git_ssh_url":"git@example.com:mike/diaspora.git",
"git_http_url":"http://example.com/mike/diaspora.git",
"namespace":"Mike",
"visibility_level":0,
"path_with_namespace":"mike/diaspora",
"default_branch":"master",
"homepage":"http://example.com/mike/diaspora",
"url":"git@example.com:mike/diasporadiaspora.git",
"ssh_url":"git@example.com:mike/diaspora.git",
"http_url":"http://example.com/mike/diaspora.git"
},
"repository":{
"name": "Diaspora",
"url": "git@example.com:mike/diasporadiaspora.git",
"description": "",
......@@ -100,8 +124,25 @@ X-Gitlab-Event: Tag Push Hook
"after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7",
"user_id": 1,
"user_name": "John Smith",
"user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80",
"project_id": 1,
"repository": {
"project":{
"name":"Example",
"description":"",
"web_url":"http://example.com/jsmith/example",
"avatar_url":null,
"git_ssh_url":"git@example.com:jsmith/example.git",
"git_http_url":"http://example.com/jsmith/example.git",
"namespace":"Jsmith",
"visibility_level":0,
"path_with_namespace":"jsmith/example",
"default_branch":"master",
"homepage":"http://example.com/jsmith/example",
"url":"git@example.com:jsmith/example.git",
"ssh_url":"git@example.com:jsmith/example.git",
"http_url":"http://example.com/jsmith/example.git"
},
"repository":{
"name": "jsmith",
"url": "ssh://git@example.com/jsmith/example.git",
"description": "",
......@@ -135,7 +176,23 @@ X-Gitlab-Event: Issue Hook
"username": "root",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"repository": {
"project":{
"name":"Gitlab Test",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/gitlabhq/gitlab-test",
"avatar_url":null,
"git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
"git_http_url":"http://example.com/gitlabhq/gitlab-test.git",
"namespace":"GitlabHQ",
"visibility_level":20,
"path_with_namespace":"gitlabhq/gitlab-test",
"default_branch":"master",
"homepage":"http://example.com/gitlabhq/gitlab-test",
"url":"http://example.com/gitlabhq/gitlab-test.git",
"ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
"http_url":"http://example.com/gitlabhq/gitlab-test.git"
},
"repository":{
"name": "Gitlab Test",
"url": "http://example.com/gitlabhq/gitlab-test.git",
"description": "Aut reprehenderit ut est.",
......@@ -197,9 +254,25 @@ X-Gitlab-Event: Note Hook
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"project_id": 5,
"repository": {
"project":{
"name":"Gitlab Test",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/gitlabhq/gitlab-test",
"avatar_url":null,
"git_ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
"git_http_url":"http://example.com/gitlabhq/gitlab-test.git",
"namespace":"GitlabHQ",
"visibility_level":20,
"path_with_namespace":"gitlabhq/gitlab-test",
"default_branch":"master",
"homepage":"http://example.com/gitlabhq/gitlab-test",
"url":"http://example.com/gitlabhq/gitlab-test.git",
"ssh_url":"git@example.com:gitlabhq/gitlab-test.git",
"http_url":"http://example.com/gitlabhq/gitlab-test.git"
},
"repository":{
"name": "Gitlab Test",
"url": "http://localhost/gitlab-org/gitlab-test.git",
"url": "http://example.com/gitlab-org/gitlab-test.git",
"description": "Aut reprehenderit ut est.",
"homepage": "http://example.com/gitlab-org/gitlab-test"
},
......@@ -260,9 +333,25 @@ X-Gitlab-Event: Note Hook
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"project_id": 5,
"repository": {
"project":{
"name":"Gitlab Test",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/gitlab-org/gitlab-test",
"avatar_url":null,
"git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
"git_http_url":"http://example.com/gitlab-org/gitlab-test.git",
"namespace":"Gitlab Org",
"visibility_level":10,
"path_with_namespace":"gitlab-org/gitlab-test",
"default_branch":"master",
"homepage":"http://example.com/gitlab-org/gitlab-test",
"url":"http://example.com/gitlab-org/gitlab-test.git",
"ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
"http_url":"http://example.com/gitlab-org/gitlab-test.git"
},
"repository":{
"name": "Gitlab Test",
"url": "http://example.com/gitlab-org/gitlab-test.git",
"url": "http://localhost/gitlab-org/gitlab-test.git",
"description": "Aut reprehenderit ut est.",
"homepage": "http://example.com/gitlab-org/gitlab-test"
},
......@@ -300,21 +389,37 @@ X-Gitlab-Event: Note Hook
"description": "Et voluptas corrupti assumenda temporibus. Architecto cum animi eveniet amet asperiores. Vitae numquam voluptate est natus sit et ad id.",
"position": 0,
"locked_at": null,
"source": {
"name": "Gitlab Test",
"ssh_url": "git@example.com:gitlab-org/gitlab-test.git",
"http_url": "http://example.com/gitlab-org/gitlab-test.git",
"web_url": "http://example.com/gitlab-org/gitlab-test",
"namespace": "Gitlab Org",
"visibility_level": 10
"source":{
"name":"Gitlab Test",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/gitlab-org/gitlab-test",
"avatar_url":null,
"git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
"git_http_url":"http://example.com/gitlab-org/gitlab-test.git",
"namespace":"Gitlab Org",
"visibility_level":10,
"path_with_namespace":"gitlab-org/gitlab-test",
"default_branch":"master",
"homepage":"http://example.com/gitlab-org/gitlab-test",
"url":"http://example.com/gitlab-org/gitlab-test.git",
"ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
"http_url":"http://example.com/gitlab-org/gitlab-test.git"
},
"target": {
"name": "Gitlab Test",
"ssh_url": "git@example.com:gitlab-org/gitlab-test.git",
"http_url": "http://example.com/gitlab-org/gitlab-test.git",
"web_url": "http://example.com/gitlab-org/gitlab-test",
"namespace": "Gitlab Org",
"visibility_level": 10
"name":"Gitlab Test",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/gitlab-org/gitlab-test",
"avatar_url":null,
"git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
"git_http_url":"http://example.com/gitlab-org/gitlab-test.git",
"namespace":"Gitlab Org",
"visibility_level":10,
"path_with_namespace":"gitlab-org/gitlab-test",
"default_branch":"master",
"homepage":"http://example.com/gitlab-org/gitlab-test",
"url":"http://example.com/gitlab-org/gitlab-test.git",
"ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
"http_url":"http://example.com/gitlab-org/gitlab-test.git"
},
"last_commit": {
"id": "562e173be03b8ff2efb05345d12df18815438a4b",
......@@ -355,11 +460,27 @@ X-Gitlab-Event: Note Hook
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"project_id": 5,
"repository": {
"name": "Gitlab Test",
"url": "http://example.com/gitlab-org/gitlab-test.git",
"description": "Aut reprehenderit ut est.",
"homepage": "http://example.com/gitlab-org/gitlab-test"
"project":{
"name":"Gitlab Test",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/gitlab-org/gitlab-test",
"avatar_url":null,
"git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
"git_http_url":"http://example.com/gitlab-org/gitlab-test.git",
"namespace":"Gitlab Org",
"visibility_level":10,
"path_with_namespace":"gitlab-org/gitlab-test",
"default_branch":"master",
"homepage":"http://example.com/gitlab-org/gitlab-test",
"url":"http://example.com/gitlab-org/gitlab-test.git",
"ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
"http_url":"http://example.com/gitlab-org/gitlab-test.git"
},
"repository":{
"name":"diaspora",
"url":"git@example.com:mike/diasporadiaspora.git",
"description":"",
"homepage":"http://example.com/mike/diaspora"
},
"object_attributes": {
"id": 1241,
......@@ -397,7 +518,6 @@ X-Gitlab-Event: Note Hook
### Comment on code snippet
**Request header**:
```
......@@ -415,11 +535,27 @@ X-Gitlab-Event: Note Hook
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
},
"project_id": 5,
"repository": {
"name": "Gitlab Test",
"url": "http://example.com/gitlab-org/gitlab-test.git",
"description": "Aut reprehenderit ut est.",
"homepage": "http://example.com/gitlab-org/gitlab-test"
"project":{
"name":"Gitlab Test",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/gitlab-org/gitlab-test",
"avatar_url":null,
"git_ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
"git_http_url":"http://example.com/gitlab-org/gitlab-test.git",
"namespace":"Gitlab Org",
"visibility_level":10,
"path_with_namespace":"gitlab-org/gitlab-test",
"default_branch":"master",
"homepage":"http://example.com/gitlab-org/gitlab-test",
"url":"http://example.com/gitlab-org/gitlab-test.git",
"ssh_url":"git@example.com:gitlab-org/gitlab-test.git",
"http_url":"http://example.com/gitlab-org/gitlab-test.git"
},
"repository":{
"name":"Gitlab Test",
"url":"http://example.com/gitlab-org/gitlab-test.git",
"description":"Aut reprehenderit ut est.",
"homepage":"http://example.com/gitlab-org/gitlab-test"
},
"object_attributes": {
"id": 1245,
......@@ -491,21 +627,37 @@ X-Gitlab-Event: Merge Request Hook
"target_project_id": 14,
"iid": 1,
"description": "",
"source": {
"name": "awesome_project",
"ssh_url": "ssh://git@example.com/awesome_space/awesome_project.git",
"http_url": "http://example.com/awesome_space/awesome_project.git",
"web_url": "http://example.com/awesome_space/awesome_project",
"visibility_level": 20,
"namespace": "awesome_space"
"source":{
"name":"Awesome Project",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/awesome_space/awesome_project",
"avatar_url":null,
"git_ssh_url":"git@example.com:awesome_space/awesome_project.git",
"git_http_url":"http://example.com/awesome_space/awesome_project.git",
"namespace":"Awesome Space",
"visibility_level":20,
"path_with_namespace":"awesome_space/awesome_project",
"default_branch":"master",
"homepage":"http://example.com/awesome_space/awesome_project",
"url":"http://example.com/awesome_space/awesome_project.git",
"ssh_url":"git@example.com:awesome_space/awesome_project.git",
"http_url":"http://example.com/awesome_space/awesome_project.git"
},
"target": {
"name": "awesome_project",
"ssh_url": "ssh://git@example.com/awesome_space/awesome_project.git",
"http_url": "http://example.com/awesome_space/awesome_project.git",
"web_url": "http://example.com/awesome_space/awesome_project",
"visibility_level": 20,
"namespace": "awesome_space"
"name":"Awesome Project",
"description":"Aut reprehenderit ut est.",
"web_url":"http://example.com/awesome_space/awesome_project",
"avatar_url":null,
"git_ssh_url":"git@example.com:awesome_space/awesome_project.git",
"git_http_url":"http://example.com/awesome_space/awesome_project.git",
"namespace":"Awesome Space",
"visibility_level":20,
"path_with_namespace":"awesome_space/awesome_project",
"default_branch":"master",
"homepage":"http://example.com/awesome_space/awesome_project",
"url":"http://example.com/awesome_space/awesome_project.git",
"ssh_url":"git@example.com:awesome_space/awesome_project.git",
"http_url":"http://example.com/awesome_space/awesome_project.git"
},
"last_commit": {
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
......
......@@ -53,13 +53,10 @@ def build_base_data(project, user, note)
object_kind: "note",
user: user.hook_attrs,
project_id: project.id,
repository: {
name: project.name,
url: project.url_to_repo,
description: project.description,
homepage: project.web_url,
},
object_attributes: note.hook_attrs
project: project.hook_attrs,
object_attributes: note.hook_attrs,
# DEPRECATED
repository: project.hook_attrs.slice(:name, :url, :description, :homepage)
}
base_data[:object_attributes][:url] =
......
......@@ -47,18 +47,14 @@ def build(project, user, oldrev, newrev, ref, commits = [], message = nil)
user_id: user.id,
user_name: user.name,
user_email: user.email,
user_avatar: user.avatar_url,
project_id: project.id,
repository: {
name: project.name,
url: project.url_to_repo,
description: project.description,
homepage: project.web_url,
git_http_url: project.http_url_to_repo,
git_ssh_url: project.ssh_url_to_repo,
visibility_level: project.visibility_level
},
project: project.hook_attrs,
commits: commit_attrs,
total_commits_count: commits_count
total_commits_count: commits_count,
# DEPRECATED
repository: project.hook_attrs.slice(:name, :url, :description, :homepage,
:git_http_url, :git_ssh_url, :visibility_level)
}
data
......
......@@ -16,62 +16,80 @@
end
describe 'When asking for a note on commit' do
let(:note) { create(:note_on_commit) }
let(:note) { create(:note_on_commit, project: project) }
it 'returns the note and commit-specific data' do
expect(data).to have_key(:commit)
end
include_examples 'project hook data'
include_examples 'deprecated repository hook data'
end
describe 'When asking for a note on commit diff' do
let(:note) { create(:note_on_commit_diff) }
let(:note) { create(:note_on_commit_diff, project: project) }
it 'returns the note and commit-specific data' do
expect(data).to have_key(:commit)
end
include_examples 'project hook data'
include_examples 'deprecated repository hook data'
end
describe 'When asking for a note on issue' do
let(:issue) { create(:issue, created_at: fixed_time, updated_at: fixed_time) }
let(:note) { create(:note_on_issue, noteable_id: issue.id) }
let(:note) { create(:note_on_issue, noteable_id: issue.id, project: project) }
it 'returns the note and issue-specific data' do
expect(data).to have_key(:issue)
expect(data[:issue].except('updated_at')).to eq(issue.hook_attrs.except('updated_at'))
expect(data[:issue]['updated_at']).to be > issue.hook_attrs['updated_at']
end
include_examples 'project hook data'
include_examples 'deprecated repository hook data'
end
describe 'When asking for a note on merge request' do
let(:merge_request) { create(:merge_request, created_at: fixed_time, updated_at: fixed_time) }
let(:note) { create(:note_on_merge_request, noteable_id: merge_request.id) }
let(:note) { create(:note_on_merge_request, noteable_id: merge_request.id, project: project) }
it 'returns the note and merge request data' do
expect(data).to have_key(:merge_request)
expect(data[:merge_request].except('updated_at')).to eq(merge_request.hook_attrs.except('updated_at'))
expect(data[:merge_request]['updated_at']).to be > merge_request.hook_attrs['updated_at']
end
include_examples 'project hook data'
include_examples 'deprecated repository hook data'
end
describe 'When asking for a note on merge request diff' do
let(:merge_request) { create(:merge_request, created_at: fixed_time, updated_at: fixed_time) }
let(:note) { create(:note_on_merge_request_diff, noteable_id: merge_request.id) }
let(:note) { create(:note_on_merge_request_diff, noteable_id: merge_request.id, project: project) }
it 'returns the note and merge request diff data' do
expect(data).to have_key(:merge_request)
expect(data[:merge_request].except('updated_at')).to eq(merge_request.hook_attrs.except('updated_at'))
expect(data[:merge_request]['updated_at']).to be > merge_request.hook_attrs['updated_at']
end
include_examples 'project hook data'
include_examples 'deprecated repository hook data'
end
describe 'When asking for a note on project snippet' do
let!(:snippet) { create(:project_snippet, created_at: fixed_time, updated_at: fixed_time) }
let!(:note) { create(:note_on_project_snippet, noteable_id: snippet.id) }
let!(:note) { create(:note_on_project_snippet, noteable_id: snippet.id, project: project) }
it 'returns the note and project snippet data' do
expect(data).to have_key(:snippet)
expect(data[:snippet].except('updated_at')).to eq(snippet.hook_attrs.except('updated_at'))
expect(data[:snippet]['updated_at']).to be > snippet.hook_attrs['updated_at']
end
include_examples 'project hook data'
include_examples 'deprecated repository hook data'
end
end
......@@ -13,13 +13,13 @@
it { expect(data[:after]).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
it { expect(data[:ref]).to eq('refs/heads/master') }
it { expect(data[:commits].size).to eq(3) }
it { expect(data[:repository][:git_http_url]).to eq(project.http_url_to_repo) }
it { expect(data[:repository][:git_ssh_url]).to eq(project.ssh_url_to_repo) }
it { expect(data[:repository][:visibility_level]).to eq(project.visibility_level) }
it { expect(data[:total_commits_count]).to eq(3) }
it { expect(data[:commits].first[:added]).to eq(["gitlab-grack"]) }
it { expect(data[:commits].first[:modified]).to eq([".gitmodules"]) }
it { expect(data[:commits].first[:removed]).to eq([]) }
include_examples 'project hook data'
include_examples 'deprecated repository hook data'
end
describe :build do
......
......@@ -69,27 +69,28 @@
end
describe "#to_hook_data" do
let(:hook_data) { issue.to_hook_data(user) }
let(:data) { issue.to_hook_data(user) }
let(:project) { issue.project }
it "returns correct hook data" do
expect(hook_data[:object_kind]).to eq("issue")
expect(hook_data[:user]).to eq(user.hook_attrs)
expect(hook_data[:repository][:name]).to eq(issue.project.name)
expect(hook_data[:repository][:url]).to eq(issue.project.url_to_repo)
expect(hook_data[:repository][:description]).to eq(issue.project.description)
expect(hook_data[:repository][:homepage]).to eq(issue.project.web_url)
expect(hook_data[:object_attributes]).to eq(issue.hook_attrs)
expect(hook_data).to_not have_key(:assignee)
expect(data[:object_kind]).to eq("issue")
expect(data[:user]).to eq(user.hook_attrs)
expect(data[:object_attributes]).to eq(issue.hook_attrs)
expect(data).to_not have_key(:assignee)
end
context "issue is assigned" do
before { issue.update_attribute(:assignee, user) }
it "returns correct hook data" do
expect(hook_data[:object_attributes]['assignee_id']).to eq(user.id)
expect(hook_data[:assignee]).to eq(user.hook_attrs)
expect(data[:object_attributes]['assignee_id']).to eq(user.id)
expect(data[:assignee]).to eq(user.hook_attrs)
end
end
include_examples 'project hook data'
include_examples 'deprecated repository hook data'
end
describe '#card_attributes' do
......
......@@ -254,13 +254,22 @@
end
describe "#hook_attrs" do
let(:attrs_hash) { subject.hook_attrs.to_h }
[:source, :target].each do |key|
describe "#{key} key" do
include_examples 'project hook data', project_key: key do
let(:data) { attrs_hash }
let(:project) { subject.send("#{key}_project") }
end
end
end
it "has all the required keys" do
attrs = subject.hook_attrs
attrs = attrs.to_h
expect(attrs).to include(:source)
expect(attrs).to include(:target)
expect(attrs).to include(:last_commit)
expect(attrs).to include(:work_in_progress)
expect(attrs_hash).to include(:source)
expect(attrs_hash).to include(:target)
expect(attrs_hash).to include(:last_commit)
expect(attrs_hash).to include(:work_in_progress)
end
end
......
RSpec.shared_examples 'project hook data' do |project_key: :project|
it 'contains project data' do
expect(data[project_key][:name]).to eq(project.name)
expect(data[project_key][:description]).to eq(project.description)
expect(data[project_key][:web_url]).to eq(project.web_url)
expect(data[project_key][:avatar_url]).to eq(project.avatar_url)