summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLin Jen-Shin <godfat@godfat.org>2017-06-14 16:23:41 +0800
committerLin Jen-Shin <godfat@godfat.org>2017-06-14 16:23:41 +0800
commit931ab01adba637f6c36a976a19250e93096bc552 (patch)
tree8c2e0de40b88abc7d2b92bb0705351e28c1ec425
parentf99cee8e9cfcc8eaf340e487503682bb5699591a (diff)
parentb29bf62602b6e962ceb31dd7535743a7d8c4864c (diff)
downloadgitlab-ce-931ab01adba637f6c36a976a19250e93096bc552.tar.gz
Merge remote-tracking branch 'upstream/master' into 33149-rename-more-builds
* upstream/master: (34 commits) Revert "Merge branch 'karma-headless-chrome' into 'master'" Make small pipeline schedules UI enhancements. Remove js classes from vue component that are not needed in vue component Update tests and application Adds "Pipeline" to job's sidebar Change border color of job's scroll controllers to $border-color Add database helpers 'add_timestamps_with_timezone' and 'timestamps_with_timezone' Added Tectonic to the page. Always check read_issue permissions when loading issue Handle legacy jobs without name Do not expose internal artifacts hash in build entity Use wait_for_requests instead of sleep 0.3 Limit wiki container width Fix migrations testing support RSpec hooks order Rename BuildEntity to JobEntity Fix support for external_url for commit statuses Allow to access pipelines even if they are disabled, but only present jobs and commit statuses without giving ability to access them add CHANGELOG.md entry for !12036 remove phantomjs-specific test hacks update karma job to use chrome build image created by gitlab-build-images!41 ...
-rw-r--r--app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue16
-rw-r--r--app/assets/stylesheets/framework/forms.scss3
-rw-r--r--app/assets/stylesheets/framework/layout.scss4
-rw-r--r--app/assets/stylesheets/pages/builds.scss2
-rw-r--r--app/assets/stylesheets/pages/pipeline_schedules.scss2
-rw-r--r--app/assets/stylesheets/pages/wiki.scss9
-rw-r--r--app/controllers/projects/application_controller.rb4
-rw-r--r--app/controllers/projects/graphs_controller.rb1
-rw-r--r--app/controllers/projects/issues_controller.rb15
-rw-r--r--app/controllers/projects/pipelines_controller.rb1
-rw-r--r--app/helpers/projects_helper.rb5
-rw-r--r--app/models/commit_status.rb4
-rw-r--r--app/models/generic_commit_status.rb1
-rw-r--r--app/policies/project_policy.rb2
-rw-r--r--app/serializers/build_details_entity.rb9
-rw-r--r--app/serializers/build_serializer.rb2
-rw-r--r--app/serializers/deployment_entity.rb4
-rw-r--r--app/serializers/job_entity.rb (renamed from app/serializers/build_entity.rb)4
-rw-r--r--app/serializers/job_group_entity.rb2
-rw-r--r--app/services/git_push_service.rb6
-rw-r--r--app/services/git_tag_push_service.rb4
-rw-r--r--app/views/projects/jobs/_sidebar.html.haml1
-rw-r--r--app/views/projects/pipeline_schedules/_form.html.haml2
-rw-r--r--app/views/projects/wikis/_form.html.haml12
-rw-r--r--app/views/projects/wikis/_new.html.haml39
-rw-r--r--app/views/projects/wikis/edit.html.haml51
-rw-r--r--app/views/projects/wikis/git_access.html.haml67
-rw-r--r--app/views/projects/wikis/history.html.haml69
-rw-r--r--app/views/projects/wikis/show.html.haml45
-rw-r--r--app/views/shared/_clone_panel.html.haml2
-rw-r--r--changelogs/unreleased/32054-rails-should-use-timestamptz-database-type-for-postgresql.yml4
-rw-r--r--changelogs/unreleased/feature-add-support-for-services-configuration.yml4
-rw-r--r--changelogs/unreleased/fix-github-clone-wiki.yml4
-rw-r--r--changelogs/unreleased/fix-support-for-external-ci-services.yml4
-rw-r--r--changelogs/unreleased/zj-commit-status-sortable-name.yml4
-rw-r--r--config/initializers/active_record_data_types.rb24
-rw-r--r--config/initializers/active_record_table_definition.rb24
-rw-r--r--db/migrate/20160314114439_add_requested_at_to_members.rb1
-rw-r--r--db/migrate/20160415062917_create_personal_access_tokens.rb2
-rw-r--r--db/migrate/20160610204157_add_deployments.rb1
-rw-r--r--db/migrate/20160610204158_add_environments.rb1
-rw-r--r--db/migrate/20160705054938_add_protected_branches_push_access.rb1
-rw-r--r--db/migrate/20160705054952_add_protected_branches_merge_access.rb1
-rw-r--r--db/migrate/20160724205507_add_resolved_to_notes.rb1
-rw-r--r--db/migrate/20160727163552_create_user_agent_details.rb1
-rw-r--r--db/migrate/20160727191041_create_boards.rb1
-rw-r--r--db/migrate/20160727193336_create_lists.rb1
-rw-r--r--db/migrate/20160805041956_add_deleted_at_to_namespaces.rb1
-rw-r--r--db/migrate/20160824124900_add_table_issue_metrics.rb2
-rw-r--r--db/migrate/20160825052008_add_table_merge_request_metrics.rb2
-rw-r--r--db/migrate/20160831214002_create_project_features.rb1
-rw-r--r--db/migrate/20160915042921_create_merge_requests_closing_issues.rb1
-rw-r--r--db/migrate/20161014173530_create_label_priorities.rb1
-rw-r--r--db/migrate/20161113184239_create_user_chat_names_table.rb2
-rw-r--r--db/migrate/20161124111402_add_routes_table.rb1
-rw-r--r--db/migrate/20161221152132_add_last_used_at_to_key.rb1
-rw-r--r--db/migrate/20161223034646_create_timelogs_ce.rb1
-rw-r--r--db/migrate/20161228124936_change_expires_at_to_date_in_personal_access_tokens.rb1
-rw-r--r--db/migrate/20170120131253_create_chat_teams.rb1
-rw-r--r--db/migrate/20170130221926_create_uploads.rb1
-rw-r--r--db/migrate/20170222143317_drop_ci_projects.rb1
-rw-r--r--db/migrate/20170301205639_remove_unused_ci_tables_and_columns.rb1
-rw-r--r--db/migrate/20170309173138_create_protected_tags.rb1
-rw-r--r--db/migrate/20170314082049_create_system_note_metadata.rb1
-rw-r--r--db/migrate/20170315194013_add_closed_at_to_issues.rb1
-rw-r--r--db/migrate/20170322013926_create_container_repository.rb1
-rw-r--r--db/migrate/20170329095907_create_ci_trigger_schedules.rb1
-rw-r--r--db/migrate/20170425112128_create_pipeline_schedules_table.rb2
-rw-r--r--db/migrate/20170427215854_create_redirect_routes.rb1
-rw-r--r--db/migrate/20170503004125_add_last_repository_updated_at_to_projects.rb1
-rw-r--r--db/migrate/20170523121229_create_conversational_development_index_metrics.rb1
-rw-r--r--db/migrate/20170525132202_create_pipeline_stages.rb1
-rw-r--r--db/post_migrate/20170425130047_drop_ci_trigger_schedules_table.rb1
-rw-r--r--doc/development/migration_style_guide.md39
-rw-r--r--doc/install/kubernetes/index.md2
-rw-r--r--features/steps/project/issues/award_emoji.rb4
-rw-r--r--lib/api/entities.rb8
-rw-r--r--lib/ci/api/entities.rb16
-rw-r--r--lib/github/import.rb2
-rw-r--r--lib/gitlab/ci/build/image.rb11
-rw-r--r--lib/gitlab/ci/config/entry/image.rb30
-rw-r--r--lib/gitlab/ci/config/entry/service.rb34
-rw-r--r--lib/gitlab/ci/config/entry/services.rb25
-rw-r--r--lib/gitlab/ci/config/entry/validators.rb8
-rw-r--r--lib/gitlab/ci/status/external/common.rb4
-rw-r--r--lib/gitlab/database/migration_helpers.rb33
-rw-r--r--rubocop/cop/migration/add_timestamps.rb25
-rw-r--r--rubocop/cop/migration/datetime.rb36
-rw-r--r--rubocop/cop/migration/timestamps.rb27
-rw-r--r--rubocop/rubocop.rb3
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb37
-rw-r--r--spec/factories/ci/builds.rb4
-rw-r--r--spec/features/projects/features_visibility_spec.rb5
-rw-r--r--spec/features/projects/pipeline_schedules_spec.rb2
-rw-r--r--spec/helpers/projects_helper_spec.rb33
-rw-r--r--spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js13
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb173
-rw-r--r--spec/lib/gitlab/ci/build/image_spec.rb61
-rw-r--r--spec/lib/gitlab/ci/config/entry/global_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/config/entry/image_spec.rb113
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/service_spec.rb117
-rw-r--r--spec/lib/gitlab/ci/config/entry/services_spec.rb41
-rw-r--r--spec/lib/gitlab/ci/status/external/common_spec.rb9
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb37
-rw-r--r--spec/models/ci/legacy_stage_spec.rb11
-rw-r--r--spec/policies/project_policy_spec.rb12
-rw-r--r--spec/requests/api/runner_spec.rb7
-rw-r--r--spec/requests/ci/api/builds_spec.rb12
-rw-r--r--spec/rubocop/cop/migration/add_timestamps_spec.rb90
-rw-r--r--spec/rubocop/cop/migration/datetime_spec.rb90
-rw-r--r--spec/rubocop/cop/migration/timestamps_spec.rb99
-rw-r--r--spec/serializers/build_details_entity_spec.rb6
-rw-r--r--spec/serializers/job_entity_spec.rb (renamed from spec/serializers/build_entity_spec.rb)47
-rw-r--r--spec/serializers/pipeline_details_entity_spec.rb14
-rw-r--r--spec/serializers/stage_entity_spec.rb11
-rw-r--r--spec/spec_helper.rb16
117 files changed, 1485 insertions, 393 deletions
diff --git a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
index af2b4c6786e..1c6ef071a6d 100644
--- a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
+++ b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
@@ -20,12 +20,6 @@ export default {
default: 'top',
},
- shortFormat: {
- type: Boolean,
- required: false,
- default: false,
- },
-
cssClass: {
type: String,
required: false,
@@ -37,18 +31,12 @@ export default {
tooltipMixin,
timeagoMixin,
],
-
- computed: {
- timeagoCssClass() {
- return this.shortFormat ? 'js-short-timeago' : 'js-timeago';
- },
- },
};
</script>
<template>
<time
- :class="[timeagoCssClass, cssClass]"
- class="js-timeago js-timeago-render"
+ :class="cssClass"
+ class="js-vue-timeago"
:title="tooltipTitle(time)"
:data-placement="tooltipPlacement"
data-container="body"
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 432024779fd..a78179e727f 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -148,7 +148,8 @@ label {
margin-top: 35px;
}
-.form-group .control-label {
+.form-group .control-label,
+.form-group .control-label-full-width {
font-weight: normal;
}
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index 9e8acf4e73c..49bff23452d 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -51,6 +51,10 @@ body {
&.limit-container-width {
max-width: $limited-layout-width;
}
+
+ &.limit-container-width-sm {
+ max-width: 790px;
+ }
}
.alert-wrapper {
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index 203fd6d07e4..39022714d28 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -72,7 +72,7 @@
display: flex;
justify-content: flex-end;
background: $gray-light;
- border: 1px solid $gray-normal;
+ border: 1px solid $border-color;
color: $gl-text-color;
.truncated-info {
diff --git a/app/assets/stylesheets/pages/pipeline_schedules.scss b/app/assets/stylesheets/pages/pipeline_schedules.scss
index ab417948931..595eb40fec7 100644
--- a/app/assets/stylesheets/pages/pipeline_schedules.scss
+++ b/app/assets/stylesheets/pages/pipeline_schedules.scss
@@ -12,7 +12,7 @@
.interval-pattern-form-group {
label {
margin-right: 10px;
- font-size: 12px;
+ font-weight: normal;
&[for='custom'] {
margin-right: 0;
diff --git a/app/assets/stylesheets/pages/wiki.scss b/app/assets/stylesheets/pages/wiki.scss
index b64b89485f7..94d0a39f397 100644
--- a/app/assets/stylesheets/pages/wiki.scss
+++ b/app/assets/stylesheets/pages/wiki.scss
@@ -42,9 +42,7 @@
}
.git-access-header {
- padding: 16px 40px 11px 0;
- line-height: 28px;
- font-size: 18px;
+ padding: $gl-padding 0 $gl-padding-top;
}
.git-clone-holder {
@@ -66,6 +64,7 @@
.git-clone-holder {
width: 480px;
+ padding-bottom: $gl-padding;
}
.nav-controls {
@@ -89,9 +88,9 @@
margin: $gl-padding 0;
h3 {
- font-size: 22px;
+ font-size: 19px;
font-weight: normal;
- margin-top: 1.4em;
+ margin: $gl-padding 0;
}
}
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index cb4bd0ad5f5..603a51266da 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -80,10 +80,6 @@ class Projects::ApplicationController < ApplicationController
cookies.permanent[:diff_view] = params.delete(:view) if params[:view].present?
end
- def builds_enabled
- return render_404 unless @project.feature_available?(:builds, current_user)
- end
-
def require_pages_enabled!
not_found unless Gitlab.config.pages.enabled
end
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index 43fc0c39801..df5221fe95f 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -5,7 +5,6 @@ class Projects::GraphsController < Projects::ApplicationController
before_action :require_non_empty_project
before_action :assign_ref_vars
before_action :authorize_download_code!
- before_action :builds_enabled, only: :ci
def show
respond_to do |format|
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index ebb163bf9dc..56f76e752d0 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -10,11 +10,7 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :redirect_to_external_issue_tracker, only: [:index, :new]
before_action :module_enabled
- before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests,
- :related_branches, :can_create_branch, :realtime_changes, :create_merge_request]
-
- # Allow read any issue
- before_action :authorize_read_issue!, only: [:show, :realtime_changes]
+ before_action :issue, except: [:index, :new, :create, :bulk_update]
# Allow write(create) issue
before_action :authorize_create_issue!, only: [:new, :create]
@@ -229,18 +225,19 @@ class Projects::IssuesController < Projects::ApplicationController
protected
def issue
+ return @issue if defined?(@issue)
# The Sortable default scope causes performance issues when used with find_by
@noteable = @issue ||= @project.issues.where(iid: params[:id]).reorder(nil).take!
+
+ return render_404 unless can?(current_user, :read_issue, @issue)
+
+ @issue
end
alias_method :subscribable_resource, :issue
alias_method :issuable, :issue
alias_method :awardable, :issue
alias_method :spammable, :issue
- def authorize_read_issue!
- return render_404 unless can?(current_user, :read_issue, @issue)
- end
-
def authorize_update_issue!
return render_404 unless can?(current_user, :update_issue, @issue)
end
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 6223e7943f8..8effb792689 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -4,7 +4,6 @@ class Projects::PipelinesController < Projects::ApplicationController
before_action :authorize_read_pipeline!
before_action :authorize_create_pipeline!, only: [:new, :create]
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
- before_action :builds_enabled, only: :charts
wrap_parameters Ci::Pipeline
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 7441b58fddb..c11dd49f4a7 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -218,6 +218,10 @@ module ProjectsHelper
nav_tabs << :container_registry
end
+ if project.builds_enabled? && can?(current_user, :read_pipeline, project)
+ nav_tabs << :pipelines
+ end
+
tab_ability_map.each do |tab, ability|
if can?(current_user, ability, project)
nav_tabs << tab
@@ -231,7 +235,6 @@ module ProjectsHelper
{
environments: :read_environment,
milestones: :read_milestone,
- pipelines: :read_pipeline,
snippets: :read_project_snippet,
settings: :admin_project,
builds: :read_build,
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index cb425706a9e..07cec63b939 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -112,7 +112,7 @@ class CommitStatus < ActiveRecord::Base
end
def group_name
- name.gsub(/\d+[\s:\/\\]+\d+\s*/, '').strip
+ name.to_s.gsub(/\d+[\s:\/\\]+\d+\s*/, '').strip
end
def failed_but_allowed?
@@ -156,7 +156,7 @@ class CommitStatus < ActiveRecord::Base
end
def sortable_name
- name.split(/(\d+)/).map do |v|
+ name.to_s.split(/(\d+)/).map do |v|
v =~ /\d+/ ? v.to_i : v
end
end
diff --git a/app/models/generic_commit_status.rb b/app/models/generic_commit_status.rb
index 8867ba0d2ff..532b8f4ad69 100644
--- a/app/models/generic_commit_status.rb
+++ b/app/models/generic_commit_status.rb
@@ -11,6 +11,7 @@ class GenericCommitStatus < CommitStatus
def set_default_values
self.context ||= 'default'
self.stage ||= 'external'
+ self.stage_idx ||= 1000000
end
def tags
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 3959b895f44..47518dddb61 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -203,7 +203,7 @@ class ProjectPolicy < BasePolicy
unless project.feature_available?(:builds, user) && repository_enabled
cannot!(*named_abilities(:build))
- cannot!(*named_abilities(:pipeline))
+ cannot!(*named_abilities(:pipeline) - [:read_pipeline])
cannot!(*named_abilities(:pipeline_schedule))
cannot!(*named_abilities(:environment))
cannot!(*named_abilities(:deployment))
diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb
index b04a42105aa..eeb5399aa8b 100644
--- a/app/serializers/build_details_entity.rb
+++ b/app/serializers/build_details_entity.rb
@@ -1,18 +1,15 @@
-class BuildDetailsEntity < BuildEntity
+class BuildDetailsEntity < JobEntity
expose :coverage, :erased_at, :duration
expose :tag_list, as: :tags
-
expose :user, using: UserEntity
+ expose :runner, using: RunnerEntity
+ expose :pipeline, using: PipelineEntity
expose :erased_by, if: -> (*) { build.erased? }, using: UserEntity
expose :erase_path, if: -> (*) { build.erasable? && can?(current_user, :update_build, project) } do |build|
erase_namespace_project_job_path(project.namespace, project, build)
end
- expose :artifacts, using: BuildArtifactEntity
- expose :runner, using: RunnerEntity
- expose :pipeline, using: PipelineEntity
-
expose :merge_request, if: -> (*) { can?(current_user, :read_merge_request, build.merge_request) } do
expose :iid do |build|
build.merge_request.iid
diff --git a/app/serializers/build_serializer.rb b/app/serializers/build_serializer.rb
index 79b67001199..bae9932847f 100644
--- a/app/serializers/build_serializer.rb
+++ b/app/serializers/build_serializer.rb
@@ -1,5 +1,5 @@
class BuildSerializer < BaseSerializer
- entity BuildEntity
+ entity JobEntity
def represent_status(resource)
data = represent(resource, { only: [:status] })
diff --git a/app/serializers/deployment_entity.rb b/app/serializers/deployment_entity.rb
index 8b3de1bed0f..e493c9162fd 100644
--- a/app/serializers/deployment_entity.rb
+++ b/app/serializers/deployment_entity.rb
@@ -24,6 +24,6 @@ class DeploymentEntity < Grape::Entity
expose :user, using: UserEntity
expose :commit, using: CommitEntity
- expose :deployable, using: BuildEntity
- expose :manual_actions, using: BuildEntity
+ expose :deployable, using: JobEntity
+ expose :manual_actions, using: JobEntity
end
diff --git a/app/serializers/build_entity.rb b/app/serializers/job_entity.rb
index 67001f4547d..d6de43bcbcb 100644
--- a/app/serializers/build_entity.rb
+++ b/app/serializers/job_entity.rb
@@ -1,11 +1,11 @@
-class BuildEntity < Grape::Entity
+class JobEntity < Grape::Entity
include RequestAwareEntity
expose :id
expose :name
expose :build_path do |build|
- path_to(:namespace_project_job, build)
+ build.target_url || path_to(:namespace_project_job, build)
end
expose :retry_path, if: -> (*) { retryable? } do |build|
diff --git a/app/serializers/job_group_entity.rb b/app/serializers/job_group_entity.rb
index 04487e59009..8554de55517 100644
--- a/app/serializers/job_group_entity.rb
+++ b/app/serializers/job_group_entity.rb
@@ -4,7 +4,7 @@ class JobGroupEntity < Grape::Entity
expose :name
expose :size
expose :detailed_status, as: :status, with: StatusEntity
- expose :jobs, with: BuildEntity
+ expose :jobs, with: JobEntity
private
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index f080e6326a1..fb1d4aed58b 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -101,12 +101,12 @@ class GitPushService < BaseService
UpdateMergeRequestsWorker
.perform_async(@project.id, current_user.id, params[:oldrev], params[:newrev], params[:ref])
- SystemHookPushWorker.perform_async(build_push_data.dup, :push_hooks)
-
EventCreateService.new.push(@project, current_user, build_push_data)
+ Ci::CreatePipelineService.new(@project, current_user, build_push_data).execute(:push)
+
+ SystemHookPushWorker.perform_async(build_push_data.dup, :push_hooks)
@project.execute_hooks(build_push_data.dup, :push_hooks)
@project.execute_services(build_push_data.dup, :push_hooks)
- Ci::CreatePipelineService.new(@project, current_user, build_push_data).execute(:push)
if push_remove_branch?
AfterBranchDeleteService
diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb
index 7c424fba428..9917a39b795 100644
--- a/app/services/git_tag_push_service.rb
+++ b/app/services/git_tag_push_service.rb
@@ -8,10 +8,12 @@ class GitTagPushService < BaseService
@push_data = build_push_data
EventCreateService.new.push(project, current_user, @push_data)
+ Ci::CreatePipelineService.new(project, current_user, @push_data).execute(:push)
+
SystemHooksService.new.execute_hooks(build_system_push_data.dup, :tag_push_hooks)
project.execute_hooks(@push_data.dup, :tag_push_hooks)
project.execute_services(@push_data.dup, :tag_push_hooks)
- Ci::CreatePipelineService.new(project, current_user, @push_data).execute(:push)
+
ProjectCacheWorker.perform_async(project.id, [], [:commit_count, :repository_size])
true
diff --git a/app/views/projects/jobs/_sidebar.html.haml b/app/views/projects/jobs/_sidebar.html.haml
index 8b9e6e57ec4..93e8a4e385c 100644
--- a/app/views/projects/jobs/_sidebar.html.haml
+++ b/app/views/projects/jobs/_sidebar.html.haml
@@ -72,6 +72,7 @@
.title
%span{ class: "ci-status-icon-#{@build.pipeline.status}" }
= ci_icon_for_status(@build.pipeline.status)
+ Pipeline
= link_to "##{@build.pipeline.id}", namespace_project_pipeline_path(@project.namespace, @project, @build.pipeline), class: 'link-commit'
from
= link_to "#{@build.pipeline.ref}", namespace_project_branch_path(@project.namespace, @project, @build.pipeline.ref), class: 'link-commit'
diff --git a/app/views/projects/pipeline_schedules/_form.html.haml b/app/views/projects/pipeline_schedules/_form.html.haml
index 25ae4e0e18f..e8dedf26206 100644
--- a/app/views/projects/pipeline_schedules/_form.html.haml
+++ b/app/views/projects/pipeline_schedules/_form.html.haml
@@ -20,7 +20,7 @@
.form-group
.col-md-9
= f.label :ref, _('Target Branch'), class: 'label-light'
- = dropdown_tag(_("Select target branch"), options: { toggle_class: 'btn js-target-branch-dropdown git-revision-dropdown-toggle', dropdown_class: 'git-revision-dropdown', title: _("Select target branch"), filter: true, placeholder: _("Filter"), data: { data: @project.repository.branch_names, default_branch: @project.default_branch } } )
+ = dropdown_tag(_("Select target branch"), options: { toggle_class: 'btn js-target-branch-dropdown', dropdown_class: 'git-revision-dropdown', title: _("Select target branch"), filter: true, placeholder: _("Filter"), data: { data: @project.repository.branch_names, default_branch: @project.default_branch } } )
= f.text_field :ref, value: @schedule.ref, id: 'schedule_ref', class: 'hidden', name: 'schedule[ref]', required: true
.form-group
.col-md-9
diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml
index 6cb7c1e9c4d..c10b3004bc3 100644
--- a/app/views/projects/wikis/_form.html.haml
+++ b/app/views/projects/wikis/_form.html.haml
@@ -5,13 +5,13 @@
= f.hidden_field :title, value: @page.title
.form-group
- = f.label :format, class: 'control-label'
- .col-sm-10
+ .col-sm-12= f.label :format, class: 'control-label-full-width'
+ .col-sm-12
= f.select :format, options_for_select(ProjectWiki::MARKUPS, {selected: @page.format}), {}, class: "form-control"
.form-group
- = f.label :content, class: 'control-label'
- .col-sm-10
+ .col-sm-12= f.label :content, class: 'control-label-full-width'
+ .col-sm-12
= render layout: 'projects/md_preview', locals: { url: namespace_project_wiki_preview_markdown_path(@project.namespace, @project, @page.slug) } do
= render 'projects/zen', f: f, attr: :content, classes: 'note-textarea', placeholder: 'Write your content or drag files here...'
= render 'shared/notes/hints'
@@ -29,8 +29,8 @@
= link_to 'documentation', help_page_path("user/markdown", anchor: "wiki-specific-markdown")
.form-group
- = f.label :commit_message, class: 'control-label'
- .col-sm-10= f.text_field :message, class: 'form-control', rows: 18, value: commit_message
+ .col-sm-12= f.label :commit_message, class: 'control-label-full-width'
+ .col-sm-12= f.text_field :message, class: 'form-control', rows: 18, value: commit_message
.form-actions
- if @page && @page.persisted?
diff --git a/app/views/projects/wikis/_new.html.haml b/app/views/projects/wikis/_new.html.haml
index ba47574563d..1e553940593 100644
--- a/app/views/projects/wikis/_new.html.haml
+++ b/app/views/projects/wikis/_new.html.haml
@@ -1,21 +1,18 @@
-- @no_container = true
-
-%div{ class: container_class }
- #modal-new-wiki.modal
- .modal-dialog
- .modal-content
- .modal-header
- %a.close{ href: "#", "data-dismiss" => "modal" } ×
- %h3.page-title New Wiki Page
- .modal-body
- %form.new-wiki-page
- .form-group
- = label_tag :new_wiki_path do
- %span Page slug
- = text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => namespace_project_wikis_path(@project.namespace, @project), autofocus: true
- %span.new-wiki-page-slug-tip
- = icon('lightbulb-o')
- Tip: You can specify the full path for the new file.
- We will automatically create any missing directories.
- .form-actions
- = button_tag 'Create page', class: 'build-new-wiki btn btn-create'
+#modal-new-wiki.modal
+ .modal-dialog
+ .modal-content
+ .modal-header
+ %a.close{ href: "#", "data-dismiss" => "modal" } ×
+ %h3.page-title New Wiki Page
+ .modal-body
+ %form.new-wiki-page
+ .form-group
+ = label_tag :new_wiki_path do
+ %span Page slug
+ = text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => namespace_project_wikis_path(@project.namespace, @project), autofocus: true
+ %span.new-wiki-page-slug-tip
+ = icon('lightbulb-o')
+ Tip: You can specify the full path for the new file.
+ We will automatically create any missing directories.
+ .form-actions
+ = button_tag 'Create page', class: 'build-new-wiki btn btn-create'
diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml
index b995d08cd02..fbe192a40ec 100644
--- a/app/views/projects/wikis/edit.html.haml
+++ b/app/views/projects/wikis/edit.html.haml
@@ -1,35 +1,34 @@
-- @no_container = true
+- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout
- page_title "Edit", @page.title.capitalize, "Wiki"
-%div{ class: container_class }
- .wiki-page-header.has-sidebar-toggle
- %button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
- = icon('angle-double-left')
+.wiki-page-header.has-sidebar-toggle
+ %button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
+ = icon('angle-double-left')
- .nav-text
- %h2.wiki-page-title
+ .nav-text
+ %h2.wiki-page-title
+ - if @page.persisted?
+ = link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page)
+ - else
+ = @page.title.capitalize
+ %span.light
+ &middot;
- if @page.persisted?
- = link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page)
+ Edit Page
- else
- = @page.title.capitalize
- %span.light
- &middot;
- - if @page.persisted?
- Edit Page
- - else
- Create Page
+ Create Page
- .nav-controls
- - if can?(current_user, :create_wiki, @project)
- = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
- New page
- - if @page.persisted?
- = link_to namespace_project_wiki_history_path(@project.namespace, @project, @page), class: "btn" do
- Page history
- - if can?(current_user, :admin_wiki, @project)
- = link_to namespace_project_wiki_path(@project.namespace, @project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-danger" do
- Delete
+ .nav-controls
+ - if can?(current_user, :create_wiki, @project)
+ = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
+ New page
+ - if @page.persisted?
+ = link_to namespace_project_wiki_history_path(@project.namespace, @project, @page), class: "btn" do
+ Page history
+ - if can?(current_user, :admin_wiki, @project)
+ = link_to namespace_project_wiki_path(@project.namespace, @project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-danger" do
+ Delete
- = render 'form'
+= render 'form'
= render 'sidebar'
diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml
index 68862206248..e64dd6085fe 100644
--- a/app/views/projects/wikis/git_access.html.haml
+++ b/app/views/projects/wikis/git_access.html.haml
@@ -1,43 +1,42 @@
-- @no_container = true
+- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout
- page_title "Git Access", "Wiki"
-%div{ class: container_class }
- .wiki-page-header.has-sidebar-toggle
- %button.btn.btn-default.visible-xs.visible-sm.pull-right.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
- = icon('angle-double-left')
+.wiki-page-header.has-sidebar-toggle
+ %button.btn.btn-default.visible-xs.visible-sm.pull-right.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
+ = icon('angle-double-left')
- .git-access-header
- Clone repository
- %strong= @project_wiki.path_with_namespace
+ .git-access-header
+ Clone repository
+ %strong= @project_wiki.path_with_namespace
- = render "shared/clone_panel", project: @project_wiki
+ = render "shared/clone_panel", project: @project_wiki
- .wiki-git-access
- %h3 Install Gollum
- %pre.dark
- :preserve
- gem install gollum
- %p
- It is recommended to install
- %code github-markdown
- so that GFM features render locally:
- %pre.dark
- :preserve
- gem install github-markdown
+.wiki-git-access
+ %h3 Install Gollum
+ %pre.dark
+ :preserve
+ gem install gollum
+ %p
+ It is recommended to install
+ %code github-markdown
+ so that GFM features render locally:
+ %pre.dark
+ :preserve
+ gem install github-markdown
- %h3 Clone your wiki
- %pre.dark
- :preserve
- git clone #{ content_tag(:span, h(default_url_to_repo(@project_wiki)), class: 'clone')}
- cd #{h @project_wiki.path}
+ %h3 Clone your wiki
+ %pre.dark
+ :preserve
+ git clone #{ content_tag(:span, h(default_url_to_repo(@project_wiki)), class: 'clone')}
+ cd #{h @project_wiki.path}
- %h3 Start Gollum and edit locally
- %pre.dark
- :preserve
- gollum
- == Sinatra/1.3.5 has taken the stage on 4567 for development with backup from Thin
- >> Thin web server (v1.5.0 codename Knife)
- >> Maximum connections set to 1024
- >> Listening on 0.0.0.0:4567, CTRL+C to stop
+ %h3 Start Gollum and edit locally
+ %pre.dark
+ :preserve
+ gollum
+ == Sinatra/1.3.5 has taken the stage on 4567 for development with backup from Thin
+ >> Thin web server (v1.5.0 codename Knife)
+ >> Maximum connections set to 1024
+ >> Listening on 0.0.0.0:4567, CTRL+C to stop
= render 'sidebar'
diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml
index dd7213622c1..0e47e2a5fa3 100644
--- a/app/views/projects/wikis/history.html.haml
+++ b/app/views/projects/wikis/history.html.haml
@@ -1,42 +1,41 @@
- page_title "History", @page.title.capitalize, "Wiki"
-%div{ class: container_class }
- .wiki-page-header.has-sidebar-toggle
- %button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
- = icon('angle-double-left')
+.wiki-page-header.has-sidebar-toggle
+ %button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
+ = icon('angle-double-left')
- .nav-text
- %h2.wiki-page-title
- = link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page)
- %span.light
- &middot;
- History
+ .nav-text
+ %h2.wiki-page-title
+ = link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page)
+ %span.light
+ &middot;
+ History
- .table-holder
- %table.table
- %thead
+.table-holder
+ %table.table
+ %thead
+ %tr
+ %th Page version
+ %th Author
+ %th Commit Message
+ %th Last updated
+ %th Format
+ %tbody
+ - @page.versions.each_with_index do |version, index|
+ - commit = version
%tr
- %th Page version
- %th Author
- %th Commit Message
- %th Last updated
- %th Format
- %tbody
- - @page.versions.each_with_index do |version, index|
- - commit = version
- %tr
- %td
- = link_to project_wiki_path_with_version(@project, @page,
- commit.id, index == 0) do
- = truncate_sha(commit.id)
- %td
- = commit.author.name
- %td
- = commit.message
- %td
- #{time_ago_with_tooltip(version.authored_date)}
- %td
- %strong
- = @page.page.wiki.page(@page.page.name, commit.id).try(:format)
+ %td
+ = link_to project_wiki_path_with_version(@project, @page,
+ commit.id, index == 0) do
+ = truncate_sha(commit.id)
+ %td
+ = commit.author.name
+ %td
+ = commit.message
+ %td
+ #{time_ago_with_tooltip(version.authored_date)}
+ %td
+ %strong
+ = @page.page.wiki.page(@page.page.name, commit.id).try(:format)
= render 'sidebar'
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index c00967546aa..f003ff6b63f 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -1,32 +1,31 @@
-- @no_container = true
+- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout
- page_title @page.title.capitalize, "Wiki"
-%div{ class: container_class }
- .wiki-page-header.has-sidebar-toggle
- %button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
- = icon('angle-double-left')
+.wiki-page-header.has-sidebar-toggle
+ %button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
+ = icon('angle-double-left')
- .wiki-breadcrumb
- %span= breadcrumb(@page.slug)
+ .wiki-breadcrumb
+ %span= breadcrumb(@page.slug)
- .nav-text
- %h2.wiki-page-title= @page.title.capitalize
- %span.wiki-last-edit-by
- Last edited by
- %strong
- #{@page.commit.author.name}
- #{time_ago_with_tooltip(@page.commit.authored_date)}
+ .nav-text
+ %h2.wiki-page-title= @page.title.capitalize
+ %span.wiki-last-edit-by
+ Last edited by
+ %strong
+ #{@page.commit.author.name}
+ #{time_ago_with_tooltip(@page.commit.authored_date)}
- .nav-controls
- = render 'main_links'
+ .nav-controls
+ = render 'main_links'
- - if @page.historical?
- .warning_message
- This is an old version of this page.
- You can view the #{link_to "most recent version", namespace_project_wiki_path(@project.namespace, @project, @page)} or browse the #{link_to "history", namespace_project_wiki_history_path(@project.namespace, @project, @page)}.
+- if @page.historical?
+ .warning_message
+ This is an old version of this page.
+ You can view the #{link_to "most recent version", namespace_project_wiki_path(@project.namespace, @project, @page)} or browse the #{link_to "history", namespace_project_wiki_history_path(@project.namespace, @project, @page)}.
- .wiki-holder.prepend-top-default.append-bottom-default
- .wiki
- = render_wiki_content(@page)
+.wiki-holder.prepend-top-default.append-bottom-default
+ .wiki
+ = render_wiki_content(@page)
= render 'sidebar'
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 0aad4d0714f..75704eda361 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -19,7 +19,7 @@
= text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true, aria: { label: 'Project clone URL' }
.input-group-btn
- = clipboard_button(target: '#project_clone', title: _("Copy URL to clipboard"))
+ = clipboard_button(target: '#project_clone', title: _("Copy URL to clipboard"), class: "btn-default btn-clipboard")
:javascript
$('ul.clone-options-dropdown a').on('click',function(e){
diff --git a/changelogs/unreleased/32054-rails-should-use-timestamptz-database-type-for-postgresql.yml b/changelogs/unreleased/32054-rails-should-use-timestamptz-database-type-for-postgresql.yml
new file mode 100644
index 00000000000..7fc9e0a4f0e
--- /dev/null
+++ b/changelogs/unreleased/32054-rails-should-use-timestamptz-database-type-for-postgresql.yml
@@ -0,0 +1,4 @@
+---
+title: Add database helpers 'add_timestamps_with_timezone' and 'timestamps_with_timezone'
+merge_request: 11229
+author: @blackst0ne
diff --git a/changelogs/unreleased/feature-add-support-for-services-configuration.yml b/changelogs/unreleased/feature-add-support-for-services-configuration.yml
new file mode 100644
index 00000000000..88a3eacd774
--- /dev/null
+++ b/changelogs/unreleased/feature-add-support-for-services-configuration.yml
@@ -0,0 +1,4 @@
+---
+title: Add support for image and services configuration in .gitlab-ci.yml
+merge_request: 8578
+author:
diff --git a/changelogs/unreleased/fix-github-clone-wiki.yml b/changelogs/unreleased/fix-github-clone-wiki.yml
new file mode 100644
index 00000000000..eadd90e1390
--- /dev/null
+++ b/changelogs/unreleased/fix-github-clone-wiki.yml
@@ -0,0 +1,4 @@
+---
+title: Github - Fix token interpolation when cloning wiki repository
+merge_request:
+author:
diff --git a/changelogs/unreleased/fix-support-for-external-ci-services.yml b/changelogs/unreleased/fix-support-for-external-ci-services.yml
new file mode 100644
index 00000000000..eecb4519259
--- /dev/null
+++ b/changelogs/unreleased/fix-support-for-external-ci-services.yml
@@ -0,0 +1,4 @@
+---
+title: Fix support for external CI services
+merge_request: 11176
+author:
diff --git a/changelogs/unreleased/zj-commit-status-sortable-name.yml b/changelogs/unreleased/zj-commit-status-sortable-name.yml
new file mode 100644
index 00000000000..1be9ac6380f
--- /dev/null
+++ b/changelogs/unreleased/zj-commit-status-sortable-name.yml
@@ -0,0 +1,4 @@
+---
+title: Handle nameless legacy jobs
+merge_request:
+author:
diff --git a/config/initializers/active_record_data_types.rb b/config/initializers/active_record_data_types.rb
new file mode 100644
index 00000000000..beb97c6fce0
--- /dev/null
+++ b/config/initializers/active_record_data_types.rb
@@ -0,0 +1,24 @@
+# ActiveRecord custom data type for storing datetimes with timezone information.
+# See https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11229
+
+if Gitlab::Database.postgresql?
+ require 'active_record/connection_adapters/postgresql_adapter'
+
+ module ActiveRecord
+ module ConnectionAdapters
+ class PostgreSQLAdapter
+ NATIVE_DATABASE_TYPES.merge!(datetime_with_timezone: { name: 'timestamptz' })
+ end
+ end
+ end
+elsif Gitlab::Database.mysql?
+ require 'active_record/connection_adapters/mysql2_adapter'
+
+ module ActiveRecord
+ module ConnectionAdapters
+ class AbstractMysqlAdapter
+ NATIVE_DATABASE_TYPES.merge!(datetime_with_timezone: { name: 'timestamp' })
+ end
+ end
+ end
+end
diff --git a/config/initializers/active_record_table_definition.rb b/config/initializers/active_record_table_definition.rb
new file mode 100644
index 00000000000..4f59e35f4da
--- /dev/null
+++ b/config/initializers/active_record_table_definition.rb
@@ -0,0 +1,24 @@
+# ActiveRecord custom method definitions with timezone information.
+# See https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11229
+
+require 'active_record/connection_adapters/abstract/schema_definitions'
+
+# Appends columns `created_at` and `updated_at` to a table.
+#
+# It is used in table creation like:
+# create_table 'users' do |t|
+# t.timestamps_with_timezone
+# end
+module ActiveRecord
+ module ConnectionAdapters
+ class TableDefinition
+ def timestamps_with_timezone(**options)
+ options[:null] = false if options[:null].nil?
+
+ [:created_at, :updated_at].each do |column_name|
+ column(column_name, :datetime_with_timezone, options)
+ end
+ end
+ end
+ end
+end
diff --git a/db/migrate/20160314114439_add_requested_at_to_members.rb b/db/migrate/20160314114439_add_requested_at_to_members.rb
index 273819d4cd8..76c8b8a1a24 100644
--- a/db/migrate/20160314114439_add_requested_at_to_members.rb
+++ b/db/migrate/20160314114439_add_requested_at_to_members.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
class AddRequestedAtToMembers < ActiveRecord::Migration
def change
add_column :members, :requested_at, :datetime
diff --git a/db/migrate/20160415062917_create_personal_access_tokens.rb b/db/migrate/20160415062917_create_personal_access_tokens.rb
index ce0b33f32bd..c7b49870bf7 100644
--- a/db/migrate/20160415062917_create_personal_access_tokens.rb
+++ b/db/migrate/20160415062917_create_personal_access_tokens.rb
@@ -1,3 +1,5 @@
+# rubocop:disable Migration/Datetime
+# rubocop:disable Migration/Timestamps
class CreatePersonalAccessTokens < ActiveRecord::Migration
def change
create_table :personal_access_tokens do |t|
diff --git a/db/migrate/20160610204157_add_deployments.rb b/db/migrate/20160610204157_add_deployments.rb
index cb144ea8a6d..0e7e6e747a3 100644
--- a/db/migrate/20160610204157_add_deployments.rb
+++ b/db/migrate/20160610204157_add_deployments.rb
@@ -1,6 +1,7 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
+# rubocop:disable Migration/Datetime
class AddDeployments < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20160610204158_add_environments.rb b/db/migrate/20160610204158_add_environments.rb
index e1c71d173c4..699cee2b246 100644
--- a/db/migrate/20160610204158_add_environments.rb
+++ b/db/migrate/20160610204158_add_environments.rb
@@ -1,6 +1,7 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
+# rubocop:disable Migration/Datetime
class AddEnvironments < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20160705054938_add_protected_branches_push_access.rb b/db/migrate/20160705054938_add_protected_branches_push_access.rb
index f27295524e1..97aaaf9d2c8 100644
--- a/db/migrate/20160705054938_add_protected_branches_push_access.rb
+++ b/db/migrate/20160705054938_add_protected_branches_push_access.rb
@@ -1,6 +1,7 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
+# rubocop:disable Migration/Timestamps
class AddProtectedBranchesPushAccess < ActiveRecord::Migration
DOWNTIME = false
diff --git a/db/migrate/20160705054952_add_protected_branches_merge_access.rb b/db/migrate/20160705054952_add_protected_branches_merge_access.rb
index 32adfa266cd..51a52a5ac17 100644
--- a/db/migrate/20160705054952_add_protected_branches_merge_access.rb
+++ b/db/migrate/20160705054952_add_protected_branches_merge_access.rb
@@ -1,6 +1,7 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
+# rubocop:disable Migration/Timestamps
class AddProtectedBranchesMergeAccess < ActiveRecord::Migration
DOWNTIME = false
diff --git a/db/migrate/20160724205507_add_resolved_to_notes.rb b/db/migrate/20160724205507_add_resolved_to_notes.rb
index b8ebcdbd156..3aca272a3f7 100644
--- a/db/migrate/20160724205507_add_resolved_to_notes.rb
+++ b/db/migrate/20160724205507_add_resolved_to_notes.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
class AddResolvedToNotes < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20160727163552_create_user_agent_details.rb b/db/migrate/20160727163552_create_user_agent_details.rb
index ed4ccfedc0a..3eb36f8464f 100644
--- a/db/migrate/20160727163552_create_user_agent_details.rb
+++ b/db/migrate/20160727163552_create_user_agent_details.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateUserAgentDetails < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20160727191041_create_boards.rb b/db/migrate/20160727191041_create_boards.rb
index 56afbd4e030..9ec8df1b8e8 100644
--- a/db/migrate/20160727191041_create_boards.rb
+++ b/db/migrate/20160727191041_create_boards.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateBoards < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20160727193336_create_lists.rb b/db/migrate/20160727193336_create_lists.rb
index 61d501215f2..3fd95dc8cfc 100644
--- a/db/migrate/20160727193336_create_lists.rb
+++ b/db/migrate/20160727193336_create_lists.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateLists < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20160805041956_add_deleted_at_to_namespaces.rb b/db/migrate/20160805041956_add_deleted_at_to_namespaces.rb
index 30d98a0124e..404c253e18b 100644
--- a/db/migrate/20160805041956_add_deleted_at_to_namespaces.rb
+++ b/db/migrate/20160805041956_add_deleted_at_to_namespaces.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
# rubocop:disable RemoveIndex
class AddDeletedAtToNamespaces < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20160824124900_add_table_issue_metrics.rb b/db/migrate/20160824124900_add_table_issue_metrics.rb
index e9bb79b3c62..30d35ef1db2 100644
--- a/db/migrate/20160824124900_add_table_issue_metrics.rb
+++ b/db/migrate/20160824124900_add_table_issue_metrics.rb
@@ -1,6 +1,8 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
+# rubocop:disable Migration/Datetime
+# rubocop:disable Migration/Timestamps
class AddTableIssueMetrics < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20160825052008_add_table_merge_request_metrics.rb b/db/migrate/20160825052008_add_table_merge_request_metrics.rb
index e01cc5038b9..56b39634dfd 100644
--- a/db/migrate/20160825052008_add_table_merge_request_metrics.rb
+++ b/db/migrate/20160825052008_add_table_merge_request_metrics.rb
@@ -1,6 +1,8 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
+# rubocop:disable Migration/Datetime
+# rubocop:disable Migration/Timestamps
class AddTableMergeRequestMetrics < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20160831214002_create_project_features.rb b/db/migrate/20160831214002_create_project_features.rb
index 343953826f0..7ac6c8ec654 100644
--- a/db/migrate/20160831214002_create_project_features.rb
+++ b/db/migrate/20160831214002_create_project_features.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateProjectFeatures < ActiveRecord::Migration
DOWNTIME = false
diff --git a/db/migrate/20160915042921_create_merge_requests_closing_issues.rb b/db/migrate/20160915042921_create_merge_requests_closing_issues.rb
index 94874a853da..10c5604bb5c 100644
--- a/db/migrate/20160915042921_create_merge_requests_closing_issues.rb
+++ b/db/migrate/20160915042921_create_merge_requests_closing_issues.rb
@@ -1,6 +1,7 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
+# rubocop:disable Migration/Timestamps
class CreateMergeRequestsClosingIssues < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20161014173530_create_label_priorities.rb b/db/migrate/20161014173530_create_label_priorities.rb
index 2c22841c28a..28937c81e02 100644
--- a/db/migrate/20161014173530_create_label_priorities.rb
+++ b/db/migrate/20161014173530_create_label_priorities.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateLabelPriorities < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20161113184239_create_user_chat_names_table.rb b/db/migrate/20161113184239_create_user_chat_names_table.rb
index 97b597654f7..62ccb599f2e 100644
--- a/db/migrate/20161113184239_create_user_chat_names_table.rb
+++ b/db/migrate/20161113184239_create_user_chat_names_table.rb
@@ -1,3 +1,5 @@
+# rubocop:disable Migration/Datetime
+# rubocop:disable Migration/Timestamps
class CreateUserChatNamesTable < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20161124111402_add_routes_table.rb b/db/migrate/20161124111402_add_routes_table.rb
index a02e046a18e..f5241d906d1 100644
--- a/db/migrate/20161124111402_add_routes_table.rb
+++ b/db/migrate/20161124111402_add_routes_table.rb
@@ -1,6 +1,7 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
+# rubocop:disable Migration/Timestamps
class AddRoutesTable < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20161221152132_add_last_used_at_to_key.rb b/db/migrate/20161221152132_add_last_used_at_to_key.rb
index fb2b15817de..86dc7870247 100644
--- a/db/migrate/20161221152132_add_last_used_at_to_key.rb
+++ b/db/migrate/20161221152132_add_last_used_at_to_key.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
class AddLastUsedAtToKey < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20161223034646_create_timelogs_ce.rb b/db/migrate/20161223034646_create_timelogs_ce.rb
index 66d9cd823fb..1e894cc9161 100644
--- a/db/migrate/20161223034646_create_timelogs_ce.rb
+++ b/db/migrate/20161223034646_create_timelogs_ce.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateTimelogsCe < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20161228124936_change_expires_at_to_date_in_personal_access_tokens.rb b/db/migrate/20161228124936_change_expires_at_to_date_in_personal_access_tokens.rb
index af1bac897cc..16f7cc487ce 100644
--- a/db/migrate/20161228124936_change_expires_at_to_date_in_personal_access_tokens.rb
+++ b/db/migrate/20161228124936_change_expires_at_to_date_in_personal_access_tokens.rb
@@ -1,6 +1,7 @@
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
+# rubocop:disable Migration/Datetime
class ChangeExpiresAtToDateInPersonalAccessTokens < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20170120131253_create_chat_teams.rb b/db/migrate/20170120131253_create_chat_teams.rb
index 7995d383986..52208821911 100644
--- a/db/migrate/20170120131253_create_chat_teams.rb
+++ b/db/migrate/20170120131253_create_chat_teams.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateChatTeams < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20170130221926_create_uploads.rb b/db/migrate/20170130221926_create_uploads.rb
index 6f06c5dd840..4d9fa0bb692 100644
--- a/db/migrate/20170130221926_create_uploads.rb
+++ b/db/migrate/20170130221926_create_uploads.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
class CreateUploads < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20170222143317_drop_ci_projects.rb b/db/migrate/20170222143317_drop_ci_projects.rb
index 4db8658f36f..9973e53501c 100644
--- a/db/migrate/20170222143317_drop_ci_projects.rb
+++ b/db/migrate/20170222143317_drop_ci_projects.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
class DropCiProjects < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20170301205639_remove_unused_ci_tables_and_columns.rb b/db/migrate/20170301205639_remove_unused_ci_tables_and_columns.rb
index 69dd15b8b4e..1a77d5934a3 100644
--- a/db/migrate/20170301205639_remove_unused_ci_tables_and_columns.rb
+++ b/db/migrate/20170301205639_remove_unused_ci_tables_and_columns.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
class RemoveUnusedCiTablesAndColumns < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20170309173138_create_protected_tags.rb b/db/migrate/20170309173138_create_protected_tags.rb
index 796f3c90344..4684c9964c4 100644
--- a/db/migrate/20170309173138_create_protected_tags.rb
+++ b/db/migrate/20170309173138_create_protected_tags.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateProtectedTags < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20170314082049_create_system_note_metadata.rb b/db/migrate/20170314082049_create_system_note_metadata.rb
index dd1e6cf8172..fee47e96053 100644
--- a/db/migrate/20170314082049_create_system_note_metadata.rb
+++ b/db/migrate/20170314082049_create_system_note_metadata.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateSystemNoteMetadata < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20170315194013_add_closed_at_to_issues.rb b/db/migrate/20170315194013_add_closed_at_to_issues.rb
index 1326118cc8d..34a1bd7ca8c 100644
--- a/db/migrate/20170315194013_add_closed_at_to_issues.rb
+++ b/db/migrate/20170315194013_add_closed_at_to_issues.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
class AddClosedAtToIssues < ActiveRecord::Migration
DOWNTIME = false
diff --git a/db/migrate/20170322013926_create_container_repository.rb b/db/migrate/20170322013926_create_container_repository.rb
index 91540bc88bd..242f7b8d17d 100644
--- a/db/migrate/20170322013926_create_container_repository.rb
+++ b/db/migrate/20170322013926_create_container_repository.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateContainerRepository < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20170329095907_create_ci_trigger_schedules.rb b/db/migrate/20170329095907_create_ci_trigger_schedules.rb
index cfcfa27ebb5..06a2010db23 100644
--- a/db/migrate/20170329095907_create_ci_trigger_schedules.rb
+++ b/db/migrate/20170329095907_create_ci_trigger_schedules.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
class CreateCiTriggerSchedules < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20170425112128_create_pipeline_schedules_table.rb b/db/migrate/20170425112128_create_pipeline_schedules_table.rb
index 3612a796ae8..57df47f5f42 100644
--- a/db/migrate/20170425112128_create_pipeline_schedules_table.rb
+++ b/db/migrate/20170425112128_create_pipeline_schedules_table.rb
@@ -1,3 +1,5 @@
+# rubocop:disable Migration/Datetime
+# rubocop:disable Migration/Timestamps
class CreatePipelineSchedulesTable < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/migrate/20170427215854_create_redirect_routes.rb b/db/migrate/20170427215854_create_redirect_routes.rb
index 2bf086b3e30..6db508e5db4 100644
--- a/db/migrate/20170427215854_create_redirect_routes.rb
+++ b/db/migrate/20170427215854_create_redirect_routes.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateRedirectRoutes < ActiveRecord::Migration
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
diff --git a/db/migrate/20170503004125_add_last_repository_updated_at_to_projects.rb b/db/migrate/20170503004125_add_last_repository_updated_at_to_projects.rb
index 00c685cf342..2ea49f62742 100644
--- a/db/migrate/20170503004125_add_last_repository_updated_at_to_projects.rb
+++ b/db/migrate/20170503004125_add_last_repository_updated_at_to_projects.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
class AddLastRepositoryUpdatedAtToProjects < ActiveRecord::Migration
DOWNTIME = false
diff --git a/db/migrate/20170523121229_create_conversational_development_index_metrics.rb b/db/migrate/20170523121229_create_conversational_development_index_metrics.rb
index 9f9ec526055..7026a867ae1 100644
--- a/db/migrate/20170523121229_create_conversational_development_index_metrics.rb
+++ b/db/migrate/20170523121229_create_conversational_development_index_metrics.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreateConversationalDevelopmentIndexMetrics < ActiveRecord::Migration
DOWNTIME = false
diff --git a/db/migrate/20170525132202_create_pipeline_stages.rb b/db/migrate/20170525132202_create_pipeline_stages.rb
index 25656f2a2c2..825993aa41e 100644
--- a/db/migrate/20170525132202_create_pipeline_stages.rb
+++ b/db/migrate/20170525132202_create_pipeline_stages.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Timestamps
class CreatePipelineStages < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/db/post_migrate/20170425130047_drop_ci_trigger_schedules_table.rb b/db/post_migrate/20170425130047_drop_ci_trigger_schedules_table.rb
index 24750c58ef0..159b533eaaa 100644
--- a/db/post_migrate/20170425130047_drop_ci_trigger_schedules_table.rb
+++ b/db/post_migrate/20170425130047_drop_ci_trigger_schedules_table.rb
@@ -1,3 +1,4 @@
+# rubocop:disable Migration/Datetime
class DropCiTriggerSchedulesTable < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 77ba2a5fd87..161d2544169 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -122,7 +122,7 @@ limit can vary from installation to installation. As a result it's recommended
you do not use more than 32 threads in a single migration. Usually 4-8 threads
should be more than enough.
-## Removing indices
+## Removing indexes
When removing an index make sure to use the method `remove_concurrent_index` instead
of the regular `remove_index` method. The `remove_concurrent_index` method
@@ -142,7 +142,7 @@ class MyMigration < ActiveRecord::Migration
end
```
-## Adding indices
+## Adding indexes
If you need to add a unique index please keep in mind there is the possibility
of existing duplicates being present in the database. This means that should
@@ -222,6 +222,41 @@ add_column_with_default(:projects, :foo, :integer, default: 10, limit: 8)
add_column(:projects, :foo, :integer, default: 10, limit: 8)
```
+## Timestamp column type
+
+By default, Rails uses the `timestamp` data type that stores timestamp data without timezone information.
+The `timestamp` data type is used by calling either the `add_timestamps` or the `timestamps` method.
+Also Rails converts the `:datetime` data type to the `timestamp` one.
+
+Example:
+
+```ruby
+# timestamps
+create_table :users do |t|
+ t.timestamps
+end
+
+# add_timestamps
+def up
+ add_timestamps :users
+end
+
+# :datetime
+def up
+ add_column :users, :last_sign_in, :datetime
+end
+```
+
+Instead of using these methods one should use the following methods to store timestamps with timezones:
+
+* `add_timestamps_with_timezone`
+* `timestamps_with_timezone`
+
+This ensures all timestamps have a time zone specified. This in turn means existing timestamps won't
+suddenly use a different timezone when the system's timezone changes. It also makes it very clear which
+timezone was used in the first place.
+
+
## Testing
Make sure that your migration works with MySQL and PostgreSQL with data. An
diff --git a/doc/install/kubernetes/index.md b/doc/install/kubernetes/index.md
index 88c56a1d17c..5ea08869a9b 100644
--- a/doc/install/kubernetes/index.md
+++ b/doc/install/kubernetes/index.md
@@ -1,7 +1,7 @@
# Installing GitLab on Kubernetes
> Officially supported cloud providers are Google Container Service and Azure Container Service.
-> Officially supported schedulers are Kubernetes and Terraform.
+> Officially supported schedulers are Kubernetes, Terraform and Tectonic.
The easiest method to deploy GitLab in [Kubernetes](https://kubernetes.io/) is
to take advantage of the official GitLab Helm charts. [Helm] is a package
diff --git a/features/steps/project/issues/award_emoji.rb b/features/steps/project/issues/award_emoji.rb
index dfd0bc13305..2324edda975 100644
--- a/features/steps/project/issues/award_emoji.rb
+++ b/features/steps/project/issues/award_emoji.rb
@@ -34,8 +34,8 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
page.within '.awards' do
expect do
page.find('.js-emoji-btn.active').click
- sleep 0.3
- end.to change{ page.all(".award-control.js-emoji-btn").size }.from(3).to(2)
+ wait_for_requests
+ end.to change { page.all(".award-control.js-emoji-btn").size }.from(3).to(2)
end
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index a836df3dc81..af55c372eea 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -804,7 +804,11 @@ module API
end
class Image < Grape::Entity
- expose :name
+ expose :name, :entrypoint
+ end
+
+ class Service < Image
+ expose :alias, :command
end
class Artifacts < Grape::Entity
@@ -848,7 +852,7 @@ module API
expose :variables
expose :steps, using: Step
expose :image, using: Image
- expose :services, using: Image
+ expose :services, using: Service
expose :artifacts, using: Artifacts
expose :cache, using: Cache
expose :credentials, using: Credentials
diff --git a/lib/ci/api/entities.rb b/lib/ci/api/entities.rb
index 792ff628b09..6b82b2b4f13 100644
--- a/lib/ci/api/entities.rb
+++ b/lib/ci/api/entities.rb
@@ -45,7 +45,21 @@ module Ci
expose :artifacts_expire_at, if: ->(build, _) { build.artifacts? }
expose :options do |model|
- model.options
+ # This part ensures that output of old API is still the same after adding support
+ # for extended docker configuration options, used by new API
+ #
+ # I'm leaving this here, not in the model, because it should be removed at the same time
+ # when old API will be removed (planned for August 2017).
+ model.options.dup.tap do |options|
+ options[:image] = options[:image][:name] if options[:image].is_a?(Hash)
+ options[:services].map! do |service|
+ if service.is_a?(Hash)
+ service[:name]
+ else
+ service
+ end
+ end
+ end
end
expose :timeout do |model|
diff --git a/lib/github/import.rb b/lib/github/import.rb
index 9c7eb965f93..b20614b3060 100644
--- a/lib/github/import.rb
+++ b/lib/github/import.rb
@@ -92,7 +92,7 @@ module Github
end
def fetch_wiki_repository
- wiki_url = "https://{options.fetch(:token)}@github.com/#{repo}.wiki.git"
+ wiki_url = "https://#{options.fetch(:token)}@github.com/#{repo}.wiki.git"
wiki_path = "#{project.path_with_namespace}.wiki"
unless project.wiki.repository_exists?
diff --git a/lib/gitlab/ci/build/image.rb b/lib/gitlab/ci/build/image.rb
index c62aeb60fa9..b88b2e36d53 100644
--- a/lib/gitlab/ci/build/image.rb
+++ b/lib/gitlab/ci/build/image.rb
@@ -2,7 +2,7 @@ module Gitlab
module Ci
module Build
class Image
- attr_reader :name
+ attr_reader :alias, :command, :entrypoint, :name
class << self
def from_image(job)
@@ -21,7 +21,14 @@ module Gitlab
end
def initialize(image)
- @name = image
+ if image.is_a?(String)
+ @name = image
+ elsif image.is_a?(Hash)
+ @alias = image[:alias]
+ @command = image[:command]
+ @entrypoint = image[:entrypoint]
+ @name = image[:name]
+ end
end
def valid?
diff --git a/lib/gitlab/ci/config/entry/image.rb b/lib/gitlab/ci/config/entry/image.rb
index b5050257688..897dcff8012 100644
--- a/lib/gitlab/ci/config/entry/image.rb
+++ b/lib/gitlab/ci/config/entry/image.rb
@@ -8,8 +8,36 @@ module Gitlab
class Image < Node
include Validatable
+ ALLOWED_KEYS = %i[name entrypoint].freeze
+
validations do
- validates :config, type: String
+ validates :config, hash_or_string: true
+ validates :config, allowed_keys: ALLOWED_KEYS
+
+ validates :name, type: String, presence: true
+ validates :entrypoint, type: String, allow_nil: true
+ end
+
+ def hash?
+ @config.is_a?(Hash)
+ end
+
+ def string?
+ @config.is_a?(String)
+ end
+
+ def name
+ value[:name]
+ end
+
+ def entrypoint
+ value[:entrypoint]
+ end
+
+ def value
+ return { name: @config } if string?
+ return @config if hash?
+ {}
end
end
end
diff --git a/lib/gitlab/ci/config/entry/service.rb b/lib/gitlab/ci/config/entry/service.rb
new file mode 100644
index 00000000000..b52faf48b58
--- /dev/null
+++ b/lib/gitlab/ci/config/entry/service.rb
@@ -0,0 +1,34 @@
+module Gitlab
+ module Ci
+ class Config
+ module Entry
+ ##
+ # Entry that represents a configuration of Docker service.
+ #
+ class Service < Image
+ include Validatable
+
+ ALLOWED_KEYS = %i[name entrypoint command alias].freeze
+
+ validations do
+ validates :config, hash_or_string: true
+ validates :config, allowed_keys: ALLOWED_KEYS
+
+ validates :name, type: String, presence: true
+ validates :entrypoint, type: String, allow_nil: true
+ validates :command, type: String, allow_nil: true
+ validates :alias, type: String, allow_nil: true
+ end
+
+ def alias
+ value[:alias]
+ end
+
+ def command
+ value[:command]
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/entry/services.rb b/lib/gitlab/ci/config/entry/services.rb
index 84f8ab780f5..0066894e069 100644
--- a/lib/gitlab/ci/config/entry/services.rb
+++ b/lib/gitlab/ci/config/entry/services.rb
@@ -9,7 +9,30 @@ module Gitlab
include Validatable
validations do
- validates :config, array_of_strings: true
+ validates :config, type: Array
+ end
+
+ def compose!(deps = nil)
+ super do
+ @entries = []
+ @config.each do |config|
+ @entries << Entry::Factory.new(Entry::Service)
+ .value(config || {})
+ .create!
+ end
+
+ @entries.each do |entry|
+ entry.compose!(deps)
+ end
+ end
+ end
+
+ def value
+ @entries.map(&:value)
+ end
+
+ def descendants
+ @entries
end
end
end
diff --git a/lib/gitlab/ci/config/entry/validators.rb b/lib/gitlab/ci/config/entry/validators.rb
index bd7428b1272..b2ca3c881e4 100644
--- a/lib/gitlab/ci/config/entry/validators.rb
+++ b/lib/gitlab/ci/config/entry/validators.rb
@@ -44,6 +44,14 @@ module Gitlab
end
end
+ class HashOrStringValidator < ActiveModel::EachValidator
+ def validate_each(record, attribute, value)
+ unless value.is_a?(Hash) || value.is_a?(String)
+ record.errors.add(attribute, 'should be a hash or a string')
+ end
+ end
+ end
+
class KeyValidator < ActiveModel::EachValidator
include LegacyValidationHelpers
diff --git a/lib/gitlab/ci/status/external/common.rb b/lib/gitlab/ci/status/external/common.rb
index 4969a350862..9307545b5b1 100644
--- a/lib/gitlab/ci/status/external/common.rb
+++ b/lib/gitlab/ci/status/external/common.rb
@@ -3,6 +3,10 @@ module Gitlab
module Status
module External
module Common
+ def label
+ subject.description
+ end
+
def has_details?
subject.target_url.present? &&
can?(user, :read_commit_status, subject)
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index a412bb6dbd2..cd85f961242 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -1,6 +1,39 @@
module Gitlab
module Database
module MigrationHelpers
+ # Adds `created_at` and `updated_at` columns with timezone information.
+ #
+ # This method is an improved version of Rails' built-in method `add_timestamps`.
+ #
+ # Available options are:
+ # default - The default value for the column.
+ # null - When set to `true` the column will allow NULL values.
+ # The default is to not allow NULL values.
+ def add_timestamps_with_timezone(table_name, options = {})
+ options[:null] = false if options[:null].nil?
+
+ [:created_at, :updated_at].each do |column_name|
+ if options[:default] && transaction_open?
+ raise '`add_timestamps_with_timezone` with default value cannot be run inside a transaction. ' \
+ 'You can disable transactions by calling `disable_ddl_transaction!` ' \
+ 'in the body of your migration class'
+ end
+
+ # If default value is presented, use `add_column_with_default` method instead.
+ if options[:default]
+ add_column_with_default(
+ table_name,
+ column_name,
+ :datetime_with_timezone,
+ default: options[:default],
+ allow_null: options[:null]
+ )
+ else
+ add_column(table_name, column_name, :datetime_with_timezone, options)
+ end
+ end
+ end
+
# Creates a new index, concurrently when supported
#
# On PostgreSQL this method creates an index concurrently, on MySQL this
diff --git a/rubocop/cop/migration/add_timestamps.rb b/rubocop/cop/migration/add_timestamps.rb
new file mode 100644
index 00000000000..08ddd91e54d
--- /dev/null
+++ b/rubocop/cop/migration/add_timestamps.rb
@@ -0,0 +1,25 @@
+require_relative '../../migration_helpers'
+
+module RuboCop
+ module Cop
+ module Migration
+ # Cop that checks if 'add_timestamps' method is called with timezone information.
+ class AddTimestamps < RuboCop::Cop::Cop
+ include MigrationHelpers
+
+ MSG = 'Do not use `add_timestamps`, use `add_timestamps_with_timezone` instead'.freeze
+
+ # Check methods.
+ def on_send(node)
+ return unless in_migration?(node)
+
+ add_offense(node, :selector) if method_name(node) == :add_timestamps
+ end
+
+ def method_name(node)
+ node.children[1]
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/migration/datetime.rb b/rubocop/cop/migration/datetime.rb
new file mode 100644
index 00000000000..651935dd53e
--- /dev/null
+++ b/rubocop/cop/migration/datetime.rb
@@ -0,0 +1,36 @@
+require_relative '../../migration_helpers'
+
+module RuboCop
+ module Cop
+ module Migration
+ # Cop that checks if datetime data type is added with timezone information.
+ class Datetime < RuboCop::Cop::Cop
+ include MigrationHelpers
+
+ MSG = 'Do not use the `datetime` data type, use `datetime_with_timezone` instead'.freeze
+
+ # Check methods in table creation.
+ def on_def(node)
+ return unless in_migration?(node)
+
+ node.each_descendant(:send) do |send_node|
+ add_offense(send_node, :selector) if method_name(send_node) == :datetime
+ end
+ end
+
+ # Check methods.
+ def on_send(node)
+ return unless in_migration?(node)
+
+ node.each_descendant do |descendant|
+ add_offense(node, :expression) if descendant.type == :sym && descendant.children.last == :datetime
+ end
+ end
+
+ def method_name(node)
+ node.children[1]
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/migration/timestamps.rb b/rubocop/cop/migration/timestamps.rb
new file mode 100644
index 00000000000..71a9420cc3b
--- /dev/null
+++ b/rubocop/cop/migration/timestamps.rb
@@ -0,0 +1,27 @@
+require_relative '../../migration_helpers'
+
+module RuboCop
+ module Cop
+ module Migration
+ # Cop that checks if 'timestamps' method is called with timezone information.
+ class Timestamps < RuboCop::Cop::Cop
+ include MigrationHelpers
+
+ MSG = 'Do not use `timestamps`, use `timestamps_with_timezone` instead'.freeze
+
+ # Check methods in table creation.
+ def on_def(node)
+ return unless in_migration?(node)
+
+ node.each_descendant(:send) do |send_node|
+ add_offense(send_node, :selector) if method_name(send_node) == :timestamps
+ end
+ end
+
+ def method_name(node)
+ node.children[1]
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index dae30969abf..6b8d127dde6 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -8,7 +8,10 @@ require_relative 'cop/migration/add_column_with_default_to_large_table'
require_relative 'cop/migration/add_concurrent_foreign_key'
require_relative 'cop/migration/add_concurrent_index'
require_relative 'cop/migration/add_index'
+require_relative 'cop/migration/add_timestamps'
+require_relative 'cop/migration/datetime'
require_relative 'cop/migration/remove_concurrent_index'
require_relative 'cop/migration/remove_index'
require_relative 'cop/migration/reversible_add_column_with_default'
+require_relative 'cop/migration/timestamps'
require_relative 'cop/migration/update_column_in_batches'
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 954f89e3854..734532668d3 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -5,9 +5,12 @@ describe Projects::PipelinesController do
let(:user) { create(:user) }
let(:project) { create(:empty_project, :public) }
+ let(:feature) { ProjectFeature::DISABLED }
before do
project.add_developer(user)
+ project.project_feature.update(
+ builds_access_level: feature)
sign_in(user)
end
@@ -153,16 +156,26 @@ describe Projects::PipelinesController do
format: :json
end
- it 'retries a pipeline without returning any content' do
- expect(response).to have_http_status(:no_content)
- expect(build.reload).to be_retried
+ 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
+ end
+ end
+
+ context 'when builds are disabled' do
+ it 'fails to retry pipeline' do
+ expect(response).to have_http_status(:not_found)
+ end
end
end
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,
@@ -170,9 +183,19 @@ describe Projects::PipelinesController do
format: :json
end
- it 'cancels a pipeline without returning any content' do
- expect(response).to have_http_status(:no_content)
- expect(pipeline.reload).to be_canceled
+ 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
+ end
+ end
+
+ context 'when builds are disabled' do
+ it 'fails to retry pipeline' do
+ expect(response).to have_http_status(:not_found)
+ end
end
end
end
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 0bb5a86d9b9..0cc498f0ce9 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -194,8 +194,8 @@ FactoryGirl.define do
trait :extended_options do
options do
{
- image: 'ruby:2.1',
- services: ['postgres'],
+ image: { name: 'ruby:2.1', entrypoint: '/bin/sh' },
+ services: ['postgres', { name: 'docker:dind', entrypoint: '/bin/sh', command: 'sleep 30', alias: 'docker' }],
after_script: %w(ls date),
artifacts: {
name: 'artifacts_file',
diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb
index c49648f54bd..d76b5e4ef1b 100644
--- a/spec/features/projects/features_visibility_spec.rb
+++ b/spec/features/projects/features_visibility_spec.rb
@@ -68,9 +68,12 @@ describe 'Edit Project Settings', feature: true do
end
describe 'project features visibility pages' do
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
+ let(:job) { create(:ci_build, pipeline: pipeline) }
+
let(:tools) do
{
- builds: namespace_project_pipelines_path(project.namespace, project),
+ builds: namespace_project_job_path(project.namespace, project, job),
issues: namespace_project_issues_path(project.namespace, project),
wiki: namespace_project_wiki_path(project.namespace, project, :home),
snippets: namespace_project_snippets_path(project.namespace, project),
diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb
index 317949d6b56..2d43f7a10bc 100644
--- a/spec/features/projects/pipeline_schedules_spec.rb
+++ b/spec/features/projects/pipeline_schedules_spec.rb
@@ -127,7 +127,7 @@ feature 'Pipeline Schedules', :feature do
end
it 'shows the pipeline schedule with default ref' do
- page.within('.git-revision-dropdown-toggle') do
+ page.within('.js-target-branch-dropdown') do
expect(first('.dropdown-toggle-text').text).to eq('master')
end
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index a695621b87a..3ed0b0a756b 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -300,4 +300,37 @@ describe ProjectsHelper do
expect(helper.send(:visibility_select_options, project, Gitlab::VisibilityLevel::PRIVATE)).to include('Private')
end
end
+
+ describe '#get_project_nav_tabs' do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+
+ before do
+ allow(helper).to receive(:can?) { true }
+ end
+
+ subject do
+ helper.send(:get_project_nav_tabs, project, user)
+ end
+
+ context 'when builds feature is enabled' do
+ before do
+ allow(project).to receive(:builds_enabled?).and_return(true)
+ end
+
+ it "does include pipelines tab" do
+ is_expected.to include(:pipelines)
+ end
+ end
+
+ context 'when builds feature is disabled' do
+ before do
+ allow(project).to receive(:builds_enabled?).and_return(false)
+ end
+
+ it "do not include pipelines tab" do
+ is_expected.not_to include(:pipelines)
+ end
+ end
+ end
end
diff --git a/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js b/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js
index bf28019ef24..f3b4adc0b70 100644
--- a/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js
+++ b/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js
@@ -22,7 +22,7 @@ describe('Time ago with tooltip component', () => {
}).$mount();
expect(vm.$el.tagName).toEqual('TIME');
- expect(vm.$el.classList.contains('js-timeago')).toEqual(true);
+ expect(vm.$el.classList.contains('js-vue-timeago')).toEqual(true);
expect(
vm.$el.getAttribute('data-original-title'),
).toEqual(gl.utils.formatDate('2017-05-08T14:57:39.781Z'));
@@ -44,17 +44,6 @@ describe('Time ago with tooltip component', () => {
expect(vm.$el.getAttribute('data-placement')).toEqual('bottom');
});
- it('should render short format class', () => {
- vm = new TimeagoTooltip({
- propsData: {
- time: '2017-05-08T14:57:39.781Z',
- shortFormat: true,
- },
- }).$mount();
-
- expect(vm.$el.classList.contains('js-short-timeago')).toEqual(true);
- });
-
it('should render provided html class', () => {
vm = new TimeagoTooltip({
propsData: {
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index 2ca0773ad1d..af0e7855a9b 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -596,62 +596,117 @@ module Ci
end
describe "Image and service handling" do
- it "returns image and service when defined" do
- config = YAML.dump({
- image: "ruby:2.1",
- services: ["mysql"],
- before_script: ["pwd"],
- rspec: { script: "rspec" }
- })
+ context "when extended docker configuration is used" do
+ it "returns image and service when defined" do
+ config = YAML.dump({ image: { name: "ruby:2.1" },
+ services: ["mysql", { name: "docker:dind", alias: "docker" }],
+ before_script: ["pwd"],
+ rspec: { script: "rspec" } })
- config_processor = GitlabCiYamlProcessor.new(config, path)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
- expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
- expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
- stage: "test",
- stage_idx: 1,
- name: "rspec",
- commands: "pwd\nrspec",
- coverage_regex: nil,
- tag_list: [],
- options: {
- image: "ruby:2.1",
- services: ["mysql"]
- },
- allow_failure: false,
- when: "on_success",
- environment: nil,
- yaml_variables: []
- })
+ expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
+ expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
+ stage: "test",
+ stage_idx: 1,
+ name: "rspec",
+ commands: "pwd\nrspec",
+ coverage_regex: nil,
+ tag_list: [],
+ options: {
+ image: { name: "ruby:2.1" },
+ services: [{ name: "mysql" }, { name: "docker:dind", alias: "docker" }]
+ },
+ allow_failure: false,
+ when: "on_success",
+ environment: nil,
+ yaml_variables: []
+ })
+ end
+
+ it "returns image and service when overridden for job" do
+ config = YAML.dump({ image: "ruby:2.1",
+ services: ["mysql"],
+ before_script: ["pwd"],
+ rspec: { image: { name: "ruby:2.5" },
+ services: [{ name: "postgresql", alias: "db-pg" }, "docker:dind"], script: "rspec" } })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
+ expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
+ stage: "test",
+ stage_idx: 1,
+ name: "rspec",
+ commands: "pwd\nrspec",
+ coverage_regex: nil,
+ tag_list: [],
+ options: {
+ image: { name: "ruby:2.5" },
+ services: [{ name: "postgresql", alias: "db-pg" }, { name: "docker:dind" }]
+ },
+ allow_failure: false,
+ when: "on_success",
+ environment: nil,
+ yaml_variables: []
+ })
+ end
end
- it "returns image and service when overridden for job" do
- config = YAML.dump({
- image: "ruby:2.1",
- services: ["mysql"],
- before_script: ["pwd"],
- rspec: { image: "ruby:2.5", services: ["postgresql"], script: "rspec" }
- })
+ context "when etended docker configuration is not used" do
+ it "returns image and service when defined" do
+ config = YAML.dump({ image: "ruby:2.1",
+ services: ["mysql", "docker:dind"],
+ before_script: ["pwd"],
+ rspec: { script: "rspec" } })
- config_processor = GitlabCiYamlProcessor.new(config, path)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
- expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
- expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
- stage: "test",
- stage_idx: 1,
- name: "rspec",
- commands: "pwd\nrspec",
- coverage_regex: nil,
- tag_list: [],
- options: {
- image: "ruby:2.5",
- services: ["postgresql"]
- },
- allow_failure: false,
- when: "on_success",
- environment: nil,
- yaml_variables: []
- })
+ expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
+ expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
+ stage: "test",
+ stage_idx: 1,
+ name: "rspec",
+ commands: "pwd\nrspec",
+ coverage_regex: nil,
+ tag_list: [],
+ options: {
+ image: { name: "ruby:2.1" },
+ services: [{ name: "mysql" }, { name: "docker:dind" }]
+ },
+ allow_failure: false,
+ when: "on_success",
+ environment: nil,
+ yaml_variables: []
+ })
+ end
+
+ it "returns image and service when overridden for job" do
+ config = YAML.dump({ image: "ruby:2.1",
+ services: ["mysql"],
+ before_script: ["pwd"],
+ rspec: { image: "ruby:2.5", services: ["postgresql", "docker:dind"], script: "rspec" } })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
+ expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
+ stage: "test",
+ stage_idx: 1,
+ name: "rspec",
+ commands: "pwd\nrspec",
+ coverage_regex: nil,
+ tag_list: [],
+ options: {
+ image: { name: "ruby:2.5" },
+ services: [{ name: "postgresql" }, { name: "docker:dind" }]
+ },
+ allow_failure: false,
+ when: "on_success",
+ environment: nil,
+ yaml_variables: []
+ })
+ end
end
end
@@ -884,8 +939,8 @@ module Ci
coverage_regex: nil,
tag_list: [],
options: {
- image: "ruby:2.1",
- services: ["mysql"],
+ image: { name: "ruby:2.1" },
+ services: [{ name: "mysql" }],
artifacts: {
name: "custom_name",
paths: ["logs/", "binaries/"],
@@ -1261,7 +1316,7 @@ EOT
config = YAML.dump({ image: ["test"], rspec: { script: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "image config should be a string")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "image config should be a hash or a string")
end
it "returns errors if job name is blank" do
@@ -1282,35 +1337,35 @@ EOT
config = YAML.dump({ rspec: { script: "test", image: ["test"] } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:image config should be a string")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:image config should be a hash or a string")
end
it "returns errors if services parameter is not an array" do
config = YAML.dump({ services: "test", rspec: { script: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services config should be an array of strings")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services config should be a array")
end
it "returns errors if services parameter is not an array of strings" do
config = YAML.dump({ services: [10, "test"], rspec: { script: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services config should be an array of strings")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "service config should be a hash or a string")
end
it "returns errors if job services parameter is not an array" do
config = YAML.dump({ rspec: { script: "test", services: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:services config should be an array of strings")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:services config should be a array")
end
it "returns errors if job services parameter is not an array of strings" do
config = YAML.dump({ rspec: { script: "test", services: [10, "test"] } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:services config should be an array of strings")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "service config should be a hash or a string")
end
it "returns error if job configuration is invalid" do
@@ -1324,7 +1379,7 @@ EOT
config = YAML.dump({ extra: { script: 'rspec', services: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:extra:services config should be an array of strings")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:extra:services config should be a array")
end
it "returns errors if there are no jobs defined" do
diff --git a/spec/lib/gitlab/ci/build/image_spec.rb b/spec/lib/gitlab/ci/build/image_spec.rb
index 382385dfd6b..773a52cdfbc 100644
--- a/spec/lib/gitlab/ci/build/image_spec.rb
+++ b/spec/lib/gitlab/ci/build/image_spec.rb
@@ -10,12 +10,28 @@ describe Gitlab::Ci::Build::Image do
let(:image_name) { 'ruby:2.1' }
let(:job) { create(:ci_build, options: { image: image_name } ) }
- it 'fabricates an object of the proper class' do
- is_expected.to be_kind_of(described_class)
+ context 'when image is defined as string' do
+ it 'fabricates an object of the proper class' do
+ is_expected.to be_kind_of(described_class)
+ end
+
+ it 'populates fabricated object with the proper name attribute' do
+ expect(subject.name).to eq(image_name)
+ end
end
- it 'populates fabricated object with the proper name attribute' do
- expect(subject.name).to eq(image_name)
+ context 'when image is defined as hash' do
+ let(:entrypoint) { '/bin/sh' }
+ let(:job) { create(:ci_build, options: { image: { name: image_name, entrypoint: entrypoint } } ) }
+
+ it 'fabricates an object of the proper class' do
+ is_expected.to be_kind_of(described_class)
+ end
+
+ it 'populates fabricated object with the proper attributes' do
+ expect(subject.name).to eq(image_name)
+ expect(subject.entrypoint).to eq(entrypoint)
+ end
end
context 'when image name is empty' do
@@ -41,10 +57,39 @@ describe Gitlab::Ci::Build::Image do
let(:service_image_name) { 'postgres' }
let(:job) { create(:ci_build, options: { services: [service_image_name] }) }
- it 'fabricates an non-empty array of objects' do
- is_expected.to be_kind_of(Array)
- is_expected.not_to be_empty
- expect(subject.first.name).to eq(service_image_name)
+ context 'when service is defined as string' do
+ it 'fabricates an non-empty array of objects' do
+ is_expected.to be_kind_of(Array)
+ is_expected.not_to be_empty
+ end
+
+ it 'populates fabricated objects with the proper name attributes' do
+ expect(subject.first).to be_kind_of(described_class)
+ expect(subject.first.name).to eq(service_image_name)
+ end
+ end
+
+ context 'when service is defined as hash' do
+ let(:service_entrypoint) { '/bin/sh' }
+ let(:service_alias) { 'db' }
+ let(:service_command) { 'sleep 30' }
+ let(:job) do
+ create(:ci_build, options: { services: [{ name: service_image_name, entrypoint: service_entrypoint,
+ alias: service_alias, command: service_command }] })
+ end
+
+ it 'fabricates an non-empty array of objects' do
+ is_expected.to be_kind_of(Array)
+ is_expected.not_to be_empty
+ expect(subject.first).to be_kind_of(described_class)
+ end
+
+ it 'populates fabricated objects with the proper attributes' do
+ expect(subject.first.name).to eq(service_image_name)
+ expect(subject.first.entrypoint).to eq(service_entrypoint)
+ expect(subject.first.alias).to eq(service_alias)
+ expect(subject.first.command).to eq(service_command)
+ end
end
context 'when service image name is empty' do
diff --git a/spec/lib/gitlab/ci/config/entry/global_spec.rb b/spec/lib/gitlab/ci/config/entry/global_spec.rb
index 23270ad5053..e5f85c712ca 100644
--- a/spec/lib/gitlab/ci/config/entry/global_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/global_spec.rb
@@ -95,13 +95,13 @@ describe Gitlab::Ci::Config::Entry::Global do
describe '#image_value' do
it 'returns valid image' do
- expect(global.image_value).to eq 'ruby:2.2'
+ expect(global.image_value).to eq(name: 'ruby:2.2')
end
end
describe '#services_value' do
it 'returns array of services' do
- expect(global.services_value).to eq ['postgres:9.1', 'mysql:5.5']
+ expect(global.services_value).to eq [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }]
end
end
@@ -150,8 +150,8 @@ describe Gitlab::Ci::Config::Entry::Global do
script: %w[rspec ls],
before_script: %w(ls pwd),
commands: "ls\npwd\nrspec\nls",
- image: 'ruby:2.2',
- services: ['postgres:9.1', 'mysql:5.5'],
+ image: { name: 'ruby:2.2' },
+ services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'] },
variables: { 'VAR' => 'value' },
@@ -161,8 +161,8 @@ describe Gitlab::Ci::Config::Entry::Global do
before_script: [],
script: %w[spinach],
commands: 'spinach',
- image: 'ruby:2.2',
- services: ['postgres:9.1', 'mysql:5.5'],
+ image: { name: 'ruby:2.2' },
+ services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'] },
variables: {},
diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb
index 3c99cb0a1ee..bca22e39500 100644
--- a/spec/lib/gitlab/ci/config/entry/image_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb
@@ -3,43 +3,104 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Image do
let(:entry) { described_class.new(config) }
- describe 'validation' do
- context 'when entry config value is correct' do
- let(:config) { 'ruby:2.2' }
+ context 'when configuration is a string' do
+ let(:config) { 'ruby:2.2' }
- describe '#value' do
- it 'returns image string' do
- expect(entry.value).to eq 'ruby:2.2'
- end
+ describe '#value' do
+ it 'returns image hash' do
+ expect(entry.value).to eq({ name: 'ruby:2.2' })
end
+ end
+
+ describe '#errors' do
+ it 'does not append errors' do
+ expect(entry.errors).to be_empty
+ end
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+
+ describe '#image' do
+ it "returns image's name" do
+ expect(entry.name).to eq 'ruby:2.2'
+ end
+ end
- describe '#errors' do
- it 'does not append errors' do
- expect(entry.errors).to be_empty
- end
+ describe '#entrypoint' do
+ it "returns image's entrypoint" do
+ expect(entry.entrypoint).to be_nil
end
+ end
+ end
- describe '#valid?' do
- it 'is valid' do
- expect(entry).to be_valid
- end
+ context 'when configuration is a hash' do
+ let(:config) { { name: 'ruby:2.2', entrypoint: '/bin/sh' } }
+
+ describe '#value' do
+ it 'returns image hash' do
+ expect(entry.value).to eq(config)
end
end
- context 'when entry value is not correct' do
- let(:config) { ['ruby:2.2'] }
+ describe '#errors' do
+ it 'does not append errors' do
+ expect(entry.errors).to be_empty
+ end
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
- describe '#errors' do
- it 'saves errors' do
- expect(entry.errors)
- .to include 'image config should be a string'
- end
+ describe '#image' do
+ it "returns image's name" do
+ expect(entry.name).to eq 'ruby:2.2'
end
+ end
+
+ describe '#entrypoint' do
+ it "returns image's entrypoint" do
+ expect(entry.entrypoint).to eq '/bin/sh'
+ end
+ end
+ end
+
+ context 'when entry value is not correct' do
+ let(:config) { ['ruby:2.2'] }
+
+ describe '#errors' do
+ it 'saves errors' do
+ expect(entry.errors)
+ .to include 'image config should be a hash or a string'
+ end
+ end
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(entry).not_to be_valid
+ end
+ end
+ end
+
+ context 'when unexpected key is specified' do
+ let(:config) { { name: 'ruby:2.2', non_existing: 'test' } }
+
+ describe '#errors' do
+ it 'saves errors' do
+ expect(entry.errors)
+ .to include 'image config contains unknown keys: non_existing'
+ end
+ end
- describe '#valid?' do
- it 'is not valid' do
- expect(entry).not_to be_valid
- end
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(entry).not_to be_valid
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 9249bb9c172..8dc94a4eb33 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -104,7 +104,7 @@ describe Gitlab::Ci::Config::Entry::Job do
end
it 'overrides global config' do
- expect(entry[:image].value).to eq 'some_image'
+ expect(entry[:image].value).to eq(name: 'some_image')
expect(entry[:cache].value).to eq(key: 'test')
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb
new file mode 100644
index 00000000000..2376de74554
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb
@@ -0,0 +1,117 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Config::Entry::Service do
+ let(:entry) { described_class.new(config) }
+
+ before { entry.compose! }
+
+ context 'when configuration is a string' do
+ let(:config) { 'postgresql:9.5' }
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+
+ describe '#value' do
+ it 'returns valid hash' do
+ expect(entry.value).to include(name: 'postgresql:9.5')
+ end
+ end
+
+ describe '#image' do
+ it "returns service's image name" do
+ expect(entry.name).to eq 'postgresql:9.5'
+ end
+ end
+
+ describe '#alias' do
+ it "returns service's alias" do
+ expect(entry.alias).to be_nil
+ end
+ end
+
+ describe '#command' do
+ it "returns service's command" do
+ expect(entry.command).to be_nil
+ end
+ end
+ end
+
+ context 'when configuration is a hash' do
+ let(:config) do
+ { name: 'postgresql:9.5', alias: 'db', command: 'cmd', entrypoint: '/bin/sh' }
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+
+ describe '#value' do
+ it 'returns valid hash' do
+ expect(entry.value).to eq config
+ end
+ end
+
+ describe '#image' do
+ it "returns service's image name" do
+ expect(entry.name).to eq 'postgresql:9.5'
+ end
+ end
+
+ describe '#alias' do
+ it "returns service's alias" do
+ expect(entry.alias).to eq 'db'
+ end
+ end
+
+ describe '#command' do
+ it "returns service's command" do
+ expect(entry.command).to eq 'cmd'
+ end
+ end
+
+ describe '#entrypoint' do
+ it "returns service's entrypoint" do
+ expect(entry.entrypoint).to eq '/bin/sh'
+ end
+ end
+ end
+
+ context 'when entry value is not correct' do
+ let(:config) { ['postgresql:9.5'] }
+
+ describe '#errors' do
+ it 'saves errors' do
+ expect(entry.errors)
+ .to include 'service config should be a hash or a string'
+ end
+ end
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(entry).not_to be_valid
+ end
+ end
+ end
+
+ context 'when unexpected key is specified' do
+ let(:config) { { name: 'postgresql:9.5', non_existing: 'test' } }
+
+ describe '#errors' do
+ it 'saves errors' do
+ expect(entry.errors)
+ .to include 'service config contains unknown keys: non_existing'
+ end
+ end
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(entry).not_to be_valid
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/entry/services_spec.rb b/spec/lib/gitlab/ci/config/entry/services_spec.rb
index 66fad3b6b16..b32e52f8f26 100644
--- a/spec/lib/gitlab/ci/config/entry/services_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/services_spec.rb
@@ -3,37 +3,30 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Services do
let(:entry) { described_class.new(config) }
- describe 'validations' do
- context 'when entry config value is correct' do
- let(:config) { ['postgres:9.1', 'mysql:5.5'] }
+ before { entry.compose! }
- describe '#value' do
- it 'returns array of services as is' do
- expect(entry.value).to eq config
- end
- end
+ context 'when configuration is valid' do
+ let(:config) { ['postgresql:9.5', { name: 'postgresql:9.1', alias: 'postgres_old' }] }
- describe '#valid?' do
- it 'is valid' do
- expect(entry).to be_valid
- end
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
end
end
- context 'when entry value is not correct' do
- let(:config) { 'ls' }
-
- describe '#errors' do
- it 'saves errors' do
- expect(entry.errors)
- .to include 'services config should be an array of strings'
- end
+ describe '#value' do
+ it 'returns valid array' do
+ expect(entry.value).to eq([{ name: 'postgresql:9.5' }, { name: 'postgresql:9.1', alias: 'postgres_old' }])
end
+ end
+ end
+
+ context 'when configuration is invalid' do
+ let(:config) { 'postgresql:9.5' }
- describe '#valid?' do
- it 'is not valid' do
- expect(entry).not_to be_valid
- end
+ describe '#valid?' do
+ it 'is invalid' do
+ expect(entry).not_to be_valid
end
end
end
diff --git a/spec/lib/gitlab/ci/status/external/common_spec.rb b/spec/lib/gitlab/ci/status/external/common_spec.rb
index 5a97d98b55f..e58f5d8d4df 100644
--- a/spec/lib/gitlab/ci/status/external/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/external/common_spec.rb
@@ -4,9 +4,10 @@ describe Gitlab::Ci::Status::External::Common do
let(:user) { create(:user) }
let(:project) { external_status.project }
let(:external_target_url) { 'http://example.gitlab.com/status' }
+ let(:external_description) { 'my description' }
let(:external_status) do
- create(:generic_commit_status, target_url: external_target_url)
+ create(:generic_commit_status, target_url: external_target_url, description: external_description)
end
subject do
@@ -15,6 +16,12 @@ describe Gitlab::Ci::Status::External::Common do
.extend(described_class)
end
+ describe '#label' do
+ it 'returns description' do
+ expect(subject.label).to eq external_description
+ end
+ end
+
describe '#has_action?' do
it { is_expected.not_to have_action }
end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 3fdafd867da..30aa463faf8 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -7,7 +7,42 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
)
end
- before { allow(model).to receive(:puts) }
+ before do
+ allow(model).to receive(:puts)
+ end
+
+ describe '#add_timestamps_with_timezone' do
+ before do
+ allow(model).to receive(:transaction_open?).and_return(false)
+ end
+
+ context 'using PostgreSQL' do
+ before do
+ allow(Gitlab::Database).to receive(:postgresql?).and_return(true)
+ allow(model).to receive(:disable_statement_timeout)
+ end
+
+ it 'adds "created_at" and "updated_at" fields with the "datetime_with_timezone" data type' do
+ expect(model).to receive(:add_column).with(:foo, :created_at, :datetime_with_timezone, { null: false })
+ expect(model).to receive(:add_column).with(:foo, :updated_at, :datetime_with_timezone, { null: false })
+
+ model.add_timestamps_with_timezone(:foo)
+ end
+ end
+
+ context 'using MySQL' do
+ before do
+ allow(Gitlab::Database).to receive(:postgresql?).and_return(false)
+ end
+
+ it 'adds "created_at" and "updated_at" fields with "datetime_with_timezone" data type' do
+ expect(model).to receive(:add_column).with(:foo, :created_at, :datetime_with_timezone, { null: false })
+ expect(model).to receive(:add_column).with(:foo, :updated_at, :datetime_with_timezone, { null: false })
+
+ model.add_timestamps_with_timezone(:foo)
+ end
+ end
+ end
describe '#add_concurrent_index' do
context 'outside a transaction' do
diff --git a/spec/models/ci/legacy_stage_spec.rb b/spec/models/ci/legacy_stage_spec.rb
index 48116c7e701..d43c33d3807 100644
--- a/spec/models/ci/legacy_stage_spec.rb
+++ b/spec/models/ci/legacy_stage_spec.rb
@@ -55,6 +55,17 @@ describe Ci::LegacyStage, :models do
expect(stage.groups.map(&:name))
.to eq %w[aaaaa rspec spinach]
end
+
+ context 'when a name is nil on legacy pipelines' do
+ before do
+ pipeline.builds.first.update_attribute(:name, nil)
+ end
+
+ it 'returns an array of three groups' do
+ expect(stage.groups.map(&:name))
+ .to eq ['', 'aaaaa', 'rspec', 'spinach']
+ end
+ end
end
describe '#statuses_count' do
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 0d3af1f4499..848fd547e10 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -139,6 +139,18 @@ describe ProjectPolicy, models: true do
is_expected.not_to include(:read_build, :read_pipeline)
end
end
+
+ context 'when builds are disabled' do
+ before do
+ project.project_feature.update(
+ builds_access_level: ProjectFeature::DISABLED)
+ end
+
+ it do
+ is_expected.not_to include(:read_build)
+ is_expected.to include(:read_pipeline)
+ end
+ end
end
context 'reporter' do
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 9556c99dea1..5a4f0513248 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -356,8 +356,11 @@ describe API::Runner do
expect(json_response['token']).to eq(job.token)
expect(json_response['job_info']).to eq(expected_job_info)
expect(json_response['git_info']).to eq(expected_git_info)
- expect(json_response['image']).to eq({ 'name' => 'ruby:2.1' })
- expect(json_response['services']).to eq([{ 'name' => 'postgres' }])
+ expect(json_response['image']).to eq({ 'name' => 'ruby:2.1', 'entrypoint' => '/bin/sh' })
+ expect(json_response['services']).to eq([{ 'name' => 'postgres', 'entrypoint' => nil,
+ 'alias' => nil, 'command' => nil },
+ { 'name' => 'docker:dind', 'entrypoint' => '/bin/sh',
+ 'alias' => 'docker', 'command' => 'sleep 30' }])
expect(json_response['steps']).to eq(expected_steps)
expect(json_response['artifacts']).to eq(expected_artifacts)
expect(json_response['cache']).to eq(expected_cache)
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index 286de277ae7..04cc7708858 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -137,6 +137,18 @@ describe Ci::API::Builds do
end
end
end
+
+ context 'when docker configuration options are used' do
+ let!(:build) { create(:ci_build, :extended_options, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
+
+ it 'starts a build' do
+ register_builds info: { platform: :darwin }
+
+ expect(response).to have_http_status(201)
+ expect(json_response['options']['image']).to eq('ruby:2.1')
+ expect(json_response['options']['services']).to eq(['postgres', 'docker:dind'])
+ end
+ end
end
context 'when builds are finished' do
diff --git a/spec/rubocop/cop/migration/add_timestamps_spec.rb b/spec/rubocop/cop/migration/add_timestamps_spec.rb
new file mode 100644
index 00000000000..18df62dec3e
--- /dev/null
+++ b/spec/rubocop/cop/migration/add_timestamps_spec.rb
@@ -0,0 +1,90 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/migration/add_timestamps'
+
+describe RuboCop::Cop::Migration::AddTimestamps do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+ let(:migration_with_add_timestamps) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ add_timestamps(:users)
+ end
+ end
+ )
+ end
+
+ let(:migration_without_add_timestamps) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ end
+ end
+ )
+ end
+
+ let(:migration_with_add_timestamps_with_timezone) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ add_timestamps_with_timezone(:users)
+ end
+ end
+ )
+ end
+
+ context 'in migration' do
+ before do
+ allow(cop).to receive(:in_migration?).and_return(true)
+ end
+
+ it 'registers an offense when the "add_timestamps" method is used' do
+ inspect_source(cop, migration_with_add_timestamps)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([7])
+ end
+ end
+
+ it 'does not register an offense when the "add_timestamps" method is not used' do
+ inspect_source(cop, migration_without_add_timestamps)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+
+ it 'does not register an offense when the "add_timestamps_with_timezone" method is used' do
+ inspect_source(cop, migration_with_add_timestamps_with_timezone)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'outside of migration' do
+ it 'registers no offense' do
+ inspect_source(cop, migration_with_add_timestamps)
+ inspect_source(cop, migration_without_add_timestamps)
+ inspect_source(cop, migration_with_add_timestamps_with_timezone)
+
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+end
diff --git a/spec/rubocop/cop/migration/datetime_spec.rb b/spec/rubocop/cop/migration/datetime_spec.rb
new file mode 100644
index 00000000000..388b086ce6a
--- /dev/null
+++ b/spec/rubocop/cop/migration/datetime_spec.rb
@@ -0,0 +1,90 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/migration/datetime'
+
+describe RuboCop::Cop::Migration::Datetime do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+ let(:migration_with_datetime) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ add_column(:users, :last_sign_in, :datetime)
+ end
+ end
+ )
+ end
+
+ let(:migration_without_datetime) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ end
+ end
+ )
+ end
+
+ let(:migration_with_datetime_with_timezone) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ add_column(:users, :last_sign_in, :datetime_with_timezone)
+ end
+ end
+ )
+ end
+
+ context 'in migration' do
+ before do
+ allow(cop).to receive(:in_migration?).and_return(true)
+ end
+
+ it 'registers an offense when the ":datetime" data type is used' do
+ inspect_source(cop, migration_with_datetime)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([7])
+ end
+ end
+
+ it 'does not register an offense when the ":datetime" data type is not used' do
+ inspect_source(cop, migration_without_datetime)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+
+ it 'does not register an offense when the ":datetime_with_timezone" data type is used' do
+ inspect_source(cop, migration_with_datetime_with_timezone)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'outside of migration' do
+ it 'registers no offense' do
+ inspect_source(cop, migration_with_datetime)
+ inspect_source(cop, migration_without_datetime)
+ inspect_source(cop, migration_with_datetime_with_timezone)
+
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+end
diff --git a/spec/rubocop/cop/migration/timestamps_spec.rb b/spec/rubocop/cop/migration/timestamps_spec.rb
new file mode 100644
index 00000000000..cdf1423d0c5
--- /dev/null
+++ b/spec/rubocop/cop/migration/timestamps_spec.rb
@@ -0,0 +1,99 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/migration/timestamps'
+
+describe RuboCop::Cop::Migration::Timestamps do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+ let(:migration_with_timestamps) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ create_table :users do |t|
+ t.string :username, null: false
+ t.timestamps null: true
+ t.string :password
+ end
+ end
+ end
+ )
+ end
+
+ let(:migration_without_timestamps) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ create_table :users do |t|
+ t.string :username, null: false
+ t.string :password
+ end
+ end
+ end
+ )
+ end
+
+ let(:migration_with_timestamps_with_timezone) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ create_table :users do |t|
+ t.string :username, null: false
+ t.timestamps_with_timezone null: true
+ t.string :password
+ end
+ end
+ end
+ )
+ end
+
+ context 'in migration' do
+ before do
+ allow(cop).to receive(:in_migration?).and_return(true)
+ end
+
+ it 'registers an offense when the "timestamps" method is used' do
+ inspect_source(cop, migration_with_timestamps)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([8])
+ end
+ end
+
+ it 'does not register an offense when the "timestamps" method is not used' do
+ inspect_source(cop, migration_without_timestamps)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+
+ it 'does not register an offense when the "timestamps_with_timezone" method is used' do
+ inspect_source(cop, migration_with_timestamps_with_timezone)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'outside of migration' do
+ it 'registers no offense' do
+ inspect_source(cop, migration_with_timestamps)
+ inspect_source(cop, migration_without_timestamps)
+ inspect_source(cop, migration_with_timestamps_with_timezone)
+
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+end
diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb
index e2511e8968c..b92c1c28ba8 100644
--- a/spec/serializers/build_details_entity_spec.rb
+++ b/spec/serializers/build_details_entity_spec.rb
@@ -3,8 +3,8 @@ require 'spec_helper'
describe BuildDetailsEntity do
set(:user) { create(:admin) }
- it 'inherits from BuildEntity' do
- expect(described_class).to be < BuildEntity
+ it 'inherits from JobEntity' do
+ expect(described_class).to be < JobEntity
end
describe '#as_json' do
@@ -29,7 +29,7 @@ describe BuildDetailsEntity do
it 'contains the needed key value pairs' do
expect(subject).to include(:coverage, :erased_at, :duration)
- expect(subject).to include(:artifacts, :runner, :pipeline)
+ expect(subject).to include(:runner, :pipeline)
expect(subject).to include(:raw_path, :merge_request)
expect(subject).to include(:new_issue_path)
end
diff --git a/spec/serializers/build_entity_spec.rb b/spec/serializers/job_entity_spec.rb
index e51ff9fc709..5ca7bf2fcaf 100644
--- a/spec/serializers/build_entity_spec.rb
+++ b/spec/serializers/job_entity_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe BuildEntity do
+describe JobEntity do
let(:user) { create(:user) }
- let(:build) { create(:ci_build) }
- let(:project) { build.project }
+ let(:job) { create(:ci_build) }
+ let(:project) { job.project }
let(:request) { double('request') }
before do
@@ -12,12 +12,12 @@ describe BuildEntity do
end
let(:entity) do
- described_class.new(build, request: request)
+ described_class.new(job, request: request)
end
subject { entity.as_json }
- it 'contains paths to build page action' do
+ it 'contains paths to job page action' do
expect(subject).to include(:build_path)
end
@@ -27,7 +27,7 @@ describe BuildEntity do
end
it 'contains whether it is playable' do
- expect(subject[:playable]).to eq build.playable?
+ expect(subject[:playable]).to eq job.playable?
end
it 'contains timestamps' do
@@ -39,9 +39,9 @@ describe BuildEntity do
expect(subject[:status]).to include :icon, :favicon, :text, :label
end
- context 'when build is retryable' do
+ context 'when job is retryable' do
before do
- build.update(status: :failed)
+ job.update(status: :failed)
end
it 'contains cancel path' do
@@ -49,9 +49,9 @@ describe BuildEntity do
end
end
- context 'when build is cancelable' do
+ context 'when job is cancelable' do
before do
- build.update(status: :running)
+ job.update(status: :running)
end
it 'contains cancel path' do
@@ -59,7 +59,7 @@ describe BuildEntity do
end
end
- context 'when build is a regular build' do
+ context 'when job is a regular job' do
it 'does not contain path to play action' do
expect(subject).not_to include(:play_path)
end
@@ -69,8 +69,8 @@ describe BuildEntity do
end
end
- context 'when build is a manual action' do
- let(:build) { create(:ci_build, :manual) }
+ context 'when job is a manual action' do
+ let(:job) { create(:ci_build, :manual) }
context 'when user is allowed to trigger action' do
before do
@@ -99,4 +99,25 @@ describe BuildEntity do
end
end
end
+
+ context 'when job is generic commit status' do
+ let(:job) { create(:generic_commit_status, target_url: 'http://google.com') }
+
+ it 'contains paths to target action' do
+ expect(subject).to include(:build_path)
+ end
+
+ it 'does not contain paths to other action paths' do
+ expect(subject).not_to include(:retry_path, :cancel_path, :play_path)
+ end
+
+ it 'contains timestamps' do
+ expect(subject).to include(:created_at, :updated_at)
+ end
+
+ it 'contains details' do
+ expect(subject).to include :status
+ expect(subject[:status]).to include :icon, :favicon, :text, :label
+ end
+ end
end
diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb
index 03cc5ae9b63..5cb9b9945b6 100644
--- a/spec/serializers/pipeline_details_entity_spec.rb
+++ b/spec/serializers/pipeline_details_entity_spec.rb
@@ -91,6 +91,20 @@ describe PipelineDetailsEntity do
end
end
+ context 'when pipeline has commit statuses' do
+ let(:pipeline) { create(:ci_empty_pipeline) }
+
+ before do
+ create(:generic_commit_status, pipeline: pipeline)
+ end
+
+ it 'contains stages' do
+ expect(subject).to include(:details)
+ expect(subject[:details]).to include(:stages)
+ expect(subject[:details][:stages].first).to include(name: 'external')
+ end
+ end
+
context 'when pipeline has YAML errors' do
let(:pipeline) do
create(:ci_pipeline, config: { rspec: { invalid: :value } })
diff --git a/spec/serializers/stage_entity_spec.rb b/spec/serializers/stage_entity_spec.rb
index 64b3217b809..40e303f7b89 100644
--- a/spec/serializers/stage_entity_spec.rb
+++ b/spec/serializers/stage_entity_spec.rb
@@ -54,6 +54,17 @@ describe StageEntity do
it 'exposes the group key' do
expect(subject).to include :groups
end
+
+ context 'and contains commit status' do
+ before do
+ create(:generic_commit_status, pipeline: pipeline, stage: 'test')
+ end
+
+ it 'contains commit status' do
+ groups = subject[:groups].map { |group| group[:name] }
+ expect(groups).to include('generic')
+ end
+ end
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 1979347a178..a81d3573f8d 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -106,15 +106,13 @@ RSpec.configure do |config|
Sidekiq.redis(&:flushall)
end
- config.around(:example, :migration) do |example|
- begin
- ActiveRecord::Migrator
- .migrate(migrations_paths, previous_migration.version)
-
- example.run
- ensure
- ActiveRecord::Migrator.migrate(migrations_paths)
- end
+ config.before(:example, :migration) do
+ ActiveRecord::Migrator
+ .migrate(migrations_paths, previous_migration.version)
+ end
+
+ config.after(:example, :migration) do
+ ActiveRecord::Migrator.migrate(migrations_paths)
end
config.around(:each, :nested_groups) do |example|