Commit c11e5e84 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ce-to-ee-2017-07-26' into 'master'

CE upstream - Wednesday

Closes omnibus-gitlab#2612

See merge request !2527
parents 33186b2c b55e7469
......@@ -136,13 +136,8 @@ entry.
- Bump Faraday and dependent OAuth2 gem version to support no_proxy variable.
- Renders 404 if given project is not readable by the user on Todos dashboard.
- Render CI statuses with warnings in orange.
<<<<<<< HEAD
- Add wells to admin dashboard overview to fix spacing problems.
- Document the Delete Merged Branches functionality.
=======
- Document the Delete Merged Branches functionality.
- Add wells to admin dashboard overview to fix spacing problems.
>>>>>>> ce-com/master
- Removes hover style for nodes that are either links or buttons in the pipeline graph.
- more visual contrast in pagination widget.
- Deprecate Healthcheck Access Token in favor of IP whitelist.
......
......@@ -115,8 +115,8 @@ scheduling into milestones. Labelling is a task for everyone.
Most issues will have labels for at least one of the following:
- Type: ~"feature proposal", ~bug, ~customer, etc.
- Subject: ~wiki, ~"container registry", ~ldap, ~api, etc.
- Team: ~CI, ~Discussion, ~Edge, ~Frontend, ~Platform, etc.
- Subject: ~wiki, ~"container registry", ~ldap, ~api, ~frontend, etc.
- Team: ~CI, ~Discussion, ~Edge, ~Platform, etc.
- Priority: ~Deliverable, ~Stretch
All labels, their meaning and priority are defined on the
......@@ -279,7 +279,7 @@ For feature proposals for EE, open an issue on the
In order to help track the feature proposals, we have created a
[`feature proposal`][fpl] label. For the time being, users that are not members
of the project cannot add labels. You can instead ask one of the [core team]
members to add the label `feature proposal` to the issue or add the following
members to add the label ~"feature proposal" to the issue or add the following
code snippet right after your description in a new line: `~"feature proposal"`.
Please keep feature proposals as small and simple as possible, complex ones
......
......@@ -176,7 +176,7 @@ gem 'rainbow', '~> 2.2'
gem 'settingslogic', '~> 2.0.9'
# Linear-time regex library for untrusted regular expressions
gem 're2', '~> 1.1.0'
gem 're2', '~> 1.1.1'
# Misc
......@@ -367,7 +367,7 @@ group :development, :test do
end
group :test do
gem 'shoulda-matchers', '~> 2.8.0', require: false
gem 'shoulda-matchers', '~> 3.1.2', require: false
gem 'email_spec', '~> 1.6.0'
gem 'json-schema', '~> 2.6.2'
gem 'webmock', '~> 2.3.2'
......
......@@ -689,7 +689,7 @@ GEM
debugger-ruby_core_source (~> 1.3)
rdoc (4.2.2)
json (~> 1.4)
re2 (1.1.0)
re2 (1.1.1)
recaptcha (3.0.0)
json
recursive-open-struct (1.0.0)
......@@ -807,8 +807,8 @@ GEM
sexp_processor (4.9.0)
sham_rack (1.3.6)
rack
shoulda-matchers (2.8.0)
activesupport (>= 3.0.0)
shoulda-matchers (3.1.2)
activesupport (>= 4.0.0)
sidekiq (5.0.4)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
......@@ -1098,7 +1098,7 @@ DEPENDENCIES
raindrops (~> 0.18)
rblineprof (~> 0.3.6)
rdoc (~> 4.2)
re2 (~> 1.1.0)
re2 (~> 1.1.1)
recaptcha (~> 3.0)
redcarpet (~> 3.4)
redis (~> 3.2)
......@@ -1127,7 +1127,7 @@ DEPENDENCIES
sentry-raven (~> 2.5.3)
settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6)
shoulda-matchers (~> 2.8.0)
shoulda-matchers (~> 3.1.2)
sidekiq (~> 5.0)
sidekiq-cron (~> 0.6.0)
sidekiq-limit_fetch (~> 3.4)
......
......@@ -175,7 +175,7 @@ import Cookies from 'js-cookie';
getConflictsCountText() {
const count = this.getConflictsCount();
const text = count ? 'conflicts' : 'conflict';
const text = count > 1 ? 'conflicts' : 'conflict';
return `${count} ${text}`;
},
......
......@@ -108,7 +108,8 @@ export default {
</div>
<mr-widget-memory-usage
v-if="deployment.metrics_url"
:metricsUrl="deployment.metrics_url"
:metrics-url="deployment.metrics_url"
:metrics-monitoring-url="deployment.metrics_monitoring_url"
/>
</div>
</div>
......
......@@ -7,7 +7,14 @@ import MRWidgetService from '../services/mr_widget_service';
export default {
name: 'MemoryUsage',
props: {
metricsUrl: { type: String, required: true },
metricsUrl: {
type: String,
required: true,
},
metricsMonitoringUrl: {
type: String,
required: true,
},
},
data() {
return {
......@@ -124,7 +131,7 @@ export default {
<p
v-if="shouldShowMemoryGraph"
class="usage-info js-usage-info">
Memory usage <b>{{memoryChangeType}}</b> from {{memoryFrom}}MB to {{memoryTo}}MB
<a :href="metricsMonitoringUrl">Memory</a> usage <b>{{memoryChangeType}}</b> from {{memoryFrom}}MB to {{memoryTo}}MB
</p>
<p
v-if="shouldShowLoadFailure"
......
......@@ -163,8 +163,18 @@
td.blame-commit {
padding: 5px 10px;
min-width: 400px;
max-width: 400px;
background: $gray-light;
border-left: 3px solid;
.commit-row-title {
display: flex;
}
.item-title {
flex: 1;
margin-right: 0.5em;
}
}
@for $i from 0 through 5 {
......
......@@ -21,6 +21,11 @@ header.navbar-gitlab-new {
padding-right: 0;
color: currentColor;
img {
height: 28px;
margin-right: 10px;
}
> a {
display: flex;
align-items: center;
......
......@@ -226,12 +226,18 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
if can?(current_user, :read_environment, environment) && environment.has_metrics?
metrics_project_environment_deployment_path(environment.project, environment, deployment)
end
metrics_monitoring_url =
if can?(current_user, :read_environment, environment)
environment_metrics_path(environment)
end
{
id: environment.id,
name: environment.name,
url: project_environment_path(project, environment),
metrics_url: metrics_url,
metrics_monitoring_url: metrics_monitoring_url,
stop_url: stop_url,
external_url: environment.external_url,
external_url_formatted: environment.formatted_external_url,
......
......@@ -33,7 +33,7 @@ module Ci
has_many :merge_requests, foreign_key: "head_pipeline_id"
has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :retryable_builds, -> { latest.failed_or_canceled }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :retryable_builds, -> { latest.failed_or_canceled.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus'
has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :artifacts, -> { latest.with_artifacts_not_expired.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
......
......@@ -40,10 +40,6 @@ module Ci
update_attribute(:active, false)
end
def runnable_by_owner?
Ability.allowed?(owner, :create_pipeline, project)
end
def set_next_run_at
self.next_run_at = Gitlab::Ci::CronParser.new(cron, cron_timezone).next_time_from(Time.now)
end
......
......@@ -31,8 +31,8 @@ module ProtectedRef
end
end
def protected_ref_accessible_to?(ref, user, action:)
access_levels_for_ref(ref, action: action).any? do |access_level|
def protected_ref_accessible_to?(ref, user, action:, protected_refs: nil)
access_levels_for_ref(ref, action: action, protected_refs: protected_refs).any? do |access_level|
access_level.check_access(user)
end
end
......@@ -43,8 +43,9 @@ module ProtectedRef
end
end
def access_levels_for_ref(ref, action:)
self.matching(ref).map(&:"#{action}_access_levels").flatten
def access_levels_for_ref(ref, action:, protected_refs: nil)
self.matching(ref, protected_refs: protected_refs)
.map(&:"#{action}_access_levels").flatten
end
def matching(ref_name, protected_refs: nil)
......
......@@ -4,7 +4,7 @@ class PathLock < ActiveRecord::Base
validates :project, presence: true
validates :user, presence: true
validates :path, presence: true, uniqueness: { scope: :project }
validates :path, presence: true, uniqueness: { scope: :project_id }
validate :path_unique_validation
def downstream?(path)
......
......@@ -3,10 +3,8 @@ class JiraService < IssueTrackerService
validates :url, url: true, presence: true, if: :activated?
validates :api_url, url: true, allow_blank: true
validates :project_key, presence: true, if: :activated?
prop_accessor :username, :password, :url, :api_url, :project_key,
:jira_issue_transition_id, :title, :description
prop_accessor :username, :password, :url, :api_url, :jira_issue_transition_id, :title, :description
before_update :reset_password
......@@ -54,10 +52,6 @@ class JiraService < IssueTrackerService
@client ||= JIRA::Client.new(options)
end
def jira_project
@jira_project ||= jira_request { client.Project.find(project_key) }
end
def help
"You need to configure JIRA before enabling this service. For more details
read the
......@@ -88,18 +82,12 @@ class JiraService < IssueTrackerService
[
{ type: 'text', name: 'url', title: 'Web URL', placeholder: 'https://jira.example.com', required: true },
{ type: 'text', name: 'api_url', title: 'JIRA API URL', placeholder: 'If different from Web URL' },
{ type: 'text', name: 'project_key', placeholder: 'Project Key', required: true },
{ type: 'text', name: 'username', placeholder: '', required: true },
{ type: 'password', name: 'password', placeholder: '', required: true },
{ type: 'text', name: 'jira_issue_transition_id', placeholder: '' }
{ type: 'text', name: 'jira_issue_transition_id', title: 'Transition ID', placeholder: '' }
]
end
# URLs to redirect from Gitlab issues pages to jira issue tracker
def project_url
"#{url}/issues/?jql=project=#{project_key}"
end
def issues_url
"#{url}/browse/:id"
end
......@@ -184,7 +172,7 @@ class JiraService < IssueTrackerService
def test_settings
return unless client_url.present?
# Test settings by getting the project
jira_request { jira_project.present? }
jira_request { client.ServerInfo.all.attrs }
end
private
......
......@@ -478,8 +478,17 @@ class Repository
end
cache_method :root_ref
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/314
def exists?
refs_directory_exists?
return false unless path_with_namespace
Gitlab::GitalyClient.migrate(:repository_exists) do |enabled|
if enabled
raw_repository.exists?
else
refs_directory_exists?
end
end
end
cache_method :exists?
......@@ -1175,8 +1184,6 @@ class Repository
end
def refs_directory_exists?
return false unless path_with_namespace
File.exist?(File.join(path_to_repo, 'refs'))
end
......
module Ci
class BuildPolicy < CommitStatusPolicy
condition(:protected_action) do
next false unless @subject.action?
condition(:protected_ref) do
access = ::Gitlab::UserAccess.new(@user, project: @subject.project)
if @subject.tag?
!access.can_create_tag?(@subject.ref)
else
!access.can_merge_to_branch?(@subject.ref)
!access.can_update_branch?(@subject.ref)
end
end
rule { protected_action }.prevent :update_build
rule { protected_ref }.prevent :update_build
end
end
module Ci
class PipelinePolicy < BasePolicy
delegate { @subject.project }
condition(:protected_ref) do
access = ::Gitlab::UserAccess.new(@user, project: @subject.project)
if @subject.tag?
!access.can_create_tag?(@subject.ref)
else
!access.can_update_branch?(@subject.ref)
end
end
rule { protected_ref }.prevent :update_pipeline
end
end
......@@ -44,7 +44,7 @@ class GlobalPolicy < BasePolicy
prevent :log_in
end
rule { ~restricted_public_level }.policy do
rule { admin | ~restricted_public_level }.policy do
enable :read_users_list
end
end
......@@ -16,7 +16,8 @@ class BuildDetailsEntity < JobEntity
end
expose :path do |build|
project_merge_request_path(project, build.merge_request)
project_merge_request_path(build.merge_request.project,
build.merge_request)
end
end
......
......@@ -9,7 +9,7 @@ class DeployKeyEntity < Grape::Entity
expose :created_at
expose :updated_at
expose :projects, using: ProjectEntity do |deploy_key|
deploy_key.projects.select { |project| options[:user].can?(:read_project, project) }
deploy_key.projects.without_deleted.select { |project| options[:user].can?(:read_project, project) }
end
expose :can_edit
......
......@@ -15,6 +15,19 @@ module Ci
pipeline_schedule: schedule
)
result = validate(current_user || trigger_request.trigger.owner,
ignore_skip_ci: ignore_skip_ci,
save_on_errors: save_on_errors,
mirror_update: mirror_update)
return result if result
_create_pipeline(source, &block)
end
private
def validate(triggering_user, ignore_skip_ci:, save_on_errors:, mirror_update:)
unless project.builds_enabled?
return error('Pipeline is disabled')
end
......@@ -23,8 +36,12 @@ module Ci
return error('Pipeline is disabled for mirror updates') if mirror_update
end
unless trigger_request || can?(current_user, :create_pipeline, project)
return error('Insufficient permissions to create a new pipeline')
unless allowed_to_trigger_pipeline?(triggering_user)
if can?(triggering_user, :create_pipeline, project)
return error("Insufficient permissions for protected ref '#{ref}'")
else
return error('Insufficient permissions to create a new pipeline')
end
end
unless branch? || tag?
......@@ -50,12 +67,8 @@ module Ci
unless pipeline.has_stage_seeds?
return error('No stages / jobs for this pipeline.')
end
_create_pipeline(source, &block)
end
private
def _create_pipeline(source)
Ci::Pipeline.transaction do
update_merge_requests_head_pipeline if pipeline.save
......@@ -74,6 +87,27 @@ module Ci
pipeline.tap(&:process!)
end
def allowed_to_trigger_pipeline?(triggering_user)
if triggering_user
allowed_to_create?(triggering_user)
else # legacy triggers don't have a corresponding user
!project.protected_for?(ref)
end
end
def allowed_to_create?(triggering_user)
access = Gitlab::UserAccess.new(triggering_user, project: project)
can?(triggering_user, :create_pipeline, project) &&
if branch?
access.can_update_branch?(ref)
elsif tag?
access.can_create_tag?(ref)
else
true # Allow it for now and we'll reject when we check ref existence
end
end
def update_merge_requests_head_pipeline
return unless pipeline.latest?
......@@ -123,15 +157,21 @@ module Ci
end
def branch?
project.repository.ref_exists?(Gitlab::Git::BRANCH_REF_PREFIX + ref)
return @is_branch if defined?(@is_branch)
@is_branch =
project.repository.ref_exists?(Gitlab::Git::BRANCH_REF_PREFIX + ref)
end
def tag?
project.repository.ref_exists?(Gitlab::Git::TAG_REF_PREFIX + ref)
return @is_tag if defined?(@is_tag)
@is_tag =
project.repository.ref_exists?(Gitlab::Git::TAG_REF_PREFIX + ref)
end
def ref
Gitlab::Git.ref_name(origin_ref)
@ref ||= Gitlab::Git.ref_name(origin_ref)
end
def valid_sha?
......
module Ci
class CreateTriggerRequestService
def execute(project, trigger, ref, variables = nil)
module CreateTriggerRequestService
Result = Struct.new(:trigger_request, :pipeline)
def self.execute(project, trigger, ref, variables = nil)
trigger_request = trigger.trigger_requests.create(variables: variables)
pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: ref)
.execute(:trigger, ignore_skip_ci: true, trigger_request: trigger_request)
trigger_request if pipeline.persisted?
Result.new(trigger_request, pipeline)
end
end
end
......@@ -21,8 +21,8 @@
.commit
= author_avatar(commit, size: 36)
.commit-row-title
%strong
= link_to_gfm truncate(commit.title, length: 35), project_commit_path(@project, commit.id), class: "cdark"
%span.item-title.str-truncated-100
= link_to_gfm commit.title, project_commit_path(@project, commit.id), class: "cdark", title: commit.title
.pull-right
= link_to commit.short_id, project_commit_path(@project, commit), class: "commit-sha"
&nbsp;
......
- if @projects.any?
.project-item-select-holder
= project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at' }, with_feature_enabled: local_assigns[:with_feature_enabled]
%a.btn.btn-new.new-project-item-select-button{ data: { relative_path: local_assigns[:path] } }
= project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path] }, with_feature_enabled: local_assigns[:with_feature_enabled]
%a.btn.btn-new.new-project-item-select-button
= local_assigns[:label]
= icon('caret-down')
......@@ -6,15 +6,12 @@ class PipelineScheduleWorker
Ci::PipelineSchedule.active.where("next_run_at < ?", Time.now)
.preload(:owner, :project).find_each do |schedule|
begin
unless schedule.runnable_by_owner?
schedule.deactivate!
next
end
Ci::CreatePipelineService.new(schedule.project,
schedule.owner,
ref: schedule.ref)
pipeline = Ci::CreatePipelineService.new(schedule.project,
schedule.owner,
ref: schedule.ref)
.execute(:schedule, save_on_errors: false, schedule: schedule)
schedule.deactivate! unless pipeline.persisted?
rescue => e
Rails.logger.error "#{schedule.id}: Failed to create a scheduled pipeline: #{e.message}"
ensure
......
---
title: Fix vertical alignment in firefox and safari for pipeline mini graph
merge_request:
author:
---
title: Disallow running the pipeline if ref is protected and user cannot merge the
branch or create the tag
merge_request: 11910
author:
---
title: Remove project_key from the Jira configuration
merge_request: 12050
author:
---
title: Added link to the MR widget that directs to the monitoring dashboard
merge_request:
author:
---
title: Use only CSS to truncate commit message in blame
merge_request: 12900
author: Takuya Noguchi
---
title: Add link to doc/api/ci/lint.md
merge_request: 12914
author: Takuya Noguchi
---
title: Pending delete projects should not show in deploy keys.
merge_request: 13088
author:
---
title: Allow admin to read_users_list even if it's restricted
merge_request: 13066
author:
---
title: Add instrumentation to MarkupHelper#link_to_gfm
merge_request: 13069
author:
---
title: Free up some top level words, reject top level groups named like files in the
public folder
merge_request: 12932
author:
---
title: Fix job merge request link to a forked source project
merge_request: 12965
author:
---
title: Fix sizing of custom header logo in new navigation
merge_request:
author:
......@@ -136,6 +136,9 @@ def instrument_classes(instrumentation)
# This is a Rails scope so we have to instrument it manually.
instrumentation.instrument_method(Project, :visible_to_user)
# Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/34509
instrumentation.instrument_method(MarkupHelper, :link_to_gfm)
# Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/30224#note_32306159
instrumentation.instrument_instance_method(MergeRequestDiff, :load_commits)
end
......
......@@ -11,15 +11,11 @@ self-hosted, free to use. Every feature available in GitLab CE is also available
self-hosted, fully featured solution of GitLab, available under distinct [subscriptions](https://about.gitlab.com/products/): **GitLab Enterprise Edition Starter (EES)** and **GitLab Enterprise Edition Premium (EEP)**.
- **GitLab.com**: SaaS GitLab solution, with [free and paid subscriptions](https://about.gitlab.com/gitlab-com/). GitLab.com is hosted by GitLab, Inc., and administrated by GitLab (users don't have access to admin settings).
**GitLab EE** contains all features available in **GitLab CE**,
> **GitLab EE** contains all features available in **GitLab CE**,
plus premium features available in each version: **Enterprise Edition Starter**
(**EES**) and **Enterprise Edition Premium** (**EEP**). Everything available in
**EES** is also available in **EEP**.
**Note:** _We are unifying the documentation for CE and EE. To check if certain feature is
available in CE or EE, look for a note right below the page title containing the GitLab
version which introduced that feature._
----
Shortcuts to GitLab's most visited docs:
......@@ -40,6 +36,7 @@ Shortcuts to GitLab's most visited docs:
### User account
- [User documentation](user/index.md)
- [Authentication](topics/authentication/index.md): Account security with two-factor authentication, setup your ssh keys and deploy keys for secure access to your projects.
- [Profile settings](profile/README.md): Manage your profile settings, two factor authentication and more.
- [User permissions](user/permissions.md): Learn what each role in a project (external/guest/reporter/developer/master/owner) can do.
......
......@@ -465,23 +465,42 @@ on how to achieve that.
## Disable Container Registry but use GitLab as an auth endpoint
You can disable the embedded Container Registry to use an external one, but
still use GitLab as an auth endpoint.
**Omnibus GitLab**
You can use GitLab as an auth endpoint and use a non-bundled Container Registry.
1. Open `/etc/gitlab/gitlab.rb` and set necessary configurations:
```ruby
registry['enable'] = false
gitlab_rails['registry_enabled'] = true
gitlab_rails['registry_host'] = "registry.gitlab.example.com"
gitlab_rails['registry_port'] = "5005"
gitlab_rails['registry_api_url'] = "http://localhost:5000"
gitlab_rails['registry_key_path'] = "/var/opt/gitlab/gitlab-rails/certificate.key"
gitlab_rails['registry_path'] = "/var/opt/gitlab/gitlab-rails/shared/registry"
gitlab_rails['registry_issuer'] = "omnibus-gitlab-issuer"
```
1. A certificate keypair is required for GitLab and the Container Registry to
communicate securely. By default omnibus-gitlab will generate one keypair,
which is saved to `/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key`.
When using an non-bundled Container Registry, you will need to supply a
custom certificate key. To do that, add the following to
`/etc/gitlab/gitlab.rb`
```ruby
gitlab_rails['registry_key_path'] = "/custom/path/to/registry-key.key"
# registry['internal_key'] should contain the contents of the custom key
# file. Line breaks in the key file should be marked using `\n` character
# Example:
registry['internal_key'] = "---BEGIN RSA PRIVATE KEY---\nMIIEpQIBAA\n"
```
**Note:** The file specified at `registry_key_path` gets populated with the
content specified by `internal_key`, each time reconfigure is executed. If
no file is specified, omnibus-gitlab will default it to
`/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key` and will populate
it.
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
**Installations from source**
......
......@@ -100,9 +100,12 @@ You can use the [alpha version of the document](alpha_database.md) to try it out
Enter new password:
Enter it again:
```
1. Enable the `pg_trgm` extension:
1. Exit from editing `template1` prompt by typing `\q` and Enter.
1. Enable the `pg_trgm` extension within the `gitlabhq_production` database:
```
gitlab-psql -d gitlabhq_production
CREATE EXTENSION pg_trgm;
# Output:
......
......@@ -47,3 +47,5 @@ Example responses:
"error": "content is missing"
}
```
[ce-5953]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5953
......@@ -360,7 +360,13 @@ Example response:
"due_date": null,
"web_url": "http://example.com/example/example/issues/1",
"confidential": false,
"weight": null
"weight": null,
"_links": {
"self": "http://example.com/api/v4/projects/1/issues/2",
"notes": "http://example.com/api/v4/projects/1/issues/2/notes",
"award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji",
"project": "http://example.com/api/v4/projects/1"
}
}
```
......@@ -424,7 +430,13 @@ Example response:
"due_date": null,
"web_url": "http://example.com/example/example/issues/14",
"confidential": false,
"weight": null
"weight": null,
"_links": {
"self": "http://example.com/api/v4/projects/1/issues/2",
"notes": "http://example.com/api/v4/projects/1/issues/2/notes",
"award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji",
"project": "http://example.com/api/v4/projects/1"
}
}
```
......@@ -489,7 +501,13 @@ Example response:
"due_date": "2016-07-22",
"web_url": "http://example.com/example/example/issues/15",
"confidential": false,
"weight": null
"weight": null,
"_links": {
"self": "http://example.com/api/v4/projects/1/issues/2",
"notes": "http://example.com/api/v4/projects/1/issues/2/notes",
"award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji",
"project": "http://example.com/api/v4/projects/1"
}
}
```
......@@ -576,7 +594,13 @@ Example response:
"due_date": null,
"web_url": "http://example.com/example/example/issues/11",
"confidential": false,
"weight": null
"weight": null,
"_links": {
"self": "http://example.com/api/v4/projects/1/issues/2",
"notes": "http://example.com/api/v4/projects/1/issues/2/notes",
"award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji",
"project": "http://example.com/api/v4/projects/1"
}
}
```
......@@ -642,7 +666,13 @@ Example response:
"due_date": null,
"web_url": "http://example.com/example/example/issues/11",
"confidential": false,
"weight": null
"weight": null,
"_links": {
"self": "http://example.com/api/v4/projects/1/issues/2",
"notes": "http://example.com/api/v4/projects/1/issues/2/notes",
"award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji",
"project": "http://example.com/api/v4/projects/1"
}
}
```
......
......@@ -100,7 +100,16 @@ Parameters:
"repository_size": 1038090,
"lfs_objects_size": 0,
"job_artifacts_size": 0
}
},
"_links": {
"self": "http://example.com/api/v4/projects",
"issues": "http://example.com/api/v4/projects/1/issues",
"merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
"repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
"labels": "http://example.com/api/v4/projects/1/labels",
"events": "http://example.com/api/v4/projects/1/events",
"members": "http://example.com/api/v4/projects/1/members"
},
},
{
"id": 6,
......@@ -170,6 +179,15 @@ Parameters:
"repository_size": 2066080,
"lfs_objects_size": 0,
"job_artifacts_size": 0
},
"_links": {
"self": "http://example.com/api/v4/projects",
"issues": "http://example.com/api/v4/projects/1/issues",
"merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
"repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
"labels": "http://example.com/api/v4/projects/1/labels",
"events": "http://example.com/api/v4/projects/1/events",
"members": "http://example.com/api/v4/projects/1/members"
}
}
]
......@@ -259,6 +277,15 @@ Parameters:
"repository_size": 1038090,
"lfs_objects_size": 0,
"job_artifacts_size": 0
},
"_links": {
"self": "http://example.com/api/v4/projects",
"issues": "http://example.com/api/v4/projects/1/issues",
"merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
"repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
"labels": "http://example.com/api/v4/projects/1/labels",
"events": "http://example.com/api/v4/projects/1/events",
"members": "http://example.com/api/v4/projects/1/members"
}
},
{
......@@ -328,6 +355,15 @@ Parameters:
"repository_size": 2066080,
"lfs_objects_size": 0,
"job_artifacts_size": 0
},
"_links": {
"self": "http://example.com/api/v4/projects",
"issues": "http://example.com/api/v4/projects/1/issues",
"merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
"repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
"labels": "http://example.com/api/v4/projects/1/labels",
"events": "http://example.com/api/v4/projects/1/events",
"members": "http://example.com/api/v4/projects/1/members"
}
}
]
......@@ -431,6 +467,15 @@ Parameters:
"repository_size": 1038090,
"lfs_objects_size": 0,
"job_artifacts_size": 0
},
"_links": {
"self": "http://example.com/api/v4/projects",
"issues": "http://example.com/api/v4/projects/1/issues",
"merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
"repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
"labels": "http://example.com/api/v4/projects/1/labels",
"events": "http://example.com/api/v4/projects/1/events",
"members": "http://example.com/api/v4/projects/1/members"
}
}
```
......@@ -669,7 +714,16 @@ Example response:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
"request_access_enabled": false
"request_access_enabled": false,
"_links": {
"self": "http://example.com/api/v4/projects",
"issues": "http://example.com/api/v4/projects/1/issues",
"merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
"repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
"labels": "http://example.com/api/v4/projects/1/labels",
"events": "http://example.com/api/v4/projects/1/events",
"members": "http://example.com/api/v4/projects/1/members"
}
}
```
......@@ -735,7 +789,16 @@ Example response:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
"request_access_enabled": false
"request_access_enabled": false,
"_links": {
"self": "http://example.com/api/v4/projects",
"issues": "http://example.com/api/v4/projects/1/issues",
"merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
"repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
"labels": "http://example.com/api/v4/projects/1/labels",
"events": "http://example.com/api/v4/projects/1/events",
"members": "http://example.com/api/v4/projects/1/members"
}
}
```
......@@ -819,7 +882,16 @@ Example response:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
"request_access_enabled": false
"request_access_enabled": false,
"_links": {
"self": "http://example.com/api/v4/projects",
"issues": "http://example.com/api/v4/projects/1/issues",
"merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
"repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
"labels": "http://example.com/api/v4/projects/1/labels",
"events": "http://example.com/api/v4/projects/1/events",
"members": "http://example.com/api/v4/projects/1/members"
}
}
```
......@@ -903,7 +975,16 @@ Example response:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
"request_access_enabled": false
"request_access_enabled": false,
"_links": {
"self": "http://example.com/api/v4/projects",
"issues": "http://example.com/api/v4/projects/1/issues",
"merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
"repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
"labels": "http://example.com/api/v4/projects/1/labels",
"events": "http://example.com/api/v4/projects/1/events",
"members": "http://example.com/api/v4/projects/1/members"
}
}
```
......
......@@ -2,9 +2,11 @@
Since GitLab 9.0, API V4 is the preferred version to be used.
API V3 will be removed in GitLab 9.5, to be released on August 22, 2017. In the
meantime, we advise you to make any necessary changes to applications that use
V3. The V3 API documentation is still [available](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-16-stable/doc/api/README.md).
API V3 will be unsupported from GitLab 9.5, to be released on August
22, 2017. It will be removed in GitLab 9.5 or later. In the meantime, we advise
you to make any necessary changes to applications that use V3. The V3 API
documentation is still
[available](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-16-stable/doc/api/README.md).
Below are the changes made between V3 and V4.
......
......@@ -24,3 +24,23 @@ They are written by members of the GitLab Team and by
- [Part 2: Quick start guide - Setting up GitLab Pages](../user/project/pages/getting_started_part_two.md)
- [Part 3: Setting Up Custom Domains - DNS Records and SSL/TLS Certificates](../user/project/pages/getting_started_part_three.md)
- [Part 4: Creating and tweaking `.gitlab-ci.yml` for GitLab Pages](../user/project/pages/getting_started_part_four.md)
- [Building a new GitLab Docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/)
- [GitLab CI: Deployment & Environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/)
## Sofware development
- [In 13 minutes from Kubernetes to a complete application development tool](https://about.gitlab.com/2016/11/14/idea-to-production/)
- [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/)
- [Fast and Natural Continuous Integration with GitLab CI](https://about.gitlab.com/2017/05/22/fast-and-natural-continuous-integration-with-gitlab-ci/)
- [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/)
- [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/)
## Build, test, and deploy with GitLab CI/CD
**Build, test, and deploy** the software you develop with **[GitLab CI/CD](../ci/README.md)**
- [Continuous Delivery of a Spring Boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/)
- [Automated Debian Package Build with GitLab CI](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/)
- [Building an Elixir Release into a Docker image using GitLab CI](https://about.gitlab.com/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/)
- [Setting up GitLab CI for Android projects](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/)
- [How to use GitLab CI and MacStadium to build your macOS or iOS projects](https://about.gitlab.com/2017/05/15/how-to-use-macstadium-and-gitlab-ci-to-build-your-macos-or-ios-projects/)
......@@ -447,6 +447,7 @@ A forEach will cause side effects, it will be mutating the array being iterated.
1. `name`
1. `props`
1. `mixins`
1. `directives`
1. `data`
1. `components`
1. `computedProps`
......
......@@ -5,21 +5,25 @@ trackers and external authentication.
See the documentation below for details on how to configure these services.
- [JIRA](../user/project/integrations/jira.md) Integrate with the JIRA issue tracker
- [Akismet](akismet.md) Configure Akismet to stop spam
- [Auth0 OmniAuth](auth0.md) Enable the Auth0 OmniAuth provider
- [Bitbucket](bitbucket.md) Import projects from Bitbucket.org and login to your GitLab instance with your
- [CAS](cas.md) Configure GitLab to sign in using CAS
- [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc.
- [LDAP](ldap.md) Set up sign in via LDAP
- [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages
- [Jenkins](jenkins.md) Integrate with the Jenkins CI
- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab.com, Google, Bitbucket, Facebook, Shibboleth, SAML, Crowd, Azure and Authentiq ID
- [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider
- [CAS](cas.md) Configure GitLab to sign in using CAS
- [JIRA](../user/project/integrations/jira.md) Integrate with the JIRA issue tracker
- [Kerberos](kerberos.md) Integrate with Kerberos
- [Koding](../administration/integration/koding.md) Configure Koding to use IDE integration
- [LDAP](ldap.md) Set up sign in via LDAP
- [OAuth2 provider](oauth_provider.md) OAuth2 application creation
- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab.com, Google, Bitbucket, Facebook, Shibboleth, SAML, Crowd, Azure and Authentiq ID
- [OpenID Connect](openid_connect_provider.md) Use GitLab as an identity provider
- [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages
- [reCAPTCHA](recaptcha.md) Configure GitLab to use Google reCAPTCHA for new users
- [Akismet](akismet.md) Configure Akismet to stop spam
- [Koding](../administration/integration/koding.md) Configure Koding to use IDE integration
- [PlantUML](../administration/integration/plantuml.md) Configure PlantUML to use diagrams in AsciiDoc documents.
- [reCAPTCHA](recaptcha.md) Configure GitLab to use Google reCAPTCHA for new users
- [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider
- [Trello](trello_power_up.md) Integrate Trello with GitLab
Bitbucket.org account
> GitLab Enterprise Edition contains [advanced Jenkins support][jenkins].
......
# User documentation
Welcome to GitLab! We're glad to have you here!
As a GitLab user you'll have access to all the features
your [subscription](https://about.gitlab.com/products/)
includes, except [GitLab administrator](../README.md#administrator-documentation)
settings, unless you have admin privileges to install, configure,
and upgrade your GitLab instance.
For GitLab.com, admin privileges are restricted to the GitLab team.
If you run your own GitLab instance and are looking for the administration settings,
please refer to the [administration](../README.md#administrator-documentation)
documentation.
## Overview
GitLab is a fully integrated software development platform that enables you
and your team to work cohesively, faster, transparently, and effectively,
since the discussion of a new idea until taking that idea to production all
all the way through, from within the same platform.
Please check this page for an overview on [GitLab's features](https://about.gitlab.com/features/).
## Use cases
GitLab is a git-based platforms that integrates a great number of essential tools for software development and deployment, and project management:
- Code hosting in repositories with version control
- Track proposals for new implementations, bug reports, and feedback with a
fully featured [Issue Tracker](project/issues/index.md#issue-tracker)
- Organize and prioritize with [Issue Boards](project/issues/index.md#issue-boards)
- Code review in [Merge Requests](project/merge_requests/index.md) with live-preview changes per
branch with [Review Apps](../ci/review_apps/index.md)
- Build, test and deploy with built-in [Continuous Integration](../ci/README.md)
- Deploy your personal and professional static websites with [GitLab Pages](project/pages/index.md)
- Integrate with Docker with [GitLab Container Registry](project/container_registry.md)
- Track the development lifecycle with [GitLab Cycle Analytics](project/cycle_analytics.md)
With GitLab Enterprise Edition, you can also:
- Provide support with [Service Desk](https://docs.gitlab.com/ee/user/project/service_desk.html)
- Improve collaboration with
[Merge Request Approvals](https://docs.gitlab.com/ee/user/project/merge_requests/index.html#merge-request-approvals),
[Multiple Assignees for Issues](https://docs.gitlab.com/ee/user/project/issues/multiple_assignees_for_issues.html),
and [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards)
- Create formal relashionships between issues with [Related Issues](https://docs.gitlab.com/ee/user/project/issues/related_issues.html)
- Use [Burndown Charts](https://docs.gitlab.com/ee/user/project/milestones/burndown_charts.html) to track progress during a sprint or while working on a new version of their software.
- Leverage [Elasticsearch](https://docs.gitlab.com/ee/integration/elasticsearch.html) with [Advanced Global Search](https://docs.gitlab.com/ee/user/search/advanced_global_search.html) and [Advanced Syntax Search](https://docs.gitlab.com/ee/user/search/advanced_search_syntax.html) for faster, more advanced code search across your entire GitLab instance
- [Authenticate users with Kerberos](https://docs.gitlab.com/ee/integration/kerberos.html)
- [Mirror a repository](https://docs.gitlab.com/ee/workflow/repository_mirroring.html) from elsewhere on your local server.
- [Export issues as CSV](https://docs.gitlab.com/ee/user/project/issues/csv_export.html)
- View your entire CI/CD pipeline involving more than one project with [Multiple-Project Pipeline Graphs](https://docs.gitlab.com/ee/ci/multi_project_pipeline_graphs.html)
- [Lock files](https://docs.gitlab.com/ee/user/project/file_lock.html) to prevent conflicts
- View of the current health and status of each CI environment running on Kubernetes with [Deploy Boards](https://docs.gitlab.com/ee/user/project/deploy_boards.html)
- Leverage your continuous delivery method with [Canary Deployments](https://docs.gitlab.com/ee/user/project/canary_deployments.html)
You can also [integrate](project/integrations/project_services.md) GitLab with numerous third-party applications, such as Mattermost, Microsoft Teams, HipChat, Trello, Slack, Bamboo CI, JIRA, and a lot more.
### Articles
For a complete workflow use case please check [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/#gitlab-workflow-use-case-scenario).
For more use cases please check our [Technical Articles](../articles/index.md).
## Projects
In GitLab, you can create projects for numerous reasons, such as, host
your code, use it as an issue tracker, collaborate on code, and continuously
build, test, and deploy your app with built-in GitLab CI/CD. Or, you can do
it all at once, from one single project.
### Issues
Explore the best of GitLab [Issues](project/issues/index.md).
### Merge Requests
Collanorate on code, gather reviews, live preview changes per branch, and
request approvals with [Merge Requests](project/merge_requests/index.md).
### Milestones
Work on multiple issues and merge requests towards the same target date
with [Milestones](project/milestones/index.md).
### GitLab Pages
Publish your static site directly from GitLab with [GitLab Pages](project/pages/index.md). You
can [build, test, and deploy any Static Site Generator](https://about.gitlab.com/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/) with Pages.
### Container Registry
Build and deploy Docker images with [GitLab Container Registry](project/container_registry.md).
## GitLab CI/CD
Use built-in [GitLab CI/CD](../ci/README.md) to test, build, and deploy your applications
directly from GitLab. No third-party integrations needed.
### Auto Deploy
Deploy your application out-of-the-box with [GitLab Auto Deploy](../ci/autodeploy/index.md).
### Review Apps
Live-preview the changes introduced by a merge request with [Review Apps](../ci/review_apps/index.md).
## Groups
With GitLab [Groups](group/index.md) you can assemble related projects together
and grant members access to several projects at once.
### Subgroups
Groups can also be nested in [subgroups](group/subgroups/index.md).
## Account
There is a lot you can customize and configure
to enjoy the best of GitLab.
Manage your user settings to change your personal info,
personal access tokens, authorized applications, integrations, etc.
### Authentication
Read through the [authentication](../topics/authentication/index.md) methods available in GitLab.
### Permissions
Learn the different set of [permissions](permissions.md) for user type (guest, reporter, developer, master, owner).
## Integrations
[Integrate GitLab](../integration/README.md) with your preferred tool,
such as Trello, JIRA, etc.
## Git and GitLab
Learn what is [Git](../topics/git/index.md) and its best practices.
## Discussions
In GitLab, you can comment and mention collaborators in issues,
merge requests, code snippets, and commits.
When performing inline reviews to implementations
to your codebase through merge requests you can
gather feedback through [resolvable discussions](discussions/index.md#resolvable-discussions).
## Todos
Never forget to reply to your collaborators. [GitLab Todos](../workflow/todos.md)
are a tool for working faster and more effectively with your team,
by listing all user or group mentions, as well as issues and merge
requests you're assigned to.
## Snippets
[Snippets](snippets.md) are code blocks that you want to store in GitLab, from which
you have quick access to. You can also gather feedback on them through
[discussions](#discussions).
## Webhooks
Configure [webhooks](project/integrations/webhooks.html) to listen for
specific events like pushes, issues or merge requests. GitLab will send a
POST request with data to the webhook URL.
## API
Automate GitLab via [API](../api/README.html).
......@@ -98,11 +98,11 @@ in the table below.
| Field | Description |
| ----- | ----------- |
| `Web URL` | The base URL to the JIRA instance web interface which is being linked to this GitLab project. E.g., `https://jira.example.com`. |
| `JIRA API URL` | The base URL to the JIRA instance API. E.g., `https://jira-api.example.com`. This is optional. If not entered, the Web URL value be used. |
| `JIRA API URL` | The base URL to the JIRA instance API. Web URL value will be used if not set. E.g., `https://jira-api.example.com`. |
| `Project key` | Put a JIRA project key (in uppercase), e.g. `MARS` in this field. This is only for testing the configuration settings. JIRA integration in GitLab works with _all_ JIRA projects in your JIRA instance. This field will be removed in a future release. |
| `Username` | The user name created in [configuring JIRA step](#configuring-jira). |
| `Password` |The password of the user created in [configuring JIRA step](#configuring-jira). |
| `JIRA issue transition` | This is the ID of a transition that moves issues to a closed state. You can find this number under JIRA workflow administration ([see screenshot](img/jira_workflow_screenshot.png)). **Closing JIRA issues via commits or Merge Requests won't work if you don't set the ID correctly.** |
| `Transition ID` | This is the ID of a transition that moves issues to a closed state. You can find this number under JIRA workflow administration ([see screenshot](img/jira_workflow_screenshot.png)). **Closing JIRA issues via commits or Merge Requests won't work if you don't set the ID correctly.** |
After saving the configuration, your GitLab project will be able to interact
with all JIRA projects in your JIRA instance.
......
......@@ -71,9 +71,10 @@ The next time a pipeline is scheduled, your credentials will be used.
>**Note:**
When the owner of the schedule doesn't have the ability to create pipelines
anymore, due to e.g., being blocked or removed from the project, the schedule
is deactivated. Another user can take ownership and activate it, so the
schedule can be run again.
anymore, due to e.g., being blocked or removed from the project, or lacking
the permission to run on protected branches or tags. When this happened, the
schedule is deactivated. Another user can take ownership and activate it, so
the schedule can be run again.
## Advanced admin configuration
......
......@@ -175,7 +175,6 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
fill_in 'JIRA API URL', with: 'http://jira.example/api'
fill_in 'Username', with: 'gitlab'
fill_in 'Password', with: 'gitlab'
fill_in 'Project Key', with: 'GITLAB'
click_button 'Save'
end
......
......@@ -13,7 +13,7 @@ module API
def expose_url(path)
url_options = Rails.application.routes.default_url_options
host, protocol, port = url_options.slice(:host, :protocol, :port).values
protocol, host, port = url_options.slice(:protocol, :host, :port).values
URI::HTTP.build(scheme: protocol, host: host, port: port, path: path).to_s
end
......
......@@ -312,12 +312,6 @@ module API
type: String,
desc: 'The base URL to the JIRA instance API. Web URL value will be used if not set. E.g., https://jira-api.example.com'
},
{
required: true,
name: :project_key,
type: String,
desc: 'The short identifier for your JIRA project, all uppercase, e.g., PROJ'
},
{
required: false,
name: :username,
......
......@@ -28,12 +28,13 @@ module API
end
# create request and trigger builds
trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref].to_s, variables)
if trigger_request
present trigger_request, with: ::API::V3::Entities::TriggerRequest
result = Ci::CreateTriggerRequestService.execute(project, trigger, params[:ref].to_s, variables)
pipeline = result.pipeline
if pipeline.persisted?
present result.trigger_request, with: ::API::V3::Entities::TriggerRequest
else
errors = 'No builds created'
render_api_error!(errors, 400)
render_validation_error!(pipeline)
end
end
......
......@@ -24,12 +24,13 @@ module Ci
end
# create request and trigger builds
trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref], variables)
if trigger_request
present trigger_request, with: Entities::TriggerRequest
result = Ci::CreateTriggerRequestService.execute(project, trigger, params[:ref], variables)
pipeline = result.pipeline
if pipeline.persisted?
present result.trigger_request, with: Entities::TriggerRequest
else
errors = 'No builds created'
render_api_error!(errors, 400)
render_validation_error!(pipeline)
end
end
end
......
......@@ -45,6 +45,8 @@ module Gitlab
:bare?,
to: :rugged
delegate :exists?, to: :gitaly_repository_client
# Default branch in the repository
def root_ref
@root_ref ||= gitaly_migrate(:root_ref) do |is_enabled|
......@@ -212,10 +214,6 @@ module Gitlab
!empty?
end
def repo_exists?
!!rugged
end
# Discovers the default branch based on the repository's available branches
#
# - If no branches are present, returns nil
......@@ -657,6 +655,10 @@ module Gitlab
@gitaly_commit_client ||= Gitlab::GitalyClient::CommitService.new(self)
end
def gitaly_repository_client
@gitaly_repository_client ||= Gitlab::GitalyClient::RepositoryService.new(self)
end
private
# Gitaly note: JV: Trying to get rid of the 'filter' option so we can implement this with 'git'.
......
......@@ -57,7 +57,7 @@ module Gitlab
metadata = yield(metadata) if block_given?
stub(service, storage).send(rpc, request, metadata)
end
def self.request_metadata(storage)
encoded_token = Base64.strict_encode64(token(storage).to_s)
{ metadata: { 'authorization' => "Bearer #{encoded_token}" } }
......
module Gitlab
module GitalyClient
class RepositoryService
def initialize(repository)
@repository = repository
@gitaly_repo = repository.gitaly_repository
end
def exists?
request = Gitaly::RepositoryExistsRequest.new(repository: @gitaly_repo)
GitalyClient.call(@repository.storage, :repository_service, :exists, request).exists
end
end
end
end
......@@ -14,42 +14,44 @@ module Gitlab
TOP_LEVEL_ROUTES = %w[
-
.well-known
404.html
422.html
500.html
502.html
503.html
abuse_reports
admin
all
api
apple-touch-icon-precomposed.png
apple-touch-icon.png
assets
autocomplete
ci
dashboard
deploy.html
explore
favicon.ico
files
groups
header_logo_dark.png
header_logo_light.png
health_check
help
hooks
import
invites
issues
jwt
koding
member
merge_requests
new
notes
notification_settings
oauth
profile
projects
public
repository
robots.txt
s
search
sent_notifications
services
slash-command-logo.png
snippets
teams
u
unicorn_test
unsubscribes
......
......@@ -37,8 +37,8 @@ module Gitlab
request_cache def can_create_tag?(ref)
return false unless can_access_git?
if ProtectedTag.protected?(project, ref)
project.protected_tags.protected_ref_accessible_to?(ref, user, action: :create)
if protected?(ProtectedTag, project, ref)
protected_tag_accessible_to?(ref, action: :create)
else
user.can?(:push_code, project)
end
......@@ -47,20 +47,24 @@ module Gitlab
request_cache def can_delete_branch?(ref)
return false unless can_access_git?
if ProtectedBranch.protected?(project, ref)
if protected?(ProtectedBranch, project, ref)
user.can?(:delete_protected_branch, project)
else
user.can?(:push_code, project)
end
end
def can_update_branch?(ref)
can_push_to_branch?(ref) || can_merge_to_branch?(ref)
end
request_cache def can_push_to_branch?(ref)
return false unless can_access_git?
if ProtectedBranch.protected?(project, ref)
if protected?(ProtectedBranch, project, ref)
return true if project.empty_repo? && project.user_can_push_to_empty_repo?(user)
project.protected_branches.protected_ref_accessible_to?(ref, user, action: :push)
protected_branch_accessible_to?(ref, action: :push)
else
user.can?(:push_code, project)
end
......@@ -69,8 +73,8 @@ module Gitlab
request_cache def can_merge_to_branch?(ref)
return false unless can_access_git?
if ProtectedBranch.protected?(project, ref)
project.protected_branches.protected_ref_accessible_to?(ref, user, action: :merge)
if protected?(ProtectedBranch, project, ref)
protected_branch_accessible_to?(ref, action: :merge)
else
user.can?(:push_code, project)
end
......@@ -87,5 +91,23 @@ module Gitlab
def can_access_git?
user && user.can?(:access_git)
end
def protected_branch_accessible_to?(ref, action:)
ProtectedBranch.protected_ref_accessible_to?(
ref, user,
action: action,
protected_refs: project.protected_branches)
end
def protected_tag_accessible_to?(ref, action:)
ProtectedTag.protected_ref_accessible_to?(
ref, user,
action: action,
protected_refs: project.protected_tags)
end
request_cache def protected?(kind, project, ref)
kind.protected?(project, ref)
end
end
end
# Андрей Витюк <andruwa13@gmail.com>, 2017. #zanata
# Huang Tao <htve@outlook.com>, 2017. #zanata
# Андрей Витюк <andruwa13@gmail.com>, 2017. #zanata
msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-28 13:32+0200\n"
"POT-Creation-Date: 2017-07-05 08:50-0500\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2017-07-12 09:05-0400\n"
"Last-Translator: Андрей Витюк <andruwa13@gmail.com>\n"
"Language-Team: Ukrainian (https://translate.zanata.org/project/view/GitLab)\n"
"PO-Revision-Date: 2017-07-25 03:27-0400\n"
"Last-Translator: Андрей Витюк <andruwa13@gmail.com>\n"
"Language: uk\n"
"X-Generator: Zanata 3.9.6\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
......@@ -57,7 +57,7 @@ msgid "Add Changelog"
msgstr "Додати список змін (Changelog)"
msgid "Add Contribution guide"
msgstr "Додати керівництво для контрибуторів"
msgstr "Додати керівництво для контриб’юторів"
msgid "Add License"
msgstr "Додати ліцензію"
......@@ -209,7 +209,9 @@ msgstr[1] "Комміта"
msgstr[2] "Коммітів"
msgid "Commit duration in minutes for last 30 commits"
msgstr "Комміт тривалість у хвилинах за останні 30 коммітів"
msgstr ""
"Тривалість коммітів протягом декількох хвилин на протязі 30 останніх "
"коммітів"
msgid "Commit message"
msgstr "Комміт повідомлення"
......@@ -236,10 +238,10 @@ msgid "Compare"
msgstr "Порівняти"
msgid "Contribution guide"
msgstr "Керівництво контрибуторів"
msgstr "Керівництво контриб’юторів"
msgid "Contributors"
msgstr "Контрибутори"
msgstr "Контриб’ютори"
msgid "Copy URL to clipboard"
msgstr "Скопіювати URL в буфер обміну"
......@@ -352,16 +354,16 @@ msgid "Download"
msgstr "Завантажити"
msgid "Download tar"
msgstr "Завантажити в форматі tar"
msgstr "Завантажити tar"
msgid "Download tar.bz2"
msgstr "Завантажити в форматі tar.bz2"
msgstr "Завантажити tar.bz2"
msgid "Download tar.gz"
msgstr "Завантажити в форматі tar.gz"
msgstr "Завантажити tar.gz"
msgid "Download zip"
msgstr "Завантажити в форматі zip"
msgstr "Завантажити zip"
msgid "DownloadArtifacts|Download"
msgstr "Завантажити"
......@@ -397,7 +399,7 @@ msgid "Failed to remove the pipeline schedule"
msgstr "Не вдалося видалити розклад Конвеєра"
msgid "Files"
msgstr "Файли"
msgstr "Файлів"
msgid "Filter by commit message"
msgstr "Фільтрувати повідомлення коммітів"
......@@ -436,7 +438,7 @@ msgid "GoToYourFork|Fork"
msgstr "Форк"
msgid "Home"
msgstr "Початок"
msgstr "Головна"
msgid "Housekeeping successfully started"
msgstr "Очищення успішно розпочато"
......@@ -451,13 +453,13 @@ msgid "Introducing Cycle Analytics"
msgstr "Представляємо аналітику циклу"
msgid "Jobs for last month"
msgstr "Завдання за останній місяць"
msgstr "Кількість завдань за останній місяць"
msgid "Jobs for last week"
msgstr "Завдання за останній тиждень"
msgstr "Кількість завдань за останній тиждень"
msgid "Jobs for last year"
msgstr "Завдання за останній рік"
msgstr "Кількість завдань за останній рік"
msgid "LFSStatus|Disabled"
msgstr "Вимкнено"
......@@ -508,7 +510,7 @@ msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] "Нова проблема"
msgstr[1] "Нові проблеми"
msgstr[2] "Новах проблем"
msgstr[2] "Нових проблем"
msgid "New Pipeline Schedule"
msgstr "Новий розклад Конвеєра"
......@@ -654,6 +656,12 @@ msgstr "Всі"
msgid "PipelineSchedules|Inactive"
msgstr "Неактивні"
msgid "PipelineSchedules|Input variable key"
msgstr "Введіть ім'я змінної"
msgid "PipelineSchedules|Input variable value"
msgstr "Вхідні значення змінних"
msgid "PipelineSchedules|Next Run"
msgstr "Наступний запуск"
......@@ -663,12 +671,18 @@ msgstr "Немає"
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Задайте короткий опис для цього Конвеєру"
msgid "PipelineSchedules|Remove variable row"
msgstr "Видалити змінні"
msgid "PipelineSchedules|Take ownership"
msgstr "Стати власником"
msgid "PipelineSchedules|Target"
msgstr "Ціль"
msgid "PipelineSchedules|Variables"
msgstr "Змінні"
msgid "PipelineSheduleIntervalPattern|Custom"
msgstr "Власні"
......@@ -745,7 +759,7 @@ msgid "ProjectLifecycle|Stage"
msgstr "Етап"
msgid "ProjectNetworkGraph|Graph"
msgstr "Графік"
msgstr "Історія"
msgid "Read more"
msgstr "Докладніше"
......@@ -840,7 +854,7 @@ msgid "Source code"
msgstr "Код"
msgid "StarProject|Star"
msgstr "Старт"
msgstr "Підписатися"
msgid "Start a %{new_merge_request} with these changes"
msgstr "Почати %{new_merge_request} з цих змін"
......@@ -976,19 +990,19 @@ msgid "Timeago|%s minutes remaining"
msgstr "%s хвилини залишитися"
msgid "Timeago|%s months ago"
msgstr "%s місяців тому"
msgstr "%s місяці(в) тому"
msgid "Timeago|%s months remaining"
msgstr "%s місяці, що залишилися"
msgstr "%s місяці(в), що залишилися"
msgid "Timeago|%s seconds remaining"
msgstr "%s секунд, що залишаються"
msgid "Timeago|%s weeks ago"
msgstr "%s тижнів тому"
msgstr "%s тижні(в) тому"
msgid "Timeago|%s weeks remaining"
msgstr "%s тижнів залишилися"
msgstr "%s тижні(в) залишилися"
msgid "Timeago|%s years ago"
msgstr "%s років тому"
......@@ -1018,7 +1032,7 @@ msgid "Timeago|Past due"
msgstr "Прострочені"
msgid "Timeago|a day ago"
msgstr "годин тому"
msgstr "День тому"
msgid "Timeago|a month ago"
msgstr "місяць тому"
......@@ -1042,28 +1056,28 @@ msgid "Timeago|about an hour ago"
msgstr "Близько години тому"
msgid "Timeago|in %s days"
msgstr "через %s днїв"
msgstr "через %s дні(в)"
msgid "Timeago|in %s hours"
msgstr "через %s години"
msgstr "через %s годин(и)"
msgid "Timeago|in %s minutes"
msgstr "через %s хвилини"
msgstr "через %s хвилин(и)"
msgid "Timeago|in %s months"
msgstr "через %s місяців"
msgstr "через %s місяці(в)"
msgid "Timeago|in %s seconds"
msgstr "через %s секунд"
msgstr "через %s секунд(и)"
msgid "Timeago|in %s weeks"
msgstr "через %s тижні"
msgstr "через %s тижні(в)"
msgid "Timeago|in %s years"
msgstr "через %s років"
msgstr "через %s роки(ів)"
msgid "Timeago|in 1 day"
msgstr "через день"
msgstr "через 1 день"
msgid "Timeago|in 1 hour"
msgstr "через годину"
......@@ -1081,22 +1095,22 @@ msgid "Timeago|in 1 year"
msgstr "через рік"
msgid "Timeago|less than a minute ago"
msgstr "менш хвилини тому"
msgstr "менше хвилини тому"
msgid "Time|hr"
msgid_plural "Time|hrs"
msgstr[0] "Година"
msgstr[1] "Годині"
msgstr[2] "Годин"
msgstr[0] "година"
msgstr[1] "години"
msgstr[2] "годин"
msgid "Time|min"
msgid_plural "Time|mins"
msgstr[0] "хвилина"
msgstr[1] "хвилині"
msgstr[1] "хвилини"
msgstr[2] "хвилин"
msgid "Time|s"
msgstr "секунда"
msgstr "секунд(а)"
msgid "Total Time"
msgstr "Загальний час"
......@@ -1105,7 +1119,7 @@ msgid "Total test time for all commits/merges"
msgstr "Загальний час, щоб перевірити всі фіксації/злиття"
msgid "Unstar"
msgstr "Зняти позначку"
msgstr "Відписатись"
msgid "Upload New File"
msgstr "Завантажити новий файл"
......@@ -1117,7 +1131,7 @@ msgid "UploadLink|click to upload"
msgstr "Натисніть, щоб завантажити"
msgid "Use your global notification setting"
msgstr "Використовуються глобальний налаштування повідомлень"
msgstr "Використовуються глобальні налаштування повідомлень"
msgid "View open merge request"
msgstr "Перегляд відкритих запитів на злиття"
......@@ -1140,6 +1154,15 @@ msgstr "Ми не маємо достатньо даних для показу
msgid "Withdraw Access Request"
msgstr "Скасувати запит доступу"
msgid ""
"You are going to remove %{group_name}.\n"
"Removed groups CANNOT be restored!\n"
"Are you ABSOLUTELY sure?"
msgstr ""
"Ви хочете видалити %{group_name}.\n"
"Видалені групи НЕ МОЖНА буду відновити!\n"
"Ви АБСОЛЮТНО впевнені?"
msgid ""
"You are going to remove %{project_name_with_namespace}.\n"
"Removed project CANNOT be restored!\n"
......
......@@ -187,7 +187,7 @@ describe Admin::GeoNodesController, :postgresql do
end
it 'displays a flash message' do
expect(controller).to set_flash.now[:alert].to("Primary node can't be disabled.")
expect(controller).to set_flash[:alert].to("Primary node can't be disabled.")
end
it 'redirects to the geo nodes page' do
......@@ -208,7 +208,7 @@ describe Admin::GeoNodesController, :postgresql do
end
it 'displays a flash message' do
expect(controller).to set_flash.now[:notice].to('Node http://example.com/ was successfully disabled.')
expect(controller).to set_flash[:notice].to('Node http://example.com/ was successfully disabled.')
end
it 'redirects to the geo nodes page' do
......@@ -227,7 +227,7 @@ describe Admin::GeoNodesController, :postgresql do
end
it 'displays a flash message' do
expect(controller).to set_flash.now[:alert].to('There was a problem disabling node http://example.com/.')
expect(controller).to set_flash[:alert].to('There was a problem disabling node http://example.com/.')
end
it 'redirects to the geo nodes page' do
......
......@@ -827,7 +827,7 @@ describe Projects::IssuesController do
delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid
expect(response).to have_http_status(302)
expect(controller).to set_flash[:notice].to(/The issue was successfully deleted\./).now
expect(controller).to set_flash[:notice].to(/The issue was successfully deleted\./)
end
it 'delegates the update of the todos count cache to TodoService' do
......
......@@ -7,6 +7,10 @@ describe Projects::JobsController do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:user) { create(:user) }
before do
stub_not_protect_default_branch
end
describe 'GET index' do
context 'when scope is pending' do
before do
......
......@@ -440,7 +440,7 @@ describe Projects::MergeRequestsController do
delete :destroy, namespace_id: project.namespace, project_id: project, id: merge_request.iid
expect(response).to have_http_status(302)
expect(controller).to set_flash[:notice].to(/The merge request was successfully deleted\./).now
expect(controller).to set_flash[:notice].to(/The merge request was successfully deleted\./)
end
it 'delegates the update of the todos count cache to TodoService' do
......
......@@ -8,6 +8,7 @@ describe Projects::PipelinesController do
let(:feature) { ProjectFeature::DISABLED }
before do
stub_not_protect_default_branch
project.add_developer(user)
project.project_feature.update(
builds_access_level: feature)
......@@ -158,7 +159,7 @@ describe Projects::PipelinesController do
context 'when builds are enabled' do
let(:feature) { ProjectFeature::ENABLED }
it 'retries a pipeline without returning any content' do
expect(response).to have_http_status(:no_content)
expect(build.reload).to be_retried
......@@ -175,7 +176,7 @@ describe Projects::PipelinesController do
describe 'POST cancel.json' do
let!(:pipeline) { create(:ci_pipeline, project: project) }
let!(:build) { create(:ci_build, :running, pipeline: pipeline) }
before do
post :cancel, namespace_id: project.namespace,
project_id: project,
......@@ -185,7 +186,7 @@ describe Projects::PipelinesController do
context 'when builds are enabled' do
let(:feature) { ProjectFeature::ENABLED }
it 'cancels a pipeline without returning any content' do
expect(response).to have_http_status(:no_content)
expect(pipeline.reload).to be_canceled
......
......@@ -23,7 +23,7 @@ describe SentNotificationsController do
end
it 'sets the flash message' do
expect(controller).to set_flash[:notice].to(/unsubscribed/).now
expect(controller).to set_flash[:notice].to(/unsubscribed/)
end
it 'redirects to the login page' do
......@@ -83,7 +83,7 @@ describe SentNotificationsController do
end
it 'sets the flash message' do
expect(controller).to set_flash[:notice].to(/unsubscribed/).now
expect(controller).to set_flash[:notice].to(/unsubscribed/)
end
it 'redirects to the issue page' do
......@@ -109,7 +109,7 @@ describe SentNotificationsController do
end
it 'sets the flash message' do
expect(controller).to set_flash[:notice].to(/unsubscribed/).now
expect(controller).to set_flash[:notice].to(/unsubscribed/)
end
it 'redirects to the merge request page' do
......
......@@ -78,5 +78,27 @@ RSpec.describe 'Dashboard Issues' do
expect(page).not_to have_content(project_with_issues_disabled.name_with_namespace)
end
end
it 'shows the new issue page', js: true do
original_defaults = Gitlab::Application.routes.default_url_options
Gitlab::Application.routes.default_url_options = {
host: Capybara.current_session.server.host,
port: Capybara.current_session.server.port,
protocol: 'http'
}
find('.new-project-item-select-button').trigger('click')
wait_for_requests
find('.select2-results li').click
expect(page).to have_current_path("/#{project.path_with_namespace}/issues/new")
page.within('#content-body') do
expect(page).to have_selector('.issue-form')
end
Gitlab::Application.routes.default_url_options = original_defaults
end
end
end
......@@ -6,17 +6,12 @@ feature 'Setup Jira service', :js do
let(:service) { project.create_jira_service }
let(:url) { 'http://jira.example.com' }
def stub_project_url
WebMock.stub_request(:get, 'http://jira.example.com/rest/api/2/project/GitLabProject')
.with(basic_auth: %w(username password))
end
let(:test_url) { 'http://jira.example.com/rest/api/2/serverInfo' }
def fill_form(active = true)
check 'Active' if active
fill_in 'service_url', with: url
fill_in 'service_project_key', with: 'GitLabProject'
fill_in 'service_username', with: 'username'
fill_in 'service_password', with: 'password'
fill_in 'service_jira_issue_transition_id', with: '25'
......@@ -31,11 +26,10 @@ feature 'Setup Jira service', :js do
describe 'user sets and activates Jira Service' do
context 'when Jira connection test succeeds' do
before do
stub_project_url
end
it 'activates the JIRA service' do
server_info = { key: 'value' }.to_json
WebMock.stub_request(:get, test_url).with(basic_auth: %w(username password)).to_return(body: server_info)
click_link('JIRA')
fill_form
click_button('Test settings and save changes')
......@@ -47,10 +41,6 @@ feature 'Setup Jira service', :js do
end
context 'when Jira connection test fails' do
before do
stub_project_url.to_return(status: 401)
end
it 'shows errors when some required fields are not filled in' do
click_link('JIRA')
......@@ -64,6 +54,9 @@ feature 'Setup Jira service', :js do
end
it 'activates the JIRA service' do
WebMock.stub_request(:get, test_url).with(basic_auth: %w(username password))
.to_raise(JIRA::HTTPError.new(double(message: 'message')))
click_link('JIRA')
fill_form
click_button('Test settings and save changes')
......
{
"type": "array",
"items": {
"type": "object",
"properties" : {
"id": { "type": "integer" },
"iid": { "type": "integer" },
"project_id": { "type": "integer" },
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"labels": {
"type": "array",
"items": {
"type": "string"
}
},
"milestone": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"iid": { "type": "integer" },
"project_id": { "type": "integer" },
"group_id": { "type": ["integer", "null"] },
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
"created_at": { "type": "date" },
"updated_at": { "type": "date" },
"due_date": { "type": "date" },
"start_date": { "type": "date" }
},
"additionalProperties": false
},
"assignees": {
"type": "array",
"items": {
"type": ["object", "null"],
"properties": {
"name": { "type": "string" },
"username": { "type": "string" },
"id": { "type": "integer" },
"state": { "type": "string" },
"avatar_url": { "type": "uri" },
"web_url": { "type": "uri" }
},
"additionalProperties": false
}
},
"assignee": {
"type": ["object", "null"],
"properties": {
"name": { "type": "string" },
"username": { "type": "string" },
"id": { "type": "integer" },
"state": { "type": "string" },
"avatar_url": { "type": "uri" },
"web_url": { "type": "uri" }
},
"additionalProperties": false
},
"author": {
"type": "object",
"properties": {
"name": { "type": "string" },
"username": { "type": "string" },
"id": { "type": "integer" },
"state": { "type": "string" },
"avatar_url": { "type": "uri" },
"web_url": { "type": "uri" }
},
"additionalProperties": false
},
"user_notes_count": { "type": "integer" },
"upvotes": { "type": "integer" },
"downvotes": { "type": "integer" },
"due_date": { "type": ["date", "null"] },
"confidential": { "type": "boolean" },
"web_url": { "type": "uri" },
"weight": { "type": ["integer", "null"] }
},
"required": [
"id", "iid", "project_id", "title", "description",
"state", "created_at", "updated_at", "labels",
"milestone", "assignees", "author", "user_notes_count",
"upvotes", "downvotes", "due_date", "confidential",
"web_url", "weight"
],
"additionalProperties": false
}
"allOf": [
{ "$ref": "../issues.json" },
{
"properties": {
"weight": { "type": ["integer", "null"] }
}
}
]
}
......@@ -86,7 +86,6 @@
"milestone", "assignees", "author", "user_notes_count",
"upvotes", "downvotes", "due_date", "confidential",
"web_url"
],
"additionalProperties": false
]
}
}
......@@ -10,6 +10,7 @@ const deploymentMockData = [
url: '/root/acets-review-apps/environments/15',
stop_url: '/root/acets-review-apps/environments/15/stop',
metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
external_url: 'http://diplo.',
external_url_formatted: 'diplo.',
deployed_at: '2017-03-22T22:44:42.258Z',
......
......@@ -3,6 +3,7 @@ import memoryUsageComponent from '~/vue_merge_request_widget/components/mr_widge
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
const url = '/root/acets-review-apps/environments/15/deployments/1/metrics';
const monitoringUrl = '/root/acets-review-apps/environments/15/metrics';
const metricsMockData = {
success: true,
......@@ -39,6 +40,7 @@ const createComponent = () => {
el: document.createElement('div'),
propsData: {
metricsUrl: url,
metricsMonitoringUrl: monitoringUrl,
memoryMetrics: [],
deploymentTime: 0,
hasMetrics: false,
......
......@@ -48,7 +48,9 @@ describe Gitlab::Ci::Status::Build::Cancelable do
describe '#has_action?' do
context 'when user is allowed to update build' do
before do
build.project.team << [user, :developer]
stub_not_protect_default_branch
build.project.add_developer(user)
end
it { is_expected.to have_action }
......
......@@ -7,7 +7,9 @@ describe Gitlab::Ci::Status::Build::Factory do
let(:factory) { described_class.new(build, user) }
before do
project.team << [user, :developer]
stub_not_protect_default_branch
project.add_developer(user)
end
context 'when build is successful' do
......@@ -225,19 +227,19 @@ describe Gitlab::Ci::Status::Build::Factory do
end
context 'when user has ability to play action' do
before do
project.add_developer(user)
create(:protected_branch, :developers_can_merge,
name: build.ref, project: project)
end
it 'fabricates status that has action' do
expect(status).to have_action
end
end
context 'when user does not have ability to play action' do
before do
allow(build.project).to receive(:empty_repo?).and_return(false)
create(:protected_branch, :no_one_can_push,
name: build.ref, project: build.project)
end
it 'fabricates status that has no action' do
expect(status).not_to have_action
end
......@@ -262,6 +264,13 @@ describe Gitlab::Ci::Status::Build::Factory do
end
context 'when user is not allowed to execute manual action' do
before do
allow(build.project).to receive(:empty_repo?).and_return(false)
create(:protected_branch, :no_one_can_push,
name: build.ref, project: build.project)
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'manual'
expect(status.group).to eq 'manual'
......
......@@ -48,7 +48,9 @@ describe Gitlab::Ci::Status::Build::Retryable do
describe '#has_action?' do
context 'when user is allowed to update build' do
before do
build.project.team << [user, :developer]
stub_not_protect_default_branch
build.project.add_developer(user)
end
it { is_expected.to have_action }
......
......@@ -20,7 +20,9 @@ describe Gitlab::Ci::Status::Build::Stop do
describe '#has_action?' do
context 'when user is allowed to update build' do
before do
build.project.team << [user, :developer]
stub_not_protect_default_branch
build.project.add_developer(user)
end
it { is_expected.to have_action }
......
require 'spec_helper'
describe Gitlab::GitalyClient::RepositoryService do
set(:project) { create(:empty_project) }
let(:storage_name) { project.repository_storage }
let(:relative_path) { project.path_with_namespace + '.git' }
let(:client) { described_class.new(project.repository) }
describe '#exists?' do
it 'sends an exists message' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:exists)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
.and_call_original
client.exists?
end
end
end
......@@ -36,9 +36,12 @@ describe Gitlab::PathRegex do
described_class::PROJECT_WILDCARD_ROUTES.include?(path.split('/').first)
end
def failure_message(missing_words, constant_name, migration_helper)
def failure_message(constant_name, migration_helper, missing_words: [], additional_words: [])
missing_words = Array(missing_words)
<<-MSG
additional_words = Array(additional_words)
message = ""
if missing_words.any?
message += <<-MISSING
Found new routes that could cause conflicts with existing namespaced routes
for groups or projects.
......@@ -51,7 +54,18 @@ describe Gitlab::PathRegex do
Make sure to make a note of the renamed records in the release blog post.
MSG
MISSING
end
if additional_words.any?
message += <<-ADDITIONAL
Why are <#{additional_words.join(', ')}> in `#{constant_name}`?
If they are really required, update these specs to reflect that.
ADDITIONAL
end
message
end
let(:all_routes) do
......@@ -68,9 +82,23 @@ describe Gitlab::PathRegex do
let(:routes_not_starting_in_wildcard) { routes_without_format.select { |p| p !~ %r{^/[:*]} } }
let(:top_level_words) do
routes_not_starting_in_wildcard.map do |route|
words = routes_not_starting_in_wildcard.map do |route|
route.split('/')[1]
end.compact.uniq
words + files_in_public + Array(API::API.prefix.to_s)
end
let(:ee_top_level_words) do
['unsubscribes']
end
let(:files_in_public) do
git = Gitlab.config.git.bin_path
`cd #{Rails.root} && #{git} ls-files public`
.split("\n")
.map { |entry| entry.gsub('public/', '') }
.uniq
end
# All routes that start with a namespaced path, that have 1 or more
......@@ -118,15 +146,26 @@ describe Gitlab::PathRegex do
end.uniq
end
let(:ee_paths_after_group_id) do
%w(analytics
ldap
ldap_group_links
notification_setting
audit_events
pipeline_quota hooks)
end
describe 'TOP_LEVEL_ROUTES' do
it 'includes all the top level namespaces' do
failure_block = lambda do
missing_words = top_level_words - described_class::TOP_LEVEL_ROUTES
failure_message(missing_words, 'TOP_LEVEL_ROUTES', 'rename_root_paths')
additional_words = described_class::TOP_LEVEL_ROUTES - top_level_words
failure_message('TOP_LEVEL_ROUTES', 'rename_root_paths',
missing_words: missing_words, additional_words: additional_words)
end
expect(described_class::TOP_LEVEL_ROUTES)
.to include(*top_level_words), failure_block
.to contain_exactly(*top_level_words), failure_block
end
end
......@@ -134,11 +173,13 @@ describe Gitlab::PathRegex do
it "don't contain a second wildcard" do
failure_block = lambda do
missing_words = paths_after_group_id - described_class::GROUP_ROUTES
failure_message(missing_words, 'GROUP_ROUTES', 'rename_child_paths')
additional_words = described_class::GROUP_ROUTES - paths_after_group_id
failure_message('GROUP_ROUTES', 'rename_child_paths',
missing_words: missing_words, additional_words: additional_words)
end
expect(described_class::GROUP_ROUTES)
.to include(*paths_after_group_id), failure_block
.to contain_exactly(*paths_after_group_id), failure_block
end
end
......@@ -147,7 +188,7 @@ describe Gitlab::PathRegex do
aggregate_failures do
all_wildcard_paths.each do |path|
expect(wildcards_include?(path))
.to be(true), failure_message(path, 'PROJECT_WILDCARD_ROUTES', 'rename_wildcard_paths')
.to be(true), failure_message('PROJECT_WILDCARD_ROUTES', 'rename_wildcard_paths', missing_words: path)
end
end
end
......
......@@ -738,6 +738,8 @@ describe Ci::Pipeline do
context 'on failure and build retry' do
before do
stub_not_protect_default_branch
build.drop
project.add_developer(user)
......@@ -1003,6 +1005,8 @@ describe Ci::Pipeline do
let(:latest_status) { pipeline.statuses.latest.pluck(:status) }
before do
stub_not_protect_default_branch
project.add_developer(user)
end
......
......@@ -13,12 +13,6 @@ describe List do
it { is_expected.to validate_presence_of(:position) }
it { is_expected.to validate_numericality_of(:position).only_integer.is_greater_than_or_equal_to(0) }
it 'validates uniqueness of label scoped to board_id' do
create(:list)
expect(subject).to validate_uniqueness_of(:label_id).scoped_to(:board_id)
end
context 'when list_type is set to closed' do
subject { described_class.new(list_type: :closed) }
......
......@@ -11,7 +11,14 @@ RSpec.describe NotificationSetting do
it { is_expected.to validate_presence_of(:user) }
it { is_expected.to validate_presence_of(:level) }
it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:source_id, :source_type]).with_message(/already exists in source/) }
describe 'user_id' do
before do
subject.user = create(:user)
end
it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:source_type, :source_id]).with_message(/already exists in source/) }
end
context "events" do
let(:user) { create(:user) }
......
......@@ -11,7 +11,7 @@ describe PagesDomain do
context 'is unique' do
let(:domain) { 'my.domain.com' }
it { is_expected.to validate_uniqueness_of(:domain) }
it { is_expected.to validate_uniqueness_of(:domain).case_insensitive }
end
{
......
......@@ -15,7 +15,6 @@ describe JiraService do
end
it { is_expected.to validate_presence_of(:url) }
it { is_expected.to validate_presence_of(:project_key) }
it_behaves_like 'issue tracker service URL attribute', :url
end
......@@ -34,7 +33,6 @@ describe JiraService do
active: true,
username: 'username',
password: 'test',
project_key: 'TEST',
jira_issue_transition_id: 24,
url: 'http://jira.test.com'
)
......@@ -88,7 +86,6 @@ describe JiraService do
url: 'http://jira.example.com',
username: 'gitlab_jira_username',
password: 'gitlab_jira_password',
project_key: 'GitLabProject',
jira_issue_transition_id: "custom-id"
)
......@@ -196,15 +193,14 @@ describe JiraService do
project: create(:project),
url: 'http://jira.example.com',
username: 'jira_username',
password: 'jira_password',
project_key: 'GitLabProject'
password: 'jira_password'
)
end
def test_settings(api_url)
project_url = "http://#{api_url}/rest/api/2/project/GitLabProject"
test_url = "http://#{api_url}/rest/api/2/serverInfo"
WebMock.stub_request(:get, project_url).with(basic_auth: %w(jira_username jira_password))
WebMock.stub_request(:get, test_url).with(basic_auth: %w(jira_username jira_password)).to_return(body: { url: 'http://url' }.to_json )
jira_service.test_settings
end
......
......@@ -11,7 +11,7 @@ describe RedirectRoute do
describe 'validations' do
it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path) }
it { is_expected.to validate_uniqueness_of(:path).case_insensitive }
end
describe '.matching_path_and_descendants' do
......
......@@ -956,21 +956,25 @@ describe Repository do
end
end
describe '#exists?' do
shared_examples 'repo exists check' do
it 'returns true when a repository exists' do
expect(repository.exists?).to eq(true)
end
it 'returns false when a repository does not exist' do
allow(repository).to receive(:refs_directory_exists?).and_return(false)
it 'returns false if no full path can be constructed' do
allow(repository).to receive(:path_with_namespace).and_return(nil)
expect(repository.exists?).to eq(false)
end
end
it 'returns false when there is no namespace' do
allow(repository).to receive(:path_with_namespace).and_return(nil)
describe '#exists?' do
context 'when repository_exists is disabled' do
it_behaves_like 'repo exists check'
end
expect(repository.exists?).to eq(false)
context 'when repository_exists is enabled', skip_gitaly_mock: true do
it_behaves_like 'repo exists check'
end
end
......
......@@ -15,7 +15,7 @@ describe Route do
it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path) }
it { is_expected.to validate_uniqueness_of(:path).case_insensitive }
end
describe 'callbacks' do
......
......@@ -123,7 +123,9 @@ describe User do
end
it 'validates uniqueness' do
expect(subject).to validate_uniqueness_of(:username).case_insensitive
user = build(:user)
expect(user).to validate_uniqueness_of(:username).case_insensitive
end
end
......
......@@ -96,87 +96,57 @@ describe Ci::BuildPolicy do
end
end
describe 'rules for manual actions' do
describe 'rules for protected ref' do
let(:project) { create(:project) }
let(:build) { create(:ci_build, ref: 'some-ref', pipeline: pipeline) }
before do
project.add_developer(user)
end
shared_examples 'protected ref' do
context 'when build is a manual action' do
let(:build) do
create(:ci_build, :manual, ref: 'some-ref', pipeline: pipeline)
end
it 'does not include ability to update build' do
expect(policy).to be_disallowed :update_build
end
context 'when no one can push or merge to the branch' do
before do
create(:protected_branch, :no_one_can_push,
name: build.ref, project: project)
end
context 'when build is not a manual action' do
let(:build) do
create(:ci_build, ref: 'some-ref', pipeline: pipeline)
end
it 'includes ability to update build' do
expect(policy).to be_allowed :update_build
end
it 'does not include ability to update build' do
expect(policy).to be_disallowed :update_build
end
end
context 'when build is against a protected branch' do
context 'when developers can push to the branch' do
before do
create(:protected_branch, :no_one_can_push,
name: 'some-ref', project: project)
create(:protected_branch, :developers_can_merge,
name: build.ref, project: project)
end
it_behaves_like 'protected ref'
it 'includes ability to update build' do
expect(policy).to be_allowed :update_build
end
end
context 'when build is against a protected tag' do
context 'when no one can create the tag' do
before do
create(:protected_tag, :no_one_can_create,
name: 'some-ref', project: project)
name: build.ref, project: project)
build.update(tag: true)
end
it_behaves_like 'protected ref'
it 'does not include ability to update build' do
expect(policy).to be_disallowed :update_build
end
end
context 'when build is against a protected tag but it is not a tag' do
context 'when no one can create the tag but it is not a tag' do
before do
create(:protected_tag, :no_one_can_create,
name: 'some-ref', project: project)
name: build.ref, project: project)
end
context 'when build is a manual action' do
let(:build) do
create(:ci_build, :manual, ref: 'some-ref', pipeline: pipeline)
end
it 'includes ability to update build' do
expect(policy).to be_allowed :update_build
end
end
end
context 'when branch build is assigned to is not protected' do
context 'when build is a manual action' do
let(:build) { create(:ci_build, :manual, pipeline: pipeline) }
it 'includes ability to update build' do
expect(policy).to be_allowed :update_build
end
end
context 'when build is not a manual action' do
let(:build) { create(:ci_build, pipeline: pipeline) }
it 'includes ability to update build' do
expect(policy).to be_allowed :update_build
end
it 'includes ability to update build' do
expect(policy).to be_allowed :update_build
end
end
end
......
require 'spec_helper'
describe Ci::PipelinePolicy, :models do
let(:user) { create(:user) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:policy) do
described_class.new(user, pipeline)
end
describe 'rules' do
describe 'rules for protected ref' do
let(:project) { create(:project) }
before do
project.add_developer(user)
end
context 'when no one can push or merge to the branch' do
before do
create(:protected_branch, :no_one_can_push,
name: pipeline.ref, project: project)
end
it 'does not include ability to update pipeline' do
expect(policy).to be_disallowed :update_pipeline
end
end
context 'when developers can push to the branch' do
before do
create(:protected_branch, :developers_can_merge,
name: pipeline.ref, project: project)
end
it 'includes ability to update pipeline' do
expect(policy).to be_allowed :update_pipeline
end
end
context 'when no one can create the tag' do
before do
create(:protected_tag, :no_one_can_create,
name: pipeline.ref, project: project)
pipeline.update(tag: true)
end
it 'does not include ability to update pipeline' do
expect(policy).to be_disallowed :update_pipeline
end
end
context 'when no one can create the tag but it is not a tag' do
before do
create(:protected_tag, :no_one_can_create,
name: pipeline.ref, project: project)
end
it 'includes ability to update pipeline' do
expect(policy).to be_allowed :update_pipeline
end
end
end
end
end
......@@ -30,5 +30,25 @@ describe GlobalPolicy do
it { is_expected.to be_allowed(:read_users_list) }
end
end
context "for an admin" do
let(:current_user) { create(:admin) }
context "when the public level is restricted" do
before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
end
it { is_expected.to be_allowed(:read_users_list) }
end
context "when the public level is not restricted" do
before do
stub_application_setting(restricted_visibility_levels: [])
end
it { is_expected.to be_allowed(:read_users_list) }
end
end
end
end
This diff is collapsed.
......@@ -55,7 +55,8 @@ describe API::Triggers do
post api("/projects/#{project.id}/trigger/pipeline"), options.merge(ref: 'other-branch')
expect(response).to have_http_status(400)
expect(json_response['message']).to eq('base' => ["Reference not found"])
expect(json_response['message']['base'])
.to contain_exactly('Reference not found')
end
context 'Validates variables' do
......@@ -92,7 +93,7 @@ describe API::Triggers do
expect(response).to have_http_status(404)
end
it 'creates builds from the ref given in the URL, not in the body' do
expect do
post api("/projects/#{project.id}/ref/master/trigger/pipeline?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' }
......@@ -113,7 +114,7 @@ describe API::Triggers do
end
end
end
context 'when triggering a pipeline from a job token' do
let(:other_job) { create(:ci_build, :running, user: other_user) }
let(:params) { { ref: 'refs/heads/other-branch' } }
......@@ -127,7 +128,7 @@ describe API::Triggers do
it 'does not leak the presence of project when using valid token' do
subject
expect(response).to have_http_status(404)
end
end
......
......@@ -55,17 +55,22 @@ describe API::Users do
context "when public level is restricted" do
before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
allow_any_instance_of(API::Helpers).to receive(:authenticate!).and_return(true)
end
it "renders 403" do
get api("/users")
expect(response).to have_http_status(403)
context 'when authenticate as a regular user' do
it "renders 403" do
get api("/users", user)
expect(response).to have_gitlab_http_status(403)
end
end
it "renders 404" do
get api("/users/#{user.id}")
expect(response).to have_http_status(404)
context 'when authenticate as an admin' do
it "renders 200" do
get api("/users", admin)
expect(response).to have_gitlab_http_status(200)
end
end
end
......
......@@ -52,7 +52,8 @@ describe API::V3::Triggers do
it 'returns bad request with no builds created if there\'s no commit for that ref' do
post v3_api("/projects/#{project.id}/trigger/builds"), options.merge(ref: 'other-branch')
expect(response).to have_http_status(400)
expect(json_response['message']).to eq('No builds created')
expect(json_response['message']['base'])
.to contain_exactly('Reference not found')
end
context 'Validates variables' do
......
......@@ -5,7 +5,14 @@ describe Ci::API::Triggers do
let!(:trigger_token) { 'secure token' }
let!(:project) { create(:project, :repository, ci_id: 10) }
let!(:project2) { create(:empty_project, ci_id: 11) }
let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) }
let!(:trigger) do
create(:ci_trigger,
project: project,
token: trigger_token,
owner: create(:user))
end
let(:options) do
{
token: trigger_token
......@@ -14,6 +21,8 @@ describe Ci::API::Triggers do
before do
stub_ci_pipeline_to_return_yaml_file
project.add_developer(trigger.owner)
end
context 'Handles errors' do
......@@ -47,7 +56,8 @@ describe Ci::API::Triggers do
it 'returns bad request with no builds created if there\'s no commit for that ref' do
post ci_api("/projects/#{project.ci_id}/refs/other-branch/trigger"), options
expect(response).to have_http_status(400)
expect(json_response['message']).to eq('No builds created')
expect(json_response['message']['base'])
.to contain_exactly('Reference not found')
end
context 'Validates variables' do
......
......@@ -9,47 +9,96 @@ describe BuildDetailsEntity do
describe '#as_json' do
let(:project) { create(:project, :repository) }
let!(:build) { create(:ci_build, :failed, project: project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, :failed, pipeline: pipeline) }
let(:request) { double('request') }
let(:entity) { described_class.new(build, request: request, current_user: user, project: project) }
let(:entity) do
described_class.new(build, request: request,
current_user: user,
project: project)
end
subject { entity.as_json }
before do
allow(request).to receive(:current_user).and_return(user)
end
it 'contains the needed key value pairs' do
expect(subject).to include(:coverage, :erased_at, :duration)
expect(subject).to include(:runner, :pipeline)
expect(subject).to include(:raw_path, :new_issue_path)
end
context 'when the user has access to issues and merge requests' do
let!(:merge_request) do
create(:merge_request, source_project: project, source_branch: build.ref)
end
context 'when merge request orginates from the same project' do
let(:merge_request) do
create(:merge_request, source_project: project, source_branch: build.ref)
end
before do
allow(build).to receive(:merge_request).and_return(merge_request)
end
before do
allow(build).to receive(:merge_request).and_return(merge_request)
end
it 'contains the needed key value pairs' do
expect(subject).to include(:merge_request)
expect(subject).to include(:new_issue_path)
end
it 'contains the needed key value pairs' do
expect(subject).to include(:coverage, :erased_at, :duration)
expect(subject).to include(:runner, :pipeline)
expect(subject).to include(:raw_path, :merge_request)
expect(subject).to include(:new_issue_path)
it 'exposes correct details of the merge request' do
expect(subject[:merge_request][:iid]).to eq merge_request.iid
end
it 'has a correct merge request path' do
expect(subject[:merge_request][:path]).to include project.full_path
end
end
it 'exposes details of the merge request' do
expect(subject[:merge_request]).to include(:iid, :path)
context 'when merge request is from a fork' do
let(:fork_project) do
create(:empty_project, forked_from_project: project)
end
let(:pipeline) { create(:ci_pipeline, project: fork_project) }
before do
allow(build).to receive(:merge_request).and_return(merge_request)
end
let(:merge_request) do
create(:merge_request, source_project: fork_project,
target_project: project,
source_branch: build.ref)
end
it 'contains the needed key value pairs' do
expect(subject).to include(:merge_request)
expect(subject).to include(:new_issue_path)
end
it 'exposes details of the merge request' do
expect(subject[:merge_request][:iid]).to eq merge_request.iid
end
it 'has a merge request path to a target project' do
expect(subject[:merge_request][:path])
.to include project.full_path
end
end
context 'when the build has been erased' do
let!(:build) { create(:ci_build, :erasable, project: project) }
context 'when the build has not been erased' do
let(:build) { create(:ci_build, :erasable, project: project) }
it 'exposes the user whom erased the build' do
it 'exposes a build erase path' do
expect(subject).to include(:erase_path)
end
end
context 'when the build has been erased' do
let!(:build) { create(:ci_build, erased_at: Time.now, project: project, erased_by: user) }
let(:build) { create(:ci_build, :erased, project: project) }
it 'exposes the user whom erased the build' do
it 'exposes the user who erased the build' do
expect(subject).to include(:erased_by)
end
end
......
......@@ -2,13 +2,15 @@ require 'spec_helper'
describe DeployKeyEntity do
include RequestAwareEntity
let(:user) { create(:user) }
let(:project) { create(:empty_project, :internal)}
let(:project_private) { create(:empty_project, :private)}
let!(:project_pending_delete) { create(:empty_project, :internal, pending_delete: true) }
let(:deploy_key) { create(:deploy_key) }
let!(:deploy_key_internal) { create(:deploy_keys_project, project: project, deploy_key: deploy_key) }
let!(:deploy_key_private) { create(:deploy_keys_project, project: project_private, deploy_key: deploy_key) }
let!(:deploy_key_pending_delete) { create(:deploy_keys_project, project: project_pending_delete, deploy_key: deploy_key) }
let(:entity) { described_class.new(deploy_key, user: user) }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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