From 9809a9af8a3980f8a65262295cfd9701e793ac11 Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Wed, 21 Dec 2016 16:21:55 +0100 Subject: Introduce "Set up autodeploy" button to help configure GitLab CI for deployment The button allows to choose a ".gitlab-ci.yml" template that automatically sets up the deployment of an application. The currently supported template is Kubernetes template. --- app/helpers/blob_helper.rb | 2 +- app/helpers/projects_helper.rb | 6 ++- app/views/projects/show.html.haml | 4 ++ changelogs/unreleased/adam-auto-deploy.yml | 4 ++ doc/ci/README.md | 1 + doc/ci/autodeploy/img/autodeploy_button.png | Bin 0 -> 41799 bytes doc/ci/autodeploy/img/autodeploy_dropdown.png | Bin 0 -> 46761 bytes doc/ci/autodeploy/index.md | 39 ++++++++++++++ lib/gitlab/template/gitlab_ci_yml_template.rb | 10 +++- spec/factories/projects.rb | 26 +++++----- spec/features/auto_deploy_spec.rb | 56 +++++++++++++++++++++ spec/features/environment_spec.rb | 2 +- spec/features/environments_spec.rb | 2 +- spec/models/environment_spec.rb | 6 +-- .../project_services/kubernetes_service_spec.rb | 2 +- spec/models/project_spec.rb | 2 +- spec/workers/reactive_caching_worker_spec.rb | 2 +- 17 files changed, 138 insertions(+), 26 deletions(-) create mode 100644 changelogs/unreleased/adam-auto-deploy.yml create mode 100644 doc/ci/autodeploy/img/autodeploy_button.png create mode 100644 doc/ci/autodeploy/img/autodeploy_dropdown.png create mode 100644 doc/ci/autodeploy/index.md create mode 100644 spec/features/auto_deploy_spec.rb diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index f31d4fb897d..c3508443d8a 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -188,7 +188,7 @@ module BlobHelper end def gitlab_ci_ymls - @gitlab_ci_ymls ||= Gitlab::Template::GitlabCiYmlTemplate.dropdown_names + @gitlab_ci_ymls ||= Gitlab::Template::GitlabCiYmlTemplate.dropdown_names(params[:context]) end def dockerfile_names diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index d2177f683a1..7445f3c113c 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -280,13 +280,15 @@ module ProjectsHelper end end - def add_special_file_path(project, file_name:, commit_message: nil) + def add_special_file_path(project, file_name:, commit_message: nil, target_branch: nil, context: nil) namespace_project_new_blob_path( project.namespace, project, project.default_branch || 'master', file_name: file_name, - commit_message: commit_message || "Add #{file_name.downcase}" + commit_message: commit_message || "Add #{file_name.downcase}", + target_branch: target_branch, + context: context ) end diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 8a214e1de58..a915c159cb4 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -68,6 +68,10 @@ - if koding_enabled? && @repository.koding_yml.blank? %li.missing = link_to 'Set up Koding', add_koding_stack_path(@project) + - if @repository.gitlab_ci_yml.blank? && @project.deployment_service.present? + %li.missing + = link_to add_special_file_path(@project, file_name: '.gitlab-ci.yml', commit_message: 'Set up autodeploy', target_branch: 'autodeploy', context: 'autodeploy') do + Set up autodeploy - if @repository.commit .project-last-commit{ class: container_class } diff --git a/changelogs/unreleased/adam-auto-deploy.yml b/changelogs/unreleased/adam-auto-deploy.yml new file mode 100644 index 00000000000..9d3348468d5 --- /dev/null +++ b/changelogs/unreleased/adam-auto-deploy.yml @@ -0,0 +1,4 @@ +--- +title: Introduce "Set up autodeploy" button to help configure GitLab CI for deployment +merge_request: 8135 +author: diff --git a/doc/ci/README.md b/doc/ci/README.md index 73bd2516d46..6a9495f8892 100644 --- a/doc/ci/README.md +++ b/doc/ci/README.md @@ -23,6 +23,7 @@ - [CI/CD pipelines settings](../user/project/pipelines/settings.md) - [Review Apps](review_apps/index.md) - [Git submodules](git_submodules.md) Using Git submodules in your CI jobs +- [Autodeploy](autodeploy/index.md) ## Breaking changes diff --git a/doc/ci/autodeploy/img/autodeploy_button.png b/doc/ci/autodeploy/img/autodeploy_button.png new file mode 100644 index 00000000000..9e2cd57a0ba Binary files /dev/null and b/doc/ci/autodeploy/img/autodeploy_button.png differ diff --git a/doc/ci/autodeploy/img/autodeploy_dropdown.png b/doc/ci/autodeploy/img/autodeploy_dropdown.png new file mode 100644 index 00000000000..1486a8ec0ea Binary files /dev/null and b/doc/ci/autodeploy/img/autodeploy_dropdown.png differ diff --git a/doc/ci/autodeploy/index.md b/doc/ci/autodeploy/index.md new file mode 100644 index 00000000000..503a00969d5 --- /dev/null +++ b/doc/ci/autodeploy/index.md @@ -0,0 +1,39 @@ +# Autodeploy + +> [Introduced][mr-8135] in GitLab 8.15. + +Autodeploy is an easy way to configure GitLab CI for the deployment of your +application. GitLab Community maintains a list of `.gitlab-ci.yml` +templates for various infrastructure providers and deployment scripts +powering them. These scripts are responsible for packaging your application, +setting up the infrastructure and spinning up necessary services (for +example a database). + +You can use [project services][project-services] to store credentials to +your infrastructure provider and they will be available during the +deployment. + +## Supported templates + +The list of supported autodeploy templates is available [here][autodeploy-templates]. + +## Configuration + +1. Enable a deployment [project service][project-services] to store your +credentials. For example, if you want to deploy to a Kubernetes cluster +you have to enable [Kubernetes service][kubernetes-service]. +1. Configure GitLab Runner to use [docker-in-docker executor][docker-in-docker]. +1. Navigate to the "Project" tab and click "Set up autodeploy" button. + ![Autodeploy button](img/autodeploy_button.png) +1. Select a template. + ![Dropdown with autodeploy templates](img/autodeploy_dropdown.png) +1. Commit your changes and create a merge request. +1. Test your deployment configuration using a [Review App][review-app] that was +created automatically for you. + +[mr-8135]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8135 +[project-services]: ../../project_services/project_services.md +[autodeploy-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml/tree/master/autodeploy +[kubernetes-service]: ../../project_services/kubernetes.md +[docker-in-docker]: ../docker/using_docker_build.md#use-docker-in-docker-executor +[review-app]: ../review_apps/index.md diff --git a/lib/gitlab/template/gitlab_ci_yml_template.rb b/lib/gitlab/template/gitlab_ci_yml_template.rb index 8d1a1ed54c9..d19b0a52043 100644 --- a/lib/gitlab/template/gitlab_ci_yml_template.rb +++ b/lib/gitlab/template/gitlab_ci_yml_template.rb @@ -13,8 +13,9 @@ module Gitlab def categories { - "General" => '', - "Pages" => 'Pages' + 'General' => '', + 'Pages' => 'Pages', + 'Autodeploy' => 'autodeploy' } end @@ -25,6 +26,11 @@ module Gitlab def finder(project = nil) Gitlab::Template::Finders::GlobalTemplateFinder.new(self.base_dir, self.extension, self.categories) end + + def dropdown_names(context) + categories = context == 'autodeploy' ? ['Autodeploy'] : ['General', 'Pages'] + super().slice(*categories) + end end end end diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index f7fa834d7a2..f4ab732caa4 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -48,6 +48,19 @@ FactoryGirl.define do end end + trait :kubernetes do + after :create do |project| + project.create_kubernetes_service( + active: true, + properties: { + namespace: project.path, + api_url: 'https://kubernetes.example.com/api', + token: 'a' * 40, + } + ) + end + end + # Nest Project Feature attributes transient do wiki_access_level ProjectFeature::ENABLED @@ -137,17 +150,4 @@ FactoryGirl.define do ) end end - - factory :kubernetes_project, parent: :empty_project do - after :create do |project| - project.create_kubernetes_service( - active: true, - properties: { - namespace: project.path, - api_url: 'https://kubernetes.example.com', - token: 'a' * 40, - } - ) - end - end end diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb new file mode 100644 index 00000000000..92c5b1cbb3b --- /dev/null +++ b/spec/features/auto_deploy_spec.rb @@ -0,0 +1,56 @@ +require 'spec_helper' + +describe 'Auto deploy' do + include WaitForAjax + + let(:user) { create(:user) } + let(:project) { create(:project, :kubernetes) } + + before do + project.team << [user, :master] + login_as user + end + + context 'when no deployment service is active' do + before do + project.kubernetes_service.update!(active: false) + end + + it 'does not show a button to set up auto deploy' do + visit namespace_project_path(project.namespace, project) + expect(page).to have_no_content('Set up autodeploy') + end + end + + context 'when a deployment service is active' do + before do + project.kubernetes_service.update!(active: true) + visit namespace_project_path(project.namespace, project) + end + + it 'shows a button to set up auto deploy' do + expect(page).to have_link('Set up autodeploy') + end + + it 'includes Kubernetes as an available template', js: true do + click_link 'Set up autodeploy' + click_button 'Choose a GitLab CI Yaml template' + + within '.gitlab-ci-yml-selector' do + expect(page).to have_content('Kubernetes') + end + end + + it 'creates a merge request using "autodeploy" branch', js: true do + click_link 'Set up autodeploy' + click_button 'Choose a GitLab CI Yaml template' + within '.gitlab-ci-yml-selector' do + click_on 'Kubernetes' + end + wait_for_ajax + click_button 'Commit Changes' + + expect(page).to have_content('New Merge Request From autodeploy into master') + end + end +end diff --git a/spec/features/environment_spec.rb b/spec/features/environment_spec.rb index 56f6cd2e095..c7411f1f4ac 100644 --- a/spec/features/environment_spec.rb +++ b/spec/features/environment_spec.rb @@ -93,7 +93,7 @@ feature 'Environment', :feature do end context 'with terminal' do - let(:project) { create(:kubernetes_project, :test_repo) } + let(:project) { create(:empty_project, :kubernetes, :test_repo) } context 'for project master' do let(:role) { :master } diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index 72b984cfab8..e1387e44be8 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -151,7 +151,7 @@ feature 'Environments page', :feature, :js do end context 'with terminal' do - let(:project) { create(:kubernetes_project, :test_repo) } + let(:project) { create(:empty_project, :kubernetes, :test_repo) } context 'for project master' do let(:role) { :master } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 93eb402e060..2aa63d7bcc3 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -200,7 +200,7 @@ describe Environment, models: true do context 'when the enviroment is available' do context 'with a deployment service' do - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } context 'and a deployment' do let!(:deployment) { create(:deployment, environment: environment) } @@ -218,14 +218,14 @@ describe Environment, models: true do end context 'when the environment is unavailable' do - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } before { environment.stop } it { is_expected.to be_falsy } end end describe '#terminals' do - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } subject { environment.terminals } context 'when the environment has terminals' do diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 4f3cd14e941..0b20f4d3154 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -4,7 +4,7 @@ describe KubernetesService, models: true, caching: true do include KubernetesHelpers include ReactiveCachingHelpers - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } let(:service) { project.kubernetes_service } # We use Kubeclient to interactive with the Kubernetes API. It will diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 88d5d14f855..8be99bbf3ee 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1719,7 +1719,7 @@ describe Project, models: true do end context 'when project has a deployment service' do - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } it 'returns variables from this service' do expect(project.deployment_variables).to include( diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb index 5f4453c15d6..c6009e25713 100644 --- a/spec/workers/reactive_caching_worker_spec.rb +++ b/spec/workers/reactive_caching_worker_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ReactiveCachingWorker do - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } let(:service) { project.deployment_service } subject { described_class.new.perform("KubernetesService", service.id) } -- cgit v1.2.1 From 3cb8f01b9a33925bd65347f4a97c6db2f787589c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 21 Dec 2016 21:13:13 +0100 Subject: Added Autodeploy script for OpenShift --- spec/features/auto_deploy_spec.rb | 4 +- .../autodeploy/OpenShift.gitlab-ci.yml | 74 ++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 vendor/gitlab-ci-yml/autodeploy/OpenShift.gitlab-ci.yml diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb index 92c5b1cbb3b..e581aa411b0 100644 --- a/spec/features/auto_deploy_spec.rb +++ b/spec/features/auto_deploy_spec.rb @@ -37,7 +37,7 @@ describe 'Auto deploy' do click_button 'Choose a GitLab CI Yaml template' within '.gitlab-ci-yml-selector' do - expect(page).to have_content('Kubernetes') + expect(page).to have_content('OpenShift') end end @@ -45,7 +45,7 @@ describe 'Auto deploy' do click_link 'Set up autodeploy' click_button 'Choose a GitLab CI Yaml template' within '.gitlab-ci-yml-selector' do - click_on 'Kubernetes' + click_on 'OpenShift' end wait_for_ajax click_button 'Commit Changes' diff --git a/vendor/gitlab-ci-yml/autodeploy/OpenShift.gitlab-ci.yml b/vendor/gitlab-ci-yml/autodeploy/OpenShift.gitlab-ci.yml new file mode 100644 index 00000000000..e384b585ae0 --- /dev/null +++ b/vendor/gitlab-ci-yml/autodeploy/OpenShift.gitlab-ci.yml @@ -0,0 +1,74 @@ +image: registry.gitlab.com/gitlab-examples/openshift-deploy + +variables: + # Application deployment domain + KUBE_DOMAIN: domain.example.com + +stages: + - build + - test + - review + - staging + - production + +build: + stage: build + script: + - command build + only: + - branches + +production: + stage: production + variables: + CI_ENVIRONMENT_URL: http://production.$KUBE_DOMAIN + script: + - command deploy + environment: + name: production + url: http://production.$KUBE_DOMAIN + when: manual + only: + - master + +staging: + stage: staging + variables: + CI_ENVIRONMENT_URL: http://staging.$KUBE_DOMAIN + script: + - command deploy + environment: + name: staging + url: http://staging.$KUBE_DOMAIN + only: + - master + +review: + stage: review + variables: + CI_ENVIRONMENT_URL: http://$CI_ENVIRONMENT_SLUG.$KUBE_DOMAIN + script: + - command deploy + environment: + name: review/$CI_BUILD_REF_NAME + url: http://$CI_ENVIRONMENT_SLUG.$KUBE_DOMAIN + on_stop: stop_review + only: + - branches + except: + - master + +stop_review: + stage: review + variables: + GIT_STRATEGY: none + script: + - command destroy + environment: + name: review/$CI_BUILD_REF_NAME + action: stop + when: manual + only: + - branches + except: + - master -- cgit v1.2.1 From 4a1e1281ac862a0c86d62473ab09d559c7ec5485 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 21 Dec 2016 21:25:23 +0100 Subject: Revert conflicting EE changes --- spec/factories/projects.rb | 26 +++++++++++----------- spec/features/auto_deploy_spec.rb | 10 ++++++++- spec/features/environment_spec.rb | 2 +- spec/features/environments_spec.rb | 2 +- spec/models/environment_spec.rb | 6 ++--- .../project_services/kubernetes_service_spec.rb | 2 +- spec/models/project_spec.rb | 2 +- spec/workers/reactive_caching_worker_spec.rb | 2 +- 8 files changed, 30 insertions(+), 22 deletions(-) diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index f4ab732caa4..f7fa834d7a2 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -48,19 +48,6 @@ FactoryGirl.define do end end - trait :kubernetes do - after :create do |project| - project.create_kubernetes_service( - active: true, - properties: { - namespace: project.path, - api_url: 'https://kubernetes.example.com/api', - token: 'a' * 40, - } - ) - end - end - # Nest Project Feature attributes transient do wiki_access_level ProjectFeature::ENABLED @@ -150,4 +137,17 @@ FactoryGirl.define do ) end end + + factory :kubernetes_project, parent: :empty_project do + after :create do |project| + project.create_kubernetes_service( + active: true, + properties: { + namespace: project.path, + api_url: 'https://kubernetes.example.com', + token: 'a' * 40, + } + ) + end + end end diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb index e581aa411b0..92f1ab90881 100644 --- a/spec/features/auto_deploy_spec.rb +++ b/spec/features/auto_deploy_spec.rb @@ -4,9 +4,17 @@ describe 'Auto deploy' do include WaitForAjax let(:user) { create(:user) } - let(:project) { create(:project, :kubernetes) } + let(:project) { create(:project) } before do + project.create_kubernetes_service( + active: true, + properties: { + namespace: project.path, + api_url: 'https://kubernetes.example.com', + token: 'a' * 40, + } + ) project.team << [user, :master] login_as user end diff --git a/spec/features/environment_spec.rb b/spec/features/environment_spec.rb index c7411f1f4ac..56f6cd2e095 100644 --- a/spec/features/environment_spec.rb +++ b/spec/features/environment_spec.rb @@ -93,7 +93,7 @@ feature 'Environment', :feature do end context 'with terminal' do - let(:project) { create(:empty_project, :kubernetes, :test_repo) } + let(:project) { create(:kubernetes_project, :test_repo) } context 'for project master' do let(:role) { :master } diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index e1387e44be8..72b984cfab8 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -151,7 +151,7 @@ feature 'Environments page', :feature, :js do end context 'with terminal' do - let(:project) { create(:empty_project, :kubernetes, :test_repo) } + let(:project) { create(:kubernetes_project, :test_repo) } context 'for project master' do let(:role) { :master } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 2aa63d7bcc3..93eb402e060 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -200,7 +200,7 @@ describe Environment, models: true do context 'when the enviroment is available' do context 'with a deployment service' do - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } context 'and a deployment' do let!(:deployment) { create(:deployment, environment: environment) } @@ -218,14 +218,14 @@ describe Environment, models: true do end context 'when the environment is unavailable' do - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } before { environment.stop } it { is_expected.to be_falsy } end end describe '#terminals' do - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } subject { environment.terminals } context 'when the environment has terminals' do diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 0b20f4d3154..4f3cd14e941 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -4,7 +4,7 @@ describe KubernetesService, models: true, caching: true do include KubernetesHelpers include ReactiveCachingHelpers - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } let(:service) { project.kubernetes_service } # We use Kubeclient to interactive with the Kubernetes API. It will diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 8be99bbf3ee..88d5d14f855 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1719,7 +1719,7 @@ describe Project, models: true do end context 'when project has a deployment service' do - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } it 'returns variables from this service' do expect(project.deployment_variables).to include( diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb index c6009e25713..5f4453c15d6 100644 --- a/spec/workers/reactive_caching_worker_spec.rb +++ b/spec/workers/reactive_caching_worker_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ReactiveCachingWorker do - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } let(:service) { project.deployment_service } subject { described_class.new.perform("KubernetesService", service.id) } -- cgit v1.2.1