summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_bundle.js1
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_table.vue5
-rw-r--r--app/assets/javascripts/merge_request_tabs.js1
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_url.vue63
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_table.vue5
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_table_row.vue9
-rw-r--r--app/assets/javascripts/vue_shared/directives/popover.js20
-rw-r--r--app/assets/stylesheets/pages/commits.scss8
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss9
-rw-r--r--app/controllers/projects/pipelines_settings_controller.rb12
-rw-r--r--app/controllers/projects/settings/ci_cd_controller.rb5
-rw-r--r--app/helpers/application_settings_helper.rb1
-rw-r--r--app/models/ci/build.rb1
-rw-r--r--app/models/ci/pipeline.rb48
-rw-r--r--app/models/project.rb21
-rw-r--r--app/models/project_auto_devops.rb11
-rw-r--r--app/serializers/pipeline_entity.rb1
-rw-r--r--app/views/admin/application_settings/_form.html.haml12
-rw-r--r--app/views/projects/commit/_pipelines_list.haml1
-rw-r--r--app/views/projects/pipelines/index.html.haml3
-rw-r--r--app/views/projects/pipelines_settings/_show.html.haml41
-rw-r--r--changelogs/unreleased/zj-auto-devops-table.yml5
-rw-r--r--config/initializers/0_inflections.rb7
-rw-r--r--db/migrate/20170824101926_add_auto_devops_enabled_to_application_settings.rb15
-rw-r--r--db/migrate/20170828093725_create_project_auto_dev_ops.rb19
-rw-r--r--db/migrate/20170831092813_add_config_source_to_pipelines.rb7
-rw-r--r--db/schema.rb13
-rw-r--r--lib/gitlab/import_export/import_export.yml3
-rw-r--r--lib/gitlab/import_export/relation_factory.rb1
-rw-r--r--spec/factories/project_auto_devops.rb7
-rw-r--r--spec/features/projects/settings/pipelines_settings_spec.rb10
-rw-r--r--spec/javascripts/commit/pipelines/pipelines_spec.js4
-rw-r--r--spec/javascripts/pipelines/pipeline_url_spec.js27
-rw-r--r--spec/javascripts/pipelines/pipelines_table_row_spec.js2
-rw-r--r--spec/javascripts/pipelines/pipelines_table_spec.js3
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml8
-rw-r--r--spec/models/application_setting_spec.rb1
-rw-r--r--spec/models/ci/build_spec.rb24
-rw-r--r--spec/models/ci/pipeline_spec.rb114
-rw-r--r--spec/models/project_auto_devops_spec.rb23
-rw-r--r--spec/models/project_spec.rb130
-rw-r--r--spec/serializers/pipeline_entity_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb2
45 files changed, 658 insertions, 50 deletions
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
index 687f09882a7..16c5d0fa344 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
+++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
@@ -35,6 +35,7 @@ document.addEventListener('DOMContentLoaded', () => {
propsData: {
endpoint: pipelineTableViewEl.dataset.endpoint,
helpPagePath: pipelineTableViewEl.dataset.helpPagePath,
+ autoDevopsHelpPath: pipelineTableViewEl.dataset.helpAutoDevopsPath,
},
}).$mount();
pipelineTableViewEl.appendChild(table.$el);
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.vue b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
index dd751ec97a8..c931e1e0ea5 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_table.vue
+++ b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
@@ -13,6 +13,10 @@
type: String,
required: true,
},
+ autoDevopsHelpPath: {
+ type: String,
+ required: true,
+ },
},
mixins: [
pipelinesMixin,
@@ -95,6 +99,7 @@
<pipelines-table-component
:pipelines="state.pipelines"
:update-graph-dropdown="updateGraphDropdown"
+ :auto-devops-help-path="autoDevopsHelpPath"
/>
</div>
</div>
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index 3b3620fe61b..0c3c877ff15 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -243,6 +243,7 @@ import bp from './breakpoints';
propsData: {
endpoint: pipelineTableViewEl.dataset.endpoint,
helpPagePath: pipelineTableViewEl.dataset.helpPagePath,
+ autoDevopsHelpPath: pipelineTableViewEl.dataset.helpAutoDevopsPath,
},
}).$mount();
diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue
index 2ca5ac2912f..f0b44dfa6d8 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue
@@ -1,29 +1,45 @@
<script>
-import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
-import tooltip from '../../vue_shared/directives/tooltip';
+ import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
+ import tooltip from '../../vue_shared/directives/tooltip';
+ import popover from '../../vue_shared/directives/popover';
-export default {
- props: {
- pipeline: {
- type: Object,
- required: true,
+ export default {
+ props: {
+ pipeline: {
+ type: Object,
+ required: true,
+ },
+ autoDevopsHelpPath: {
+ type: String,
+ required: true,
+ },
},
- },
- components: {
- userAvatarLink,
- },
- directives: {
- tooltip,
- },
- computed: {
- user() {
- return this.pipeline.user;
+ components: {
+ userAvatarLink,
},
- },
-};
+ directives: {
+ tooltip,
+ popover,
+ },
+ computed: {
+ user() {
+ return this.pipeline.user;
+ },
+ popoverOptions() {
+ return {
+ html: true,
+ delay: { hide: 600 },
+ trigger: 'hover',
+ placement: 'top',
+ title: '<div class="autodevops-title">This pipeline makes use of a predefined CI/CD configuration enabled by <b>Auto DevOps.</b></div>',
+ content: `<a class="autodevops-link" href="${this.autoDevopsHelpPath}" target="_blank" rel="noopener noreferrer nofollow">Learn more about Auto DevOps</a>`,
+ };
+ },
+ },
+ };
</script>
<template>
- <div class="table-section section-15 hidden-xs hidden-sm">
+ <div class="table-section section-15 hidden-xs hidden-sm pipeline-tags">
<a
:href="pipeline.path"
class="js-pipeline-url-link">
@@ -57,6 +73,13 @@ export default {
:title="pipeline.yaml_errors">
yaml invalid
</span>
+ <a
+ v-if="pipeline.flags.auto_devops"
+ class="js-pipeline-url-autodevops label label-info autodevops-badge"
+ v-popover="popoverOptions"
+ role="button">
+ Auto DevOps
+ </a>
<span
v-if="pipeline.flags.stuck"
class="js-pipeline-url-stuck label label-warning">
diff --git a/app/assets/javascripts/pipelines/components/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines.vue
index 010063a0240..5ce4fe58e55 100644
--- a/app/assets/javascripts/pipelines/components/pipelines.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines.vue
@@ -27,6 +27,7 @@
endpoint: pipelinesData.endpoint,
cssClass: pipelinesData.cssClass,
helpPagePath: pipelinesData.helpPagePath,
+ autoDevopsPath: pipelinesData.helpAutoDevopsPath,
newPipelinePath: pipelinesData.newPipelinePath,
canCreatePipeline: pipelinesData.canCreatePipeline,
allPath: pipelinesData.allPath,
@@ -200,6 +201,7 @@
<pipelines-table-component
:pipelines="state.pipelines"
:update-graph-dropdown="updateGraphDropdown"
+ :auto-devops-help-path="autoDevopsPath"
/>
</div>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_table.vue
index 5088d92209f..7aa0c0e8a7f 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_table.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_table.vue
@@ -17,6 +17,10 @@
required: false,
default: false,
},
+ autoDevopsHelpPath: {
+ type: String,
+ required: true,
+ },
},
components: {
pipelinesTableRowComponent,
@@ -54,6 +58,7 @@
:key="model.id"
:pipeline="model"
:update-graph-dropdown="updateGraphDropdown"
+ :auto-devops-help-path="autoDevopsHelpPath"
/>
</div>
</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
index c3f1c426d8a..5b9bb6c3750 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
@@ -25,6 +25,10 @@ export default {
required: false,
default: false,
},
+ autoDevopsHelpPath: {
+ type: String,
+ required: true,
+ },
},
components: {
asyncButtonComponent,
@@ -218,7 +222,10 @@ export default {
</div>
</div>
- <pipeline-url :pipeline="pipeline" />
+ <pipeline-url
+ :pipeline="pipeline"
+ :auto-devops-help-path="autoDevopsHelpPath"
+ />
<div class="table-section section-25">
<div
diff --git a/app/assets/javascripts/vue_shared/directives/popover.js b/app/assets/javascripts/vue_shared/directives/popover.js
new file mode 100644
index 00000000000..05fa563cbd0
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/directives/popover.js
@@ -0,0 +1,20 @@
+/**
+ * Helper to user bootstrap popover in vue.js.
+ * Follow docs for html attributes: https://getbootstrap.com/docs/3.3/javascript/#static-popover
+ *
+ * @example
+ * import popover from 'vue_shared/directives/popover.js';
+ * {
+ * directives: [popover]
+ * }
+ * <a v-popover="{options}">popover</a>
+ */
+export default {
+ bind(el, binding) {
+ $(el).popover(binding.value);
+ },
+
+ unbind(el) {
+ $(el).popover('destroy');
+ },
+};
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 587a202d6dd..994707422bb 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -226,6 +226,14 @@
vertical-align: baseline;
}
+ a.autodevops-badge {
+ color: $white-light;
+ }
+
+ a.autodevops-link {
+ color: $gl-link-color;
+ }
+
.commit-row-description {
font-size: 14px;
padding: 10px 15px;
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index cb8815e4775..296b6310552 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -202,6 +202,10 @@
.btn-group.open .dropdown-toggle {
box-shadow: none;
}
+
+ .pipeline-tags .label-container {
+ white-space: normal;
+ }
}
.stage-cell {
@@ -932,3 +936,8 @@ button.mini-pipeline-graph-dropdown-toggle {
.pipelines-container .top-area .nav-controls > .btn:last-child {
float: none;
}
+
+.autodevops-title {
+ font-weight: $gl-font-weight-normal;
+ line-height: 1.5;
+}
diff --git a/app/controllers/projects/pipelines_settings_controller.rb b/app/controllers/projects/pipelines_settings_controller.rb
index 9d24ebe2138..abab2e2f0c9 100644
--- a/app/controllers/projects/pipelines_settings_controller.rb
+++ b/app/controllers/projects/pipelines_settings_controller.rb
@@ -6,7 +6,7 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
end
def update
- if @project.update_attributes(update_params)
+ if @project.update(update_params)
flash[:notice] = "Pipelines settings for '#{@project.name}' were successfully updated."
redirect_to project_settings_ci_cd_path(@project)
else
@@ -16,14 +16,12 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
private
- def create_params
- params.require(:pipeline).permit(:ref)
- end
-
def update_params
params.require(:project).permit(
- :runners_token, :builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
- :public_builds, :auto_cancel_pending_pipelines, :ci_config_path
+ :runners_token, :builds_enabled, :build_allow_git_fetch,
+ :build_timeout_in_minutes, :build_coverage_regex, :public_builds,
+ :auto_cancel_pending_pipelines, :ci_config_path,
+ auto_devops_attributes: [:id, :domain, :enabled]
)
end
end
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index 15a2ff56b92..b029b31f9af 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -8,6 +8,7 @@ module Projects
define_secret_variables
define_triggers_variables
define_badges_variables
+ define_auto_devops_variables
end
private
@@ -42,6 +43,10 @@ module Projects
badge.new(@project, @ref).metadata
end
end
+
+ def define_auto_devops_variables
+ @auto_devops = @project.auto_devops || ProjectAutoDevops.new
+ end
end
end
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index b93f5f0af1c..7bd34df5c95 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -115,6 +115,7 @@ module ApplicationSettingsHelper
:after_sign_up_text,
:akismet_api_key,
:akismet_enabled,
+ :auto_devops_enabled,
:clientside_sentry_dsn,
:clientside_sentry_enabled,
:container_registry_token_expire_delay,
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 64c93966dff..5ebe6f180e6 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -216,6 +216,7 @@ module Ci
variables += runner.predefined_variables if runner
variables += project.container_registry_variables
variables += project.deployment_variables if has_environment?
+ variables += project.auto_devops_variables
variables += yaml_variables
variables += user_variables
variables += project.group.secret_variables_for(ref, project).map(&:to_runner_variable) if project.group
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 46e5c344fdc..871c76fbad3 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -38,6 +38,7 @@ module Ci
validates :status, presence: { unless: :importing? }
validate :valid_commit_sha, unless: :importing?
+ after_initialize :set_config_source, if: :new_record?
after_create :keep_around_commits, unless: :importing?
enum source: {
@@ -50,6 +51,12 @@ module Ci
external: 6
}
+ enum config_source: {
+ unknown_source: nil,
+ repository_source: 1,
+ auto_devops_source: 2
+ }
+
state_machine :status, initial: :created do
event :enqueue do
transition created: :pending
@@ -316,6 +323,14 @@ module Ci
builds.latest.failed_but_allowed.any?
end
+ def set_config_source
+ if ci_yaml_from_repo
+ self.config_source = :repository_source
+ elsif implied_ci_yaml_file
+ self.config_source = :auto_devops_source
+ end
+ end
+
def config_processor
return unless ci_yaml_file
return @config_processor if defined?(@config_processor)
@@ -342,11 +357,17 @@ module Ci
def ci_yaml_file
return @ci_yaml_file if defined?(@ci_yaml_file)
- @ci_yaml_file = begin
- project.repository.gitlab_ci_yml_for(sha, ci_yaml_file_path)
- rescue Rugged::ReferenceError, GRPC::NotFound, GRPC::Internal
- self.yaml_errors =
- "Failed to load CI/CD config file at #{ci_yaml_file_path}"
+ @ci_yaml_file =
+ if auto_devops_source?
+ implied_ci_yaml_file
+ else
+ ci_yaml_from_repo
+ end
+
+ if @ci_yaml_file
+ @ci_yaml_file
+ else
+ self.yaml_errors = "Failed to load CI/CD config file for #{sha}"
nil
end
end
@@ -434,6 +455,23 @@ module Ci
private
+ def ci_yaml_from_repo
+ return unless project
+ return unless sha
+
+ project.repository.gitlab_ci_yml_for(sha, ci_yaml_file_path)
+ rescue GRPC::NotFound, Rugged::ReferenceError, GRPC::Internal
+ nil
+ end
+
+ def implied_ci_yaml_file
+ return unless project
+
+ if project.auto_devops_enabled?
+ Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps').content
+ end
+ end
+
def pipeline_data
Gitlab::DataBuilder::Pipeline.build(self)
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 18800921c6c..039dacf1945 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -187,9 +187,12 @@ class Project < ActiveRecord::Base
has_many :active_runners, -> { active }, through: :runner_projects, source: :runner, class_name: 'Ci::Runner'
+ has_one :auto_devops, class_name: 'ProjectAutoDevops'
+
accepts_nested_attributes_for :variables, allow_destroy: true
accepts_nested_attributes_for :project_feature
accepts_nested_attributes_for :import_data
+ accepts_nested_attributes_for :auto_devops
delegate :name, to: :owner, allow_nil: true, prefix: true
delegate :members, to: :team, prefix: true
@@ -466,6 +469,14 @@ class Project < ActiveRecord::Base
self[:lfs_enabled] && Gitlab.config.lfs.enabled
end
+ def auto_devops_enabled?
+ if auto_devops&.enabled.nil?
+ current_application_settings.auto_devops_enabled?
+ else
+ auto_devops.enabled?
+ end
+ end
+
def repository_storage_path
Gitlab.config.repositories.storages[repository_storage].try(:[], 'path')
end
@@ -1378,6 +1389,10 @@ class Project < ActiveRecord::Base
Gitlab::Utils.slugify(full_path.to_s)
end
+ def has_ci?
+ repository.gitlab_ci_yml || auto_devops_enabled?
+ end
+
def predefined_variables
[
{ key: 'CI_PROJECT_ID', value: id.to_s, public: true },
@@ -1423,6 +1438,12 @@ class Project < ActiveRecord::Base
deployment_service.predefined_variables
end
+ def auto_devops_variables
+ return [] unless auto_devops_enabled?
+
+ auto_devops&.variables || []
+ end
+
def append_or_update_attribute(name, value)
old_values = public_send(name.to_s) # rubocop:disable GitlabSecurity/PublicSend
diff --git a/app/models/project_auto_devops.rb b/app/models/project_auto_devops.rb
new file mode 100644
index 00000000000..53731579e87
--- /dev/null
+++ b/app/models/project_auto_devops.rb
@@ -0,0 +1,11 @@
+class ProjectAutoDevops < ActiveRecord::Base
+ belongs_to :project
+
+ validates :domain, allow_blank: true, hostname: { allow_numeric_hostname: true }
+
+ def variables
+ variables = []
+ variables << { key: 'AUTO_DEVOPS_DOMAIN', value: domain, public: true } if domain.present?
+ variables
+ end
+end
diff --git a/app/serializers/pipeline_entity.rb b/app/serializers/pipeline_entity.rb
index c4f000b0ca3..357fc71f877 100644
--- a/app/serializers/pipeline_entity.rb
+++ b/app/serializers/pipeline_entity.rb
@@ -16,6 +16,7 @@ class PipelineEntity < Grape::Entity
expose :flags do
expose :latest?, as: :latest
expose :stuck?, as: :stuck
+ expose :auto_devops_source?, as: :auto_devops
expose :has_yaml_errors?, as: :yaml_errors
expose :can_retry?, as: :retryable
expose :can_cancel?, as: :cancelable
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index a010b4691bf..dbaed1d09fb 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -226,7 +226,17 @@
.help-block 0 for unlimited
%fieldset
- %legend Continuous Integration
+ %legend Continuous Integration and Deployment
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :auto_devops_enabled do
+ = f.check_box :auto_devops_enabled
+ Enabled Auto DevOps (Beta) for projects by default
+ .help-block
+ It will automatically build, test, and deploy applications based on a predefined CI/CD configuration
+ = link_to icon('question-circle'), help_page_path('topics/autodevops/index.md')
+
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
diff --git a/app/views/projects/commit/_pipelines_list.haml b/app/views/projects/commit/_pipelines_list.haml
index 09e3a775d1c..bef96786b73 100644
--- a/app/views/projects/commit/_pipelines_list.haml
+++ b/app/views/projects/commit/_pipelines_list.haml
@@ -2,6 +2,7 @@
#commit-pipeline-table-view{ data: { disable_initialization: disable_initialization,
endpoint: endpoint,
"help-page-path" => help_page_path('ci/quick_start/README'),
+ "help-auto-devops-path" => help_page_path('topics/autodevops/index.md'),
} }
- content_for :page_specific_javascripts do
diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml
index c1729850cf4..579f681abaa 100644
--- a/app/views/projects/pipelines/index.html.haml
+++ b/app/views/projects/pipelines/index.html.haml
@@ -5,6 +5,7 @@
#pipelines-list-vue{ data: { endpoint: project_pipelines_path(@project, format: :json),
"css-class" => container_class,
"help-page-path" => help_page_path('ci/quick_start/README'),
+ "help-auto-devops-path" => help_page_path('topics/autodevops/index.md'),
"new-pipeline-path" => new_project_pipeline_path(@project),
"can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s,
"all-path" => project_pipelines_path(@project),
@@ -13,7 +14,7 @@
"finished-path" => project_pipelines_path(@project, scope: :finished),
"branches-path" => project_pipelines_path(@project, scope: :branches),
"tags-path" => project_pipelines_path(@project, scope: :tags),
- "has-ci" => @repository.gitlab_ci_yml,
+ "has-ci" => @project.has_ci?,
"ci-lint-path" => ci_lint_path } }
= page_specific_javascript_bundle_tag('common_vue')
diff --git a/app/views/projects/pipelines_settings/_show.html.haml b/app/views/projects/pipelines_settings/_show.html.haml
index 8bf76b646f7..324cd423ede 100644
--- a/app/views/projects/pipelines_settings/_show.html.haml
+++ b/app/views/projects/pipelines_settings/_show.html.haml
@@ -2,11 +2,42 @@
.col-lg-12
= form_for @project, url: project_pipelines_settings_path(@project) do |f|
%fieldset.builds-feature
- - unless @repository.gitlab_ci_yml
- .form-group
- %p Pipelines need to be configured before you can begin using Continuous Integration.
- = link_to 'Get started with Pipelines', help_page_path('ci/quick_start/README'), class: 'btn btn-info'
- %hr
+ .form-group
+ %p Pipelines need to have Auto DevOps enabled or have a .gitlab-ci.yml configured before you can begin using Continuous Integration and Delivery.
+ %h5 Auto DevOps (Beta)
+ %p
+ Auto DevOps will automatically build, test, and deploy your application based on a predefined Continious Integration and Delivery configuration.
+ = link_to 'Learn more about Auto DevOps', help_page_path('topics/autodevops/index.md')
+ = f.fields_for :auto_devops_attributes, @auto_devops do |form|
+ .radio
+ = form.label :enabled_true do
+ = form.radio_button :enabled, 'true'
+ %strong Enable Auto DevOps
+ %br
+ %span.descr
+ The Auto DevOps pipeline configuration will be used when there is no .gitlab-ci.yml
+ in the project.
+ .radio
+ = form.label :enabled_false do
+ = form.radio_button :enabled, 'false'
+ %strong Disable Auto DevOps
+ %br
+ %span.descr
+ A specific .gitlab-ci.yml file needs to be specified before you can begin using Continious Integration and Delivery.
+ .radio
+ = form.label :enabled do
+ = form.radio_button :enabled, nil
+ %strong
+ Instance default (status: #{current_application_settings.auto_devops_enabled?})
+ %br
+ %span.descr
+ Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific .gitlab-ci.yml file specified.
+ %br
+ %p
+ Define a domain used by Auto DevOps to deploy towards, this is required for deploys to succeed.
+ = form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
+
+ %hr
.form-group.append-bottom-default
= f.label :runners_token, "Runner token", class: 'label-light'
= f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
diff --git a/changelogs/unreleased/zj-auto-devops-table.yml b/changelogs/unreleased/zj-auto-devops-table.yml
new file mode 100644
index 00000000000..f1a004ebd19
--- /dev/null
+++ b/changelogs/unreleased/zj-auto-devops-table.yml
@@ -0,0 +1,5 @@
+---
+title: Allow users and administrator to configure Auto-DevOps
+merge_request: 13923
+author:
+type: added
diff --git a/config/initializers/0_inflections.rb b/config/initializers/0_inflections.rb
index f977104ff9d..1ad9ddca877 100644
--- a/config/initializers/0_inflections.rb
+++ b/config/initializers/0_inflections.rb
@@ -10,5 +10,10 @@
# end
#
ActiveSupport::Inflector.inflections do |inflect|
- inflect.uncountable %w(award_emoji project_statistics system_note_metadata)
+ inflect.uncountable %w(
+ award_emoji
+ project_statistics
+ system_note_metadata
+ project_auto_devops
+ )
end
diff --git a/db/migrate/20170824101926_add_auto_devops_enabled_to_application_settings.rb b/db/migrate/20170824101926_add_auto_devops_enabled_to_application_settings.rb
new file mode 100644
index 00000000000..da518d8215c
--- /dev/null
+++ b/db/migrate/20170824101926_add_auto_devops_enabled_to_application_settings.rb
@@ -0,0 +1,15 @@
+class AddAutoDevopsEnabledToApplicationSettings < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default(:application_settings, :auto_devops_enabled, :boolean, default: false)
+ end
+
+ def down
+ remove_column(:application_settings, :auto_devops_enabled, :boolean)
+ end
+end
diff --git a/db/migrate/20170828093725_create_project_auto_dev_ops.rb b/db/migrate/20170828093725_create_project_auto_dev_ops.rb
new file mode 100644
index 00000000000..c1bb4f20c1d
--- /dev/null
+++ b/db/migrate/20170828093725_create_project_auto_dev_ops.rb
@@ -0,0 +1,19 @@
+class CreateProjectAutoDevOps < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ create_table :project_auto_devops do |t|
+ t.belongs_to :project, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
+ t.datetime_with_timezone :created_at, null: false
+ t.datetime_with_timezone :updated_at, null: false
+ t.boolean :enabled, default: nil, null: true
+ t.string :domain
+ end
+ end
+
+ def down
+ drop_table(:project_auto_devops)
+ end
+end
diff --git a/db/migrate/20170831092813_add_config_source_to_pipelines.rb b/db/migrate/20170831092813_add_config_source_to_pipelines.rb
new file mode 100644
index 00000000000..ff51e968abd
--- /dev/null
+++ b/db/migrate/20170831092813_add_config_source_to_pipelines.rb
@@ -0,0 +1,7 @@
+class AddConfigSourceToPipelines < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:ci_pipelines, :config_source, :integer, allow_null: true)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 86c1dda537e..bcb750184db 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -133,6 +133,7 @@ ActiveRecord::Schema.define(version: 20170905112933) do
t.integer "performance_bar_allowed_group_id"
t.boolean "hashed_storage_enabled", default: false, null: false
t.boolean "project_export_enabled", default: true, null: false
+ t.boolean "auto_devops_enabled", default: false, null: false
end
create_table "audit_events", force: :cascade do |t|
@@ -340,6 +341,7 @@ ActiveRecord::Schema.define(version: 20170905112933) do
t.integer "auto_canceled_by_id"
t.integer "pipeline_schedule_id"
t.integer "source"
+ t.integer "config_source"
t.boolean "protected"
end
@@ -1108,6 +1110,16 @@ ActiveRecord::Schema.define(version: 20170905112933) do
add_index "project_authorizations", ["project_id"], name: "index_project_authorizations_on_project_id", using: :btree
add_index "project_authorizations", ["user_id", "project_id", "access_level"], name: "index_project_authorizations_on_user_id_project_id_access_level", unique: true, using: :btree
+ create_table "project_auto_devops", force: :cascade do |t|
+ t.integer "project_id", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.boolean "enabled"
+ t.string "domain"
+ end
+
+ add_index "project_auto_devops", ["project_id"], name: "index_project_auto_devops_on_project_id", unique: true, using: :btree
+
create_table "project_features", force: :cascade do |t|
t.integer "project_id"
t.integer "merge_requests_access_level"
@@ -1724,6 +1736,7 @@ ActiveRecord::Schema.define(version: 20170905112933) do
add_foreign_key "personal_access_tokens", "users"
add_foreign_key "project_authorizations", "projects", on_delete: :cascade
add_foreign_key "project_authorizations", "users", on_delete: :cascade
+ add_foreign_key "project_auto_devops", "projects", on_delete: :cascade
add_foreign_key "project_features", "projects", name: "fk_18513d9b92", on_delete: :cascade
add_foreign_key "project_group_links", "projects", name: "fk_daa8cee94c", on_delete: :cascade
add_foreign_key "project_import_data", "projects", name: "fk_ffb9ee3a10", on_delete: :cascade
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index ec73846d844..2171c6c7bbb 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -50,6 +50,7 @@ project_tree:
- :push_event_payload
- :stages
- :statuses
+ - :auto_devops
- :triggers
- :pipeline_schedules
- :services
@@ -142,4 +143,4 @@ methods:
events:
- :action
push_event_payload:
- - :action \ No newline at end of file
+ - :action
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index d563a87dcfd..380b336395d 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -14,6 +14,7 @@ module Gitlab
create_access_levels: 'ProtectedTag::CreateAccessLevel',
labels: :project_labels,
priorities: :label_priorities,
+ auto_devops: :project_auto_devops,
label: :project_label }.freeze
USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id created_by_id last_edited_by_id merge_user_id resolved_by_id].freeze
diff --git a/spec/factories/project_auto_devops.rb b/spec/factories/project_auto_devops.rb
new file mode 100644
index 00000000000..8d124dc2381
--- /dev/null
+++ b/spec/factories/project_auto_devops.rb
@@ -0,0 +1,7 @@
+FactoryGirl.define do
+ factory :project_auto_devops do
+ project
+ enabled true
+ domain "example.com"
+ end
+end
diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb
index 232d796a200..975d204e75e 100644
--- a/spec/features/projects/settings/pipelines_settings_spec.rb
+++ b/spec/features/projects/settings/pipelines_settings_spec.rb
@@ -41,5 +41,15 @@ feature "Pipelines settings" do
checkbox = find_field('project_auto_cancel_pending_pipelines')
expect(checkbox).to be_checked
end
+
+ scenario 'update auto devops settings' do
+ fill_in('project_auto_devops_attributes_domain', with: 'test.com')
+ page.choose('project_auto_devops_attributes_enabled_false')
+ click_on 'Save changes'
+
+ expect(page.status_code).to eq(200)
+ expect(project.auto_devops).to be_present
+ expect(project.auto_devops).not_to be_enabled
+ end
end
end
diff --git a/spec/javascripts/commit/pipelines/pipelines_spec.js b/spec/javascripts/commit/pipelines/pipelines_spec.js
index a34cadec0ab..454f187ccbc 100644
--- a/spec/javascripts/commit/pipelines/pipelines_spec.js
+++ b/spec/javascripts/commit/pipelines/pipelines_spec.js
@@ -29,6 +29,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
propsData: {
endpoint: 'endpoint',
helpPagePath: 'foo',
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
});
@@ -64,6 +65,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
propsData: {
endpoint: 'endpoint',
helpPagePath: 'foo',
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
});
@@ -115,6 +117,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
propsData: {
endpoint: 'endpoint',
helpPagePath: 'foo',
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
element.appendChild(this.component.$el);
@@ -136,6 +139,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
propsData: {
endpoint: 'endpoint',
helpPagePath: 'foo',
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
});
diff --git a/spec/javascripts/pipelines/pipeline_url_spec.js b/spec/javascripts/pipelines/pipeline_url_spec.js
index 3c4b20a5f06..256fdbe743c 100644
--- a/spec/javascripts/pipelines/pipeline_url_spec.js
+++ b/spec/javascripts/pipelines/pipeline_url_spec.js
@@ -16,6 +16,7 @@ describe('Pipeline Url Component', () => {
path: 'foo',
flags: {},
},
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
@@ -30,6 +31,7 @@ describe('Pipeline Url Component', () => {
path: 'foo',
flags: {},
},
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
@@ -50,6 +52,7 @@ describe('Pipeline Url Component', () => {
path: '/',
},
},
+ autoDevopsHelpPath: 'foo',
};
const component = new PipelineUrlComponent({
@@ -73,6 +76,7 @@ describe('Pipeline Url Component', () => {
path: 'foo',
flags: {},
},
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
@@ -91,6 +95,7 @@ describe('Pipeline Url Component', () => {
stuck: true,
},
},
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
@@ -98,4 +103,26 @@ describe('Pipeline Url Component', () => {
expect(component.$el.querySelector('.js-pipeline-url-yaml').textContent).toContain('yaml invalid');
expect(component.$el.querySelector('.js-pipeline-url-stuck').textContent).toContain('stuck');
});
+
+ it('should render a badge for autodevops', () => {
+ const component = new PipelineUrlComponent({
+ propsData: {
+ pipeline: {
+ id: 1,
+ path: 'foo',
+ flags: {
+ latest: true,
+ yaml_errors: true,
+ stuck: true,
+ auto_devops: true,
+ },
+ },
+ autoDevopsHelpPath: 'foo',
+ },
+ }).$mount();
+
+ expect(
+ component.$el.querySelector('.js-pipeline-url-autodevops').textContent.trim(),
+ ).toEqual('Auto DevOps');
+ });
});
diff --git a/spec/javascripts/pipelines/pipelines_table_row_spec.js b/spec/javascripts/pipelines/pipelines_table_row_spec.js
index 7ce39dca112..d7456a48bc1 100644
--- a/spec/javascripts/pipelines/pipelines_table_row_spec.js
+++ b/spec/javascripts/pipelines/pipelines_table_row_spec.js
@@ -9,7 +9,7 @@ describe('Pipelines Table Row', () => {
el: document.querySelector('.test-dom-element'),
propsData: {
pipeline,
- service: {},
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
};
diff --git a/spec/javascripts/pipelines/pipelines_table_spec.js b/spec/javascripts/pipelines/pipelines_table_spec.js
index 3afe89c8db4..4f5eb42eb35 100644
--- a/spec/javascripts/pipelines/pipelines_table_spec.js
+++ b/spec/javascripts/pipelines/pipelines_table_spec.js
@@ -22,6 +22,7 @@ describe('Pipelines Table', () => {
component = new PipelinesTableComponent({
propsData: {
pipelines: [],
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
});
@@ -47,6 +48,7 @@ describe('Pipelines Table', () => {
const component = new PipelinesTableComponent({
propsData: {
pipelines: [],
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
expect(component.$el.querySelectorAll('.commit.gl-responsive-table-row').length).toEqual(0);
@@ -58,6 +60,7 @@ describe('Pipelines Table', () => {
const component = new PipelinesTableComponent({
propsData: {
pipelines: [pipeline],
+ autoDevopsHelpPath: 'foo',
},
}).$mount();
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index beed4e77e8b..3fb8edeb701 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -256,6 +256,7 @@ project:
- environments
- deployments
- project_feature
+- auto_devops
- pages_domains
- authorized_users
- project_authorizations
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 1613b968bb6..899d17d97c2 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -223,6 +223,7 @@ Ci::Pipeline:
- lock_version
- auto_canceled_by_id
- pipeline_schedule_id
+- config_source
- protected
Ci::Stage:
- id
@@ -466,3 +467,10 @@ Timelog:
- user_id
- created_at
- updated_at
+ProjectAutoDevops:
+- id
+- enabled
+- domain
+- project_id
+- created_at
+- updated_at
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index f921545668d..c7a9eabdf06 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -5,6 +5,7 @@ describe ApplicationSetting do
it { expect(setting).to be_valid }
it { expect(setting.uuid).to be_present }
+ it { expect(setting).to have_db_column(:auto_devops_enabled) }
describe 'validations' do
let(:http) { 'http://example.com' }
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 08d22f166e4..c2c9f1c12d1 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -1688,6 +1688,30 @@ describe Ci::Build do
{ key: 'secret', value: 'value', public: false }])
end
end
+
+ context 'when using auto devops' do
+ context 'and is enabled' do
+ before do
+ project.create_auto_devops!(enabled: true, domain: 'example.com')
+ end
+
+ it "includes AUTO_DEVOPS_DOMAIN" do
+ is_expected.to include(
+ { key: 'AUTO_DEVOPS_DOMAIN', value: 'example.com', public: true })
+ end
+ end
+
+ context 'and is disabled' do
+ before do
+ project.create_auto_devops!(enabled: false, domain: 'example.com')
+ end
+
+ it "includes AUTO_DEVOPS_DOMAIN" do
+ is_expected.not_to include(
+ { key: 'AUTO_DEVOPS_DOMAIN', value: 'example.com', public: true })
+ end
+ end
+ end
end
describe 'state transition: any => [:pending]' do
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 84656ffe0b9..95da97b7bc5 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -799,14 +799,118 @@ describe Ci::Pipeline, :mailer do
end
end
+ describe '#set_config_source' do
+ context 'on object initialisation' do
+ context 'when pipelines does not contain needed data' do
+ let(:pipeline) do
+ Ci::Pipeline.new
+ end
+
+ it 'defines source to be unknown' do
+ expect(pipeline).to be_unknown_source
+ end
+ end
+
+ context 'when pipeline contains all needed data' do
+ let(:pipeline) do
+ Ci::Pipeline.new(
+ project: project,
+ sha: '1234',
+ ref: 'master',
+ source: :push)
+ end
+
+ context 'when the repository has a config file' do
+ before do
+ allow(project.repository).to receive(:gitlab_ci_yml_for)
+ .and_return('config')
+ end
+
+ it 'defines source to be from repository' do
+ expect(pipeline).to be_repository_source
+ end
+
+ context 'when loading an object' do
+ let(:new_pipeline) { Ci::Pipeline.find(pipeline.id) }
+
+ it 'does not redefine the source' do
+ # force to overwrite the source
+ pipeline.unknown_source!
+
+ expect(new_pipeline).to be_unknown_source
+ end
+ end
+ end
+
+ context 'when the repository does not have a config file' do
+ let(:implied_yml) { Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps').content }
+
+ context 'auto devops enabled' do
+ before do
+ stub_application_setting(auto_devops_enabled: true)
+ allow(project).to receive(:ci_config_path) { 'custom' }
+ end
+
+ it 'defines source to be auto devops' do
+ subject
+
+ expect(pipeline).to be_auto_devops_source
+ end
+ end
+ end
+ end
+ end
+ end
+
describe '#ci_yaml_file' do
- it 'reports error if the file is not found' do
- allow(pipeline.project).to receive(:ci_config_path) { 'custom' }
+ let(:implied_yml) { Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps').content }
+
+ context 'the source is unknown' do
+ before do
+ pipeline.unknown_source!
+ end
+
+ it 'returns the configuration if found' do
+ allow(pipeline.project.repository).to receive(:gitlab_ci_yml_for)
+ .and_return('config')
+
+ expect(pipeline.ci_yaml_file).to be_a(String)
+ expect(pipeline.ci_yaml_file).not_to eq(implied_yml)
+ expect(pipeline.yaml_errors).to be_nil
+ end
+
+ it 'sets yaml errors if not found' do
+ expect(pipeline.ci_yaml_file).to be_nil
+ expect(pipeline.yaml_errors)
+ .to start_with('Failed to load CI/CD config file')
+ end
+ end
+
+ context 'the source is the repository' do
+ before do
+ pipeline.repository_source!
+ end
- pipeline.ci_yaml_file
+ it 'returns the configuration if found' do
+ allow(pipeline.project.repository).to receive(:gitlab_ci_yml_for)
+ .and_return('config')
- expect(pipeline.yaml_errors)
- .to eq('Failed to load CI/CD config file at custom')
+ expect(pipeline.ci_yaml_file).to be_a(String)
+ expect(pipeline.ci_yaml_file).not_to eq(implied_yml)
+ expect(pipeline.yaml_errors).to be_nil
+ end
+ end
+
+ context 'when the source is auto_devops_source' do
+ before do
+ stub_application_setting(auto_devops_enabled: true)
+ pipeline.auto_devops_source!
+ end
+
+ it 'finds the implied config' do
+ expect(pipeline.ci_yaml_file).to eq(implied_yml)
+ expect(pipeline.yaml_errors).to be_nil
+ end
end
end
diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb
new file mode 100644
index 00000000000..ca13af4d73e
--- /dev/null
+++ b/spec/models/project_auto_devops_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe ProjectAutoDevops do
+ set(:project) { build(:project) }
+
+ it { is_expected.to belong_to(:project) }
+
+ it { is_expected.to respond_to(:created_at) }
+ it { is_expected.to respond_to(:updated_at) }
+
+ describe 'variables' do
+ let(:auto_devops) { build_stubbed(:project_auto_devops, project: project, domain: domain) }
+
+ context 'when domain is defined' do
+ let(:domain) { 'example.com' }
+
+ it 'returns AUTO_DEVOPS_DOMAIN' do
+ expect(auto_devops.variables).to include(
+ { key: 'AUTO_DEVOPS_DOMAIN', value: 'example.com', public: true })
+ end
+ end
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 1f7c6a82b91..75c99b62150 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -53,6 +53,7 @@ describe Project do
it { is_expected.to have_one(:import_data).class_name('ProjectImportData') }
it { is_expected.to have_one(:last_event).class_name('Event') }
it { is_expected.to have_one(:forked_from_project).through(:forked_project_link) }
+ it { is_expected.to have_one(:auto_devops).class_name('ProjectAutoDevops') }
it { is_expected.to have_many(:commit_statuses) }
it { is_expected.to have_many(:pipelines) }
it { is_expected.to have_many(:builds) }
@@ -2508,4 +2509,133 @@ describe Project do
end
end
end
+
+ describe '#has_ci?' do
+ set(:project) { create(:project) }
+ let(:repository) { double }
+
+ before do
+ expect(project).to receive(:repository) { repository }
+ end
+
+ context 'when has .gitlab-ci.yml' do
+ before do
+ expect(repository).to receive(:gitlab_ci_yml) { 'content' }
+ end
+
+ it "CI is available" do
+ expect(project).to have_ci
+ end
+ end
+
+ context 'when there is no .gitlab-ci.yml' do
+ before do
+ expect(repository).to receive(:gitlab_ci_yml) { nil }
+ end
+
+ it "CI is not available" do
+ expect(project).not_to have_ci
+ end
+
+ context 'when auto devops is enabled' do
+ before do
+ stub_application_setting(auto_devops_enabled: true)
+ end
+
+ it "CI is available" do
+ expect(project).to have_ci
+ end
+ end
+ end
+ end
+
+ describe '#auto_devops_enabled?' do
+ set(:project) { create(:project) }
+
+ subject { project.auto_devops_enabled? }
+
+ context 'when enabled in settings' do
+ before do
+ stub_application_setting(auto_devops_enabled: true)
+ end
+
+ it 'auto devops is implicitly enabled' do
+ expect(project.auto_devops).to be_nil
+ expect(project).to be_auto_devops_enabled
+ end
+
+ context 'when explicitly enabled' do
+ before do
+ create(:project_auto_devops, project: project)
+ end
+
+ it "auto devops is enabled" do
+ expect(project).to be_auto_devops_enabled
+ end
+ end
+
+ context 'when explicitly disabled' do
+ before do
+ create(:project_auto_devops, project: project, enabled: false)
+ end
+
+ it "auto devops is disabled" do
+ expect(project).not_to be_auto_devops_enabled
+ end
+ end
+ end
+
+ context 'when disabled in settings' do
+ before do
+ stub_application_setting(auto_devops_enabled: false)
+ end
+
+ it 'auto devops is implicitly disabled' do
+ expect(project.auto_devops).to be_nil
+ expect(project).not_to be_auto_devops_enabled
+ end
+
+ context 'when explicitly enabled' do
+ before do
+ create(:project_auto_devops, project: project)
+ end
+
+ it "auto devops is enabled" do
+ expect(project).to be_auto_devops_enabled
+ end
+ end
+ end
+ end
+
+ context '#auto_devops_variables' do
+ set(:project) { create(:project) }
+
+ subject { project.auto_devops_variables }
+
+ context 'when enabled in settings' do
+ before do
+ stub_application_setting(auto_devops_enabled: true)
+ end
+
+ context 'when domain is empty' do
+ before do
+ create(:project_auto_devops, project: project, domain: nil)
+ end
+
+ it 'variables are empty' do
+ is_expected.to be_empty
+ end
+ end
+
+ context 'when domain is configured' do
+ before do
+ create(:project_auto_devops, project: project, domain: 'example.com')
+ end
+
+ it "variables are not empty" do
+ is_expected.not_to be_empty
+ end
+ end
+ end
+ end
end
diff --git a/spec/serializers/pipeline_entity_spec.rb b/spec/serializers/pipeline_entity_spec.rb
index 881f2b6bfd8..f8df461bc81 100644
--- a/spec/serializers/pipeline_entity_spec.rb
+++ b/spec/serializers/pipeline_entity_spec.rb
@@ -36,7 +36,7 @@ describe PipelineEntity do
it 'contains flags' do
expect(subject).to include :flags
expect(subject[:flags])
- .to include :latest, :stuck,
+ .to include :latest, :stuck, :auto_devops,
:yaml_errors, :retryable, :cancelable
end
end
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index 009d67a3fbe..4c2ff08039c 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Ci::CreatePipelineService do
- let(:project) { create(:project, :repository) }
+ set(:project) { create(:project, :repository) }
let(:user) { create(:admin) }
let(:ref_name) { 'refs/heads/master' }