Merge branch 'zj-auto-devops-table' of gitlab.com:zj/gitlab-ce into 37158-autodevops-banner
This commit is contained in:
commit
e5e0acfc4d
|
@ -247,7 +247,6 @@ setup-test-env:
|
|||
script:
|
||||
- node --version
|
||||
- yarn install --frozen-lockfile --cache-folder .yarn-cache
|
||||
- bundle exec rake gettext:po_to_json
|
||||
- bundle exec rake gitlab:assets:compile
|
||||
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
|
||||
- scripts/gitaly-test-build # Do not use 'bundle exec' here
|
||||
|
@ -412,7 +411,6 @@ db:migrate:reset-mysql:
|
|||
|
||||
.migration-paths: &migration-paths
|
||||
<<: *dedicated-runner
|
||||
<<: *only-canonical-masters
|
||||
<<: *pull-cache
|
||||
stage: test
|
||||
variables:
|
||||
|
@ -496,7 +494,6 @@ gitlab:assets:compile:
|
|||
NO_COMPRESSION: "true"
|
||||
script:
|
||||
- yarn install --frozen-lockfile --production --cache-folder .yarn-cache
|
||||
- bundle exec rake gettext:po_to_json
|
||||
- bundle exec rake gitlab:assets:compile
|
||||
artifacts:
|
||||
name: webpack-report
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.37.0
|
||||
0.38.0
|
||||
|
|
6
Gemfile
6
Gemfile
|
@ -31,7 +31,7 @@ gem 'omniauth-cas3', '~> 1.1.4'
|
|||
gem 'omniauth-facebook', '~> 4.0.0'
|
||||
gem 'omniauth-github', '~> 1.1.1'
|
||||
gem 'omniauth-gitlab', '~> 1.0.2'
|
||||
gem 'omniauth-google-oauth2', '~> 0.4.1'
|
||||
gem 'omniauth-google-oauth2', '~> 0.5.2'
|
||||
gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
|
||||
gem 'omniauth-oauth2-generic', '~> 0.2.2'
|
||||
gem 'omniauth-saml', '~> 1.7.0'
|
||||
|
@ -324,7 +324,7 @@ group :development, :test do
|
|||
# Generate Fake data
|
||||
gem 'ffaker', '~> 2.4'
|
||||
|
||||
gem 'capybara', '~> 2.6.2'
|
||||
gem 'capybara', '~> 2.15.0'
|
||||
gem 'capybara-screenshot', '~> 1.0.0'
|
||||
gem 'poltergeist', '~> 1.9.0'
|
||||
|
||||
|
@ -397,7 +397,7 @@ group :ed25519 do
|
|||
end
|
||||
|
||||
# Gitaly GRPC client
|
||||
gem 'gitaly-proto', '~> 0.32.0', require: 'gitaly'
|
||||
gem 'gitaly-proto', '~> 0.33.0', require: 'gitaly'
|
||||
|
||||
gem 'toml-rb', '~> 0.3.15', require: false
|
||||
|
||||
|
|
19
Gemfile.lock
19
Gemfile.lock
|
@ -100,9 +100,9 @@ GEM
|
|||
bundler (~> 1.2)
|
||||
thor (~> 0.18)
|
||||
byebug (9.0.6)
|
||||
capybara (2.6.2)
|
||||
capybara (2.15.1)
|
||||
addressable
|
||||
mime-types (>= 1.16)
|
||||
mini_mime (>= 0.1.3)
|
||||
nokogiri (>= 1.3.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
|
@ -275,7 +275,7 @@ GEM
|
|||
po_to_json (>= 1.0.0)
|
||||
rails (>= 3.2.0)
|
||||
gherkin-ruby (0.3.2)
|
||||
gitaly-proto (0.32.0)
|
||||
gitaly-proto (0.33.0)
|
||||
google-protobuf (~> 3.1)
|
||||
grpc (~> 1.0)
|
||||
github-linguist (4.7.6)
|
||||
|
@ -479,6 +479,7 @@ GEM
|
|||
method_source (0.8.2)
|
||||
mime-types (2.99.3)
|
||||
mimemagic (0.3.0)
|
||||
mini_mime (0.1.4)
|
||||
mini_portile2 (2.2.0)
|
||||
minitest (5.7.0)
|
||||
mmap2 (2.2.7)
|
||||
|
@ -529,8 +530,8 @@ GEM
|
|||
omniauth-gitlab (1.0.2)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.0)
|
||||
omniauth-google-oauth2 (0.4.1)
|
||||
jwt (~> 1.5.2)
|
||||
omniauth-google-oauth2 (0.5.2)
|
||||
jwt (~> 1.5)
|
||||
multi_json (~> 1.3)
|
||||
omniauth (>= 1.1.1)
|
||||
omniauth-oauth2 (>= 1.3.1)
|
||||
|
@ -948,7 +949,7 @@ GEM
|
|||
expression_parser
|
||||
rinku
|
||||
xml-simple (1.1.5)
|
||||
xpath (2.0.0)
|
||||
xpath (2.1.0)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
PLATFORMS
|
||||
|
@ -979,7 +980,7 @@ DEPENDENCIES
|
|||
browser (~> 2.2)
|
||||
bullet (~> 5.5.0)
|
||||
bundler-audit (~> 0.5.0)
|
||||
capybara (~> 2.6.2)
|
||||
capybara (~> 2.15.0)
|
||||
capybara-screenshot (~> 1.0.0)
|
||||
carrierwave (~> 1.1)
|
||||
charlock_holmes (~> 0.7.5)
|
||||
|
@ -1021,7 +1022,7 @@ DEPENDENCIES
|
|||
gettext (~> 3.2.2)
|
||||
gettext_i18n_rails (~> 1.8.0)
|
||||
gettext_i18n_rails_js (~> 1.2.0)
|
||||
gitaly-proto (~> 0.32.0)
|
||||
gitaly-proto (~> 0.33.0)
|
||||
github-linguist (~> 4.7.0)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab-markup (~> 1.5.1)
|
||||
|
@ -1075,7 +1076,7 @@ DEPENDENCIES
|
|||
omniauth-facebook (~> 4.0.0)
|
||||
omniauth-github (~> 1.1.1)
|
||||
omniauth-gitlab (~> 1.0.2)
|
||||
omniauth-google-oauth2 (~> 0.4.1)
|
||||
omniauth-google-oauth2 (~> 0.5.2)
|
||||
omniauth-kerberos (~> 0.3.0)
|
||||
omniauth-oauth2-generic (~> 0.2.2)
|
||||
omniauth-saml (~> 1.7.0)
|
||||
|
|
|
@ -175,7 +175,7 @@ GitLabDropdownFilter = (function() {
|
|||
elements.show().removeClass('option-hidden');
|
||||
}
|
||||
|
||||
elements.parent().find('.dropdown-menu-empty-link').toggleClass('hidden', elements.is(':visible'));
|
||||
elements.parent().find('.dropdown-menu-empty-item').toggleClass('hidden', elements.is(':visible'));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -247,7 +247,7 @@ GitLabDropdown = (function() {
|
|||
|
||||
currentIndex = -1;
|
||||
|
||||
NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link';
|
||||
NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-item';
|
||||
|
||||
SELECTABLE_CLASSES = ".dropdown-content li:not(" + NON_SELECTABLE_CLASSES + ", .option-hidden)";
|
||||
|
||||
|
@ -702,7 +702,7 @@ GitLabDropdown = (function() {
|
|||
|
||||
GitLabDropdown.prototype.noResults = function() {
|
||||
var html;
|
||||
return html = '<li class="dropdown-menu-empty-link"><a href="#" class="is-focused">No matching results</a></li>';
|
||||
return '<li class="dropdown-menu-empty-item"><a>No matching results</a></li>';
|
||||
};
|
||||
|
||||
GitLabDropdown.prototype.rowClicked = function(el) {
|
||||
|
|
|
@ -363,7 +363,7 @@
|
|||
|
||||
restoreMenu() {
|
||||
var html;
|
||||
html = "<ul> <li><a class='dropdown-menu-empty-link is-focused'>Loading...</a></li> </ul>";
|
||||
html = '<ul><li class="dropdown-menu-empty-item"><a>Loading...</a></li></ul>';
|
||||
return this.dropdownContent.html(html);
|
||||
}
|
||||
|
||||
|
|
|
@ -163,12 +163,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.dropdown-menu-empty-link {
|
||||
&.is-focused {
|
||||
background-color: $dropdown-empty-row-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&.dropdown-menu-user-link {
|
||||
line-height: 16px;
|
||||
}
|
||||
|
@ -256,6 +250,13 @@
|
|||
@include dropdown-link;
|
||||
}
|
||||
|
||||
.dropdown-menu-empty-item a {
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-header {
|
||||
color: $gl-text-color-secondary;
|
||||
font-size: 13px;
|
||||
|
@ -800,6 +801,13 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.dropdown-menu-empty-item a {
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.dropdown-menu-selectable {
|
||||
|
|
|
@ -515,16 +515,6 @@ header.navbar-gitlab-new {
|
|||
}
|
||||
}
|
||||
|
||||
.top-area {
|
||||
.nav-controls-new-nav {
|
||||
.dropdown {
|
||||
@media (min-width: $screen-sm-min) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-sign-in {
|
||||
margin-top: 3px;
|
||||
background-color: $indigo-100;
|
||||
|
|
|
@ -578,12 +578,12 @@
|
|||
@media (min-width: $screen-sm-min) {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 34px;
|
||||
top: 24px;
|
||||
background-color: $white-light;
|
||||
z-index: 190;
|
||||
|
||||
&.diff-files-changed-merge-request {
|
||||
top: 84px;
|
||||
top: 76px;
|
||||
}
|
||||
|
||||
+ .files,
|
||||
|
@ -614,6 +614,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
@media (min-width: $screen-sm-min) {
|
||||
.with-performance-bar {
|
||||
.diff-files-changed.diff-files-changed-merge-request {
|
||||
top: 76px + $performance-bar-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.diff-file-changes {
|
||||
width: 450px;
|
||||
z-index: 150;
|
||||
|
|
|
@ -220,7 +220,7 @@
|
|||
|
||||
.right-sidebar {
|
||||
position: absolute;
|
||||
top: $header-height;
|
||||
top: $new-navbar-height;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
transition: width .3s;
|
||||
|
@ -230,7 +230,7 @@
|
|||
|
||||
.issuable-sidebar {
|
||||
width: calc(100% + 100px);
|
||||
height: calc(100% - #{$header-height});
|
||||
height: calc(100% - #{$new-navbar-height});
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
@ -479,10 +479,10 @@
|
|||
}
|
||||
|
||||
.with-performance-bar .right-sidebar {
|
||||
top: $header-height + $performance-bar-height;
|
||||
top: $new-navbar-height + $performance-bar-height;
|
||||
|
||||
.issuable-sidebar {
|
||||
height: calc(100% - #{$header-height} - #{$performance-bar-height});
|
||||
height: calc(100% - #{$new-navbar-height} - #{$performance-bar-height});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -645,7 +645,7 @@
|
|||
}
|
||||
|
||||
.merge-request-tabs-holder {
|
||||
top: $header-height;
|
||||
top: $new-navbar-height;
|
||||
z-index: 200;
|
||||
background-color: $white-light;
|
||||
border-bottom: 1px solid $border-color;
|
||||
|
@ -675,7 +675,7 @@
|
|||
}
|
||||
|
||||
.with-performance-bar .merge-request-tabs-holder {
|
||||
top: $header-height + $performance-bar-height;
|
||||
top: $new-navbar-height + $performance-bar-height;
|
||||
}
|
||||
|
||||
.merge-request-tabs {
|
||||
|
|
|
@ -20,8 +20,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
def usage_data
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
usage_data = Gitlab::UsageData.data
|
||||
usage_data_json = params[:pretty] ? JSON.pretty_generate(usage_data) : usage_data.to_json
|
||||
usage_data_json = JSON.pretty_generate(Gitlab::UsageData.data)
|
||||
|
||||
render html: Gitlab::Highlight.highlight('payload.json', usage_data_json)
|
||||
end
|
||||
|
|
|
@ -99,7 +99,9 @@ module TreeHelper
|
|||
end
|
||||
|
||||
# returns the relative path of the first subdir that doesn't have only one directory descendant
|
||||
def flatten_tree(tree)
|
||||
def flatten_tree(root_path, tree)
|
||||
return tree.flat_path.sub(/\A#{root_path}\//, '') if tree.flat_path.present?
|
||||
|
||||
subtree = Gitlab::Git::Tree.where(@repository, @commit.id, tree.path)
|
||||
if subtree.count == 1 && subtree.first.dir?
|
||||
return tree_join(tree.name, flatten_tree(subtree.first))
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
= succeed '.' do
|
||||
= link_to 'application settings', admin_application_settings_path(anchor: 'usage-statistics')
|
||||
|
||||
%pre.usage-data.js-syntax-highlight.code.highlight{ data: { endpoint: usage_data_admin_application_settings_path(format: :html, pretty: true) } }
|
||||
%pre.usage-data.js-syntax-highlight.code.highlight{ data: { endpoint: usage_data_admin_application_settings_path(format: :html) } }
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
- if current_user.can_create_group?
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to "New group", new_group_path, class: "btn btn-new"
|
||||
|
||||
.top-area
|
||||
%ul.nav-links
|
||||
= nav_link(page: dashboard_groups_path) do
|
||||
|
@ -10,8 +6,8 @@
|
|||
= nav_link(page: explore_groups_path) do
|
||||
= link_to explore_groups_path, title: 'Explore public groups' do
|
||||
Explore public groups
|
||||
.nav-controls.nav-controls-new-nav
|
||||
.nav-controls
|
||||
= render 'shared/groups/search_form'
|
||||
= render 'shared/groups/dropdown'
|
||||
- if current_user.can_create_group?
|
||||
= link_to "New group", new_group_path, class: "btn btn-new visible-xs"
|
||||
= link_to "New group", new_group_path, class: "btn btn-new"
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
= content_for :flash_message do
|
||||
= render 'shared/project_limit'
|
||||
|
||||
- if current_user.can_create_project?
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to "New project", new_project_path, class: 'btn btn-new'
|
||||
|
||||
.top-area.scrolling-tabs-container.inner-page-scroll-tabs
|
||||
.fade-left= icon('angle-left')
|
||||
.fade-right= icon('angle-right')
|
||||
|
@ -19,8 +15,8 @@
|
|||
= link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
|
||||
Explore projects
|
||||
|
||||
.nav-controls.nav-controls-new-nav
|
||||
.nav-controls
|
||||
= render 'shared/projects/search_form'
|
||||
= render 'shared/projects/dropdown'
|
||||
- if current_user.can_create_project?
|
||||
= link_to "New project", new_project_path, class: "btn btn-new visible-xs"
|
||||
= link_to "New project", new_project_path, class: "btn btn-new"
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
- if current_user
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to "New snippet", new_snippet_path, class: "btn btn-new", title: "New snippet"
|
||||
|
||||
.top-area
|
||||
%ul.nav-links
|
||||
= nav_link(page: dashboard_snippets_path, html_options: {class: 'home'}) do
|
||||
|
@ -10,3 +6,7 @@
|
|||
= nav_link(page: explore_snippets_path) do
|
||||
= link_to explore_snippets_path, title: 'Explore snippets', data: {placement: 'right'} do
|
||||
Explore Snippets
|
||||
|
||||
- if current_user
|
||||
.nav-controls.hidden-xs
|
||||
= link_to "New snippet", new_snippet_path, class: "btn btn-new", title: "New snippet"
|
||||
|
|
|
@ -4,14 +4,9 @@
|
|||
= content_for :meta_tags do
|
||||
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{current_user.name} issues")
|
||||
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to params.merge(rss_url_options), class: 'btn has-tooltip append-right-10', title: 'Subscribe' do
|
||||
= icon('rss')
|
||||
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
|
||||
|
||||
.top-area
|
||||
= render 'shared/issuable/nav', type: :issues
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
= link_to params.merge(rss_url_options), class: 'btn has-tooltip', title: 'Subscribe' do
|
||||
= icon('rss')
|
||||
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
- page_title "Merge Requests"
|
||||
- header_title "Merge Requests", merge_requests_dashboard_path(assignee_id: current_user.id)
|
||||
|
||||
- content_for :breadcrumbs_extra do
|
||||
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
|
||||
|
||||
.top-area
|
||||
= render 'shared/issuable/nav', type: :merge_requests
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
|
||||
|
||||
= render 'shared/issuable/filter', type: :merge_requests
|
||||
|
|
|
@ -2,13 +2,10 @@
|
|||
- page_title 'Milestones'
|
||||
- header_title 'Milestones', dashboard_milestones_path
|
||||
|
||||
- content_for :breadcrumbs_extra do
|
||||
= render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true, type: :milestones
|
||||
|
||||
.top-area
|
||||
= render 'shared/milestones_filter', counts: @milestone_states
|
||||
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
= render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true, type: :milestones
|
||||
|
||||
.milestones
|
||||
|
|
|
@ -8,18 +8,10 @@
|
|||
= webpack_bundle_tag 'common_vue'
|
||||
= webpack_bundle_tag 'filtered_search'
|
||||
|
||||
- if group_issues_exists
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to params.merge(rss_url_options), class: 'btn btn-default append-right-10' do
|
||||
= icon('rss')
|
||||
%span.icon-label
|
||||
Subscribe
|
||||
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", type: :issues
|
||||
|
||||
- if group_issues_exists
|
||||
.top-area
|
||||
= render 'shared/issuable/nav', type: :issues
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
= link_to params.merge(rss_url_options), class: 'btn' do
|
||||
= icon('rss')
|
||||
%span.icon-label
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
- page_title 'Labels'
|
||||
- if can?(current_user, :admin_label, @group)
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to "New label", new_group_label_path(@group), class: "btn btn-new"
|
||||
|
||||
= render "groups/head_issues"
|
||||
|
||||
|
@ -10,7 +7,7 @@
|
|||
.nav-text
|
||||
Labels can be applied to issues and merge requests. Group labels are available for any project within the group.
|
||||
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
- if can?(current_user, :admin_label, @group)
|
||||
= link_to "New label", new_group_label_path(@group), class: "btn btn-new"
|
||||
|
||||
|
|
|
@ -4,17 +4,13 @@
|
|||
= webpack_bundle_tag 'common_vue'
|
||||
= webpack_bundle_tag 'filtered_search'
|
||||
|
||||
- if current_user
|
||||
- content_for :breadcrumbs_extra do
|
||||
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests
|
||||
|
||||
- if @group_merge_requests.empty?
|
||||
= render 'shared/empty_states/merge_requests', project_select_button: true
|
||||
- else
|
||||
.top-area
|
||||
= render 'shared/issuable/nav', type: :merge_requests
|
||||
- if current_user
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests
|
||||
|
||||
= render 'shared/issuable/search_bar', type: :merge_requests
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
- page_title "Milestones"
|
||||
- if can?(current_user, :admin_milestones, @group)
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"
|
||||
|
||||
= render "groups/head_issues"
|
||||
|
||||
.top-area
|
||||
= render 'shared/milestones_filter', counts: @milestone_states
|
||||
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
- if can?(current_user, :admin_milestones, @group)
|
||||
= link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
.dropdown-menu.dropdown-select
|
||||
= dropdown_content do
|
||||
%ul
|
||||
%li
|
||||
%a.is-focused.dropdown-menu-empty-link
|
||||
%li.dropdown-menu-empty-item
|
||||
%a
|
||||
Loading...
|
||||
= dropdown_loading
|
||||
%i.search-icon
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
- hide_top_links = @hide_top_links || false
|
||||
|
||||
%nav.breadcrumbs{ role: "navigation", class: [container, @content_class] }
|
||||
.breadcrumbs-container{ class: [container, @content_class] }
|
||||
.breadcrumbs-container
|
||||
- if defined?(@left_sidebar)
|
||||
= button_tag class: 'toggle-mobile-nav', type: 'button' do
|
||||
%span.sr-only Open sidebar
|
||||
|
@ -17,6 +17,4 @@
|
|||
= render "layouts/nav/breadcrumbs/collapsed_dropdown", location: :after
|
||||
%li
|
||||
%h2.breadcrumbs-sub-title= @breadcrumb_title
|
||||
- if content_for?(:breadcrumbs_extra)
|
||||
.breadcrumbs-extra.hidden-xs= yield :breadcrumbs_extra
|
||||
= yield :header_content
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
- @content_class = "limit-container-width" unless fluid_layout
|
||||
= render 'profiles/head'
|
||||
|
||||
= bootstrap_form_for @user, url: profile_path, method: :put, html: { multipart: true, class: 'edit-user prepend-top-default' }, authenticity_token: true do |f|
|
||||
= bootstrap_form_for @user, url: profile_path, method: :put, html: { multipart: true, class: 'edit-user prepend-top-default js-quick-submit' }, authenticity_token: true do |f|
|
||||
= form_errors(@user)
|
||||
|
||||
.row
|
||||
|
|
|
@ -29,6 +29,6 @@
|
|||
+#{diff_file.added_lines}
|
||||
%span.cred<
|
||||
\-#{diff_file.removed_lines}
|
||||
%li.dropdown-menu-empty-link.hidden
|
||||
%a{ href: "#" }
|
||||
%li.dropdown-menu-empty-item.hidden
|
||||
%a
|
||||
No files found.
|
||||
|
|
|
@ -13,14 +13,11 @@
|
|||
= content_for :meta_tags do
|
||||
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@project.name} issues")
|
||||
|
||||
- content_for :breadcrumbs_extra do
|
||||
= render "projects/issues/nav_btns"
|
||||
|
||||
- if project_issues(@project).exists?
|
||||
%div{ class: (container_class) }
|
||||
.top-area
|
||||
= render 'shared/issuable/nav', type: :issues
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
= render "projects/issues/nav_btns"
|
||||
= render 'shared/issuable/search_bar', type: :issues
|
||||
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
- hide_class = ''
|
||||
- can_admin_label = can?(current_user, :admin_label, @project)
|
||||
|
||||
- if can?(current_user, :admin_label, @project)
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to "New label", new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new"
|
||||
|
||||
= render "shared/mr_head"
|
||||
|
||||
- if @labels.exists? || @prioritized_labels.exists?
|
||||
|
@ -18,7 +14,7 @@
|
|||
Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.
|
||||
|
||||
- if can_admin_label
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
= link_to new_project_label_path(@project), class: "btn btn-new" do
|
||||
New label
|
||||
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
= webpack_bundle_tag 'common_vue'
|
||||
= webpack_bundle_tag 'filtered_search'
|
||||
|
||||
- content_for :breadcrumbs_extra do
|
||||
= render "projects/merge_requests/nav_btns", merge_project: merge_project, new_merge_request_path: new_merge_request_path
|
||||
|
||||
= render 'projects/last_push'
|
||||
|
||||
- if @project.merge_requests.exists?
|
||||
|
@ -23,7 +20,7 @@
|
|||
= render 'shared/auto_devops_callout'
|
||||
.top-area
|
||||
= render 'shared/issuable/nav', type: :merge_requests
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
= render "projects/merge_requests/nav_btns", merge_project: merge_project, new_merge_request_path: new_merge_request_path
|
||||
|
||||
= render 'shared/issuable/search_bar', type: :merge_requests
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
- @no_container = true
|
||||
- page_title 'Milestones'
|
||||
|
||||
- if can?(current_user, :admin_milestone, @project)
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to "New milestone", new_namespace_project_milestone_path(@project.namespace, @project), class: 'btn btn-new', title: 'New milestone'
|
||||
|
||||
= render "shared/mr_head"
|
||||
|
||||
%div{ class: container_class }
|
||||
.top-area
|
||||
= render 'shared/milestones_filter', counts: milestone_counts(@project.milestones)
|
||||
|
||||
.nav-controls.nav-controls-new-nav
|
||||
.nav-controls
|
||||
= render 'shared/milestones_sort_dropdown'
|
||||
- if can?(current_user, :admin_milestone, @project)
|
||||
= link_to new_project_milestone_path(@project), class: "btn btn-new visible-xs", title: 'New milestone' do
|
||||
= link_to new_project_milestone_path(@project), class: "btn btn-new", title: 'New milestone' do
|
||||
New milestone
|
||||
|
||||
.milestones
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
- @no_container = true
|
||||
- page_title _("Pipeline Schedules")
|
||||
|
||||
- if can?(current_user, :create_pipeline_schedule, @project)
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to _('New schedule'), new_namespace_project_pipeline_schedule_path(@project.namespace, @project), class: 'btn btn-create'
|
||||
|
||||
= render "projects/pipelines/head"
|
||||
|
||||
%div{ class: container_class }
|
||||
|
@ -20,7 +16,7 @@
|
|||
= render "tabs", schedule_path_proc: schedule_path_proc, all_schedules: @all_schedules, scope: @scope
|
||||
|
||||
- if can?(current_user, :create_pipeline_schedule, @project)
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
= link_to new_project_pipeline_schedule_path(@project), class: 'btn btn-create' do
|
||||
%span= _('New schedule')
|
||||
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
- page_title "Snippets"
|
||||
|
||||
- if can?(current_user, :create_project_snippet, @project)
|
||||
- content_for :breadcrumbs_extra do
|
||||
= link_to "New snippet", new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New snippet"
|
||||
|
||||
- if current_user
|
||||
.top-area
|
||||
- include_private = @project.team.member?(current_user) || current_user.admin?
|
||||
= render partial: 'snippets/snippets_scope_menu', locals: { subject: @project, include_private: include_private }
|
||||
|
||||
.nav-controls.visible-xs
|
||||
.nav-controls
|
||||
- if can?(current_user, :create_project_snippet, @project)
|
||||
= link_to "New snippet", new_project_snippet_path(@project), class: "btn btn-new", title: "New snippet"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
%tr{ class: "tree-item #{tree_hex_class(tree_item)}" }
|
||||
%td.tree-item-file-name
|
||||
= tree_icon(type, tree_item.mode, tree_item.name)
|
||||
- path = flatten_tree(tree_item)
|
||||
- path = flatten_tree(@path, tree_item)
|
||||
= link_to project_tree_path(@project, tree_join(@id || @commit.id, path)), title: path do
|
||||
%span.str-truncated= path
|
||||
%td.hidden-xs.tree-commit
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove focus styles from dropdown empty links
|
||||
merge_request:
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add description template examples to documentation
|
||||
merge_request:
|
||||
author:
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add quick submission on user settings page
|
||||
merge_request: 14007
|
||||
author: Vitaliy @blackst0ne Klachkov
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add API support for wiki pages
|
||||
merge_request: 13372
|
||||
author: Vitaliy @blackst0ne Klachkov
|
||||
type: added
|
|
@ -18,6 +18,7 @@ class MigrateIssuesToGhostUser < ActiveRecord::Migration
|
|||
ActiveRecord::Base.clear_cache!
|
||||
|
||||
::User.reset_column_information
|
||||
::Namespace.reset_column_information
|
||||
end
|
||||
|
||||
def up
|
||||
|
|
|
@ -3,19 +3,14 @@ class CreateProjectAutoDevOps < ActiveRecord::Migration
|
|||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
create_table :project_auto_devops do |t|
|
||||
t.belongs_to :project, null: false, index: { unique: true }
|
||||
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
|
||||
|
||||
add_timestamps_with_timezone(:project_auto_devops, null: false)
|
||||
|
||||
# No need to check for violations as its a new table
|
||||
add_concurrent_foreign_key(:project_auto_devops, :projects, column: :project_id)
|
||||
end
|
||||
|
||||
def down
|
||||
|
|
|
@ -1130,10 +1130,10 @@ ActiveRecord::Schema.define(version: 20170905112933) do
|
|||
|
||||
create_table "project_auto_devops", force: :cascade do |t|
|
||||
t.integer "project_id", null: false
|
||||
t.boolean "enabled"
|
||||
t.string "domain"
|
||||
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
|
||||
|
@ -1755,7 +1755,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", name: "fk_45436b12b2", 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
|
||||
|
|
|
@ -58,6 +58,7 @@ following locations:
|
|||
- [Validate CI configuration](lint.md)
|
||||
- [V3 to V4](v3_to_v4.md)
|
||||
- [Version](version.md)
|
||||
- [Wikis](wikis.md)
|
||||
|
||||
## Road to GraphQL
|
||||
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
# Wikis API
|
||||
|
||||
> [Introduced][ce-13372] in GitLab 10.0.
|
||||
|
||||
Available only in APIv4.
|
||||
|
||||
## List wiki pages
|
||||
|
||||
Get all wiki pages for a given project.
|
||||
|
||||
```
|
||||
GET /projects/:id/wikis
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ------- | -------- | --------------------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
|
||||
| `with_content` | boolean | no | Include pages' content |
|
||||
|
||||
```bash
|
||||
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/wikis?with_content=1
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"content" : "Here is an instruction how to deploy this project.",
|
||||
"format" : "markdown",
|
||||
"slug" : "deploy",
|
||||
"title" : "deploy"
|
||||
},
|
||||
{
|
||||
"content" : "Our development process is described here.",
|
||||
"format" : "markdown",
|
||||
"slug" : "development",
|
||||
"title" : "development"
|
||||
},{
|
||||
"content" : "* [Deploy](deploy)\n* [Development](development)",
|
||||
"format" : "markdown",
|
||||
"slug" : "home",
|
||||
"title" : "home"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Get a wiki page
|
||||
|
||||
Get a wiki page for a given project.
|
||||
|
||||
```
|
||||
GET /projects/:id/wikis/:slug
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ------- | -------- | --------------------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
|
||||
| `slug` | string | yes | The slug (a unique string) of the wiki page |
|
||||
|
||||
```bash
|
||||
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/wikis/home
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"content" : "home page",
|
||||
"format" : "markdown",
|
||||
"slug" : "home",
|
||||
"title" : "home"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Create a new wiki page
|
||||
|
||||
Creates a new wiki page for the given repository with the given title, slug, and content.
|
||||
|
||||
```
|
||||
POST /projects/:id/wikis
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| ------------- | ------- | -------- | ---------------------------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
|
||||
| `content` | string | yes | The content of the wiki page |
|
||||
| `title` | string | yes | The title of the wiki page |
|
||||
| `format` | string | no | The format of the wiki page. Available formats are: `markdown` (default), `rdoc`, and `asciidoc` |
|
||||
|
||||
```bash
|
||||
curl --data "format=rdoc&title=Hello&content=Hello world" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/wikis"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"content" : "Hello world",
|
||||
"format" : "markdown",
|
||||
"slug" : "Hello",
|
||||
"title" : "Hello"
|
||||
}
|
||||
```
|
||||
|
||||
## Edit an existing wiki page
|
||||
|
||||
Updates an existing wiki page. At least one parameter is required to update the wiki page.
|
||||
|
||||
```
|
||||
PUT /projects/:id/wikis/:slug
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------------- | ------- | --------------------------------- | ------------------------------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
|
||||
| `content` | string | yes if `title` is not provided | The content of the wiki page |
|
||||
| `title` | string | yes if `content` is not provided | The title of the wiki page |
|
||||
| `format` | string | no | The format of the wiki page. Available formats are: `markdown` (default), `rdoc`, and `asciidoc` |
|
||||
| `slug` | string | yes | The slug (a unique string) of the wiki page |
|
||||
|
||||
|
||||
```bash
|
||||
curl --request PUT --data "format=rdoc&content=documentation&title=Docs" --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/wikis/foo"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"content" : "documentation",
|
||||
"format" : "markdown",
|
||||
"slug" : "Docs",
|
||||
"title" : "Docs"
|
||||
}
|
||||
```
|
||||
|
||||
## Delete a wiki page
|
||||
|
||||
Deletes a wiki page with a given slug.
|
||||
|
||||
```
|
||||
DELETE /projects/:id/wikis/:slug
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ------- | -------- | --------------------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
|
||||
| `slug` | string | yes | The slug (a unique string) of the wiki page |
|
||||
|
||||
```bash
|
||||
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/wikis/foo"
|
||||
```
|
||||
|
||||
On success the HTTP status code is `204` and no JSON response is expected.
|
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
Binary file not shown.
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 74 KiB |
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -1,8 +1,13 @@
|
|||
# Auto deploy
|
||||
# Auto Deploy
|
||||
|
||||
> [Introduced][mr-8135] in GitLab 8.15.
|
||||
> Auto deploy is an experimental feature and is not recommended for Production use at this time.
|
||||
> As of GitLab 9.1, access to the container registry is only available while the Pipeline is running. Restarting a pod, scaling a service, or other actions which require on-going access will fail. On-going secure access is planned for a subsequent release.
|
||||
>**Notes:**
|
||||
- [Introduced][mr-8135] in GitLab 8.15.
|
||||
- Auto deploy is an experimental feature and is not recommended for Production
|
||||
use at this time.
|
||||
- As of GitLab 9.1, access to the Container Registry is only available while
|
||||
the Pipeline is running. Restarting a pod, scaling a service, or other actions
|
||||
which require on-going access will fail. On-going secure access is planned for
|
||||
a subsequent release.
|
||||
|
||||
Auto deploy is an easy way to configure GitLab CI for the deployment of your
|
||||
application. GitLab Community maintains a list of `.gitlab-ci.yml`
|
||||
|
@ -11,9 +16,23 @@ 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.
|
||||
## How it works
|
||||
|
||||
The Autodeploy templates are based on the [kubernetes-deploy][kube-deploy]
|
||||
project which is used to simplify the deployment process to Kubernetes by
|
||||
providing intelligent `build`, `deploy`, and `destroy` commands which you can
|
||||
use in your `.gitlab-ci.yml` as is. It uses [Herokuish](https://github.com/gliderlabs/herokuish),
|
||||
which uses [Heroku buildpacks](https://devcenter.heroku.com/articles/buildpacks)
|
||||
to do some of the work, plus some of GitLab's own tools to package it all up. For
|
||||
your convenience, a [Docker image][kube-image] is also provided.
|
||||
|
||||
You can use the [Kubernetes project service](../../user/project/integrations/kubernetes.md)
|
||||
to store credentials to your infrastructure provider and they will be available
|
||||
during the deployment.
|
||||
|
||||
## Quick start
|
||||
|
||||
We made a [simple guide](quick_start_guide.md) to using Auto Deploy with GitLab.com.
|
||||
|
||||
## Supported templates
|
||||
|
||||
|
@ -22,20 +41,27 @@ The list of supported auto deploy templates is available in the
|
|||
|
||||
## Configuration
|
||||
|
||||
>**Note:**
|
||||
In order to understand why the following steps are required, read the
|
||||
[how it works](#how-it-works) section.
|
||||
|
||||
To configure Autodeploy, you will need to:
|
||||
|
||||
1. Enable a deployment [project service][project-services] to store your
|
||||
credentials. For example, if you want to deploy to OpenShift you have to
|
||||
enable [Kubernetes service][kubernetes-service].
|
||||
1. Configure GitLab Runner to use Docker or Kubernetes executor with
|
||||
[privileged mode enabled][docker-in-docker].
|
||||
credentials. For example, if you want to deploy to OpenShift you have to
|
||||
enable [Kubernetes service][kubernetes-service].
|
||||
1. Configure GitLab Runner to use the
|
||||
[Docker or Kubernetes executor](https://docs.gitlab.com/runner/executors/) with
|
||||
[privileged mode enabled][docker-in-docker].
|
||||
1. Navigate to the "Project" tab and click "Set up auto deploy" button.
|
||||
![Auto deploy button](img/auto_deploy_button.png)
|
||||
1. Select a template.
|
||||
![Dropdown with auto deploy templates](img/auto_deploy_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.
|
||||
created automatically for you.
|
||||
|
||||
## Private Project Support
|
||||
## Private project support
|
||||
|
||||
> Experimental support [introduced][mr-2] in GitLab 9.1.
|
||||
|
||||
|
@ -43,7 +69,7 @@ When a project has been marked as private, GitLab's [Container Registry][contain
|
|||
|
||||
After the pipeline completes, Kubernetes will no longer be able to access the container registry. Restarting a pod, scaling a service, or other actions which require on-going access to the registry will fail. On-going secure access is planned for a subsequent release.
|
||||
|
||||
## PostgreSQL Database Support
|
||||
## PostgreSQL database support
|
||||
|
||||
> Experimental support [introduced][mr-8] in GitLab 9.1.
|
||||
|
||||
|
@ -51,25 +77,13 @@ In order to support applications that require a database, [PostgreSQL][postgresq
|
|||
|
||||
PostgreSQL provisioning can be disabled by setting the variable `DISABLE_POSTGRES` to `"yes"`.
|
||||
|
||||
### PostgreSQL Variables
|
||||
The following PostgreSQL variables are supported:
|
||||
|
||||
1. `DISABLE_POSTGRES: "yes"`: disable automatic deployment of PostgreSQL
|
||||
1. `POSTGRES_USER: "my-user"`: use custom username for PostgreSQL
|
||||
1. `POSTGRES_PASSWORD: "password"`: use custom password for PostgreSQL
|
||||
1. `POSTGRES_DB: "my database"`: use custom database name for PostgreSQL
|
||||
|
||||
[mr-8135]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8135
|
||||
[mr-2]: https://gitlab.com/gitlab-examples/kubernetes-deploy/merge_requests/2
|
||||
[mr-8]: https://gitlab.com/gitlab-examples/kubernetes-deploy/merge_requests/8
|
||||
[project-settings]: https://docs.gitlab.com/ce/public_access/public_access.html
|
||||
[project-services]: ../../user/project/integrations/project_services.md
|
||||
[auto-deploy-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml/tree/master/autodeploy
|
||||
[kubernetes-service]: ../../user/project/integrations/kubernetes.md
|
||||
[docker-in-docker]: ../docker/using_docker_build.md#use-docker-in-docker-executor
|
||||
[review-app]: ../review_apps/index.md
|
||||
[container-registry]: https://docs.gitlab.com/ce/user/project/container_registry.html
|
||||
[postgresql]: https://www.postgresql.org/
|
||||
|
||||
## Auto Monitoring
|
||||
|
||||
> Introduced in [GitLab 9.5](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13438).
|
||||
|
@ -94,3 +108,18 @@ If you have installed GitLab using a different method:
|
|||
1. [Deploy Prometheus](../../user/project/integrations/prometheus.md#configuring-your-own-prometheus-server-within-kubernetes) into your Kubernetes cluster
|
||||
1. If you would like response metrics, ensure you are running at least version 0.9.0 of NGINX Ingress and [enable Prometheus metrics](https://github.com/kubernetes/ingress/blob/master/examples/customization/custom-vts-metrics/nginx/nginx-vts-metrics-conf.yaml).
|
||||
1. Finally, [annotate](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) the NGINX Ingress deployment to be scraped by Prometheus using `prometheus.io/scrape: "true"` and `prometheus.io/port: "10254"`.
|
||||
|
||||
[mr-8135]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8135
|
||||
[mr-2]: https://gitlab.com/gitlab-examples/kubernetes-deploy/merge_requests/2
|
||||
[mr-8]: https://gitlab.com/gitlab-examples/kubernetes-deploy/merge_requests/8
|
||||
[project-settings]: https://docs.gitlab.com/ce/public_access/public_access.html
|
||||
[project-services]: ../../user/project/integrations/project_services.md
|
||||
[auto-deploy-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml/tree/master/autodeploy
|
||||
[kubernetes-service]: ../../user/project/integrations/kubernetes.md
|
||||
[docker-in-docker]: ../docker/using_docker_build.md#use-docker-in-docker-executor
|
||||
[review-app]: ../review_apps/index.md
|
||||
[kube-image]: https://gitlab.com/gitlab-examples/kubernetes-deploy/container_registry "Kubernetes deploy Container Registry"
|
||||
[kube-deploy]: https://gitlab.com/gitlab-examples/kubernetes-deploy "Kubernetes deploy example project"
|
||||
[container-registry]: https://docs.gitlab.com/ce/user/project/container_registry.html
|
||||
[postgresql]: https://www.postgresql.org/
|
||||
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
# Auto Deploy: quick start guide
|
||||
|
||||
This is a step-by-step guide to deploying a project hosted on GitLab.com to Google Cloud, using Auto Deploy.
|
||||
|
||||
We made a minimal [Ruby application](https://gitlab.com/gitlab-examples/minimal-ruby-app) to use as an example for this guide. It contains two files:
|
||||
|
||||
* `server.rb` - our application. It will start an HTTP server on port 5000 and render “Hello, world!”
|
||||
* `Dockerfile` - to build our app into a container image. It will use a ruby base image and run `server.rb`
|
||||
|
||||
## Fork sample project on GitLab.com
|
||||
|
||||
Let’s start by forking our sample application. Go to [the project page](https://gitlab.com/gitlab-examples/minimal-ruby-app) and press the `Fork` button. Soon you should have a project under your namespace with the necessary files.
|
||||
|
||||
## Setup your own cluster on Google Container Engine
|
||||
|
||||
If you do not already have a Google Cloud account, create one at https://console.cloud.google.com.
|
||||
|
||||
Visit the [`Container Engine`](https://console.cloud.google.com/kubernetes/list) tab and create a new cluster. You can change the name and leave the rest of the default settings. Once you have your cluster running, you need to connect to the cluster by following the Google interface.
|
||||
|
||||
## Connect to Kubernetes cluster
|
||||
|
||||
You need to have the Google Cloud SDK installed. e.g.
|
||||
On OSX, install [homebrew](https://brew.sh):
|
||||
|
||||
1. Install Brew Caskroom: `brew install caskroom/cask/brew-cask`
|
||||
2. Install Google Cloud SDK: `brew cask install google-cloud-sdk`
|
||||
3. Add `kubectl`: `gcloud components install kubectl`
|
||||
4. Log in: `gcloud auth login`
|
||||
|
||||
Now go back to the Google interface, find your cluster, and follow the instructions under `Connect to the cluster` and open the Kubernetes Dashboard. It will look something like `gcloud container clusters get-credentials ruby-autodeploy \ --zone europe-west2-c --project api-project-XXXXXXX` and then `kubectl proxy`.
|
||||
|
||||
![connect to cluster](img/guide_connect_cluster.png)
|
||||
|
||||
## Copy credentials to GitLab.com project
|
||||
|
||||
Once you have the Kubernetes Dashboard interface running, you should visit `Secrets` under the `Config` section. There you should find the settings we need for GitLab integration: ca.crt and token.
|
||||
|
||||
![connect to cluster](img/guide_secret.png)
|
||||
|
||||
You need to copy-paste the ca.crt and token into your project on GitLab.com in the Kubernetes integration page under project `Settings` > `Integrations` > `Project services` > `Kubernetes`. Don't actually copy the namespace though. Each project should have a unique namespace, and by leaving it blank, GitLab will create one for you.
|
||||
|
||||
![connect to cluster](img/guide_integration.png)
|
||||
|
||||
For API URL, you should use the `Endpoint` IP from your cluster page on Google Cloud Platform.
|
||||
|
||||
## Expose the application to the internet
|
||||
|
||||
In order to be able to visit your application, you need to install an NGINX ingress controller and point your domain name to its external IP address.
|
||||
|
||||
### Set up Ingress controller
|
||||
|
||||
You’ll need to make sure you have an ingress controller. If you don’t have one, do:
|
||||
|
||||
```sh
|
||||
brew install kubernetes-helm
|
||||
helm init
|
||||
helm install --name ruby-app stable/nginx-ingress
|
||||
```
|
||||
|
||||
This should create several services including `ruby-app-nginx-ingress-controller`. You can list your services by running `kubectl get svc` to confirm that.
|
||||
|
||||
### Point DNS at Cluster IP
|
||||
|
||||
Find out the external IP address of the `ruby-app-nginx-ingress-controller` by running:
|
||||
|
||||
```sh
|
||||
kubectl get svc ruby-app-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
|
||||
```
|
||||
|
||||
Use this IP address to configure your DNS. This part heavily depends on your preferences and domain provider. But in case you are not sure, just create an A record with a wildcard host like `*.<your-domain>` pointing to the external IP address you found above.
|
||||
|
||||
Use `nslookup minimal-ruby-app-staging.<yourdomain>` to confirm that domain is assigned to the cluster IP.
|
||||
|
||||
## Setup Auto Deploy
|
||||
|
||||
Visit the home page of your GitLab.com project and press "Set up Auto Deploy" button.
|
||||
|
||||
![auto deploy button](img/auto_deploy_btn.png)
|
||||
|
||||
You will be redirected to the "New file" page where you can apply one of the Auto Deploy templates. Select "Kubernetes" to apply the template, then in the file, replace `domain.example.com` with your domain name and make any other adjustments you need.
|
||||
|
||||
![auto deploy template](img/auto_deploy_dropdown.png)
|
||||
|
||||
Change the target branch to `master`, and submit your changes. This should create
|
||||
a new pipeline with several jobs. If you made only the domain name change, the
|
||||
pipeline will have three jobs: `build`, `staging`, and `production`.
|
||||
|
||||
The `build` job will create a Docker image with your new change and push it to
|
||||
the GitLab Container Registry. The `staging` job will deploy this image on your
|
||||
cluster. Once the deploy job succeeds you should be able to see your application by
|
||||
visiting the Kubernetes dashboard. Select the namespace of your project, which
|
||||
will look like `ruby-autodeploy-23`, but with a unique ID for your project, and
|
||||
your app will be listed as "staging" under the "Deployment" tab.
|
||||
|
||||
Once its ready - just visit http://minimal-ruby-app-staging.yourdomain.com to see “Hello, world!”
|
|
@ -222,6 +222,30 @@ total running time should be:
|
|||
Pipeline status and test coverage report badges are available. You can find their
|
||||
respective link in the [Pipelines settings] page.
|
||||
|
||||
## Security on protected branches
|
||||
|
||||
A strict security model is enforced when pipelines are executed on
|
||||
[protected branches](../user/project/protected_branches.md).
|
||||
|
||||
The following actions are allowed on protected branches only if the user is
|
||||
[allowed to merge or push](../user/project/protected_branches.md#using-the-allowed-to-merge-and-allowed-to-push-settings)
|
||||
on that specific branch:
|
||||
- run **manual pipelines** (using Web UI or Pipelines API)
|
||||
- run **scheduled pipelines**
|
||||
- run pipelines using **triggers**
|
||||
- trigger **manual actions** on existing pipelines
|
||||
- **retry/cancel** existing jobs (using Web UI or Pipelines API)
|
||||
|
||||
**Secret variables** marked as **protected** are accessible only to jobs that
|
||||
run on protected branches, avoiding untrusted users to get unintended access to
|
||||
sensitive information like deployment credentials and tokens.
|
||||
|
||||
**Runners** marked as **protected** can run jobs only on protected
|
||||
branches, avoiding untrusted code to be executed on the protected runner and
|
||||
preserving deployment keys and other credentials from being unintentionally
|
||||
accessed. In order to ensure that jobs intended to be executed on protected
|
||||
runners will not use regular runners, they must be tagged accordingly.
|
||||
|
||||
[jobs]: #jobs
|
||||
[jobs-yaml]: yaml/README.md#jobs
|
||||
[manual]: yaml/README.md#manual
|
||||
|
|
|
@ -230,6 +230,14 @@ users:
|
|||
GitLab 8.12 has a completely redesigned job permissions system. To learn more,
|
||||
read through the documentation on the [new CI/CD permissions model](project/new_ci_build_permissions_model.md#new-ci-job-permissions-model).
|
||||
|
||||
## Running pipelines on protected branches
|
||||
|
||||
The permission to merge or push to protected branches is used to define if a user can
|
||||
run CI/CD pipelines and execute actions on jobs that are related to those branches.
|
||||
|
||||
See [Security on protected branches](../ci/pipelines.md#security-on-protected-branches)
|
||||
for details about the pipelines security model.
|
||||
|
||||
## LDAP users permissions
|
||||
|
||||
Since GitLab 8.15, LDAP user permissions can now be manually overridden by an admin user.
|
||||
|
|
|
@ -39,4 +39,58 @@ changes you made after picking the template and return it to its initial status.
|
|||
|
||||
![Description templates](img/description_templates.png)
|
||||
|
||||
## Description template example
|
||||
|
||||
We make use of Description Templates for Issues and Merge Requests within the GitLab Community Edition project. Please refer to the [`.gitlab` folder][gitlab-ce-templates] for some examples.
|
||||
|
||||
> **Tip:**
|
||||
It is possible to use [quick actions](./quick_actions.md) within description templates to quickly add labels, assignees, and milestones. The quick actions will only be executed if the user submitting the Issue or Merge Request has the permissions perform the relevant actions.
|
||||
|
||||
Here is an example for a Bug report template:
|
||||
|
||||
```
|
||||
Summary
|
||||
|
||||
(Summarize the bug encountered concisely)
|
||||
|
||||
|
||||
Steps to reproduce
|
||||
|
||||
(How one can reproduce the issue - this is very important)
|
||||
|
||||
|
||||
Example Project
|
||||
|
||||
(If possible, please create an example project here on GitLab.com that exhibits the problematic behaviour, and link to it here in the bug report)
|
||||
|
||||
(If you are using an older version of GitLab, this will also determine whether the bug has been fixed in a more recent version)
|
||||
|
||||
|
||||
What is the current bug behavior?
|
||||
|
||||
(What actually happens)
|
||||
|
||||
|
||||
What is the expected correct behavior?
|
||||
|
||||
(What you should see instead)
|
||||
|
||||
|
||||
Relevant logs and/or screenshots
|
||||
|
||||
(Paste any relevant logs - please use code blocks (```) to format console output,
|
||||
logs, and code as it's very hard to read otherwise.)
|
||||
|
||||
|
||||
Possible fixes
|
||||
|
||||
(If you can, link to the line of code that might be responsible for the problem)
|
||||
|
||||
/label ~bug ~reproduced ~needs-investigation
|
||||
/cc @project-manager
|
||||
/assign @qa-tester
|
||||
```
|
||||
|
||||
[ce-4981]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4981
|
||||
[gitlab-ce-templates]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/.gitlab
|
||||
|
||||
|
|
|
@ -23,4 +23,4 @@ Prometheus server up and running. You have two options here:
|
|||
In order to isolate and only display relevant metrics for a given environment
|
||||
however, GitLab needs a method to detect which labels are associated. To do this, GitLab will [look for an `environment` label](metrics.md#identifying-environments).
|
||||
|
||||
If you are using [GitLab Auto-Deploy][autodeploy] and one of the two [provided Kubernetes monitoring solutions](../prometheus.md#getting-started-with-prometheus-monitoring), the `environment` label will be automatically added.
|
||||
If you are using [GitLab Auto-Deploy][../../../ci/autodeploy/index.md] and one of the two [provided Kubernetes monitoring solutions](../prometheus.md#getting-started-with-prometheus-monitoring), the `environment` label will be automatically added.
|
||||
|
|
|
@ -115,6 +115,14 @@ Deleting a protected branch is only allowed via the web interface, not via Git.
|
|||
This means that you can't accidentally delete a protected branch from your
|
||||
command line or a Git client application.
|
||||
|
||||
## Running pipelines on protected branches
|
||||
|
||||
The permission to merge or push to protected branches is used to define if a user can
|
||||
run CI/CD pipelines and execute actions on jobs that are related to those branches.
|
||||
|
||||
See [Security on protected branches](../../ci/pipelines.md#security-on-protected-branches)
|
||||
for details about the pipelines security model.
|
||||
|
||||
## Changelog
|
||||
|
||||
**9.2**
|
||||
|
|
|
@ -47,7 +47,7 @@ class Spinach::Features::GroupMilestones < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
step 'I click new milestone button' do
|
||||
page.within('.breadcrumbs') do
|
||||
page.within('.nav-controls') do
|
||||
click_link "New milestone"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -62,7 +62,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
step 'I click link "New issue"' do
|
||||
page.within '.breadcrumbs' do
|
||||
page.within '#content-body' do
|
||||
page.has_link?('New Issue') ? click_link('New Issue') : click_link('New issue')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
step 'I click link "New Milestone"' do
|
||||
page.within('.breadcrumbs') do
|
||||
page.within('.nav-controls') do
|
||||
click_link "New milestone"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,7 +14,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
step 'I click link "New Merge Request"' do
|
||||
page.within '.breadcrumbs' do
|
||||
page.within '.nav-controls' do
|
||||
page.has_link?('New Merge Request') ? click_link("New Merge Request") : click_link('New merge request')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,7 +23,7 @@ class Spinach::Features::ProjectSnippets < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
step 'I click link "New snippet"' do
|
||||
page.within '.breadcrumbs' do
|
||||
page.within '.nav-controls' do
|
||||
first(:link, "New snippet").click
|
||||
end
|
||||
end
|
||||
|
|
|
@ -144,6 +144,7 @@ module API
|
|||
mount ::API::Variables
|
||||
mount ::API::GroupVariables
|
||||
mount ::API::Version
|
||||
mount ::API::Wikis
|
||||
|
||||
route :any, '*path' do
|
||||
error!('404 Not Found', 404)
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
module API
|
||||
module Entities
|
||||
class WikiPageBasic < Grape::Entity
|
||||
expose :format
|
||||
expose :slug
|
||||
expose :title
|
||||
end
|
||||
|
||||
class WikiPage < WikiPageBasic
|
||||
expose :content
|
||||
end
|
||||
|
||||
class UserSafe < Grape::Entity
|
||||
expose :id, :name, :username
|
||||
end
|
||||
|
|
|
@ -56,6 +56,12 @@ module API
|
|||
@project ||= find_project!(params[:id])
|
||||
end
|
||||
|
||||
def wiki_page
|
||||
page = user_project.wiki.find_page(params[:slug])
|
||||
|
||||
page || not_found!('Wiki Page')
|
||||
end
|
||||
|
||||
def available_labels
|
||||
@available_labels ||= LabelsFinder.new(current_user, project_id: user_project.id).execute
|
||||
end
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
module API
|
||||
class Wikis < Grape::API
|
||||
helpers do
|
||||
params :wiki_page_params do
|
||||
requires :content, type: String, desc: 'Content of a wiki page'
|
||||
requires :title, type: String, desc: 'Title of a wiki page'
|
||||
optional :format,
|
||||
type: String,
|
||||
values: ProjectWiki::MARKUPS.values.map(&:to_s),
|
||||
default: 'markdown',
|
||||
desc: 'Format of a wiki page. Available formats are markdown, rdoc, and asciidoc'
|
||||
end
|
||||
end
|
||||
|
||||
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
|
||||
desc 'Get a list of wiki pages' do
|
||||
success Entities::WikiPageBasic
|
||||
end
|
||||
params do
|
||||
optional :with_content, type: Boolean, default: false, desc: "Include pages' content"
|
||||
end
|
||||
get ':id/wikis' do
|
||||
authorize! :read_wiki, user_project
|
||||
|
||||
entity = params[:with_content] ? Entities::WikiPage : Entities::WikiPageBasic
|
||||
present user_project.wiki.pages, with: entity
|
||||
end
|
||||
|
||||
desc 'Get a wiki page' do
|
||||
success Entities::WikiPage
|
||||
end
|
||||
params do
|
||||
requires :slug, type: String, desc: 'The slug of a wiki page'
|
||||
end
|
||||
get ':id/wikis/:slug' do
|
||||
authorize! :read_wiki, user_project
|
||||
|
||||
present wiki_page, with: Entities::WikiPage
|
||||
end
|
||||
|
||||
desc 'Create a wiki page' do
|
||||
success Entities::WikiPage
|
||||
end
|
||||
params do
|
||||
use :wiki_page_params
|
||||
end
|
||||
post ':id/wikis' do
|
||||
authorize! :create_wiki, user_project
|
||||
|
||||
page = WikiPages::CreateService.new(user_project, current_user, params).execute
|
||||
|
||||
if page.valid?
|
||||
present page, with: Entities::WikiPage
|
||||
else
|
||||
render_validation_error!(page)
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Update a wiki page' do
|
||||
success Entities::WikiPage
|
||||
end
|
||||
params do
|
||||
use :wiki_page_params
|
||||
end
|
||||
put ':id/wikis/:slug' do
|
||||
authorize! :create_wiki, user_project
|
||||
|
||||
page = WikiPages::UpdateService.new(user_project, current_user, params).execute(wiki_page)
|
||||
|
||||
if page.valid?
|
||||
present page, with: Entities::WikiPage
|
||||
else
|
||||
render_validation_error!(page)
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Delete a wiki page'
|
||||
params do
|
||||
requires :slug, type: String, desc: 'The slug of a wiki page'
|
||||
end
|
||||
delete ':id/wikis/:slug' do
|
||||
authorize! :admin_wiki, user_project
|
||||
|
||||
status 204
|
||||
WikiPages::DestroyService.new(user_project, current_user).execute(wiki_page)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,7 +5,7 @@ module Gitlab
|
|||
class Tree
|
||||
include Gitlab::EncodingHelper
|
||||
|
||||
attr_accessor :id, :root_id, :name, :path, :type,
|
||||
attr_accessor :id, :root_id, :name, :path, :flat_path, :type,
|
||||
:mode, :commit_id, :submodule_url
|
||||
|
||||
class << self
|
||||
|
@ -19,8 +19,7 @@ module Gitlab
|
|||
|
||||
Gitlab::GitalyClient.migrate(:tree_entries) do |is_enabled|
|
||||
if is_enabled
|
||||
client = Gitlab::GitalyClient::CommitService.new(repository)
|
||||
client.tree_entries(repository, sha, path)
|
||||
repository.gitaly_commit_client.tree_entries(repository, sha, path)
|
||||
else
|
||||
tree_entries_from_rugged(repository, sha, path)
|
||||
end
|
||||
|
@ -88,7 +87,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def initialize(options)
|
||||
%w(id root_id name path type mode commit_id).each do |key|
|
||||
%w(id root_id name path flat_path type mode commit_id).each do |key|
|
||||
self.send("#{key}=", options[key.to_sym]) # rubocop:disable GitlabSecurity/PublicSend
|
||||
end
|
||||
end
|
||||
|
@ -101,6 +100,10 @@ module Gitlab
|
|||
encode! @path
|
||||
end
|
||||
|
||||
def flat_path
|
||||
encode! @flat_path
|
||||
end
|
||||
|
||||
def dir?
|
||||
type == :tree
|
||||
end
|
||||
|
|
|
@ -88,14 +88,14 @@ module Gitlab
|
|||
|
||||
response.flat_map do |message|
|
||||
message.entries.map do |gitaly_tree_entry|
|
||||
entry_path = gitaly_tree_entry.path.dup
|
||||
Gitlab::Git::Tree.new(
|
||||
id: gitaly_tree_entry.oid,
|
||||
root_id: gitaly_tree_entry.root_oid,
|
||||
type: gitaly_tree_entry.type.downcase,
|
||||
mode: gitaly_tree_entry.mode.to_s(8),
|
||||
name: File.basename(entry_path),
|
||||
path: entry_path,
|
||||
name: File.basename(gitaly_tree_entry.path),
|
||||
path: GitalyClient.encode(gitaly_tree_entry.path),
|
||||
flat_path: GitalyClient.encode(gitaly_tree_entry.flat_path),
|
||||
commit_id: gitaly_tree_entry.commit_oid
|
||||
)
|
||||
end
|
||||
|
|
|
@ -50,7 +50,7 @@ feature 'Dashboard Issues filtering', :js do
|
|||
it 'updates atom feed link' do
|
||||
visit_issues(milestone_title: '', assignee_id: user.id)
|
||||
|
||||
link = find('.breadcrumbs a[title="Subscribe"]')
|
||||
link = find('.nav-controls a[title="Subscribe"]')
|
||||
params = CGI.parse(URI.parse(link[:href]).query)
|
||||
auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
|
||||
auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
|
||||
|
|
|
@ -115,9 +115,9 @@ feature 'Dashboard Projects' do
|
|||
|
||||
expect(page).to have_selector('.merge-request-form')
|
||||
expect(current_path).to eq project_new_merge_request_path(project)
|
||||
expect(find('#merge_request_target_project_id').value).to eq project.id.to_s
|
||||
expect(find('input#merge_request_source_branch').value).to eq 'feature'
|
||||
expect(find('input#merge_request_target_branch').value).to eq 'master'
|
||||
expect(find('#merge_request_target_project_id', visible: false).value).to eq project.id.to_s
|
||||
expect(find('input#merge_request_source_branch', visible: false).value).to eq 'feature'
|
||||
expect(find('input#merge_request_target_branch', visible: false).value).to eq 'master'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -577,7 +577,7 @@ describe 'Issues' do
|
|||
it 'redirects to signin then back to new issue after signin' do
|
||||
visit project_issues_path(project)
|
||||
|
||||
page.within '.breadcrumbs' do
|
||||
page.within '.nav-controls' do
|
||||
click_link 'New issue'
|
||||
end
|
||||
|
||||
|
|
|
@ -196,10 +196,11 @@ feature 'Diff notes resolve', js: true do
|
|||
end
|
||||
|
||||
it 'does not mark discussion as resolved when resolving single note' do
|
||||
page.first '.diff-content .note' do
|
||||
page.within("#note_#{note.id}") do
|
||||
first('.line-resolve-btn').click
|
||||
|
||||
expect(page).to have_selector('.note-action-button .loading')
|
||||
wait_for_requests
|
||||
|
||||
expect(first('.line-resolve-btn')['data-original-title']).to eq("Resolved by #{user.name}")
|
||||
end
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ feature 'User wants to create a file' do
|
|||
file_name = find('#file_name')
|
||||
file_name.set options[:file_name] || 'README.md'
|
||||
|
||||
file_content = find('#file-content')
|
||||
file_content = find('#file-content', visible: false)
|
||||
file_content.set options[:file_content] || 'Some content'
|
||||
|
||||
click_button 'Commit changes'
|
||||
|
|
|
@ -295,7 +295,7 @@ describe "Search" do
|
|||
fill_in 'search', with: 'foo'
|
||||
click_button 'Search'
|
||||
|
||||
expect(find('#group_id').value).to eq(project.namespace.id.to_s)
|
||||
expect(find('#group_id', visible: false).value).to eq(project.namespace.id.to_s)
|
||||
end
|
||||
|
||||
it 'preserves the project being searched in' do
|
||||
|
@ -304,7 +304,7 @@ describe "Search" do
|
|||
fill_in 'search', with: 'foo'
|
||||
click_button 'Search'
|
||||
|
||||
expect(find('#project_id').value).to eq(project.id.to_s)
|
||||
expect(find('#project_id', visible: false).value).to eq(project.id.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,25 +3,35 @@ require 'spec_helper'
|
|||
describe TreeHelper do
|
||||
describe 'flatten_tree' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:repository) { project.repository }
|
||||
let(:sha) { 'ce369011c189f62c815f5971d096b26759bab0d1' }
|
||||
let(:tree) { repository.tree(sha, 'files') }
|
||||
let(:root_path) { 'files' }
|
||||
let(:tree_item) { tree.entries.find { |entry| entry.path == path } }
|
||||
|
||||
before do
|
||||
@repository = project.repository
|
||||
@commit = project.commit("e56497bb")
|
||||
end
|
||||
subject { flatten_tree(root_path, tree_item) }
|
||||
|
||||
context "on a directory containing more than one file/directory" do
|
||||
let(:tree_item) { double(name: "files", path: "files") }
|
||||
let(:path) { 'files/html' }
|
||||
|
||||
it "returns the directory name" do
|
||||
expect(flatten_tree(tree_item)).to match('files')
|
||||
expect(subject).to match('html')
|
||||
end
|
||||
end
|
||||
|
||||
context "on a directory containing only one directory" do
|
||||
let(:tree_item) { double(name: "foo", path: "foo") }
|
||||
let(:path) { 'files/flat' }
|
||||
|
||||
it "returns the flattened path" do
|
||||
expect(flatten_tree(tree_item)).to match('foo/bar')
|
||||
expect(subject).to match('flat/path/correct')
|
||||
end
|
||||
|
||||
context "with a nested root path" do
|
||||
let(:root_path) { 'files/flat' }
|
||||
|
||||
it "returns the flattened path with the root path suffix removed" do
|
||||
expect(subject).to match('path/correct')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ describe('glDropdown', function describeDropdown() {
|
|||
preloadFixtures('static/gl_dropdown.html.raw');
|
||||
loadJSONFixtures('projects.json');
|
||||
|
||||
const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link';
|
||||
const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-item';
|
||||
const SEARCH_INPUT_SELECTOR = '.dropdown-input-field';
|
||||
const ITEM_SELECTOR = `.dropdown-content li:not(${NON_SELECTABLE_CLASSES})`;
|
||||
const FOCUSED_ITEM_SELECTOR = `${ITEM_SELECTOR} a.is-focused`;
|
||||
|
|
|
@ -20,6 +20,7 @@ describe Gitlab::Git::Tree, seed_helper: true do
|
|||
it { expect(dir.commit_id).to eq(SeedRepo::Commit::ID) }
|
||||
it { expect(dir.name).to eq('encoding') }
|
||||
it { expect(dir.path).to eq('encoding') }
|
||||
it { expect(dir.flat_path).to eq('encoding') }
|
||||
it { expect(dir.mode).to eq('40000') }
|
||||
|
||||
context :subdir do
|
||||
|
@ -30,6 +31,7 @@ describe Gitlab::Git::Tree, seed_helper: true do
|
|||
it { expect(subdir.commit_id).to eq(SeedRepo::Commit::ID) }
|
||||
it { expect(subdir.name).to eq('html') }
|
||||
it { expect(subdir.path).to eq('files/html') }
|
||||
it { expect(subdir.flat_path).to eq('files/html') }
|
||||
end
|
||||
|
||||
context :subdir_file do
|
||||
|
@ -40,6 +42,7 @@ describe Gitlab::Git::Tree, seed_helper: true do
|
|||
it { expect(subdir_file.commit_id).to eq(SeedRepo::Commit::ID) }
|
||||
it { expect(subdir_file.name).to eq('popen.rb') }
|
||||
it { expect(subdir_file.path).to eq('files/ruby/popen.rb') }
|
||||
it { expect(subdir_file.flat_path).to eq('files/ruby/popen.rb') }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,679 @@
|
|||
require 'spec_helper'
|
||||
|
||||
# For every API endpoint we test 3 states of wikis:
|
||||
# - disabled
|
||||
# - enabled only for team members
|
||||
# - enabled for everyone who has access
|
||||
# Every state is tested for 3 user roles:
|
||||
# - guest
|
||||
# - developer
|
||||
# - master
|
||||
# because they are 3 edge cases of using wiki pages.
|
||||
|
||||
describe API::Wikis do
|
||||
let(:user) { create(:user) }
|
||||
let(:payload) { { content: 'content', format: 'rdoc', title: 'title' } }
|
||||
let(:expected_keys_with_content) { %w(content format slug title) }
|
||||
let(:expected_keys_without_content) { %w(format slug title) }
|
||||
|
||||
shared_examples_for 'returns list of wiki pages' do
|
||||
context 'when wiki has pages' do
|
||||
let!(:pages) do
|
||||
[create(:wiki_page, wiki: project.wiki, attrs: { title: 'page1', content: 'content of page1' }),
|
||||
create(:wiki_page, wiki: project.wiki, attrs: { title: 'page2', content: 'content of page2' })]
|
||||
end
|
||||
|
||||
it 'returns the list of wiki pages without content' do
|
||||
get api(url, user)
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json_response.size).to eq(2)
|
||||
|
||||
json_response.each_with_index do |page, index|
|
||||
expect(page.keys).to match_array(expected_keys_without_content)
|
||||
expect(page['slug']).to eq(pages[index].slug)
|
||||
expect(page['title']).to eq(pages[index].title)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns the list of wiki pages with content' do
|
||||
get api(url, user), with_content: 1
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json_response.size).to eq(2)
|
||||
|
||||
json_response.each_with_index do |page, index|
|
||||
expect(page.keys).to match_array(expected_keys_with_content)
|
||||
expect(page['content']).to eq(pages[index].content)
|
||||
expect(page['slug']).to eq(pages[index].slug)
|
||||
expect(page['title']).to eq(pages[index].title)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'return the empty list of wiki pages' do
|
||||
get api(url, user)
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json_response.size).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'returns wiki page' do
|
||||
it 'returns the wiki page' do
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json_response.size).to eq(4)
|
||||
expect(json_response.keys).to match_array(expected_keys_with_content)
|
||||
expect(json_response['content']).to eq(page.content)
|
||||
expect(json_response['slug']).to eq(page.slug)
|
||||
expect(json_response['title']).to eq(page.title)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'creates wiki page' do
|
||||
it 'creates the wiki page' do
|
||||
post(api(url, user), payload)
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(json_response.size).to eq(4)
|
||||
expect(json_response.keys).to match_array(expected_keys_with_content)
|
||||
expect(json_response['content']).to eq(payload[:content])
|
||||
expect(json_response['slug']).to eq(payload[:title].tr(' ', '-'))
|
||||
expect(json_response['title']).to eq(payload[:title])
|
||||
expect(json_response['rdoc']).to eq(payload[:rdoc])
|
||||
end
|
||||
|
||||
[:title, :content].each do |part|
|
||||
it "responds with validation error on empty #{part}" do
|
||||
payload.delete(part)
|
||||
|
||||
post(api(url, user), payload)
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
expect(json_response.size).to eq(1)
|
||||
expect(json_response['error']).to eq("#{part} is missing")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'updates wiki page' do
|
||||
it 'updates the wiki page' do
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json_response.size).to eq(4)
|
||||
expect(json_response.keys).to match_array(expected_keys_with_content)
|
||||
expect(json_response['content']).to eq(payload[:content])
|
||||
expect(json_response['slug']).to eq(payload[:title].tr(' ', '-'))
|
||||
expect(json_response['title']).to eq(payload[:title])
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for '403 Forbidden' do
|
||||
it 'returns 403 Forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
expect(json_response.size).to eq(1)
|
||||
expect(json_response['message']).to eq('403 Forbidden')
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for '404 Wiki Page Not Found' do
|
||||
it 'returns 404 Wiki Page Not Found' do
|
||||
expect(response).to have_http_status(404)
|
||||
expect(json_response.size).to eq(1)
|
||||
expect(json_response['message']).to eq('404 Wiki Page Not Found')
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for '404 Project Not Found' do
|
||||
it 'returns 404 Project Not Found' do
|
||||
expect(response).to have_http_status(404)
|
||||
expect(json_response.size).to eq(1)
|
||||
expect(json_response['message']).to eq('404 Project Not Found')
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for '204 No Content' do
|
||||
it 'returns 204 No Content' do
|
||||
expect(response).to have_http_status(204)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /projects/:id/wikis' do
|
||||
let(:url) { "/projects/#{project.id}/wikis" }
|
||||
|
||||
context 'when wiki is disabled' do
|
||||
let(:project) { create(:project, :wiki_disabled) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
get api(url)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
||||
get api(url, user)
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
|
||||
get api(url, user)
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is available only for team members' do
|
||||
let(:project) { create(:project, :wiki_private) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
get api(url)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
include_examples 'returns list of wiki pages'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
end
|
||||
|
||||
include_examples 'returns list of wiki pages'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is available for everyone with access' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
get api(url)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
include_examples 'returns list of wiki pages'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
end
|
||||
|
||||
include_examples 'returns list of wiki pages'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /projects/:id/wikis/:slug' do
|
||||
let(:page) { create(:wiki_page, wiki: project.wiki) }
|
||||
let(:url) { "/projects/#{project.id}/wikis/#{page.slug}" }
|
||||
|
||||
context 'when wiki is disabled' do
|
||||
let(:project) { create(:project, :wiki_disabled) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
get api(url)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
||||
get api(url, user)
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
|
||||
get api(url, user)
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is available only for team members' do
|
||||
let(:project) { create(:project, :wiki_private) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
get api(url)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
get api(url, user)
|
||||
end
|
||||
|
||||
include_examples 'returns wiki page'
|
||||
|
||||
context 'when page is not existing' do
|
||||
let(:url) { "/projects/#{project.id}/wikis/unknown" }
|
||||
|
||||
include_examples '404 Wiki Page Not Found'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
|
||||
get api(url, user)
|
||||
end
|
||||
|
||||
include_examples 'returns wiki page'
|
||||
|
||||
context 'when page is not existing' do
|
||||
let(:url) { "/projects/#{project.id}/wikis/unknown" }
|
||||
|
||||
include_examples '404 Wiki Page Not Found'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is available for everyone with access' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
get api(url)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
||||
get api(url, user)
|
||||
end
|
||||
|
||||
include_examples 'returns wiki page'
|
||||
|
||||
context 'when page is not existing' do
|
||||
let(:url) { "/projects/#{project.id}/wikis/unknown" }
|
||||
|
||||
include_examples '404 Wiki Page Not Found'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
|
||||
get api(url, user)
|
||||
end
|
||||
|
||||
include_examples 'returns wiki page'
|
||||
|
||||
context 'when page is not existing' do
|
||||
let(:url) { "/projects/#{project.id}/wikis/unknown" }
|
||||
|
||||
include_examples '404 Wiki Page Not Found'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /projects/:id/wikis' do
|
||||
let(:payload) { { title: 'title', content: 'content' } }
|
||||
let(:url) { "/projects/#{project.id}/wikis" }
|
||||
|
||||
context 'when wiki is disabled' do
|
||||
let(:project) { create(:project, :wiki_disabled) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
post(api(url), payload)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
post(api(url, user), payload)
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
post(api(url, user), payload)
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is available only for team members' do
|
||||
let(:project) { create(:project, :wiki_private) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
post(api(url), payload)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
include_examples 'creates wiki page'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
end
|
||||
|
||||
include_examples 'creates wiki page'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is available for everyone with access' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
post(api(url), payload)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
include_examples 'creates wiki page'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
end
|
||||
|
||||
include_examples 'creates wiki page'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /projects/:id/wikis/:slug' do
|
||||
let(:page) { create(:wiki_page, wiki: project.wiki) }
|
||||
let(:payload) { { title: 'new title', content: 'new content' } }
|
||||
let(:url) { "/projects/#{project.id}/wikis/#{page.slug}" }
|
||||
|
||||
context 'when wiki is disabled' do
|
||||
let(:project) { create(:project, :wiki_disabled) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
put(api(url), payload)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
||||
put(api(url, user), payload)
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
|
||||
put(api(url, user), payload)
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is available only for team members' do
|
||||
let(:project) { create(:project, :wiki_private) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
put(api(url), payload)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
||||
put(api(url, user), payload)
|
||||
end
|
||||
|
||||
include_examples 'updates wiki page'
|
||||
|
||||
context 'when page is not existing' do
|
||||
let(:url) { "/projects/#{project.id}/wikis/unknown" }
|
||||
|
||||
include_examples '404 Wiki Page Not Found'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
|
||||
put(api(url, user), payload)
|
||||
end
|
||||
|
||||
include_examples 'updates wiki page'
|
||||
|
||||
context 'when page is not existing' do
|
||||
let(:url) { "/projects/#{project.id}/wikis/unknown" }
|
||||
|
||||
include_examples '404 Wiki Page Not Found'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is available for everyone with access' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
put(api(url), payload)
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
||||
put(api(url, user), payload)
|
||||
end
|
||||
|
||||
include_examples 'updates wiki page'
|
||||
|
||||
context 'when page is not existing' do
|
||||
let(:url) { "/projects/#{project.id}/wikis/unknown" }
|
||||
|
||||
include_examples '404 Wiki Page Not Found'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
|
||||
put(api(url, user), payload)
|
||||
end
|
||||
|
||||
include_examples 'updates wiki page'
|
||||
|
||||
context 'when page is not existing' do
|
||||
let(:url) { "/projects/#{project.id}/wikis/unknown" }
|
||||
|
||||
include_examples '404 Wiki Page Not Found'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /projects/:id/wikis/:slug' do
|
||||
let(:page) { create(:wiki_page, wiki: project.wiki) }
|
||||
let(:url) { "/projects/#{project.id}/wikis/#{page.slug}" }
|
||||
|
||||
context 'when wiki is disabled' do
|
||||
let(:project) { create(:project, :wiki_disabled) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
delete(api(url))
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
||||
delete(api(url, user))
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
|
||||
delete(api(url, user))
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is available only for team members' do
|
||||
let(:project) { create(:project, :wiki_private) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
delete(api(url))
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
||||
delete(api(url, user))
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
|
||||
delete(api(url, user))
|
||||
end
|
||||
|
||||
include_examples '204 No Content'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when wiki is available for everyone with access' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
context 'when user is guest' do
|
||||
before do
|
||||
delete(api(url))
|
||||
end
|
||||
|
||||
include_examples '404 Project Not Found'
|
||||
end
|
||||
|
||||
context 'when user is developer' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
||||
delete(api(url, user))
|
||||
end
|
||||
|
||||
include_examples '403 Forbidden'
|
||||
end
|
||||
|
||||
context 'when user is master' do
|
||||
before do
|
||||
project.add_master(user)
|
||||
|
||||
delete(api(url, user))
|
||||
end
|
||||
|
||||
include_examples '204 No Content'
|
||||
|
||||
context 'when page is not existing' do
|
||||
let(:url) { "/projects/#{project.id}/wikis/unknown" }
|
||||
|
||||
include_examples '404 Wiki Page Not Found'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,3 +3,50 @@ https://gitlab.com/gitlab-org/Dockerfile.
|
|||
|
||||
GitLab only mirrors the templates. Please submit your merge requests to
|
||||
https://gitlab.com/gitlab-org/Dockerfile.
|
||||
|
||||
## Contributing
|
||||
|
||||
Thank you for your interest in contributing to this GitLab project! We welcome
|
||||
all contributions. By participating in this project, you agree to abide by the
|
||||
[code of conduct](#code-of-conduct).
|
||||
|
||||
## Contributor license agreement
|
||||
|
||||
By submitting code as an individual you agree to the [individual contributor
|
||||
license agreement][individual-agreement].
|
||||
|
||||
By submitting code as an entity you agree to the [corporate contributor license
|
||||
agreement][corporate-agreement].
|
||||
|
||||
## Code of conduct
|
||||
|
||||
As contributors and maintainers of this project, we pledge to respect all people
|
||||
who contribute through reporting issues, posting feature requests, updating
|
||||
documentation, submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free
|
||||
experience for everyone, regardless of level of experience, gender, gender
|
||||
identity and expression, sexual orientation, disability, personal appearance,
|
||||
body size, race, ethnicity, age, or religion.
|
||||
|
||||
Examples of unacceptable behavior by participants include the use of sexual
|
||||
language or imagery, derogatory comments or personal attacks, trolling, public
|
||||
or private harassment, insults, or other unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct. Project maintainers who do not follow the
|
||||
Code of Conduct may be removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior can be
|
||||
reported by emailing contact@gitlab.com.
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant], version 1.1.0,
|
||||
available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/).
|
||||
|
||||
[contributor-covenant]: http://contributor-covenant.org
|
||||
[individual-agreement]: https://docs.gitlab.com/ee/legal/individual_contributor_license_agreement.html
|
||||
[corporate-agreement]: https://docs.gitlab.com/ee/legal/corporate_contributor_license_agreement.html
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
# Build and Release Folders
|
||||
bin/
|
||||
bin-debug/
|
||||
bin-release/
|
||||
[Oo]bj/ # FlashDevelop obj
|
||||
[Bb]in/ # FlashDevelop bin
|
||||
[Oo]bj/
|
||||
[Bb]in/
|
||||
|
||||
# Other files and folders
|
||||
.settings/
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
# Ignore configuration files that may contain sensitive information.
|
||||
sites/*/*settings*.php
|
||||
sites/example.sites.php
|
||||
|
||||
# Ignore paths that contain generated content.
|
||||
files/
|
||||
sites/*/files
|
||||
sites/*/private
|
||||
sites/*/translations
|
||||
|
||||
# Ignore default text files
|
||||
robots.txt
|
||||
|
@ -16,6 +18,7 @@ robots.txt
|
|||
/UPGRADE.txt
|
||||
/README.txt
|
||||
sites/README.txt
|
||||
sites/all/libraries/README.txt
|
||||
sites/all/modules/README.txt
|
||||
sites/all/themes/README.txt
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Java.gitignore
|
|
@ -4,7 +4,7 @@
|
|||
output/
|
||||
|
||||
# Temporary file directory
|
||||
tmp/
|
||||
tmp/nanoc/
|
||||
|
||||
# Crash Log
|
||||
crash.log
|
||||
|
|
|
@ -29,7 +29,7 @@ bower_components
|
|||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
|
|
@ -26,6 +26,8 @@ moc_*.cpp
|
|||
moc_*.h
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
*.qmlc
|
||||
*.jsc
|
||||
Makefile*
|
||||
*build-*
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ playground.xcworkspace
|
|||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
||||
# Packages/
|
||||
# Package.pins
|
||||
# Package.resolved
|
||||
.build/
|
||||
|
||||
# CocoaPods
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Compiled files
|
||||
*.tfstate
|
||||
*.tfstate.*.backup
|
||||
*.tfstate.backup
|
||||
|
||||
# Module directory
|
||||
|
|
|
@ -116,6 +116,10 @@ _TeamCity*
|
|||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
|
|
@ -1,35 +1,411 @@
|
|||
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options
|
||||
# Auto DevOps
|
||||
# This CI/CD configuration provides a standard pipeline for
|
||||
# * building a Docker image (using a buildpack if necessary),
|
||||
# * storing the image in the container registry,
|
||||
# * running tests from a buildpack,
|
||||
# * running code quality analysis,
|
||||
# * creating a review app for each topic branch,
|
||||
# * and continuous deployment to production
|
||||
#
|
||||
# In order to deploy, you must have a Kubernetes cluster configured either
|
||||
# via a project integration, or via group/project variables.
|
||||
# AUTO_DEVOPS_DOMAIN must also be set as a variable at the group or project
|
||||
# level, or manually added below.
|
||||
#
|
||||
# If you want to deploy to staging first, or enable canary deploys,
|
||||
# uncomment the relevant jobs in the pipeline below.
|
||||
#
|
||||
# If Auto DevOps fails to detect the proper buildpack, or if you want to
|
||||
# specify a custom buildpack, set a project variable `BUILDPACK_URL` to the
|
||||
# repository URL of the buildpack.
|
||||
# e.g. BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-ruby.git#v142
|
||||
# If you need multiple buildpacks, add a file to your project called
|
||||
# `.buildpacks` that contains the URLs, one on each line, in order.
|
||||
# Note: Auto CI does not work with multiple buildpacks yet
|
||||
|
||||
# you can delete this line if you're not using Docker
|
||||
image: busybox:latest
|
||||
image: alpine:latest
|
||||
|
||||
variables:
|
||||
# AUTO_DEVOPS_DOMAIN is the application deployment domain and should be set as a variable at the group or project level.
|
||||
# AUTO_DEVOPS_DOMAIN: domain.example.com
|
||||
|
||||
POSTGRES_USER: user
|
||||
POSTGRES_PASSWORD: testing-password
|
||||
POSTGRES_ENABLED: "true"
|
||||
POSTGRES_DB: $CI_ENVIRONMENT_SLUG
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- review
|
||||
- staging
|
||||
- canary
|
||||
- production
|
||||
- cleanup
|
||||
|
||||
build:
|
||||
stage: build
|
||||
image: docker:git
|
||||
services:
|
||||
- docker:dind
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
script:
|
||||
- setup_docker
|
||||
- build
|
||||
only:
|
||||
- branches
|
||||
|
||||
test:
|
||||
services:
|
||||
- postgres:latest
|
||||
variables:
|
||||
POSTGRES_DB: test
|
||||
stage: test
|
||||
image: gliderlabs/herokuish:latest
|
||||
script:
|
||||
- setup_test_db
|
||||
- cp -R . /tmp/app
|
||||
- /bin/herokuish buildpack test
|
||||
only:
|
||||
- branches
|
||||
|
||||
codequality:
|
||||
image: docker:latest
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
allow_failure: true
|
||||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- setup_docker
|
||||
- codeclimate
|
||||
artifacts:
|
||||
paths: [codeclimate.json]
|
||||
|
||||
review:
|
||||
stage: review
|
||||
script:
|
||||
- check_kube_domain
|
||||
- install_dependencies
|
||||
- download_chart
|
||||
- ensure_namespace
|
||||
- install_tiller
|
||||
- create_secret
|
||||
- deploy
|
||||
environment:
|
||||
name: review/$CI_COMMIT_REF_NAME
|
||||
url: http://$CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_SLUG.$AUTO_DEVOPS_DOMAIN
|
||||
on_stop: stop_review
|
||||
only:
|
||||
refs:
|
||||
- branches
|
||||
kubernetes: active
|
||||
except:
|
||||
- master
|
||||
|
||||
stop_review:
|
||||
stage: cleanup
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- install_dependencies
|
||||
- delete
|
||||
environment:
|
||||
name: review/$CI_COMMIT_REF_NAME
|
||||
action: stop
|
||||
when: manual
|
||||
allow_failure: true
|
||||
only:
|
||||
refs:
|
||||
- branches
|
||||
kubernetes: active
|
||||
except:
|
||||
- master
|
||||
|
||||
# Keys that start with a dot (.) will not be processed by GitLab CI.
|
||||
# Staging and canary jobs are disabled by default, to enable them
|
||||
# remove the dot (.) before the job name.
|
||||
# https://docs.gitlab.com/ee/ci/yaml/README.html#hidden-keys
|
||||
|
||||
# Staging deploys are disabled by default since
|
||||
# continuous deployment to production is enabled by default
|
||||
# If you prefer to automatically deploy to staging and
|
||||
# only manually promote to production, enable this job by removing the dot (.),
|
||||
# and uncomment the `when: manual` line in the `production` job.
|
||||
|
||||
.staging:
|
||||
stage: staging
|
||||
script:
|
||||
- check_kube_domain
|
||||
- install_dependencies
|
||||
- download_chart
|
||||
- ensure_namespace
|
||||
- install_tiller
|
||||
- create_secret
|
||||
- deploy
|
||||
environment:
|
||||
name: staging
|
||||
url: http://$CI_PROJECT_PATH_SLUG-staging.$AUTO_DEVOPS_DOMAIN
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
kubernetes: active
|
||||
|
||||
# Canaries are disabled by default, but if you want them,
|
||||
# and know what the downsides are, enable this job by removing the dot (.),
|
||||
# and uncomment the `when: manual` line in the `production` job.
|
||||
|
||||
.canary:
|
||||
stage: canary
|
||||
script:
|
||||
- check_kube_domain
|
||||
- install_dependencies
|
||||
- download_chart
|
||||
- ensure_namespace
|
||||
- install_tiller
|
||||
- create_secret
|
||||
- deploy canary
|
||||
environment:
|
||||
name: production
|
||||
url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN
|
||||
when: manual
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
kubernetes: active
|
||||
|
||||
# This job continuously deploys to production on every push to `master`.
|
||||
# To make this a manual process, either because you're enabling `staging`
|
||||
# or `canary` deploys, or you simply want more control over when you deploy
|
||||
# to production, uncomment the `when: manual` line in the `production` job.
|
||||
|
||||
production:
|
||||
stage: production
|
||||
script:
|
||||
- check_kube_domain
|
||||
- install_dependencies
|
||||
- download_chart
|
||||
- ensure_namespace
|
||||
- install_tiller
|
||||
- create_secret
|
||||
- deploy
|
||||
- delete canary
|
||||
environment:
|
||||
name: production
|
||||
url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN
|
||||
# when: manual
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
kubernetes: active
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
.auto_devops: &auto_devops |
|
||||
# Auto DevOps variables and functions
|
||||
[[ "$TRACE" ]] && set -x
|
||||
auto_database_url=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${CI_ENVIRONMENT_SLUG}-postgres:5432/${POSTGRES_DB}
|
||||
export DATABASE_URL=${DATABASE_URL-$auto_database_url}
|
||||
export CI_APPLICATION_REPOSITORY=$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG
|
||||
export CI_APPLICATION_TAG=$CI_COMMIT_SHA
|
||||
export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID}
|
||||
export TILLER_NAMESPACE=$KUBE_NAMESPACE
|
||||
|
||||
function codeclimate() {
|
||||
cc_opts="--env CODECLIMATE_CODE="$PWD" \
|
||||
--volume "$PWD":/code \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--volume /tmp/cc:/tmp/cc"
|
||||
|
||||
docker run ${cc_opts} codeclimate/codeclimate init
|
||||
docker run ${cc_opts} codeclimate/codeclimate analyze -f json > codeclimate.json
|
||||
}
|
||||
|
||||
function deploy() {
|
||||
track="${1-stable}"
|
||||
name="$CI_ENVIRONMENT_SLUG"
|
||||
|
||||
if [[ "$track" != "stable" ]]; then
|
||||
name="$name-$track"
|
||||
fi
|
||||
|
||||
replicas="1"
|
||||
service_enabled="false"
|
||||
postgres_enabled="$POSTGRES_ENABLED"
|
||||
# canary uses stable db
|
||||
[[ "$track" == "canary" ]] && postgres_enabled="false"
|
||||
|
||||
env_track=$( echo $track | tr -s '[:lower:]' '[:upper:]' )
|
||||
env_slug=$( echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]' )
|
||||
|
||||
if [[ "$track" == "stable" ]]; then
|
||||
# for stable track get number of replicas from `PRODUCTION_REPLICAS`
|
||||
eval new_replicas=\$${env_slug}_REPLICAS
|
||||
service_enabled="true"
|
||||
else
|
||||
# for all tracks get number of replicas from `CANARY_PRODUCTION_REPLICAS`
|
||||
eval new_replicas=\$${env_track}_${env_slug}_REPLICAS
|
||||
fi
|
||||
if [[ -n "$new_replicas" ]]; then
|
||||
replicas="$new_replicas"
|
||||
fi
|
||||
|
||||
helm upgrade --install \
|
||||
--wait \
|
||||
--set service.enabled="$service_enabled" \
|
||||
--set releaseOverride="$CI_ENVIRONMENT_SLUG" \
|
||||
--set image.repository="$CI_APPLICATION_REPOSITORY" \
|
||||
--set image.tag="$CI_APPLICATION_TAG" \
|
||||
--set image.pullPolicy=IfNotPresent \
|
||||
--set application.track="$track" \
|
||||
--set application.database_url="$DATABASE_URL" \
|
||||
--set service.url="$CI_ENVIRONMENT_URL" \
|
||||
--set replicaCount="$replicas" \
|
||||
--set postgresql.enabled="$postgres_enabled" \
|
||||
--set postgresql.nameOverride="postgres" \
|
||||
--set postgresql.postgresUser="$POSTGRES_USER" \
|
||||
--set postgresql.postgresPassword="$POSTGRES_PASSWORD" \
|
||||
--set postgresql.postgresDatabase="$POSTGRES_DB" \
|
||||
--namespace="$KUBE_NAMESPACE" \
|
||||
--version="$CI_PIPELINE_ID-$CI_JOB_ID" \
|
||||
"$name" \
|
||||
chart/
|
||||
|
||||
if [[ "$track" == "stable" ]]; then
|
||||
kubectl rollout status -n "$KUBE_NAMESPACE" -w "deployment/${CI_ENVIRONMENT_SLUG}-auto-deploy"
|
||||
fi
|
||||
}
|
||||
|
||||
function install_dependencies() {
|
||||
apk add -U openssl curl tar gzip bash ca-certificates git
|
||||
wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://raw.githubusercontent.com/sgerrand/alpine-pkg-glibc/master/sgerrand.rsa.pub
|
||||
wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.23-r3/glibc-2.23-r3.apk
|
||||
apk add glibc-2.23-r3.apk
|
||||
rm glibc-2.23-r3.apk
|
||||
|
||||
curl https://kubernetes-helm.storage.googleapis.com/helm-v2.6.1-linux-amd64.tar.gz | tar zx
|
||||
mv linux-amd64/helm /usr/bin/
|
||||
helm version --client
|
||||
|
||||
curl -L -o /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
|
||||
chmod +x /usr/bin/kubectl
|
||||
kubectl version --client
|
||||
}
|
||||
|
||||
function setup_docker() {
|
||||
if ! docker info &>/dev/null; then
|
||||
if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then
|
||||
export DOCKER_HOST='tcp://localhost:2375'
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function setup_test_db() {
|
||||
if [ -z ${KUBERNETES_PORT+x} ]; then
|
||||
DB_HOST=postgres
|
||||
else
|
||||
DB_HOST=localhost
|
||||
fi
|
||||
export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${DB_HOST}:5432/${POSTGRES_DB}"
|
||||
}
|
||||
|
||||
function download_chart() {
|
||||
if [[ ! -d chart ]]; then
|
||||
auto_chart=${AUTO_DEVOPS_CHART:-gitlab/auto-deploy-app}
|
||||
auto_chart_name=$(basename $auto_chart)
|
||||
auto_chart_name=${auto_chart_name%.tgz}
|
||||
else
|
||||
auto_chart="chart"
|
||||
auto_chart_name="chart"
|
||||
fi
|
||||
|
||||
helm init --client-only
|
||||
helm repo add gitlab https://charts.gitlab.io
|
||||
if [[ ! -d "$auto_chart" ]]; then
|
||||
helm fetch ${auto_chart} --untar
|
||||
fi
|
||||
if [ "$auto_chart_name" != "chart" ]; then
|
||||
mv ${auto_chart_name} chart
|
||||
fi
|
||||
|
||||
helm dependency update chart/
|
||||
helm dependency build chart/
|
||||
}
|
||||
|
||||
function ensure_namespace() {
|
||||
kubectl describe namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE"
|
||||
}
|
||||
|
||||
function check_kube_domain() {
|
||||
if [ -z ${AUTO_DEVOPS_DOMAIN+x} ]; then
|
||||
echo "In order to deploy, AUTO_DEVOPS_DOMAIN must be set as a variable at the group or project level, or manually added in .gitlab-cy.yml"
|
||||
false
|
||||
else
|
||||
true
|
||||
fi
|
||||
}
|
||||
|
||||
function build() {
|
||||
if [[ -f Dockerfile ]]; then
|
||||
echo "Building Dockerfile-based application..."
|
||||
docker build -t "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" .
|
||||
else
|
||||
echo "Building Heroku-based application using gliderlabs/herokuish docker image..."
|
||||
docker run -i --name="$CI_CONTAINER_NAME" -v "$(pwd):/tmp/app:ro" gliderlabs/herokuish /bin/herokuish buildpack build
|
||||
docker commit "$CI_CONTAINER_NAME" "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG"
|
||||
docker rm "$CI_CONTAINER_NAME" >/dev/null
|
||||
echo ""
|
||||
|
||||
echo "Configuring $CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG docker image..."
|
||||
docker create --expose 5000 --env PORT=5000 --name="$CI_CONTAINER_NAME" "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG" /bin/herokuish procfile start web
|
||||
docker commit "$CI_CONTAINER_NAME" "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG"
|
||||
docker rm "$CI_CONTAINER_NAME" >/dev/null
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [[ -n "$CI_REGISTRY_USER" ]]; then
|
||||
echo "Logging to GitLab Container Registry with CI credentials..."
|
||||
docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Pushing to GitLab Container Registry..."
|
||||
docker push "$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG"
|
||||
echo ""
|
||||
}
|
||||
|
||||
function install_tiller() {
|
||||
echo "Checking Tiller..."
|
||||
helm init --upgrade
|
||||
kubectl rollout status -n "$TILLER_NAMESPACE" -w "deployment/tiller-deploy"
|
||||
if ! helm version --debug; then
|
||||
echo "Failed to init Tiller."
|
||||
return 1
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
function create_secret() {
|
||||
kubectl create secret -n "$KUBE_NAMESPACE" \
|
||||
docker-registry gitlab-registry \
|
||||
--docker-server="$CI_REGISTRY" \
|
||||
--docker-username="$CI_REGISTRY_USER" \
|
||||
--docker-password="$CI_REGISTRY_PASSWORD" \
|
||||
--docker-email="$GITLAB_USER_EMAIL" \
|
||||
-o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f -
|
||||
}
|
||||
|
||||
function delete() {
|
||||
track="${1-stable}"
|
||||
name="$CI_ENVIRONMENT_SLUG"
|
||||
|
||||
if [[ "$track" != "stable" ]]; then
|
||||
name="$name-$track"
|
||||
fi
|
||||
|
||||
helm delete "$name" || true
|
||||
}
|
||||
|
||||
before_script:
|
||||
- echo "Before script section"
|
||||
- echo "For example you might run an update here or install a build dependency"
|
||||
- echo "Or perhaps you might print out some debugging details"
|
||||
|
||||
after_script:
|
||||
- echo "After script section"
|
||||
- echo "For example you might do some cleanup here"
|
||||
|
||||
build1:
|
||||
stage: build
|
||||
script:
|
||||
- echo "Do your build here"
|
||||
|
||||
test1:
|
||||
stage: test
|
||||
script:
|
||||
- echo "Do a test here"
|
||||
- echo "For example run a test suite"
|
||||
|
||||
test2:
|
||||
stage: test
|
||||
script:
|
||||
- echo "Do another parallel test here"
|
||||
- echo "For example run a lint test"
|
||||
|
||||
deploy1:
|
||||
stage: deploy
|
||||
script:
|
||||
- echo "Do your deploy here"
|
||||
- *auto_devops
|
||||
|
|
|
@ -4,32 +4,32 @@
|
|||
image: busybox:latest
|
||||
|
||||
before_script:
|
||||
- echo "Before script section"
|
||||
- echo "For example you might run an update here or install a build dependency"
|
||||
- echo "Or perhaps you might print out some debugging details"
|
||||
- echo "Before script section"
|
||||
- echo "For example you might run an update here or install a build dependency"
|
||||
- echo "Or perhaps you might print out some debugging details"
|
||||
|
||||
after_script:
|
||||
- echo "After script section"
|
||||
- echo "For example you might do some cleanup here"
|
||||
|
||||
build1:
|
||||
stage: build
|
||||
script:
|
||||
- echo "Do your build here"
|
||||
stage: build
|
||||
script:
|
||||
- echo "Do your build here"
|
||||
|
||||
test1:
|
||||
stage: test
|
||||
script:
|
||||
- echo "Do a test here"
|
||||
- echo "For example run a test suite"
|
||||
stage: test
|
||||
script:
|
||||
- echo "Do a test here"
|
||||
- echo "For example run a test suite"
|
||||
|
||||
test2:
|
||||
stage: test
|
||||
script:
|
||||
- echo "Do another parallel test here"
|
||||
- echo "For example run a lint test"
|
||||
stage: test
|
||||
script:
|
||||
- echo "Do another parallel test here"
|
||||
- echo "For example run a lint test"
|
||||
|
||||
deploy1:
|
||||
stage: deploy
|
||||
script:
|
||||
- echo "Do your deploy here"
|
||||
stage: deploy
|
||||
script:
|
||||
- echo "Do your deploy here"
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
image:
|
||||
name: hashicorp/packer:1.0.4
|
||||
entrypoint:
|
||||
- '/usr/bin/env'
|
||||
- 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
|
||||
|
||||
before_script:
|
||||
- packer --version
|
||||
|
||||
stages:
|
||||
- validate
|
||||
- deploy
|
||||
|
||||
validate:
|
||||
stage: validate
|
||||
script:
|
||||
- find . -maxdepth 1 -name '*.json' -print0 | xargs -t0n1 packer validate
|
||||
|
||||
build:
|
||||
stage: deploy
|
||||
environment: production
|
||||
script:
|
||||
- find . -maxdepth 1 -name '*.json' -print0 | xargs -t0n1 packer build
|
||||
when: manual
|
||||
only:
|
||||
- master
|
|
@ -0,0 +1,55 @@
|
|||
# Official image for Hashicorp's Terraform. It uses light image which is Alpine
|
||||
# based as it is much lighter.
|
||||
#
|
||||
# Entrypoint is also needed as image by default set `terraform` binary as an
|
||||
# entrypoint.
|
||||
image:
|
||||
name: hashicorp/terraform:light
|
||||
entrypoint:
|
||||
- '/usr/bin/env'
|
||||
- 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
|
||||
|
||||
# Default output file for Terraform plan
|
||||
variables:
|
||||
PLAN: plan.tfplan
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .terraform
|
||||
|
||||
before_script:
|
||||
- terraform --version
|
||||
- terraform init
|
||||
|
||||
stages:
|
||||
- validate
|
||||
- build
|
||||
- deploy
|
||||
|
||||
validate:
|
||||
stage: validate
|
||||
script:
|
||||
- terraform validate
|
||||
|
||||
plan:
|
||||
stage: build
|
||||
script:
|
||||
- terraform plan -out=$PLAN
|
||||
artifacts:
|
||||
name: plan
|
||||
paths:
|
||||
- $PLAN
|
||||
|
||||
# Separate apply job for manual launching Terraform as it can be destructive
|
||||
# action.
|
||||
apply:
|
||||
stage: deploy
|
||||
environment:
|
||||
name: production
|
||||
script:
|
||||
- terraform apply -input=false $PLAN
|
||||
dependencies:
|
||||
- plan
|
||||
when: manual
|
||||
only:
|
||||
- master
|
Loading…
Reference in New Issue