Commit 57d4a172 authored by Rémy Coutable's avatar Rémy Coutable

Merge remote-tracking branch 'origin/master' into 8-10-stable

parents 7ce5bb18 240a4aa6
...@@ -31,6 +31,7 @@ v 8.10.0 (unreleased) ...@@ -31,6 +31,7 @@ v 8.10.0 (unreleased)
- Support U2F devices in Firefox. !5177 - Support U2F devices in Firefox. !5177
- Fix issue, preventing users w/o push access to sort tags !5105 (redetection) - Fix issue, preventing users w/o push access to sort tags !5105 (redetection)
- Add Spring EmojiOne updates. - Add Spring EmojiOne updates.
- Fix fetching LFS objects for private CI projects
- Add syntax for multiline blockquote using `>>>` fence !3954 - Add syntax for multiline blockquote using `>>>` fence !3954
- Fix viewing notification settings when a project is pending deletion - Fix viewing notification settings when a project is pending deletion
- Updated compare dropdown menus to use GL dropdown - Updated compare dropdown menus to use GL dropdown
...@@ -47,6 +48,7 @@ v 8.10.0 (unreleased) ...@@ -47,6 +48,7 @@ v 8.10.0 (unreleased)
- Render inline diffs for multiple changed lines following eachother - Render inline diffs for multiple changed lines following eachother
- Wildcards for protected branches. !4665 - Wildcards for protected branches. !4665
- Allow importing from Github using Personal Access Tokens. (Eric K Idema) - Allow importing from Github using Personal Access Tokens. (Eric K Idema)
- API: Expose `due_date` for issues (Robert Schilling)
- API: Todos !3188 (Robert Schilling) - API: Todos !3188 (Robert Schilling)
- API: Expose shared groups for projects and shared projects for groups !5050 (Robert Schilling) - API: Expose shared groups for projects and shared projects for groups !5050 (Robert Schilling)
- Add "Enabled Git access protocols" to Application Settings - Add "Enabled Git access protocols" to Application Settings
...@@ -55,13 +57,16 @@ v 8.10.0 (unreleased) ...@@ -55,13 +57,16 @@ v 8.10.0 (unreleased)
- Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt)
- Only show New Snippet button to users that can create snippets. - Only show New Snippet button to users that can create snippets.
- PipelinesFinder uses git cache data - PipelinesFinder uses git cache data
- Track a user who created a pipeline
- Actually render old and new sections of parallel diff next to each other - Actually render old and new sections of parallel diff next to each other
- Throttle the update of `project.pushes_since_gc` to 1 minute. - Throttle the update of `project.pushes_since_gc` to 1 minute.
- Allow expanding and collapsing files in diff view (!4990) - Allow expanding and collapsing files in diff view (!4990)
- Collapse large diffs by default (!4990) - Collapse large diffs by default (!4990)
- Fix mentioned users list on diff notes - Fix mentioned users list on diff notes
- Fix creation of deployment on build that is retried, redeployed or rollback
- Check for conflicts with existing Project's wiki path when creating a new project. - Check for conflicts with existing Project's wiki path when creating a new project.
- Show last push widget in upstream after push to fork - Show last push widget in upstream after push to fork
- Fix stage status shown for pipelines
- Cache todos pending/done dashboard query counts. - Cache todos pending/done dashboard query counts.
- Don't instantiate a git tree on Projects show default view - Don't instantiate a git tree on Projects show default view
- Bump Rinku to 2.0.0 - Bump Rinku to 2.0.0
...@@ -82,7 +87,9 @@ v 8.10.0 (unreleased) ...@@ -82,7 +87,9 @@ v 8.10.0 (unreleased)
- Add basic system information like memory and disk usage to the admin panel - Add basic system information like memory and disk usage to the admin panel
- Don't garbage collect commits that have related DB records like comments - Don't garbage collect commits that have related DB records like comments
- More descriptive message for git hooks and file locks - More descriptive message for git hooks and file locks
- Aliases of award emoji should be stored as original name. !5060 (dixpac)
- Handle custom Git hook result in GitLab UI - Handle custom Git hook result in GitLab UI
- Allow to access Container Registry for Public and Internal projects
- Allow '?', or '&' for label names - Allow '?', or '&' for label names
- Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests - Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests
- Add date when user joined the team on the member page - Add date when user joined the team on the member page
...@@ -103,6 +110,7 @@ v 8.10.0 (unreleased) ...@@ -103,6 +110,7 @@ v 8.10.0 (unreleased)
- Fix issues importing projects from EE to CE - Fix issues importing projects from EE to CE
- Fix creating group with space in group path - Fix creating group with space in group path
- Create Todos for Issue author when assign or mention himself (Katarzyna Kobierska) - Create Todos for Issue author when assign or mention himself (Katarzyna Kobierska)
- Limit the number of retries on error to 3 for exporting projects
v 8.9.6 v 8.9.6
- Fix importing of events under notes for GitLab projects. !5154 - Fix importing of events under notes for GitLab projects. !5154
......
...@@ -129,6 +129,8 @@ ...@@ -129,6 +129,8 @@
} }
.cancel-retry-btns { .cancel-retry-btns {
vertical-align: middle;
.btn:not(:first-child) { .btn:not(:first-child) {
margin-left: 8px; margin-left: 8px;
} }
......
...@@ -204,7 +204,8 @@ class Ability ...@@ -204,7 +204,8 @@ class Ability
:download_code, :download_code,
:fork_project, :fork_project,
:read_commit_status, :read_commit_status,
:read_pipeline :read_pipeline,
:read_container_image
] ]
end end
......
...@@ -53,6 +53,7 @@ module Ci ...@@ -53,6 +53,7 @@ module Ci
new_build.stage_idx = build.stage_idx new_build.stage_idx = build.stage_idx
new_build.trigger_request = build.trigger_request new_build.trigger_request = build.trigger_request
new_build.user = user new_build.user = user
new_build.environment = build.environment
new_build.save new_build.save
MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build) MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build)
new_build new_build
......
...@@ -6,6 +6,8 @@ module Ci ...@@ -6,6 +6,8 @@ module Ci
self.table_name = 'ci_commits' self.table_name = 'ci_commits'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
belongs_to :user
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id
has_many :builds, class_name: 'Ci::Build', foreign_key: :commit_id has_many :builds, class_name: 'Ci::Build', foreign_key: :commit_id
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest', foreign_key: :commit_id has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest', foreign_key: :commit_id
......
...@@ -65,8 +65,7 @@ module Awardable ...@@ -65,8 +65,7 @@ module Awardable
def create_award_emoji(name, current_user) def create_award_emoji(name, current_user)
return unless emoji_awardable? return unless emoji_awardable?
award_emoji.create(name: normalize_name(name), user: current_user)
award_emoji.create(name: name, user: current_user)
end end
def remove_award_emoji(name, current_user) def remove_award_emoji(name, current_user)
...@@ -80,4 +79,10 @@ module Awardable ...@@ -80,4 +79,10 @@ module Awardable
create_award_emoji(emoji_name, current_user) create_award_emoji(emoji_name, current_user)
end end
end end
private
def normalize_name(name)
Gitlab::AwardEmoji.normalize_emoji_name(name)
end
end end
...@@ -229,8 +229,7 @@ class Note < ActiveRecord::Base ...@@ -229,8 +229,7 @@ class Note < ActiveRecord::Base
end end
def award_emoji_name def award_emoji_name
original_name = note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1] note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
Gitlab::AwardEmoji.normalize_emoji_name(original_name)
end end
private private
......
...@@ -162,7 +162,7 @@ class Project < ActiveRecord::Base ...@@ -162,7 +162,7 @@ class Project < ActiveRecord::Base
validates :namespace, presence: true validates :namespace, presence: true
validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :name, scope: :namespace_id
validates_uniqueness_of :path, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id
validates :import_url, addressable_url: true, if: :import_url validates :import_url, addressable_url: true, if: :external_import?
validates :star_count, numericality: { greater_than_or_equal_to: 0 } validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create validate :check_limit, on: :create
validate :avatar_type, validate :avatar_type,
...@@ -482,7 +482,7 @@ class Project < ActiveRecord::Base ...@@ -482,7 +482,7 @@ class Project < ActiveRecord::Base
end end
def create_or_update_import_data(data: nil, credentials: nil) def create_or_update_import_data(data: nil, credentials: nil)
return unless valid_import_url? return unless import_url.present? && valid_import_url?
project_import_data = import_data || build_import_data project_import_data = import_data || build_import_data
if data if data
...@@ -1038,8 +1038,8 @@ class Project < ActiveRecord::Base ...@@ -1038,8 +1038,8 @@ class Project < ActiveRecord::Base
pipelines.order(id: :desc).find_by(sha: sha, ref: ref) pipelines.order(id: :desc).find_by(sha: sha, ref: ref)
end end
def ensure_pipeline(sha, ref) def ensure_pipeline(sha, ref, current_user = nil)
pipeline(sha, ref) || pipelines.create(sha: sha, ref: ref) pipeline(sha, ref) || pipelines.create(sha: sha, ref: ref, user: current_user)
end end
def enable_ci def enable_ci
......
...@@ -85,6 +85,7 @@ class User < ActiveRecord::Base ...@@ -85,6 +85,7 @@ class User < ActiveRecord::Base
has_one :abuse_report, dependent: :destroy has_one :abuse_report, dependent: :destroy
has_many :spam_logs, dependent: :destroy has_many :spam_logs, dependent: :destroy
has_many :builds, dependent: :nullify, class_name: 'Ci::Build' has_many :builds, dependent: :nullify, class_name: 'Ci::Build'
has_many :pipelines, dependent: :nullify, class_name: 'Ci::Pipeline'
has_many :todos, dependent: :destroy has_many :todos, dependent: :destroy
has_many :notification_settings, dependent: :destroy has_many :notification_settings, dependent: :destroy
has_many :award_emoji, dependent: :destroy has_many :award_emoji, dependent: :destroy
......
...@@ -2,6 +2,7 @@ module Ci ...@@ -2,6 +2,7 @@ module Ci
class CreatePipelineService < BaseService class CreatePipelineService < BaseService
def execute def execute
pipeline = project.pipelines.new(params) pipeline = project.pipelines.new(params)
pipeline.user = current_user
unless ref_names.include?(params[:ref]) unless ref_names.include?(params[:ref])
pipeline.errors.add(:base, 'Reference not found') pipeline.errors.add(:base, 'Reference not found')
......
...@@ -14,7 +14,13 @@ class CreateCommitBuildsService ...@@ -14,7 +14,13 @@ class CreateCommitBuildsService
return false return false
end end
@pipeline = Ci::Pipeline.new(project: project, sha: sha, ref: ref, before_sha: before_sha, tag: tag) @pipeline = Ci::Pipeline.new(
project: project,
sha: sha,
ref: ref,
before_sha: before_sha,
tag: tag,
user: user)
## ##
# Skip creating pipeline if no gitlab-ci.yml is found # Skip creating pipeline if no gitlab-ci.yml is found
......
...@@ -8,7 +8,6 @@ module Notes ...@@ -8,7 +8,6 @@ module Notes
if note.award_emoji? if note.award_emoji?
noteable = note.noteable noteable = note.noteable
todo_service.new_award_emoji(noteable, current_user) todo_service.new_award_emoji(noteable, current_user)
return noteable.create_award_emoji(note.award_emoji_name, current_user) return noteable.create_award_emoji(note.award_emoji_name, current_user)
end end
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
Cant find HEAD commit for this branch Cant find HEAD commit for this branch
- stages_status = pipeline.statuses.stages_status - stages_status = pipeline.statuses.latest.stages_status
- stages.each do |stage| - stages.each do |stage|
%td %td
- status = stages_status[stage] - status = stages_status[stage]
...@@ -58,16 +58,7 @@ ...@@ -58,16 +58,7 @@
.controls.hidden-xs.pull-right .controls.hidden-xs.pull-right
- artifacts = pipeline.builds.latest.select { |b| b.artifacts? } - artifacts = pipeline.builds.latest.select { |b| b.artifacts? }
- if artifacts.present? - if artifacts.present?
.btn-group.inline .inline
.btn-group
%a.dropdown-toggle.btn.btn-default{type: 'button', 'data-toggle' => 'dropdown'}
= icon("play")
%b.caret
%ul.dropdown-menu.dropdown-menu-align-right
%li
= link_to '#' do
= icon("play")
%span Deploy to production
.btn-group .btn-group
%a.dropdown-toggle.btn.btn-default.build-artifacts{type: 'button', 'data-toggle' => 'dropdown'} %a.dropdown-toggle.btn.btn-default.build-artifacts{type: 'button', 'data-toggle' => 'dropdown'}
= icon("download") = icon("download")
...@@ -80,7 +71,7 @@ ...@@ -80,7 +71,7 @@
%span Download '#{build.name}' artifacts %span Download '#{build.name}' artifacts
- if can?(current_user, :update_pipeline, @project) - if can?(current_user, :update_pipeline, @project)
.cancel-retry-btns .cancel-retry-btns.inline
- if pipeline.retryable? - if pipeline.retryable?
= link_to retry_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn has-tooltip', title: "Retry", method: :post do = link_to retry_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn has-tooltip', title: "Retry", method: :post do
= icon("repeat") = icon("repeat")
......
class ProjectExportWorker class ProjectExportWorker
include Sidekiq::Worker include Sidekiq::Worker
sidekiq_options queue: :gitlab_shell, retry: true sidekiq_options queue: :gitlab_shell, retry: 3
def perform(current_user_id, project_id) def perform(current_user_id, project_id)
current_user = User.find(current_user_id) current_user = User.find(current_user_id)
......
class AddUserIdToPipeline < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
def change
add_column :ci_commits, :user_id, :integer
end
end
class AddIndexForPipelineUserId < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
def change
add_concurrent_index :ci_commits, :user_id
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160712171823) do ActiveRecord::Schema.define(version: 20160715134306) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -199,6 +199,7 @@ ActiveRecord::Schema.define(version: 20160712171823) do ...@@ -199,6 +199,7 @@ ActiveRecord::Schema.define(version: 20160712171823) do
t.datetime "started_at" t.datetime "started_at"
t.datetime "finished_at" t.datetime "finished_at"
t.integer "duration" t.integer "duration"
t.integer "user_id"
end end
add_index "ci_commits", ["gl_project_id", "sha"], name: "index_ci_commits_on_gl_project_id_and_sha", using: :btree add_index "ci_commits", ["gl_project_id", "sha"], name: "index_ci_commits_on_gl_project_id_and_sha", using: :btree
...@@ -210,6 +211,7 @@ ActiveRecord::Schema.define(version: 20160712171823) do ...@@ -210,6 +211,7 @@ ActiveRecord::Schema.define(version: 20160712171823) do
add_index "ci_commits", ["project_id"], name: "index_ci_commits_on_project_id", using: :btree add_index "ci_commits", ["project_id"], name: "index_ci_commits_on_project_id", using: :btree
add_index "ci_commits", ["sha"], name: "index_ci_commits_on_sha", using: :btree add_index "ci_commits", ["sha"], name: "index_ci_commits_on_sha", using: :btree
add_index "ci_commits", ["status"], name: "index_ci_commits_on_status", using: :btree add_index "ci_commits", ["status"], name: "index_ci_commits_on_status", using: :btree
add_index "ci_commits", ["user_id"], name: "index_ci_commits_on_user_id", using: :btree
create_table "ci_events", force: :cascade do |t| create_table "ci_events", force: :cascade do |t|
t.integer "project_id" t.integer "project_id"
......
...@@ -78,7 +78,8 @@ Example response: ...@@ -78,7 +78,8 @@ Example response:
"iid" : 6, "iid" : 6,
"labels" : [], "labels" : [],
"subscribed" : false, "subscribed" : false,
"user_notes_count": 1 "user_notes_count": 1,
"due_date": "2016-07-22"
} }
] ]
``` ```
...@@ -154,7 +155,8 @@ Example response: ...@@ -154,7 +155,8 @@ Example response:
"updated_at" : "2016-01-04T15:31:46.176Z", "updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z",
"subscribed" : false, "subscribed" : false,
"user_notes_count": 1 "user_notes_count": 1,
"due_date": null
} }
] ]
``` ```
...@@ -232,7 +234,8 @@ Example response: ...@@ -232,7 +234,8 @@ Example response:
"updated_at" : "2016-01-04T15:31:46.176Z", "updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z",
"subscribed" : false, "subscribed" : false,
"user_notes_count": 1 "user_notes_count": 1,
"due_date": "2016-07-22"
} }
] ]
``` ```
...@@ -295,7 +298,8 @@ Example response: ...@@ -295,7 +298,8 @@ Example response:
"updated_at" : "2016-01-04T15:31:46.176Z", "updated_at" : "2016-01-04T15:31:46.176Z",
"created_at" : "2016-01-04T15:31:46.176Z", "created_at" : "2016-01-04T15:31:46.176Z",
"subscribed": false, "subscribed": false,
"user_notes_count": 1 "user_notes_count": 1,
"due_date": null
} }
``` ```
...@@ -320,6 +324,7 @@ POST /projects/:id/issues ...@@ -320,6 +324,7 @@ POST /projects/:id/issues
| `milestone_id` | integer | no | The ID of a milestone to assign issue | | `milestone_id` | integer | no | The ID of a milestone to assign issue |
| `labels` | string | no | Comma-separated label names for an issue | | `labels` | string | no | Comma-separated label names for an issue |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` | | `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
```bash ```bash
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug
...@@ -351,7 +356,8 @@ Example response: ...@@ -351,7 +356,8 @@ Example response:
"updated_at" : "2016-01-07T12:44:33.959Z", "updated_at" : "2016-01-07T12:44:33.959Z",
"milestone" : null, "milestone" : null,
"subscribed" : true, "subscribed" : true,
"user_notes_count": 0 "user_notes_count": 0,
"due_date": null
} }
``` ```
...@@ -379,6 +385,7 @@ PUT /projects/:id/issues/:issue_id ...@@ -379,6 +385,7 @@ PUT /projects/:id/issues/:issue_id
| `labels` | string | no | Comma-separated label names for an issue | | `labels` | string | no | Comma-separated label names for an issue |
| `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it | | `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
| `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` | | `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
```bash ```bash
curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85?state_event=close curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85?state_event=close
...@@ -410,7 +417,8 @@ Example response: ...@@ -410,7 +417,8 @@ Example response:
"assignee" : null, "assignee" : null,
"milestone" : null, "milestone" : null,
"subscribed" : true, "subscribed" : true,
"user_notes_count": 0 "user_notes_count": 0,
"due_date": "2016-07-22"
} }
``` ```
...@@ -487,7 +495,8 @@ Example response: ...@@ -487,7 +495,8 @@ Example response:
"state": "active", "state": "active",
"avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
"web_url": "https://gitlab.example.com/u/solon.cremin" "web_url": "https://gitlab.example.com/u/solon.cremin"
} },
"due_date": null
} }
``` ```
...@@ -541,7 +550,8 @@ Example response: ...@@ -541,7 +550,8 @@ Example response:
"state": "active", "state": "active",
"avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon",
"web_url": "https://gitlab.example.com/u/solon.cremin" "web_url": "https://gitlab.example.com/u/solon.cremin"
} },
"due_date": null
} }
``` ```
...@@ -596,7 +606,8 @@ Example response: ...@@ -596,7 +606,8 @@ Example response:
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/u/orville" "web_url": "https://gitlab.example.com/u/orville"
}, },
"subscribed": false "subscribed": false,
"due_date": null
} }
``` ```
......
...@@ -985,11 +985,11 @@ directive defined in `.postgres_services` and `.mysql_services` respectively: ...@@ -985,11 +985,11 @@ directive defined in `.postgres_services` and `.mysql_services` respectively:
- ruby - ruby
test:postgres: test:postgres:
<< *job_definition <<: *job_definition
services: *postgres_definition services: *postgres_definition
test:mysql: test:mysql:
<< *job_definition <<: *job_definition
services: *mysql_definition services: *mysql_definition
``` ```
......
...@@ -56,9 +56,9 @@ module API ...@@ -56,9 +56,9 @@ module API
not_found!('Award Emoji') unless can_read_awardable? not_found!('Award Emoji') unless can_read_awardable?
award = awardable.award_emoji.new(name: params[:name], user: current_user) award = awardable.create_award_emoji(params[:name], current_user)
if award.save if award.persisted?
present award, with: Entities::AwardEmoji present award, with: Entities::AwardEmoji
else else
not_found!("Award Emoji #{award.errors.messages}") not_found!("Award Emoji #{award.errors.messages}")
......
...@@ -64,7 +64,7 @@ module API ...@@ -64,7 +64,7 @@ module API
ref = branches.first ref = branches.first
end end
pipeline = @project.ensure_pipeline(commit.sha, ref) pipeline = @project.ensure_pipeline(commit.sha, ref, current_user)
name = params[:name] || params[:context] name = params[:name] || params[:context]
status = GenericCommitStatus.running_or_pending.find_by(pipeline: pipeline, name: name, ref: params[:ref]) status = GenericCommitStatus.running_or_pending.find_by(pipeline: pipeline, name: name, ref: params[:ref])
......
...@@ -187,6 +187,7 @@ module API ...@@ -187,6 +187,7 @@ module API
end end
expose :user_notes_count expose :user_notes_count
expose :upvotes, :downvotes expose :upvotes, :downvotes
expose :due_date
end end
class ExternalIssue < Grape::Entity class ExternalIssue < Grape::Entity
......
...@@ -63,7 +63,12 @@ module API ...@@ -63,7 +63,12 @@ module API
if access_status.status if access_status.status
# Return the repository full path so that gitlab-shell has it when # Return the repository full path so that gitlab-shell has it when
# handling ssh commands # handling ssh commands
response[:repository_path] = project.repository.path_to_repo response[:repository_path] =
if wiki?
project.wiki.repository.path_to_repo
else
project.repository.path_to_repo
end
end end
response response
......
...@@ -152,12 +152,13 @@ module API ...@@ -152,12 +152,13 @@ module API
# milestone_id (optional) - The ID of a milestone to assign issue # milestone_id (optional) - The ID of a milestone to assign issue
# labels (optional) - The labels of an issue # labels (optional) - The labels of an issue
# created_at (optional) - Date time string, ISO 8601 formatted # created_at (optional) - Date time string, ISO 8601 formatted
# due_date (optional) - Date time string in the format YEAR-MONTH-DAY
# Example Request: # Example Request:
# POST /projects/:id/issues # POST /projects/:id/issues
post ":id/issues" do post ':id/issues' do
required_attributes! [:title] required_attributes! [:title]
keys = [:title, :description, :assignee_id, :milestone_id] keys = [:title, :description, :assignee_id, :milestone_id, :due_date]
keys << :created_at if current_user.admin? || user_project.owner == current_user keys << :created_at if current_user.admin? || user_project.owner == current_user
attrs = attributes_for_keys(keys) attrs = attributes_for_keys(keys)
...@@ -201,12 +202,13 @@ module API ...@@ -201,12 +202,13 @@ module API
# labels (optional) - The labels of an issue # labels (optional) - The labels of an issue
# state_event (optional) - The state event of an issue (close|reopen) # state_event (optional) - The state event of an issue (close|reopen)
# updated_at (optional) - Date time string, ISO 8601 formatted # updated_at (optional) - Date time string, ISO 8601 formatted
# due_date (optional) - Date time string in the format YEAR-MONTH-DAY
# Example Request: # Example Request:
# PUT /projects/:id/issues/:issue_id # PUT /projects/:id/issues/:issue_id
put ":id/issues/:issue_id" do put ':id/issues/:issue_id' do
issue = user_project.issues.find(params[:issue_id]) issue = user_project.issues.find(params[:issue_id])
authorize! :update_issue, issue authorize! :update_issue, issue
keys = [:title, :description, :assignee_id, :milestone_id, :state_event] keys = [:title, :description, :assignee_id, :milestone_id, :state_event, :due_date]
keys << :updated_at if current_user.admin? || user_project.owner == current_user keys << :updated_at if current_user.admin? || user_project.owner == current_user
attrs = attributes_for_keys(keys) attrs = attributes_for_keys(keys)
......
...@@ -19,21 +19,22 @@ module Banzai ...@@ -19,21 +19,22 @@ module Banzai
language = node.attr('class') language = node.attr('class')
code = node.text code = node.text
lexer = Rouge::Lexer.find_fancy(language) css_classes = "code highlight"
lexer = Rouge::Lexer.find_fancy(language) || Rouge::Lexers::PlainText
formatter = Rouge::Formatters::HTML.new formatter = Rouge::Formatters::HTML.new
css_classes = "code highlight js-syntax-highlight #{lexer.tag}"
begin begin
highlighted = '' code = formatter.format(lexer.lex(code))
highlighted << %(<pre class="#{css_classes}"><code>)
highlighted << formatter.format(lexer.lex(code)) css_classes << " js-syntax-highlight #{lexer.tag}"
highlighted << %(</code></pre>)
rescue rescue
# Gracefully handle syntax highlighter bugs/errors to ensure # Gracefully handle syntax highlighter bugs/errors to ensure
# users can still access an issue/comment/etc. # users can still access an issue/comment/etc.
highlighted = "<pre>#{code}</pre>"
end end
highlighted = %(<pre class="#{css_classes}"><code>#{code}</code></pre>)
# Extracted to a method to measure it # Extracted to a method to measure it
replace_parent_pre_element(node, highlighted) replace_parent_pre_element(node, highlighted)
end end
......
...@@ -63,7 +63,7 @@ module Grack ...@@ -63,7 +63,7 @@ module Grack
def ci_request?(login, password) def ci_request?(login, password)
matched_login = /(?<s>^[a-zA-Z]*-ci)-token$/.match(login) matched_login = /(?<s>^[a-zA-Z]*-ci)-token$/.match(login)
if project && matched_login.present? && git_cmd == 'git-upload-pack' if project && matched_login.present?
underscored_service = matched_login['s'].underscore underscored_service = matched_login['s'].underscore
if underscored_service == 'gitlab_ci' if underscored_service == 'gitlab_ci'
......
...@@ -47,6 +47,8 @@ module Gitlab ...@@ -47,6 +47,8 @@ module Gitlab
end end
def render_storage_upload_store_response(oid, size, tmp_file_name) def render_storage_upload_store_response(oid, size, tmp_file_name)
return render_forbidden unless tmp_file_name
render_response_to_push do render_response_to_push do
render_lfs_upload_ok(oid, size, tmp_file_name) render_lfs_upload_ok(oid, size, tmp_file_name)
end end
......
...@@ -74,8 +74,6 @@ module Gitlab ...@@ -74,8 +74,6 @@ module Gitlab
lfs.render_storage_upload_authorize_response(oid, size) lfs.render_storage_upload_authorize_response(oid, size)
else else
tmp_file_name = sanitize_tmp_filename(@request.env['HTTP_X_GITLAB_LFS_TMP']) tmp_file_name = sanitize_tmp_filename(@request.env['HTTP_X_GITLAB_LFS_TMP'])
return nil unless tmp_file_name
lfs.render_storage_upload_store_response(oid, size, tmp_file_name) lfs.render_storage_upload_store_response(oid, size, tmp_file_name)
end end
end end
......
...@@ -426,4 +426,23 @@ describe "Internal Project Access", feature: true do ...@@ -426,4 +426,23 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_denied_for :external } it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor } it { is_expected.to be_denied_for :visitor }
end end
describe "GET /:project_path/container_registry" do
before do
stub_container_registry_tags('latest')
stub_container_registry_config(enabled: true)
end
subject { namespace_project_container_registry_index_path(project.namespace, project) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
end end
...@@ -362,4 +362,23 @@ describe "Private Project Access", feature: true do ...@@ -362,4 +362,23 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_denied_for :external } it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor } it { is_expected.to be_denied_for :visitor }
end end
describe "GET /:project_path/container_registry" do
before do
stub_container_registry_tags('latest')
stub_container_registry_config(enabled: true)
end
subject { namespace_project_container_registry_index_path(project.namespace, project) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor }
end
end end
...@@ -426,4 +426,23 @@ describe "Public Project Access", feature: true do ...@@ -426,4 +426,23 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_denied_for :external } it { is_expected.to be_denied_for :external }
it { is_expected.to be_denied_for :visitor } it { is_expected.to be_denied_for :visitor }
end end
describe "GET /:project_path/container_registry" do
before do
stub_container_registry_tags('latest')
stub_container_registry_config(enabled: true)
end
subject { namespace_project_container_registry_index_path(project.namespace, project) }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for developer }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :external }
it { is_expected.to be_allowed_for :visitor }
end
end end
...@@ -3,15 +3,35 @@ require 'spec_helper' ...@@ -3,15 +3,35 @@ require 'spec_helper'
describe Banzai::Filter::SyntaxHighlightFilter, lib: true do describe Banzai::Filter::SyntaxHighlightFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
it 'highlights valid code blocks' do context "when no language is specified" do
result = filter('<pre><code>def fun end</code>') it "highlights as plaintext" do
expect(result.to_html).to eq("<pre class=\"code highlight js-syntax-highlight plaintext\"><code>def fun end</code></pre>") result = filter('<pre><code>def fun end</code></pre>')
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext"><code>def fun end</code></pre>')
end
end end
it 'passes through invalid code blocks' do context "when a valid language is specified" do
allow_any_instance_of(Rouge::Formatter).to receive(:format).and_raise(StandardError) it "highlights as that language" do
result = filter('<pre><code class="ruby">def fun end</code></pre>')
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight ruby"><code><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></code></pre>')
end
end
context "when an invalid language is specified" do
it "highlights as plaintext" do
result = filter('<pre><code class="gnuplot">This is a test</code></pre>')
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext"><code>This is a test</code></pre>')
end
end
context "when Rouge formatting fails" do
before do
allow_any_instance_of(Rouge::Formatter).to receive(:format).and_raise(StandardError)
end
result = filter('<pre><code>This is a test</code></pre>') it "highlights as plaintext" do
expect(result.to_html).to eq('<pre>This is a test</pre>') result = filter('<pre><code class="ruby">This is a test</code></pre>')
expect(result.to_html).to eq('<pre class="code highlight"><code>This is a test</code></pre>')
end
end end
end end
...@@ -54,12 +54,12 @@ describe Gitlab::BitbucketImport::Client, lib: true do ...@@ -54,12 +54,12 @@ describe Gitlab::BitbucketImport::Client, lib: true do
context 'project import' do context 'project import' do
it 'calls .from_project with no errors' do it 'calls .from_project with no errors' do
project = create(:empty_project) project = create(:empty_project)
project.import_url = "ssh://git@bitbucket.org/test/test.git"
project.create_or_update_import_data(credentials: project.create_or_update_import_data(credentials:
{ user: "git", { user: "git",
password: nil, password: nil,
bb_session: { bitbucket_access_token: "test", bb_session: { bitbucket_access_token: "test",
bitbucket_access_token_secret: "test" } }) bitbucket_access_token_secret: "test" } })
project.import_url = "ssh://git@bitbucket.org/test/test.git"
expect { described_class.from_project(project) }.not_to raise_error expect { described_class.from_project(project) }.not_to raise_error
end end
......
...@@ -5,9 +5,12 @@ describe Ci::Pipeline, models: true do ...@@ -5,9 +5,12 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { FactoryGirl.create :ci_pipeline, project: project } let(:pipeline) { FactoryGirl.create :ci_pipeline, project: project }
it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:user) }
it { is_expected.to have_many(:statuses) } it { is_expected.to have_many(:statuses) }
it { is_expected.to have_many(:trigger_requests) } it { is_expected.to have_many(:trigger_requests) }
it { is_expected.to have_many(:builds) } it { is_expected.to have_many(:builds) }
it { is_expected.to validate_presence_of :sha } it { is_expected.to validate_presence_of :sha }
it { is_expected.to validate_presence_of :status } it { is_expected.to validate_presence_of :status }
......
...@@ -177,10 +177,10 @@ describe CommitStatus, models: true do ...@@ -177,10 +177,10 @@ describe CommitStatus, models: true do
describe '#stages' do describe '#stages' do
before do before do
FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'build', stage_idx: 0, status: 'success' create :commit_status, pipeline: pipeline, stage: 'build', name: 'linux', stage_idx: 0, status: 'success'
FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'build', stage_idx: 0, status: 'failed' create :commit_status, pipeline: pipeline, stage: 'build', name: 'mac', stage_idx: 0, status: 'failed'
FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'deploy', stage_idx: 2, status: 'running' create :commit_status, pipeline: pipeline, stage: 'deploy', name: 'staging', stage_idx: 2, status: 'running'
FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'test', stage_idx: 1, status: 'success' create :commit_status, pipeline: pipeline, stage: 'test', name: 'rspec', stage_idx: 1, status: 'success'
end end
context 'stages list' do context 'stages list' do
...@@ -192,7 +192,7 @@ describe CommitStatus, models: true do ...@@ -192,7 +192,7 @@ describe CommitStatus, models: true do
end end
context 'stages with statuses' do context 'stages with statuses' do
subject { CommitStatus.where(pipeline: pipeline).stages_status } subject { CommitStatus.where(pipeline: pipeline).latest.stages_status }
it 'return list of stages with statuses' do it 'return list of stages with statuses' do
is_expected.to eq({ is_expected.to eq({
...@@ -201,6 +201,20 @@ describe CommitStatus, models: true do ...@@ -201,6 +201,20 @@ describe CommitStatus, models: true do
'deploy' => 'running' 'deploy' => 'running'
}) })
end end
context 'when build is retried' do
before do
create :commit_status, pipeline: pipeline, stage: 'build', name: 'mac', stage_idx: 0, status: 'success'
end
it 'ignores a previous state' do
is_expected.to eq({
'build' => 'success',
'test' => 'success',
'deploy' => 'running'
})
end
end
end end
end end
......
...@@ -142,10 +142,10 @@ describe Project, models: true do ...@@ -142,10 +142,10 @@ describe Project, models: true do
expect(project2).to be_valid expect(project2).to be_valid
end end
it 'does not allow to introduce an empty URI' do it 'allows an empty URI' do
project2 = build(:project, import_url: '') project2 = build(:project, import_url: '')
expect(project2).not_to be_valid expect(project2).to be_valid
end end
it 'does not produce import data on an empty URI' do it 'does not produce import data on an empty URI' do
......
...@@ -31,6 +31,8 @@ describe User, models: true do ...@@ -31,6 +31,8 @@ describe User, models: true do
it { is_expected.to have_many(:spam_logs).dependent(:destroy) } it { is_expected.to have_many(:spam_logs).dependent(:destroy) }
it { is_expected.to have_many(:todos).dependent(:destroy) } it { is_expected.to have_many(:todos).dependent(:destroy) }
it { is_expected.to have_many(:award_emoji).dependent(:destroy) } it { is_expected.to have_many(:award_emoji).dependent(:destroy) }
it { is_expected.to have_many(:builds).dependent(:nullify) }
it { is_expected.to have_many(:pipelines).dependent(:nullify) }
describe '#group_members' do describe '#group_members' do
it 'does not include group memberships for which user is a requester' do it 'does not include group memberships for which user is a requester' do
......
...@@ -135,6 +135,22 @@ describe API::API, api: true do ...@@ -135,6 +135,22 @@ describe API::API, api: true do
expect(response).to have_http_status(401) expect(response).to have_http_status(401)
end end
it "normalizes +1 as thumbsup award" do
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: '+1'
expect(issue.award_emoji.last.name).to eq("thumbsup")
end
context 'when the emoji already has been awarded' do
it 'returns a 404 status code' do
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: 'thumbsup'
post api("/projects/#{project.id}/issues/#{issue.id}/award_emoji", user), name: 'thumbsup'
expect(response).to have_http_status(404)
expect(json_response["message"]).to match("has already been taken")
end
end
end end
end end
...@@ -147,6 +163,22 @@ describe API::API, api: true do ...@@ -147,6 +163,22 @@ describe API::API, api: true do
expect(response).to have_http_status(201) expect(response).to have_http_status(201)
expect(json_response['user']['username']).to eq(user.username) expect(json_response['user']['username']).to eq(user.username)
end end
it "normalizes +1 as thumbsup award" do
post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: '+1'
expect(note.award_emoji.last.name).to eq("thumbsup")
end
context 'when the emoji already has been awarded' do
it 'returns a 404 status code' do
post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: 'rocket'
post api("/projects/#{project.id}/issues/#{issue.id}/notes/#{note.id}/award_emoji", user), name: 'rocket'
expect(response).to have_http_status(404)
expect(json_response["message"]).to match("has already been taken")
end
end
end end
describe 'DELETE /projects/:id/awardable/:awardable_id/award_emoji/:award_id' do describe 'DELETE /projects/:id/awardable/:awardable_id/award_emoji/:award_id' do
......
...@@ -56,13 +56,21 @@ describe API::API, api: true do ...@@ -56,13 +56,21 @@ describe API::API, api: true do
context "git push with project.wiki" do context "git push with project.wiki" do
it 'responds with success' do it 'responds with success' do
project_wiki = create(:project, name: 'my.wiki', path: 'my.wiki') push(key, project.wiki)
project_wiki.team << [user, :developer]
push(key, project_wiki) expect(response).to have_http_status(200)
expect(json_response["status"]).to be_truthy
expect(json_response["repository_path"]).to eq(project.wiki.repository.path_to_repo)
end
end
context "git pull with project.wiki" do
it 'responds with success' do
pull(key, project.wiki)
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response["status"]).to be_truthy expect(json_response["status"]).to be_truthy
expect(json_response["repository_path"]).to eq(project.wiki.repository.path_to_repo)
end end
end end
......
...@@ -503,6 +503,20 @@ describe API::API, api: true do ...@@ -503,6 +503,20 @@ describe API::API, api: true do
]) ])
end end
context 'with due date' do
it 'creates a new project issue' do
due_date = 2.weeks.from_now.strftime('%Y-%m-%d')
post api("/projects/#{project.id}/issues", user),
title: 'new issue', due_date: due_date
expect(response).to have_http_status(201)
expect(json_response['title']).to eq('new issue')
expect(json_response['description']).to be_nil
expect(json_response['due_date']).to eq(due_date)
end
end
context 'when an admin or owner makes the request' do context 'when an admin or owner makes the request' do
it 'accepts the creation date to be set' do it 'accepts the creation date to be set' do
creation_time = 2.weeks.ago creation_time = 2.weeks.ago
...@@ -683,6 +697,17 @@ describe API::API, api: true do ...@@ -683,6 +697,17 @@ describe API::API, api: true do
end end
end end
describe 'PUT /projects/:id/issues/:issue_id to update due date' do
it 'creates a new project issue' do
due_date = 2.weeks.from_now.strftime('%Y-%m-%d')
put api("/projects/#{project.id}/issues/#{issue.id}", user), due_date: due_date
expect(response).to have_http_status(200)
expect(json_response['due_date']).to eq(due_date)
end
end
describe "DELETE /projects/:id/issues/:issue_id" do describe "DELETE /projects/:id/issues/:issue_id" do
it "rejects a non member from deleting an issue" do it "rejects a non member from deleting an issue" do
delete api("/projects/#{project.id}/issues/#{issue.id}", non_member) delete api("/projects/#{project.id}/issues/#{issue.id}", non_member)
......
...@@ -87,51 +87,105 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do ...@@ -87,51 +87,105 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end end
context 'user authorization' do context 'user authorization' do
let(:project) { create(:project) }
let(:current_user) { create(:user) } let(:current_user) { create(:user) }
context 'allow to use scope-less authentication' do context 'for private project' do
it_behaves_like 'a valid token' let(:project) { create(:empty_project) }
end
context 'allow developer to push images' do context 'allow to use scope-less authentication' do
before { project.team << [current_user, :developer] } it_behaves_like 'a valid token'
end
let(:current_params) do context 'allow developer to push images' do
{ scope: "repository:#{project.path_with_namespace}:push" } before { project.team << [current_user, :developer] }
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:push" }
end
it_behaves_like 'a pushable'
end end
it_behaves_like 'a pushable' context 'allow reporter to pull images' do
end before { project.team << [current_user, :reporter] }
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:pull" }
end
context 'allow reporter to pull images' do it_behaves_like 'a pullable'
before { project.team << [current_user, :reporter] } end
let(:current_params) do context 'return a least of privileges' do
{ scope: "repository:#{project.path_with_namespace}:pull" } before { project.team << [current_user, :reporter] }
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:push,pull" }
end
it_behaves_like 'a pullable'
end end
it_behaves_like 'a pullable' context 'disallow guest to pull or push images' do
before { project.team << [current_user, :guest] }
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:pull,push" }
end
it_behaves_like 'an inaccessible'
end
end end
context 'return a least of privileges' do context 'for public project' do
before { project.team << [current_user, :reporter] } let(:project) { create(:empty_project, :public) }
let(:current_params) do context 'allow anyone to pull images' do
{ scope: "repository:#{project.path_with_namespace}:push,pull" } let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:pull" }
end
it_behaves_like 'a pullable'
end end
it_behaves_like 'a pullable' context 'disallow anyone to push images' do
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:push" }
end
it_behaves_like 'an inaccessible'
end
end end
context 'disallow guest to pull or push images' do context 'for internal project' do
before { project.team << [current_user, :guest] } let(:project) { create(:empty_project, :internal) }
let(:current_params) do context 'for internal user' do
{ scope: "repository:#{project.path_with_namespace}:pull,push" } context 'allow anyone to pull images' do
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:pull" }
end
it_behaves_like 'a pullable'
end
context 'disallow anyone to push images' do
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:push" }
end
it_behaves_like 'an inaccessible'
end
end end
it_behaves_like 'an inaccessible' context 'for external user' do
let(:current_user) { create(:user, external: true) }
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:pull,push" }
end
it_behaves_like 'an inaccessible'
end
end end
end end
......
...@@ -3,7 +3,7 @@ require 'spec_helper' ...@@ -3,7 +3,7 @@ require 'spec_helper'
describe CreateCommitBuildsService, services: true do describe CreateCommitBuildsService, services: true do
let(:service) { CreateCommitBuildsService.new } let(:service) { CreateCommitBuildsService.new }
let(:project) { FactoryGirl.create(:empty_project) } let(:project) { FactoryGirl.create(:empty_project) }
let(:user) { nil } let(:user) { create(:user) }
before do before do
stub_ci_pipeline_to_return_yaml_file stub_ci_pipeline_to_return_yaml_file
...@@ -24,6 +24,7 @@ describe CreateCommitBuildsService, services: true do ...@@ -24,6 +24,7 @@ describe CreateCommitBuildsService, services: true do
it { expect(pipeline).to be_valid } it { expect(pipeline).to be_valid }
it { expect(pipeline).to be_persisted } it { expect(pipeline).to be_persisted }
it { expect(pipeline).to eq(project.pipelines.last) } it { expect(pipeline).to eq(project.pipelines.last) }
it { expect(pipeline).to have_attributes(user: user) }
it { expect(pipeline.builds.first).to be_kind_of(Ci::Build) } it { expect(pipeline.builds.first).to be_kind_of(Ci::Build) }
end end
......
...@@ -89,6 +89,12 @@ describe CreateDeploymentService, services: true do ...@@ -89,6 +89,12 @@ describe CreateDeploymentService, services: true do
expect_any_instance_of(described_class).to receive(:execute) expect_any_instance_of(described_class).to receive(:execute)
subject subject
end end
it 'is set as deployable' do
subject
expect(Deployment.last.deployable).to eq(deployable)
end
end end
context 'without environment specified' do context 'without environment specified' do
...@@ -105,6 +111,8 @@ describe CreateDeploymentService, services: true do ...@@ -105,6 +111,8 @@ describe CreateDeploymentService, services: true do
context 'when build succeeds' do context 'when build succeeds' do
it_behaves_like 'does create environment and deployment' do it_behaves_like 'does create environment and deployment' do
let(:deployable) { build }
subject { build.success } subject { build.success }
end end
end end
...@@ -114,6 +122,14 @@ describe CreateDeploymentService, services: true do ...@@ -114,6 +122,14 @@ describe CreateDeploymentService, services: true do
subject { build.drop } subject { build.drop }
end end
end end
context 'when build is retried' do
it_behaves_like 'does create environment and deployment' do
let(:deployable) { Ci::Build.retry(build) }
subject { deployable.success }
end
end
end end
end end
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