Commit eca3cd3a authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 6e81d7f6
...@@ -3,6 +3,7 @@ import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_sta ...@@ -3,6 +3,7 @@ import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_sta
import BlobViewer from '~/blob/viewer/index'; import BlobViewer from '~/blob/viewer/index';
import initBlob from '~/pages/projects/init_blob'; import initBlob from '~/pages/projects/init_blob';
import GpgBadges from '~/gpg_badges'; import GpgBadges from '~/gpg_badges';
import '~/sourcegraph/load';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
new BlobViewer(); // eslint-disable-line no-new new BlobViewer(); // eslint-disable-line no-new
......
...@@ -9,6 +9,7 @@ import initNotes from '~/init_notes'; ...@@ -9,6 +9,7 @@ import initNotes from '~/init_notes';
import initChangesDropdown from '~/init_changes_dropdown'; import initChangesDropdown from '~/init_changes_dropdown';
import initDiffNotes from '~/diff_notes/diff_notes_bundle'; import initDiffNotes from '~/diff_notes/diff_notes_bundle';
import { fetchCommitMergeRequests } from '~/commit_merge_requests'; import { fetchCommitMergeRequests } from '~/commit_merge_requests';
import '~/sourcegraph/load';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const hasPerfBar = document.querySelector('.with-performance-bar'); const hasPerfBar = document.querySelector('.with-performance-bar');
......
...@@ -5,6 +5,7 @@ import { handleLocationHash } from '~/lib/utils/common_utils'; ...@@ -5,6 +5,7 @@ import { handleLocationHash } from '~/lib/utils/common_utils';
import howToMerge from '~/how_to_merge'; import howToMerge from '~/how_to_merge';
import initPipelines from '~/commit/pipelines/pipelines_bundle'; import initPipelines from '~/commit/pipelines/pipelines_bundle';
import initVueIssuableSidebarApp from '~/issuable_sidebar/sidebar_bundle'; import initVueIssuableSidebarApp from '~/issuable_sidebar/sidebar_bundle';
import initSourcegraph from '~/sourcegraph';
import initWidget from '../../../vue_merge_request_widget'; import initWidget from '../../../vue_merge_request_widget';
export default function() { export default function() {
...@@ -19,4 +20,5 @@ export default function() { ...@@ -19,4 +20,5 @@ export default function() {
handleLocationHash(); handleLocationHash();
howToMerge(); howToMerge();
initWidget(); initWidget();
initSourcegraph();
} }
import setupToggleButtons from '~/toggle_buttons'; import setupToggleButtons from '~/toggle_buttons';
function updateVisibility(selector, isVisible) {
Array.from(document.querySelectorAll(selector)).forEach(el => {
if (isVisible) {
el.classList.remove('d-none');
} else {
el.classList.add('d-none');
}
});
}
export default () => { export default () => {
const toggleContainer = document.querySelector('.js-auto-ssl-toggle-container'); const toggleContainer = document.querySelector('.js-auto-ssl-toggle-container');
if (toggleContainer) { if (toggleContainer) {
const onToggleButtonClicked = isAutoSslEnabled => { const onToggleButtonClicked = isAutoSslEnabled => {
Array.from(document.querySelectorAll('.js-shown-unless-auto-ssl')).forEach(el => { updateVisibility('.js-shown-unless-auto-ssl', !isAutoSslEnabled);
if (isAutoSslEnabled) {
el.classList.add('d-none'); updateVisibility('.js-shown-if-auto-ssl', isAutoSslEnabled);
} else {
el.classList.remove('d-none');
}
});
Array.from(document.querySelectorAll('.js-enabled-unless-auto-ssl')).forEach(el => { Array.from(document.querySelectorAll('.js-enabled-unless-auto-ssl')).forEach(el => {
if (isAutoSslEnabled) { if (isAutoSslEnabled) {
......
...@@ -64,14 +64,14 @@ export default { ...@@ -64,14 +64,14 @@ export default {
v-for="(testSuite, index) in getTestSuites" v-for="(testSuite, index) in getTestSuites"
:key="index" :key="index"
role="row" role="row"
class="gl-responsive-table-row test-reports-summary-row rounded cursor-pointer js-suite-row" class="gl-responsive-table-row gl-responsive-table-row-clickable test-reports-summary-row rounded cursor-pointer js-suite-row"
@click="tableRowClick(testSuite)" @click="tableRowClick(testSuite)"
> >
<div class="table-section section-25"> <div class="table-section section-25">
<div role="rowheader" class="table-mobile-header font-weight-bold"> <div role="rowheader" class="table-mobile-header font-weight-bold">
{{ __('Suite') }} {{ __('Suite') }}
</div> </div>
<div class="table-mobile-content test-reports-summary-suite cgray pl-3"> <div class="table-mobile-content underline cgray pl-3">
{{ testSuite.name }} {{ testSuite.name }}
</div> </div>
</div> </div>
......
...@@ -5,7 +5,7 @@ import createStore from './store'; ...@@ -5,7 +5,7 @@ import createStore from './store';
export default () => { export default () => {
const el = document.getElementById('js-edit-release-page'); const el = document.getElementById('js-edit-release-page');
const store = createStore(el.dataset); const store = createStore();
store.dispatch('setInitialState', el.dataset); store.dispatch('setInitialState', el.dataset);
return new Vue({ return new Vue({
......
...@@ -109,7 +109,7 @@ export default { ...@@ -109,7 +109,7 @@ export default {
class="text-expander" class="text-expander"
@click="toggleShowDescription" @click="toggleShowDescription"
> >
<icon name="ellipsis_h" /> <icon name="ellipsis_h" :size="10" />
</gl-button> </gl-button>
<div class="committer"> <div class="committer">
<gl-link <gl-link
...@@ -124,7 +124,7 @@ export default { ...@@ -124,7 +124,7 @@ export default {
</div> </div>
<pre <pre
v-if="commit.description" v-if="commit.description"
v-show="showDescription" :class="{ 'd-block': showDescription }"
class="commit-row-description append-bottom-8" class="commit-row-description append-bottom-8"
> >
{{ commit.description }} {{ commit.description }}
......
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { normalizeData } from 'ee_else_ce/repository/utils/commit';
import getCommits from './queries/getCommits.query.graphql'; import getCommits from './queries/getCommits.query.graphql';
import getProjectPath from './queries/getProjectPath.query.graphql'; import getProjectPath from './queries/getProjectPath.query.graphql';
import getRef from './queries/getRef.query.graphql'; import getRef from './queries/getRef.query.graphql';
...@@ -6,19 +7,6 @@ import getRef from './queries/getRef.query.graphql'; ...@@ -6,19 +7,6 @@ import getRef from './queries/getRef.query.graphql';
let fetchpromise; let fetchpromise;
let resolvers = []; let resolvers = [];
export function normalizeData(data) {
return data.map(d => ({
sha: d.commit.id,
message: d.commit.message,
committedDate: d.commit.committed_date,
commitPath: d.commit_path,
fileName: d.file_name,
type: d.type,
lockLabel: d.lock_label,
__typename: 'LogTreeCommit',
}));
}
export function resolveCommit(commits, { resolve, entry }) { export function resolveCommit(commits, { resolve, entry }) {
const commit = commits.find(c => c.fileName === entry.name && c.type === entry.type); const commit = commits.find(c => c.fileName === entry.name && c.type === entry.type);
......
fragment TreeEntryCommit on LogTreeCommit {
sha
message
committedDate
commitPath
fileName
type
}
#import "ee_else_ce/repository/queries/commit.fragment.graphql"
query getCommit($fileName: String!, $type: String!, $path: String!) { query getCommit($fileName: String!, $type: String!, $path: String!) {
commit(path: $path, fileName: $fileName, type: $type) @client { commit(path: $path, fileName: $fileName, type: $type) @client {
sha ...TreeEntryCommit
message
committedDate
commitPath
fileName
type
lockLabel
} }
} }
#import "ee_else_ce/repository/queries/commit.fragment.graphql"
query getCommits { query getCommits {
commits @client { commits @client {
sha ...TreeEntryCommit
message
committedDate
commitPath
fileName
type
lockLabel
} }
} }
...@@ -5,7 +5,7 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) { ...@@ -5,7 +5,7 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) {
lastCommit { lastCommit {
sha sha
title title
message description
webUrl webUrl
authoredDate authoredDate
author { author {
......
// eslint-disable-next-line import/prefer-default-export
export function normalizeData(data, extra = () => {}) {
return data.map(d => ({
sha: d.commit.id,
message: d.commit.message,
committedDate: d.commit.committed_date,
commitPath: d.commit_path,
fileName: d.file_name,
type: d.type,
__typename: 'LogTreeCommit',
...extra(d),
}));
}
function loadScript(path) {
const script = document.createElement('script');
script.type = 'application/javascript';
script.src = path;
script.defer = true;
document.head.appendChild(script);
}
/**
* Loads the Sourcegraph integration for support for Sourcegraph extensions and
* code intelligence.
*/
export default function initSourcegraph() {
const { url } = gon.sourcegraph || {};
if (!url) {
return;
}
const assetsUrl = new URL('/assets/webpack/sourcegraph/', window.location.href);
const scriptPath = new URL('scripts/integration.bundle.js', assetsUrl).href;
window.SOURCEGRAPH_ASSETS_URL = assetsUrl.href;
window.SOURCEGRAPH_URL = url;
window.SOURCEGRAPH_INTEGRATION = 'gitlab-integration';
loadScript(scriptPath);
}
import initSourcegraph from './index';
/**
* Load sourcegraph in it's own listener so that it's isolated from failures.
*/
document.addEventListener('DOMContentLoaded', initSourcegraph);
...@@ -168,7 +168,7 @@ export default { ...@@ -168,7 +168,7 @@ export default {
:prepend="true" :prepend="true"
tag="* [ ] " tag="* [ ] "
:button-title="__('Add a task list')" :button-title="__('Add a task list')"
icon="task-done" icon="list-task"
/> />
<toolbar-button <toolbar-button
:tag="mdTable" :tag="mdTable"
......
...@@ -572,3 +572,10 @@ img.emoji { ...@@ -572,3 +572,10 @@ img.emoji {
.gl-font-size-20 { font-size: $gl-font-size-20; } .gl-font-size-20 { font-size: $gl-font-size-20; }
.gl-font-size-28 { font-size: $gl-font-size-28; } .gl-font-size-28 { font-size: $gl-font-size-28; }
.gl-font-size-42 { font-size: $gl-font-size-42; } .gl-font-size-42 { font-size: $gl-font-size-42; }
.border-section {
@include gl-py-6;
@include gl-m-0;
border-top: 1px solid $border-color;
}
...@@ -20,6 +20,17 @@ ...@@ -20,6 +20,17 @@
@extend .gl-responsive-table-row-layout; @extend .gl-responsive-table-row-layout;
margin-top: 10px; margin-top: 10px;
border: 1px solid $border-color; border: 1px solid $border-color;
color: $gray-700;
&.gl-responsive-table-row-clickable {
&:hover {
background-color: $gray-light;
.underline {
text-decoration: underline;
}
}
}
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
margin: 0; margin: 0;
......
...@@ -1084,18 +1084,6 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -1084,18 +1084,6 @@ button.mini-pipeline-graph-dropdown-toggle {
} }
.test-reports-table { .test-reports-table {
color: $gray-700;
.test-reports-summary-row {
&:hover {
background-color: $gray-light;
.test-reports-summary-suite {
text-decoration: underline;
}
}
}
.build-trace { .build-trace {
@include build-trace(); @include build-trace();
} }
......
# frozen_string_literal: true
module SourcegraphGon
extend ActiveSupport::Concern
included do
before_action :push_sourcegraph_gon, if: :html_request?
end
private
def push_sourcegraph_gon
return unless sourcegraph_enabled?
gon.push({
sourcegraph: { url: Gitlab::CurrentSettings.sourcegraph_url }
})
end
def sourcegraph_enabled?
Gitlab::CurrentSettings.sourcegraph_enabled && sourcegraph_enabled_for_project? && current_user&.sourcegraph_enabled
end
def sourcegraph_enabled_for_project?
return false unless project && Gitlab::Sourcegraph.feature_enabled?(project)
return project.public? if Gitlab::CurrentSettings.sourcegraph_public_only
true
end
end
...@@ -47,7 +47,8 @@ class Profiles::PreferencesController < Profiles::ApplicationController ...@@ -47,7 +47,8 @@ class Profiles::PreferencesController < Profiles::ApplicationController
:preferred_language, :preferred_language,
:time_display_relative, :time_display_relative,
:time_format_in_24h, :time_format_in_24h,
:show_whitespace_in_diffs :show_whitespace_in_diffs,
:sourcegraph_enabled
] ]
end end
end end
......
...@@ -8,6 +8,8 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -8,6 +8,8 @@ class Projects::BlobController < Projects::ApplicationController
include NotesHelper include NotesHelper
include ActionView::Helpers::SanitizeHelper include ActionView::Helpers::SanitizeHelper
include RedirectsForMissingPathOnTree include RedirectsForMissingPathOnTree
include SourcegraphGon
prepend_before_action :authenticate_user!, only: [:edit] prepend_before_action :authenticate_user!, only: [:edit]
around_action :allow_gitaly_ref_name_caching, only: [:show] around_action :allow_gitaly_ref_name_caching, only: [:show]
......
...@@ -8,6 +8,7 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -8,6 +8,7 @@ class Projects::CommitController < Projects::ApplicationController
include CreatesCommit include CreatesCommit
include DiffForPath include DiffForPath
include DiffHelper include DiffHelper
include SourcegraphGon
# Authorize # Authorize
before_action :require_non_empty_project before_action :require_non_empty_project
......
...@@ -9,6 +9,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -9,6 +9,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
include ToggleAwardEmoji include ToggleAwardEmoji
include IssuableCollections include IssuableCollections
include RecordUserLastActivity include RecordUserLastActivity
include SourcegraphGon
skip_before_action :merge_request, only: [:index, :bulk_update] skip_before_action :merge_request, only: [:index, :bulk_update]
before_action :whitelist_query_limiting, only: [:assign_related_issues, :update] before_action :whitelist_query_limiting, only: [:assign_related_issues, :update]
......
...@@ -8,6 +8,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController ...@@ -8,6 +8,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController
before_action :domain, except: [:new, :create] before_action :domain, except: [:new, :create]
def show def show
redirect_to edit_project_pages_domain_path(@project, @domain)
end end
def new def new
...@@ -23,7 +24,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController ...@@ -23,7 +24,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController
flash[:alert] = 'Failed to verify domain ownership' flash[:alert] = 'Failed to verify domain ownership'
end end
redirect_to project_pages_domain_path(@project, @domain) redirect_to edit_project_pages_domain_path(@project, @domain)
end end
def edit def edit
...@@ -33,7 +34,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController ...@@ -33,7 +34,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController
@domain = @project.pages_domains.create(create_params) @domain = @project.pages_domains.create(create_params)
if @domain.valid? if @domain.valid?
redirect_to project_pages_domain_path(@project, @domain) redirect_to edit_project_pages_domain_path(@project, @domain)
else else
render 'new' render 'new'
end end
...@@ -77,7 +78,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController ...@@ -77,7 +78,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController
end end
def update_params def update_params
params.require(:pages_domain).permit(:user_provided_key, :user_provided_certificate, :auto_ssl_enabled) params.fetch(:pages_domain, {}).permit(:user_provided_key, :user_provided_certificate, :auto_ssl_enabled)
end end
def domain def domain
......
...@@ -259,6 +259,9 @@ module ApplicationSettingsHelper ...@@ -259,6 +259,9 @@ module ApplicationSettingsHelper
:shared_runners_text, :shared_runners_text,
:sign_in_text, :sign_in_text,
:signup_enabled, :signup_enabled,
:sourcegraph_enabled,
:sourcegraph_url,
:sourcegraph_public_only,
:terminal_max_session_time, :terminal_max_session_time,
:terms, :terms,
:throttle_authenticated_api_enabled, :throttle_authenticated_api_enabled,
......
# frozen_string_literal: true
module SourcegraphHelper
def sourcegraph_url_message
link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: Gitlab::CurrentSettings.sourcegraph_url }
link_end = "#{sprite_icon('external-link', size: 12, css_class: 'ml-1 vertical-align-center')}</a>".html_safe
message =
if Gitlab::CurrentSettings.sourcegraph_url_is_com?
s_('SourcegraphPreferences|Uses %{link_start}Sourcegraph.com%{link_end}.').html_safe
else
s_('SourcegraphPreferences|Uses a custom %{link_start}Sourcegraph instance%{link_end}.').html_safe
end
message % { link_start: link_start, link_end: link_end }
end
def sourcegraph_experimental_message
if Gitlab::Sourcegraph.feature_conditional?
s_("SourcegraphPreferences|This feature is experimental and currently limited to certain projects.")
elsif Gitlab::CurrentSettings.sourcegraph_public_only
s_("SourcegraphPreferences|This feature is experimental and limited to public projects.")
else
s_("SourcegraphPreferences|This feature is experimental.")
end
end
end
...@@ -99,6 +99,10 @@ class ApplicationSetting < ApplicationRecord ...@@ -99,6 +99,10 @@ class ApplicationSetting < ApplicationRecord
presence: true, presence: true,
if: :plantuml_enabled if: :plantuml_enabled
validates :sourcegraph_url,
presence: true,
if: :sourcegraph_enabled
validates :snowplow_collector_hostname, validates :snowplow_collector_hostname,
presence: true, presence: true,
hostname: true, hostname: true,
...@@ -343,6 +347,10 @@ class ApplicationSetting < ApplicationRecord ...@@ -343,6 +347,10 @@ class ApplicationSetting < ApplicationRecord
end end
after_commit :expire_performance_bar_allowed_user_ids_cache, if: -> { previous_changes.key?('performance_bar_allowed_group_id') } after_commit :expire_performance_bar_allowed_user_ids_cache, if: -> { previous_changes.key?('performance_bar_allowed_group_id') }
def sourcegraph_url_is_com?
!!(sourcegraph_url =~ /\Ahttps:\/\/(www\.)?sourcegraph\.com/)
end
def self.create_from_defaults def self.create_from_defaults
transaction(requires_new: true) do transaction(requires_new: true) do
super super
......
...@@ -102,6 +102,9 @@ module ApplicationSettingImplementation ...@@ -102,6 +102,9 @@ module ApplicationSettingImplementation
shared_runners_text: nil, shared_runners_text: nil,
sign_in_text: nil, sign_in_text: nil,
signup_enabled: Settings.gitlab['signup_enabled'], signup_enabled: Settings.gitlab['signup_enabled'],
sourcegraph_enabled: false,
sourcegraph_url: nil,
sourcegraph_public_only: true,
terminal_max_session_time: 0, terminal_max_session_time: 0,
throttle_authenticated_api_enabled: false, throttle_authenticated_api_enabled: false,
throttle_authenticated_api_period_in_seconds: 3600, throttle_authenticated_api_period_in_seconds: 3600,
......
...@@ -240,6 +240,7 @@ class User < ApplicationRecord ...@@ -240,6 +240,7 @@ class User < ApplicationRecord
delegate :time_display_relative, :time_display_relative=, to: :user_preference delegate :time_display_relative, :time_display_relative=, to: :user_preference
delegate :time_format_in_24h, :time_format_in_24h=, to: :user_preference delegate :time_format_in_24h, :time_format_in_24h=, to: :user_preference
delegate :show_whitespace_in_diffs, :show_whitespace_in_diffs=, to: :user_preference delegate :show_whitespace_in_diffs, :show_whitespace_in_diffs=, to: :user_preference
delegate :sourcegraph_enabled, :sourcegraph_enabled=, to: :user_preference
delegate :setup_for_company, :setup_for_company=, to: :user_preference delegate :setup_for_company, :setup_for_company=, to: :user_preference
accepts_nested_attributes_for :user_preference, update_only: true accepts_nested_attributes_for :user_preference, update_only: true
......
# frozen_string_literal: true # frozen_string_literal: true
module MergeRequests module Git
class WorkingCopyBaseService < MergeRequests::BaseService module Logger
attr_reader :merge_request
def source_project
@source_project ||= merge_request.source_project
end
def target_project
@target_project ||= merge_request.target_project
end
def log_error(message, save_message_on_model: false) def log_error(message, save_message_on_model: false)
Gitlab::GitLogger.error("#{self.class.name} error (#{merge_request.to_reference(full: true)}): #{message}") Gitlab::GitLogger.error("#{self.class.name} error (#{merge_request.to_reference(full: true)}): #{message}")
merge_request.update(merge_error: message) if save_message_on_model merge_request.update(merge_error: message) if save_message_on_model
end end
# Don't try to print expensive instance variables.
def inspect
"#<#{self.class} #{merge_request.to_reference(full: true)}>"
end
end end
end end
...@@ -29,6 +29,19 @@ module MergeRequests ...@@ -29,6 +29,19 @@ module MergeRequests
.execute_for_merge_request(merge_request) .execute_for_merge_request(merge_request)
end end
def source_project
@source_project ||= merge_request.source_project
end
def target_project
@target_project ||= merge_request.target_project
end
# Don't try to print expensive instance variables.
def inspect
"#<#{self.class} #{merge_request.to_reference(full: true)}>"
end
private private
def create(merge_request) def create(merge_request)
......
# frozen_string_literal: true # frozen_string_literal: true
module MergeRequests module MergeRequests
class RebaseService < MergeRequests::WorkingCopyBaseService class RebaseService < MergeRequests::BaseService
include Git::Logger
REBASE_ERROR = 'Rebase failed. Please rebase locally' REBASE_ERROR = 'Rebase failed. Please rebase locally'
attr_reader :merge_request
def execute(merge_request) def execute(merge_request)
@merge_request = merge_request @merge_request = merge_request
......
# frozen_string_literal: true # frozen_string_literal: true
module MergeRequests module MergeRequests
class SquashService < MergeRequests::WorkingCopyBaseService class SquashService < MergeRequests::BaseService
include Git::Logger
def execute def execute
# If performing a squash would result in no change, then # If performing a squash would result in no change, then
# immediately return a success message without performing a squash # immediately return a success message without performing a squash
......
- return unless Gitlab::Sourcegraph.feature_available?
- expanded = integration_expanded?('sourcegraph_')
%section.settings.as-sourcegraph.no-animate#js-sourcegraph-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Sourcegraph')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
- link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: 'https://sourcegraph.com/' }
- link_end = "#{sprite_icon('external-link', size: 12, css_class: 'ml-1 vertical-align-center')}</a>".html_safe
= s_('SourcegraphAdmin|Enable code intelligence powered by %{link_start}Sourcegraph%{link_end} on your GitLab instance\'s code views and merge requests.').html_safe % { link_start: link_start, link_end: link_end }
%span
= link_to s_('SourcegraphAdmin|More information'), help_page_path('integration/sourcegraph.md'), target: '_blank'
.settings-content
= form_for @application_setting, url: integrations_admin_application_settings_path(anchor: 'js-sourcegraph-settings'), html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
.form-check
= f.check_box :sourcegraph_enabled, class: 'form-check-input'
= f.label :sourcegraph_enabled, s_('SourcegraphAdmin|Enable Sourcegraph'), class: 'form-check-label'
.form-group
.form-check
= f.check_box :sourcegraph_public_only, class: 'form-check-input'
= f.label :sourcegraph_public_only, s_('SourcegraphAdmin|Block on private and internal projects'), class: 'form-check-label'
.form-text.text-muted
= s_('SourcegraphAdmin|If checked, only public projects will have code intelligence and communicate with Sourcegraph.')
.form-group
= f.label :sourcegraph_url, s_('SourcegraphAdmin|Sourcegraph URL'), class: 'label-bold'
= f.text_field :sourcegraph_url, class: 'form-control', placeholder: s_('SourcegraphAdmin|e.g. https://sourcegraph.example.com')
.form-text.text-muted
= s_('SourcegraphAdmin|Configure the URL to a Sourcegraph instance which can read your GitLab projects.')
= f.submit s_('SourcegraphAdmin|Save changes'), class: 'btn btn-success'
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
= render_if_exists 'admin/application_settings/elasticsearch_form' = render_if_exists 'admin/application_settings/elasticsearch_form'
= render 'admin/application_settings/plantuml' = render 'admin/application_settings/plantuml'
= render 'admin/application_settings/sourcegraph'
= render_if_exists 'admin/application_settings/slack' = render_if_exists 'admin/application_settings/slack'
= render 'admin/application_settings/third_party_offers' = render 'admin/application_settings/third_party_offers'
= render 'admin/application_settings/snowplow' = render 'admin/application_settings/snowplow'
......
- return unless Gitlab::Sourcegraph::feature_available? && Gitlab::CurrentSettings.sourcegraph_enabled
- sourcegraph_url = Gitlab::CurrentSettings.sourcegraph_url
.col-sm-12
%hr
.col-lg-4.profile-settings-sidebar
%h4.prepend-top-0
= s_('Preferences|Integrations')
%p
= s_('Preferences|Customize integrations with third party services.')
= succeed '.' do
= link_to _('Learn more'), help_page_path('user/profile/preferences.md', anchor: 'integrations'), target: '_blank'
.col-lg-8
%label.label-bold
= s_('Preferences|Sourcegraph')
= link_to icon('question-circle'), help_page_path('user/profile/preferences.md', anchor: 'sourcegraph'), target: '_blank', class: 'has-tooltip', title: _('More information')
.form-group.form-check
= f.check_box :sourcegraph_enabled, class: 'form-check-input'
= f.label :sourcegraph_enabled, class: 'form-check-label' do
- link_start = '<a href="%{url}">'.html_safe % { url: sourcegraph_url }
- link_end = '</a>'.html_safe
= s_('Preferences|Enable integrated code intelligence on code views').html_safe % { link_start: link_start, link_end: link_end }
.form-text.text-muted
= sourcegraph_url_message
= sourcegraph_experimental_message
...@@ -111,6 +111,9 @@ ...@@ -111,6 +111,9 @@
= time_display_label = time_display_label
.form-text.text-muted .form-text.text-muted
= s_('Preferences|For example: 30 mins ago.') = s_('Preferences|For example: 30 mins ago.')
= render 'sourcegraph', f: f
.col-lg-4.profile-settings-sidebar .col-lg-4.profile-settings-sidebar
.col-lg-8 .col-lg-8
.form-group .form-group
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
= markdown_toolbar_button({ icon: "link", data: { "md-tag" => "[{text}](url)", "md-select" => "url" }, title: _("Add a link") }) = markdown_toolbar_button({ icon: "link", data: { "md-tag" => "[{text}](url)", "md-select" => "url" }, title: _("Add a link") })
= markdown_toolbar_button({ icon: "list-bulleted", data: { "md-tag" => "* ", "md-prepend" => true }, title: _("Add a bullet list") }) = markdown_toolbar_button({ icon: "list-bulleted", data: { "md-tag" => "* ", "md-prepend" => true }, title: _("Add a bullet list") })
= markdown_toolbar_button({ icon: "list-numbered", data: { "md-tag" => "1. ", "md-prepend" => true }, title: _("Add a numbered list") }) = markdown_toolbar_button({ icon: "list-numbered", data: { "md-tag" => "1. ", "md-prepend" => true }, title: _("Add a numbered list") })
= markdown_toolbar_button({ icon: "task-done", data: { "md-tag" => "* [ ] ", "md-prepend" => true }, title: _("Add a task list") }) = markdown_toolbar_button({ icon: "list-task", data: { "md-tag" => "* [ ] ", "md-prepend" => true }, title: _("Add a task list") })
= markdown_toolbar_button({ icon: "table", data: { "md-tag" => "| header | header |\n| ------ | ------ |\n| cell | cell |\n| cell | cell |", "md-prepend" => true }, title: _("Add a table") }) = markdown_toolbar_button({ icon: "table", data: { "md-tag" => "| header | header |\n| ------ | ------ |\n| cell | cell |\n| cell | cell |", "md-prepend" => true }, title: _("Add a table") })
- if show_fullscreen_button - if show_fullscreen_button
%button.toolbar-btn.toolbar-fullscreen-btn.js-zen-enter.has-tooltip{ type: "button", tabindex: -1, "aria-label": "Go full screen", title: _("Go full screen"), data: { container: "body" } } %button.toolbar-btn.toolbar-fullscreen-btn.js-zen-enter.has-tooltip{ type: "button", tabindex: -1, "aria-label": "Go full screen", title: _("Go full screen"), data: { container: "body" } }
......
...@@ -21,11 +21,11 @@ ...@@ -21,11 +21,11 @@
%span.badge.badge-danger %span.badge.badge-danger
= s_('GitLabPages|Expired') = s_('GitLabPages|Expired')
%div %div
= link_to s_('GitLabPages|Details'), project_pages_domain_path(@project, domain), class: "btn btn-sm btn-grouped" = link_to s_('GitLabPages|Edit'), edit_project_pages_domain_path(@project, domain), class: "btn btn-sm btn-grouped btn-success btn-inverted"
= link_to s_('GitLabPages|Remove'), project_pages_domain_path(@project, domain), data: { confirm: s_('GitLabPages|Are you sure?')}, method: :delete, class: "btn btn-remove btn-sm btn-grouped" = link_to s_('GitLabPages|Remove'), project_pages_domain_path(@project, domain), data: { confirm: s_('GitLabPages|Are you sure?')}, method: :delete, class: "btn btn-remove btn-sm btn-grouped"
- if verification_enabled && domain.unverified? - if verification_enabled && domain.unverified?
%li.list-group-item.bs-callout-warning %li.list-group-item.bs-callout-warning
- details_link_start = "<a href='#{project_pages_domain_path(@project, domain)}'>".html_safe - details_link_start = "<a href='#{edit_project_pages_domain_path(@project, domain)}'>".html_safe
- details_link_end = '</a>'.html_safe - details_link_end = '</a>'.html_safe
= s_('GitLabPages|%{domain} is not verified. To learn how to verify ownership, visit your %{link_start}domain details%{link_end}.').html_safe % { domain: domain.domain, = s_('GitLabPages|%{domain} is not verified. To learn how to verify ownership, visit your %{link_start}domain details%{link_end}.').html_safe % { domain: domain.domain,
link_start: details_link_start, link_start: details_link_start,
......
- if @domain.auto_ssl_enabled? - auto_ssl_available = ::Gitlab::LetsEncrypt.enabled?
- if @domain.enabled? - auto_ssl_enabled = @domain.auto_ssl_enabled?
- if @domain.certificate_text - auto_ssl_available_and_enabled = auto_ssl_available && auto_ssl_enabled
%pre - has_user_defined_certificate = @domain.certificate && @domain.certificate_user_provided?
= @domain.certificate_text
- else - if auto_ssl_available
.bs-callout.bs-callout-info .form-group.border-section
= _("GitLab is obtaining a Let's Encrypt SSL certificate for this domain. This process can take some time. Please try again later.") .row
.col-sm-2
= _('Certificate')
.col-sm-10.js-auto-ssl-toggle-container
%label{ for: "pages_domain_auto_ssl_enabled_button" }
- lets_encrypt_link_url = "https://letsencrypt.org/"
- lets_encrypt_link_start = "<a href=\"%{lets_encrypt_link_url}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-nowrap\">".html_safe % { lets_encrypt_link_url: lets_encrypt_link_url }
- lets_encrypt_link_end = "</a>".html_safe
= _("Automatic certificate management using %{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end}").html_safe % { lets_encrypt_link_start: lets_encrypt_link_start, lets_encrypt_link_end: lets_encrypt_link_end }
%button{ type: "button", id: "pages_domain_auto_ssl_enabled_button",
class: "js-project-feature-toggle project-feature-toggle mt-2 #{"is-checked" if auto_ssl_available_and_enabled}",
"aria-label": _("Automatic certificate management using Let's Encrypt") }
= f.hidden_field :auto_ssl_enabled?, class: "js-project-feature-toggle-input"
%span.toggle-icon
= sprite_icon("status_success_borderless", size: 16, css_class: "toggle-icon-svg toggle-status-checked")
= sprite_icon("status_failed_borderless", size: 16, css_class: "toggle-icon-svg toggle-status-unchecked")
%p.text-secondary.mt-3
- docs_link_url = help_page_path("user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md")
- docs_link_start = "<a href=\"%{docs_link_url}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-nowrap\">".html_safe % { docs_link_url: docs_link_url }
- docs_link_end = "</a>".html_safe
= _("Let's Encrypt is a free, automated, and open certificate authority (CA) that gives digital certificates in order to enable HTTPS (SSL/TLS) for websites. Learn more about Let's Encrypt configuration by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}.").html_safe % { docs_link_url: docs_link_url, docs_link_start: docs_link_start, docs_link_end: docs_link_end }
.form-group.border-section.js-shown-unless-auto-ssl{ class: ("d-none" if auto_ssl_available_and_enabled) }
- if has_user_defined_certificate
.row
.col-sm-10.offset-sm-2
.card
.card-header
= _('Certificate')
.d-flex.justify-content-between.align-items-center.p-3
%span
= @domain.subject || _('missing')
= link_to _('Remove'),
clean_certificate_project_pages_domain_path(@project, @domain),
data: { confirm: _('Are you sure?') },
class: 'btn btn-remove btn-sm',
method: :delete
- else - else
.bs-callout.bs-callout-warning .row
= _("A Let's Encrypt SSL certificate can not be obtained until your domain is verified.") .col-sm-10.offset-sm-2
- else = f.label :user_provided_certificate, _("Certificate (PEM)")
- if @domain.certificate_text = f.text_area :user_provided_certificate,
%pre rows: 5,
= @domain.certificate_text class: "form-control js-enabled-unless-auto-ssl",
- else disabled: auto_ssl_available_and_enabled
.light %span.help-inline.text-muted= _("Upload a certificate for your domain with all intermediates")
= _("missing") .row
.col-sm-10.offset-sm-2
= f.label :user_provided_key, _("Key (PEM)")
= f.text_area :user_provided_key,
rows: 5,
class: "form-control js-enabled-unless-auto-ssl",
disabled: auto_ssl_available_and_enabled
%span.help-inline.text-muted= _("Upload a private key for your certificate")
= render 'lets_encrypt_callout', auto_ssl_available_and_enabled: auto_ssl_available_and_enabled
- verification_enabled = Gitlab::CurrentSettings.pages_domain_verification_enabled?
- dns_record = "#{@domain.domain} CNAME #{@domain.project.pages_subdomain}.#{Settings.pages.host}."
.form-group.border-section
.row
.col-sm-2
= _("DNS")
.col-sm-10
.input-group
= text_field_tag :domain_dns, dns_record , class: "monospace js-select-on-focus form-control", readonly: true
.input-group-append
= clipboard_button(target: '#domain_dns', class: 'btn-default input-group-text d-none d-sm-block')
%p.form-text.text-muted
= _("To access this domain create a new DNS record")
- if verification_enabled
- verification_record = "#{@domain.verification_domain} TXT #{@domain.keyed_verification_code}"
.form-group.border-section
.row
.col-sm-2
= _("Verification status")
.col-sm-10
.status-badge
- text, status = @domain.unverified? ? [_('Unverified'), 'badge-danger'] : [_('Verified'), 'badge-success']
.badge{ class: status }
= text
= link_to sprite_icon("redo"), verify_project_pages_domain_path(@project, @domain), method: :post, class: "btn has-tooltip", title: _("Retry verification")
.input-group
= text_field_tag :domain_verification, verification_record, class: "monospace js-select-on-focus form-control", readonly: true
.input-group-append
= clipboard_button(target: '#domain_verification', class: 'btn-default d-none d-sm-block')
%p.form-text.text-muted
- link_to_help = link_to(_('verify ownership'), help_page_path('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: '4-verify-the-domains-ownership'))
= _("To %{link_to_help} of your domain, add the above key to a TXT record within to your DNS configuration.").html_safe % { link_to_help: link_to_help }
...@@ -3,62 +3,25 @@ ...@@ -3,62 +3,25 @@
- @domain.errors.full_messages.each do |msg| - @domain.errors.full_messages.each do |msg|
= msg = msg
.form-group.row .form-group.border-section
.col-sm-2.col-form-label .row
= f.label :domain, _("Domain") - if @domain.persisted?
.col-sm-10 .col-sm-2
= f.text_field :domain, required: true, autocomplete: "off", class: "form-control", disabled: @domain.persisted? = _("Domain")
- if Gitlab.config.pages.external_https
- auto_ssl_available = ::Gitlab::LetsEncrypt.enabled?
- auto_ssl_enabled = @domain.auto_ssl_enabled?
- auto_ssl_available_and_enabled = auto_ssl_available && auto_ssl_enabled
- if auto_ssl_available
.form-group.row
.col-sm-2.col-form-label
%label{ for: "pages_domain_auto_ssl_enabled_button" }
- lets_encrypt_link_url = "https://letsencrypt.org/"
- lets_encrypt_link_start = "<a href=\"%{lets_encrypt_link_url}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-nowrap\">".html_safe % { lets_encrypt_link_url: lets_encrypt_link_url }
- lets_encrypt_link_end = "</a>".html_safe
= _("Automatic certificate management using %{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end}").html_safe % { lets_encrypt_link_start: lets_encrypt_link_start, lets_encrypt_link_end: lets_encrypt_link_end }
.col-sm-10.js-auto-ssl-toggle-container
%button{ type: "button", id: "pages_domain_auto_ssl_enabled_button",
class: "js-project-feature-toggle project-feature-toggle mt-2 #{"is-checked" if auto_ssl_available_and_enabled}",
"aria-label": _("Automatic certificate management using Let's Encrypt") }
= f.hidden_field :auto_ssl_enabled?, class: "js-project-feature-toggle-input"
%span.toggle-icon
= sprite_icon("status_success_borderless", size: 16, css_class: "toggle-icon-svg toggle-status-checked")
= sprite_icon("status_failed_borderless", size: 16, css_class: "toggle-icon-svg toggle-status-unchecked")
%p.text-secondary.mt-3
- docs_link_url = help_page_path("user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md")
- docs_link_start = "<a href=\"%{docs_link_url}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-nowrap\">".html_safe % { docs_link_url: docs_link_url }
- docs_link_end = "</a>".html_safe
= _("Let's Encrypt is a free, automated, and open certificate authority (CA) that gives digital certificates in order to enable HTTPS (SSL/TLS) for websites. Learn more about Let's Encrypt configuration by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}.").html_safe % { docs_link_url: docs_link_url, docs_link_start: docs_link_start, docs_link_end: docs_link_end }
.js-shown-unless-auto-ssl{ class: ("d-none" if auto_ssl_available_and_enabled) }
.form-group.row
.col-sm-2.col-form-label
= f.label :user_provided_certificate, _("Certificate (PEM)")
.col-sm-10 .col-sm-10
= f.text_area :user_provided_certificate, = external_link(@domain.url, @domain.url)
rows: 5, - else
class: "form-control js-enabled-unless-auto-ssl", .col-sm-2
disabled: auto_ssl_available_and_enabled = f.label :domain, _("Domain")
%span.help-inline.text-muted= _("Upload a certificate for your domain with all intermediates")
.form-group.row
.col-sm-2.col-form-label
= f.label :user_provided_key, _("Key (PEM)")
.col-sm-10 .col-sm-10
= f.text_area :user_provided_key, .input-group
rows: 5, = f.text_field :domain, required: true, autocomplete: "off", class: "form-control"
class: "form-control js-enabled-unless-auto-ssl",
disabled: auto_ssl_available_and_enabled
%span.help-inline.text-muted= _("Upload a private key for your certificate")
- if @domain.persisted?
= render 'dns'
- if Gitlab.config.pages.external_https
= render 'certificate', f: f
- else - else
.nothing-here-block .border-section.nothing-here-block
= _("Support for custom certificates is disabled. Ask your system's administrator to enable it.") = _("Support for custom certificates is disabled. Ask your system's administrator to enable it.")
- if @domain.enabled?
- if @domain.auto_ssl_enabled && !@domain.certificate
.form-group.border-section.js-shown-if-auto-ssl{ class: ("d-none" unless auto_ssl_available_and_enabled) }
.row
.col-sm-10.offset-sm-2
.bs-callout.bs-callout-info.mt-0
= _("GitLab is obtaining a Let's Encrypt SSL certificate for this domain. This process can take some time. Please try again later.")
- else
.form-group.border-section.js-shown-if-auto-ssl{ class: ("d-none" unless auto_ssl_available_and_enabled) }
.row
.col-sm-10.offset-sm-2
.bs-callout.bs-callout-warning.mt-0
= _("A Let's Encrypt SSL certificate can not be obtained until your domain is verified.")
- add_to_breadcrumbs _("Pages"), project_pages_path(@project) - add_to_breadcrumbs _("Pages"), project_pages_path(@project)
- breadcrumb_title @domain.domain - breadcrumb_title @domain.domain
- page_title @domain.domain - page_title @domain.domain
- verification_enabled = Gitlab::CurrentSettings.pages_domain_verification_enabled?
- if verification_enabled && @domain.unverified?
= content_for :flash_message do
.alert.alert-warning
.container-fluid.container-limited
= _("This domain is not verified. You will need to verify ownership before access is enabled.")
%h3.page-title %h3.page-title
= @domain.domain = _('Pages Domain')
= render 'projects/pages_domains/helper_text' = render 'projects/pages_domains/helper_text'
%hr.clearfix
%div %div
= form_for [@project.namespace.becomes(Namespace), @project, @domain], html: { class: 'fieldset-form' } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @domain], html: { class: 'fieldset-form' } do |f|
= render 'form', { f: f } = render 'form', { f: f }
.form-actions .form-actions.d-flex.justify-content-between
= f.submit _('Save Changes'), class: "btn btn-success" = f.submit _('Save Changes'), class: "btn btn-success"
= link_to _('Cancel'), project_pages_path(@project), class: 'btn btn-default btn-inverse'
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
%h3.page-title %h3.page-title
= _("New Pages Domain") = _("New Pages Domain")
= render 'projects/pages_domains/helper_text' = render 'projects/pages_domains/helper_text'
%hr.clearfix
%div %div
= form_for [@project.namespace.becomes(Namespace), @project, @domain], html: { class: 'fieldset-form' } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @domain], html: { class: 'fieldset-form' } do |f|
= render 'form', { f: f } = render 'form', { f: f }
......
...@@ -58,4 +58,4 @@ ...@@ -58,4 +58,4 @@
%td %td
= _("Certificate") = _("Certificate")
%td %td
= render 'certificate' = render 'lets_encrypt_callout', auto_ssl_available_and_enabled: false
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
= render 'shared/issuable/form/branch_chooser', issuable: issuable, form: form = render 'shared/issuable/form/branch_chooser', issuable: issuable, form: form
%hr
.form-group.row .form-group.row
= form.label :title, class: 'col-form-label col-sm-2' = form.label :title, class: 'col-form-label col-sm-2'
......
...@@ -20,3 +20,4 @@ ...@@ -20,3 +20,4 @@
= form.hidden_field(:target_branch, = form.hidden_field(:target_branch,
{ class: 'target_branch js-target-branch-select ref-name mw-xl', { class: 'target_branch js-target-branch-select ref-name mw-xl',
data: { placeholder: _('Select branch'), endpoint: refs_project_path(@project, sort: 'updated_desc', find: 'branches') }}) data: { placeholder: _('Select branch'), endpoint: refs_project_path(@project, sort: 'updated_desc', find: 'branches') }})
%hr
---
title: Require explicit null parameters to remove pages domain certificate and allow to use Let's Encrypt certificates through API
merge_request:
author:
type: changed
---
title: Replace task-done icon with list-task icon to better align with other toolbar
list icons
merge_request:
author:
type: other
---
title: Add documentation for sign-in application setting
merge_request: 19561
author: Horatiu Eugen Vlad
type: added
---
title: Merge Details Page and Edit Page for Page Domains
merge_request: 16687
author:
type: added
...@@ -255,8 +255,8 @@ module Gitlab ...@@ -255,8 +255,8 @@ module Gitlab
caching_config_hash[:compress] = false caching_config_hash[:compress] = false
caching_config_hash[:namespace] = Gitlab::Redis::Cache::CACHE_NAMESPACE caching_config_hash[:namespace] = Gitlab::Redis::Cache::CACHE_NAMESPACE
caching_config_hash[:expires_in] = 2.weeks # Cache should not grow forever caching_config_hash[:expires_in] = 2.weeks # Cache should not grow forever
if Sidekiq.server? # threaded context if Sidekiq.server? || defined?(::Puma) # threaded context
caching_config_hash[:pool_size] = Sidekiq.options[:concurrency] + 5 caching_config_hash[:pool_size] = Gitlab::Redis::Cache.pool_size
caching_config_hash[:pool_timeout] = 1 caching_config_hash[:pool_timeout] = 1
end end
......
...@@ -299,6 +299,11 @@ module.exports = { ...@@ -299,6 +299,11 @@ module.exports = {
from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/cmaps/'), from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/cmaps/'),
to: path.join(ROOT_PATH, 'public/assets/webpack/cmaps/'), to: path.join(ROOT_PATH, 'public/assets/webpack/cmaps/'),
}, },
{
from: path.join(ROOT_PATH, 'node_modules/@sourcegraph/code-host-integration/'),
to: path.join(ROOT_PATH, 'public/assets/webpack/sourcegraph/'),
ignore: ['package.json'],
},
{ {
from: path.join( from: path.join(
ROOT_PATH, ROOT_PATH,
......
...@@ -86,6 +86,12 @@ def unicode_emoji_regex ...@@ -86,6 +86,12 @@ def unicode_emoji_regex
))x ))x
end end
def count_filtered_commits(commits)
commits.count do |commit|
!commit.message.start_with?('fixup!', 'squash!')
end
end
def lint_commit(commit) # rubocop:disable Metrics/AbcSize def lint_commit(commit) # rubocop:disable Metrics/AbcSize
# For now we'll ignore merge commits, as getting rid of those is a problem # For now we'll ignore merge commits, as getting rid of those is a problem
# separate from enforcing good commit messages. # separate from enforcing good commit messages.
...@@ -285,7 +291,7 @@ def lint_commits(commits) ...@@ -285,7 +291,7 @@ def lint_commits(commits)
end end
end end
if git.commits.length > 10 && !ce_upstream? if count_filtered_commits(git.commits) > 10 && !ce_upstream?
warn( warn(
'This merge request includes more than 10 commits. ' \ 'This merge request includes more than 10 commits. ' \
'Please rebase these commits into a smaller number of commits.' 'Please rebase these commits into a smaller number of commits.'
......
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddSourcegraphConfigurationToApplicationSettings < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
def up
add_column(:application_settings, :sourcegraph_enabled, :boolean, default: false, null: false)
add_column(:application_settings, :sourcegraph_url, :string, null: true, limit: 255)
end
def down
remove_column(:application_settings, :sourcegraph_enabled)
remove_column(:application_settings, :sourcegraph_url)
end
end
# frozen_string_literal: true
class AddSourcegraphAdminAndUserPreferences < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
add_column(:application_settings, :sourcegraph_public_only, :boolean, default: true, null: false)
add_column(:user_preferences, :sourcegraph_enabled, :boolean)
end
def down
remove_column(:application_settings, :sourcegraph_public_only)
remove_column(:user_preferences, :sourcegraph_enabled)
end
end
...@@ -352,6 +352,9 @@ ActiveRecord::Schema.define(version: 2019_11_14_173624) do ...@@ -352,6 +352,9 @@ ActiveRecord::Schema.define(version: 2019_11_14_173624) do
t.string "snowplow_app_id" t.string "snowplow_app_id"
t.datetime_with_timezone "productivity_analytics_start_date" t.datetime_with_timezone "productivity_analytics_start_date"
t.string "default_ci_config_path", limit: 255 t.string "default_ci_config_path", limit: 255
t.boolean "sourcegraph_enabled", default: false, null: false
t.string "sourcegraph_url", limit: 255
t.boolean "sourcegraph_public_only", default: true, null: false
t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id" t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id"
t.index ["file_template_project_id"], name: "index_application_settings_on_file_template_project_id" t.index ["file_template_project_id"], name: "index_application_settings_on_file_template_project_id"
t.index ["instance_administration_project_id"], name: "index_applicationsettings_on_instance_administration_project_id" t.index ["instance_administration_project_id"], name: "index_applicationsettings_on_instance_administration_project_id"
...@@ -3771,6 +3774,7 @@ ActiveRecord::Schema.define(version: 2019_11_14_173624) do ...@@ -3771,6 +3774,7 @@ ActiveRecord::Schema.define(version: 2019_11_14_173624) do
t.boolean "time_format_in_24h" t.boolean "time_format_in_24h"
t.string "projects_sort", limit: 64 t.string "projects_sort", limit: 64
t.boolean "show_whitespace_in_diffs", default: true, null: false t.boolean "show_whitespace_in_diffs", default: true, null: false
t.boolean "sourcegraph_enabled"
t.boolean "setup_for_company" t.boolean "setup_for_company"
t.index ["user_id"], name: "index_user_preferences_on_user_id", unique: true t.index ["user_id"], name: "index_user_preferences_on_user_id", unique: true
end end
......
...@@ -120,7 +120,7 @@ The Pages daemon doesn't listen to the outside world. ...@@ -120,7 +120,7 @@ The Pages daemon doesn't listen to the outside world.
1. Set the external URL for GitLab Pages in `/etc/gitlab/gitlab.rb`: 1. Set the external URL for GitLab Pages in `/etc/gitlab/gitlab.rb`:
```shell ```ruby
pages_external_url 'http://example.io' pages_external_url 'http://example.io'
``` ```
...@@ -145,7 +145,7 @@ outside world. ...@@ -145,7 +145,7 @@ outside world.
1. Place the certificate and key inside `/etc/gitlab/ssl` 1. Place the certificate and key inside `/etc/gitlab/ssl`
1. In `/etc/gitlab/gitlab.rb` specify the following configuration: 1. In `/etc/gitlab/gitlab.rb` specify the following configuration:
```shell ```ruby
pages_external_url 'https://example.io' pages_external_url 'https://example.io'
pages_nginx['redirect_http_to_https'] = true pages_nginx['redirect_http_to_https'] = true
...@@ -167,7 +167,7 @@ behavior: ...@@ -167,7 +167,7 @@ behavior:
1. Edit `/etc/gitlab/gitlab.rb`. 1. Edit `/etc/gitlab/gitlab.rb`.
1. Set the `inplace_chroot` to `true` for GitLab Pages: 1. Set the `inplace_chroot` to `true` for GitLab Pages:
```shell ```ruby
gitlab_pages['inplace_chroot'] = true gitlab_pages['inplace_chroot'] = true
``` ```
...@@ -202,7 +202,7 @@ world. Custom domains are supported, but no TLS. ...@@ -202,7 +202,7 @@ world. Custom domains are supported, but no TLS.
1. Edit `/etc/gitlab/gitlab.rb`: 1. Edit `/etc/gitlab/gitlab.rb`:
```shell ```ruby
pages_external_url "http://example.io" pages_external_url "http://example.io"
nginx['listen_addresses'] = ['192.0.2.1'] nginx['listen_addresses'] = ['192.0.2.1']
pages_nginx['enable'] = false pages_nginx['enable'] = false
...@@ -233,7 +233,7 @@ world. Custom domains and TLS are supported. ...@@ -233,7 +233,7 @@ world. Custom domains and TLS are supported.
1. Edit `/etc/gitlab/gitlab.rb`: 1. Edit `/etc/gitlab/gitlab.rb`:
```shell ```ruby
pages_external_url "https://example.io" pages_external_url "https://example.io"
nginx['listen_addresses'] = ['192.0.2.1'] nginx['listen_addresses'] = ['192.0.2.1']
pages_nginx['enable'] = false pages_nginx['enable'] = false
...@@ -332,7 +332,7 @@ Follow the steps below to configure verbose logging of GitLab Pages daemon. ...@@ -332,7 +332,7 @@ Follow the steps below to configure verbose logging of GitLab Pages daemon.
If you wish to make it log events with level `DEBUG` you must configure this in If you wish to make it log events with level `DEBUG` you must configure this in
`/etc/gitlab/gitlab.rb`: `/etc/gitlab/gitlab.rb`:
```shell ```ruby
gitlab_pages['log_verbose'] = true gitlab_pages['log_verbose'] = true
``` ```
...@@ -347,7 +347,7 @@ are stored. ...@@ -347,7 +347,7 @@ are stored.
If you wish to store them in another location you must set it up in If you wish to store them in another location you must set it up in
`/etc/gitlab/gitlab.rb`: `/etc/gitlab/gitlab.rb`:
```shell ```ruby
gitlab_rails['pages_path'] = "/mnt/storage/pages" gitlab_rails['pages_path'] = "/mnt/storage/pages"
``` ```
...@@ -363,14 +363,14 @@ Omnibus GitLab 11.1. ...@@ -363,14 +363,14 @@ Omnibus GitLab 11.1.
If you wish to disable it you must configure this in If you wish to disable it you must configure this in
`/etc/gitlab/gitlab.rb`: `/etc/gitlab/gitlab.rb`:
```shell ```ruby
gitlab_pages['listen_proxy'] = nil gitlab_pages['listen_proxy'] = nil
``` ```
If you wish to make it listen on a different port you must configure this also in If you wish to make it listen on a different port you must configure this also in
`/etc/gitlab/gitlab.rb`: `/etc/gitlab/gitlab.rb`:
```shell ```ruby
gitlab_pages['listen_proxy'] = "localhost:10080" gitlab_pages['listen_proxy'] = "localhost:10080"
``` ```
...@@ -382,21 +382,26 @@ The maximum size of the unpacked archive per project can be configured in the ...@@ -382,21 +382,26 @@ The maximum size of the unpacked archive per project can be configured in the
Admin area under the Application settings in the **Maximum size of pages (MB)**. Admin area under the Application settings in the **Maximum size of pages (MB)**.
The default is 100MB. The default is 100MB.
## Running GitLab Pages in a separate server ## Running GitLab Pages on a separate server
You may want to run GitLab Pages daemon on a separate server in order to decrease the load on your main application server. You can run the GitLab Pages daemon on a separate server in order to decrease the load on your main application server.
Follow the steps below to configure GitLab Pages in a separate server.
1. Suppose you have the main GitLab application server named `app1`. Prepare To configure GitLab Pages on a separate server:
new Linux server (let's call it `app2`), create NFS share there and configure access to
this share from `app1`. Let's use the default GitLab Pages folder `/var/opt/gitlab/gitlab-rails/shared/pages`
as the shared folder on `app2` and mount it to `/mnt/pages` on `app1`.
1. On `app2` install GitLab omnibus and modify `/etc/gitlab/gitlab.rb` this way: 1. Set up a new server. This will become the **Pages server**.
```shell 1. Create an NFS share on the new server and configure this share to
allow access from your main **GitLab server**. For this example, we use the
default GitLab Pages folder `/var/opt/gitlab/gitlab-rails/shared/pages`
as the shared folder on the new server and we will mount it to `/mnt/pages`
on the **GitLab server**.
1. On the **Pages server**, install Omnibus GitLab and modify `/etc/gitlab/gitlab.rb`
to include:
```ruby
external_url 'http://<ip-address-of-the-server>' external_url 'http://<ip-address-of-the-server>'
pages_external_url "http://<your-pages-domain>" pages_external_url "http://<your-pages-server-URL>"
postgresql['enable'] = false postgresql['enable'] = false
redis['enable'] = false redis['enable'] = false
prometheus['enable'] = false prometheus['enable'] = false
...@@ -409,20 +414,82 @@ Follow the steps below to configure GitLab Pages in a separate server. ...@@ -409,20 +414,82 @@ Follow the steps below to configure GitLab Pages in a separate server.
gitlab_rails['auto_migrate'] = false gitlab_rails['auto_migrate'] = false
``` ```
1. Run `sudo gitlab-ctl reconfigure`. 1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
1. On `app1` apply the following changes to `/etc/gitlab/gitlab.rb`:
```shell 1. On the **GitLab server**, make the following changes to `/etc/gitlab/gitlab.rb`:
```ruby
gitlab_pages['enable'] = false gitlab_pages['enable'] = false
pages_external_url "http://<your-pages-domain>" pages_external_url "http://<your-pages-server-URL>"
gitlab_rails['pages_path'] = "/mnt/pages" gitlab_rails['pages_path'] = "/mnt/pages"
``` ```
1. Run `sudo gitlab-ctl reconfigure`. 1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
It is possible to run GitLab Pages on multiple servers if you wish to distribute
the load. You can do this through standard load balancing practices such as
configuring your DNS server to return multiple IPs for your Pages server,
configuring a load balancer to work at the IP level, and so on. If you wish to
set up GitLab Pages on multiple servers, perform the above procedure for each
Pages server.
### Access control when running GitLab Pages on a separate server
If you are [running GitLab Pages on a separate server](#running-gitlab-pages-on-a-separate-server),
then you must use the following procedure to configure [access control](#access-control):
1. On the **GitLab server**, add the following to `/etc/gitlab/gitlab.rb`:
```ruby
gitlab_pages['enable'] = true
gitlab_pages['access_control'] = true
```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the
changes to take effect. The `gitlab-secrets.json` file is now updated with the
new configuration.
DANGER: **Danger:**
The `gitlab-secrets.json` file contains secrets that control database encryption.
Do not edit or replace this file on the **GitLab server** or you might
experience permanent data loss. Make a backup copy of this file before proceeding,
as explained in the following steps.
1. Create a backup of the secrets file on the **GitLab server**:
```shell
cp /etc/gitlab/gitlab-secrets.json /etc/gitlab/gitlab-secrets.json.bak
```
1. Create a backup of the secrets file on the **Pages server**:
```shell
cp /etc/gitlab/gitlab-secrets.json /etc/gitlab/gitlab-secrets.json.bak
```
1. Disable Pages on the **GitLab server** by setting the following in
`/etc/gitlab/gitlab.rb`:
```ruby
gitlab_pages['enable'] = false
```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the **GitLab server**
to the **Pages server**.
1. On your **Pages server**, add the following to `/etc/gitlab/gitlab.rb`:
```ruby
gitlab_pages['gitlab_server'] = "https://<your-gitlab-server-URL>"
```
1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
## Backup ## Backup
Pages are part of the [regular backup][backup] so there is nothing to configure. GitLab Pages are part of the [regular backup][backup], so there is no separate backup to configure.
## Security ## Security
......
...@@ -22,6 +22,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/ap ...@@ -22,6 +22,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/ap
"domain": "ssl.domain.example", "domain": "ssl.domain.example",
"url": "https://ssl.domain.example", "url": "https://ssl.domain.example",
"project_id": 1337, "project_id": 1337,
"auto_ssl_enabled": false,
"certificate": { "certificate": {
"expired": false, "expired": false,
"expiration": "2020-04-12T14:32:00.000Z" "expiration": "2020-04-12T14:32:00.000Z"
...@@ -55,6 +56,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/ap ...@@ -55,6 +56,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/ap
{ {
"domain": "ssl.domain.example", "domain": "ssl.domain.example",
"url": "https://ssl.domain.example", "url": "https://ssl.domain.example",
"auto_ssl_enabled": false,
"certificate": { "certificate": {
"subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate", "subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate",
"expired": false, "expired": false,
...@@ -76,7 +78,7 @@ GET /projects/:id/pages/domains/:domain ...@@ -76,7 +78,7 @@ GET /projects/:id/pages/domains/:domain
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | -------------- | -------- | ---------------------------------------- | | --------- | -------------- | -------- | ---------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `domain` | string | yes | The domain | | `domain` | string | yes | The custom domain indicated by the user |
```bash ```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/pages/domains/www.domain.example curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/pages/domains/www.domain.example
...@@ -97,6 +99,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/ap ...@@ -97,6 +99,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/ap
{ {
"domain": "ssl.domain.example", "domain": "ssl.domain.example",
"url": "https://ssl.domain.example", "url": "https://ssl.domain.example",
"auto_ssl_enabled": false,
"certificate": { "certificate": {
"subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate", "subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate",
"expired": false, "expired": false,
...@@ -114,12 +117,13 @@ Creates a new pages domain. The user must have permissions to create new pages d ...@@ -114,12 +117,13 @@ Creates a new pages domain. The user must have permissions to create new pages d
POST /projects/:id/pages/domains POST /projects/:id/pages/domains
``` ```
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| ------------- | -------------- | -------- | ---------------------------------------- | | -------------------| -------------- | -------- | ---------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `domain` | string | yes | The domain | | `domain` | string | yes | The custom domain indicated by the user |
| `certificate` | file/string | no | The certificate in PEM format with intermediates following in most specific to least specific order.| | `auto_ssl_enabled` | boolean | no | Enables [automatic generation](../user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md) of SSL certificates issued by Let's Encrypt for custom domains. |
| `key` | file/string | no | The certificate key in PEM format. | | `certificate` | file/string | no | The certificate in PEM format with intermediates following in most specific to least specific order.|
| `key` | file/string | no | The certificate key in PEM format. |
```bash ```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain=ssl.domain.example" --form "certificate=@/path/to/cert.pem" --form "key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain=ssl.domain.example" --form "certificate=@/path/to/cert.pem" --form "key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains
...@@ -129,10 +133,15 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain ...@@ -129,10 +133,15 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain=ssl.domain.example" --form "certificate=$CERT_PEM" --form "key=$KEY_PEM" https://gitlab.example.com/api/v4/projects/5/pages/domains curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain=ssl.domain.example" --form "certificate=$CERT_PEM" --form "key=$KEY_PEM" https://gitlab.example.com/api/v4/projects/5/pages/domains
``` ```
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain=ssl.domain.example" --form "auto_ssl_enabled=true" https://gitlab.example.com/api/v4/projects/5/pages/domains
```
```json ```json
{ {
"domain": "ssl.domain.example", "domain": "ssl.domain.example",
"url": "https://ssl.domain.example", "url": "https://ssl.domain.example",
"auto_ssl_enabled": true,
"certificate": { "certificate": {
"subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate", "subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate",
"expired": false, "expired": false,
...@@ -150,12 +159,15 @@ Updates an existing project pages domain. The user must have permissions to chan ...@@ -150,12 +159,15 @@ Updates an existing project pages domain. The user must have permissions to chan
PUT /projects/:id/pages/domains/:domain PUT /projects/:id/pages/domains/:domain
``` ```
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| ------------- | -------------- | -------- | ---------------------------------------- | | ------------------ | -------------- | -------- | ---------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `domain` | string | yes | The domain | | `domain` | string | yes | The custom domain indicated by the user |
| `certificate` | file/string | no | The certificate in PEM format with intermediates following in most specific to least specific order.| | `auto_ssl_enabled` | boolean | no | Enables [automatic generation](../user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md) of SSL certificates issued by Let's Encrypt for custom domains. |
| `key` | file/string | no | The certificate key in PEM format. | | `certificate` | file/string | no | The certificate in PEM format with intermediates following in most specific to least specific order.|
| `key` | file/string | no | The certificate key in PEM format. |
### Adding certificate
```bash ```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certificate=@/path/to/cert.pem" --form "key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certificate=@/path/to/cert.pem" --form "key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
...@@ -169,6 +181,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certifi ...@@ -169,6 +181,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certifi
{ {
"domain": "ssl.domain.example", "domain": "ssl.domain.example",
"url": "https://ssl.domain.example", "url": "https://ssl.domain.example",
"auto_ssl_enabled": false,
"certificate": { "certificate": {
"subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate", "subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate",
"expired": false, "expired": false,
...@@ -178,6 +191,36 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certifi ...@@ -178,6 +191,36 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certifi
} }
``` ```
### Enabling Let's Encrypt integration for Pages custom domains
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "auto_ssl_enabled=true" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
```
```json
{
"domain": "ssl.domain.example",
"url": "https://ssl.domain.example",
"auto_ssl_enabled": true
}
```
### Removing certificate
To remove the SSL certificate attached to the Pages domain, run:
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certificate=" --form "key=" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
```
```json
{
"domain": "ssl.domain.example",
"url": "https://ssl.domain.example",
"auto_ssl_enabled": false
}
```
## Delete pages domain ## Delete pages domain
Deletes an existing project pages domain. Deletes an existing project pages domain.
...@@ -189,7 +232,7 @@ DELETE /projects/:id/pages/domains/:domain ...@@ -189,7 +232,7 @@ DELETE /projects/:id/pages/domains/:domain
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | -------------- | -------- | ---------------------------------------- | | --------- | -------------- | -------- | ---------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `domain` | string | yes | The domain | | `domain` | string | yes | The custom domain indicated by the user |
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
......
...@@ -324,6 +324,9 @@ are listed in the descriptions of the relevant settings. ...@@ -324,6 +324,9 @@ are listed in the descriptions of the relevant settings.
| `snowplow_enabled` | boolean | no | Enable snowplow tracking. | | `snowplow_enabled` | boolean | no | Enable snowplow tracking. |
| `snowplow_app_id` | string | no | The Snowplow site name / application id. (e.g. `gitlab`) | | `snowplow_app_id` | string | no | The Snowplow site name / application id. (e.g. `gitlab`) |
| `snowplow_iglu_registry_url` | string | no | The Snowplow base Iglu Schema Registry URL to use for custom context and self describing events'| | `snowplow_iglu_registry_url` | string | no | The Snowplow base Iglu Schema Registry URL to use for custom context and self describing events'|
| `sourcegraph_enabled` | boolean | no | Enables Sourcegraph integration. Default is `false`. **If enabled, requires** `sourcegraph_url`. |
| `sourcegraph_url` | string | required by: `sourcegraph_enabled` | The Sourcegraph instance URL for integration. |
| `sourcegraph_public_only` | boolean | no | Blocks Sourcegraph from being loaded on private and internal projects. Defaul is `true`. |
| `terminal_max_session_time` | integer | no | Maximum time for web terminal websocket connection (in seconds). Set to `0` for unlimited time. | | `terminal_max_session_time` | integer | no | Maximum time for web terminal websocket connection (in seconds). Set to `0` for unlimited time. |
| `terms` | text | required by: `enforce_terms` | (**Required by:** `enforce_terms`) Markdown content for the ToS. | | `terms` | text | required by: `enforce_terms` | (**Required by:** `enforce_terms`) Markdown content for the ToS. |
| `throttle_authenticated_api_enabled` | boolean | no | (**If enabled, requires:** `throttle_authenticated_api_period_in_seconds` and `throttle_authenticated_api_requests_per_period`) Enable authenticated API request rate limit. Helps reduce request volume (e.g. from crawlers or abusive bots). | | `throttle_authenticated_api_enabled` | boolean | no | (**If enabled, requires:** `throttle_authenticated_api_period_in_seconds` and `throttle_authenticated_api_requests_per_period`) Enable authenticated API request rate limit. Helps reduce request volume (e.g. from crawlers or abusive bots). |
......
...@@ -61,7 +61,7 @@ you'd want to explicitly disable that flag until the frontend half is also ready ...@@ -61,7 +61,7 @@ you'd want to explicitly disable that flag until the frontend half is also ready
to be shipped. To make sure this feature is disabled for both GitLab.com and to be shipped. To make sure this feature is disabled for both GitLab.com and
self-managed instances you'd need to explicitly call `Feature.enabled?` method self-managed instances you'd need to explicitly call `Feature.enabled?` method
before the `feature_available` method. This ensures the feature_flag is defaulting before the `feature_available` method. This ensures the feature_flag is defaulting
to `true`. to `false`.
## Feature groups ## Feature groups
......
...@@ -54,6 +54,7 @@ GitLab can be integrated with the following enhancements: ...@@ -54,6 +54,7 @@ GitLab can be integrated with the following enhancements:
- Add GitLab actions to [Gmail actions buttons](gmail_action_buttons_for_gitlab.md). - Add GitLab actions to [Gmail actions buttons](gmail_action_buttons_for_gitlab.md).
- Configure [PlantUML](../administration/integration/plantuml.md) to use diagrams in AsciiDoc documents. - Configure [PlantUML](../administration/integration/plantuml.md) to use diagrams in AsciiDoc documents.
- Attach merge requests to [Trello](trello_power_up.md) cards. - Attach merge requests to [Trello](trello_power_up.md) cards.
- Enable integrated code intelligence powered by [Sourcegraph](sourcegraph.md).
## Project services ## Project services
......
---
type: reference, how-to
---
# Sourcegraph integration
> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16556) in GitLab 12.5. Please note that this integration is [behind a feature flag](#enable-the-sourcegraph-feature-flag).
[Sourcegraph](https://sourcegraph.com) provides code intelligence features, natively integrated into the GitLab UI.
For GitLab.com users, see [Sourcegraph for GitLab.com](#sourcegraph-for-gitlabcom).
![Sourcegraph demo](img/sourcegraph_demo_v12_5.png)
NOTE: **Note:**
This feature requires user opt-in. After Sourcegraph has been enabled for your GitLab instance,
you can choose to enable Sourcegraph [through your user preferences](#enable-sourcegraph-in-user-preferences).
## Set up for self-managed GitLab instances **(CORE ONLY)**
Before you can enable Sourcegraph code intelligence in GitLab you will need to:
- Enable the `sourcegraph` feature flag for your GitLab instance.
- Configure a Sourcegraph instance with your GitLab instance as an external service.
### Enable the Sourcegraph feature flag
NOTE: **Note:**
If you are running a self-managed instance, the Sourcegraph integration will not be available
unless the feature flag `sourcegraph` is enabled. This can be done from the Rails console
by instance administrators.
Use these commands to start the Rails console:
```sh
# Omnibus GitLab
gitlab-rails console
# Installation from source
cd /home/git/gitlab
sudo -u git -H bin/rails console RAILS_ENV=production
```
Then run the following command to enable the feature flag:
```
Feature.enable(:sourcegraph)
```
You can also enable the feature flag only for specific projects with:
```
Feature.enable(:sourcegraph, Project.find_by_full_path('my_group/my_project'))
```
### Set up a self-managed Sourcegraph instance
If you are new to Sourcegraph, head over to the [Sourcegraph installation documentation](https://docs.sourcegraph.com/admin) and get your instance up and running.
### Connect your Sourcegraph instance to your GitLab instance
1. Navigate to the site admin area in Sourcegraph.
1. [Configure your GitLab external service](https://docs.sourcegraph.com/admin/external_service/gitlab).
You can skip this step if you already have your GitLab repositories searchable in Sourcegraph.
1. Validate that you can search your repositories from GitLab in your Sourcegraph instance by running a test query.
1. Add your GitLab instance URL to the [`corsOrigin` setting](https://docs.sourcegraph.com/admin/config/site_config#corsOrigin) in your site configuration.
### Configure your GitLab instance with Sourcegraph
1. In GitLab, go to **Admin Area > Settings > Integrations**.
1. Expand the **Sourcegraph** configuration section.
1. Check **Enable Sourcegraph**.
1. Set the Sourcegraph URL to your Sourcegraph instance, e.g., `https://sourcegraph.example.com`.
![Sourcegraph admin settings](img/sourcegraph_admin_v12_5.png)
## Enable Sourcegraph in user preferences
If a GitLab administrator has enabled Sourcegraph, you can enable this feature in your user preferences.
1. In GitLab, click your avatar in the top-right corner, then click **Settings**. On the left-hand nav, click **Preferences**.
1. Under **Integrations**, find the **Sourcegraph** section.
1. Check **Enable Sourcegraph**.
![Sourcegraph user preferences](img/sourcegraph_user_preferences_v12_5.png)
## Using Sourcegraph code intelligence
Once enabled, participating projects will have a code intelligence popover available in
the following code views:
- Merge request diffs
- Commit view
- File view
When visiting one of these views, you can now hover over a code reference to see a popover with:
- Details on how this reference was defined.
- **Go to definition**, which navigates to the line of code where this reference was defined.
- **Find references**, which navigates to the configured Sourcegraph instance, showing a list of references to the hilighted code.
![Sourcegraph demo](img/sourcegraph_popover_v12_5.png)
## Sourcegraph for GitLab.com
Sourcegraph powered code intelligence will be incrementally rolled out on GitLab.com. It will eventually be
available for all public projects, but for now, it is only available for some specific [`gitlab-org` projects](https://gitlab.com/gitlab-org/).
If you have a private or internal project and would like integrated code intelligence, please consider
setting up a self-managed GitLab instance.
## Sourcegraph and Privacy
From Sourcegraph's [extension documentation](https://docs.sourcegraph.com/integration/browser_extension#privacy) which is the
engine behind the native GitLab integration:
> Sourcegraph integrations never send any logs, pings, usage statistics, or telemetry to Sourcegraph.com.
> They will only connect to Sourcegraph.com as required to provide code intelligence or other functionality on public code.
> As a result, no private code, private repository names, usernames, or any other specific data is sent to Sourcegraph.com.
...@@ -14,6 +14,7 @@ include: ...@@ -14,6 +14,7 @@ include:
- [Continuous Integration and Deployment](continuous_integration.md) - [Continuous Integration and Deployment](continuous_integration.md)
- [Email](email.md) - [Email](email.md)
- [Sign up restrictions](sign_up_restrictions.md) - [Sign up restrictions](sign_up_restrictions.md)
- [Sign in restrictions](sign_in_restrictions.md)
- [Terms](terms.md) - [Terms](terms.md)
- [Third party offers](third_party_offers.md) - [Third party offers](third_party_offers.md)
- [Usage statistics](usage_statistics.md) - [Usage statistics](usage_statistics.md)
......
---
type: reference
---
# Sign-in restrictions **(CORE ONLY)**
You can use sign-in restrictions to limit the authentication with password
for web interface and Git over HTTP(S), two-factor authentication enforcing, as well as
as configuring the home page URL and after sign-out path.
## Password authentication enabled
You can restrict the password authentication for web interface and Git over HTTP(S):
- **Web interface**: When this feature is disabled, an [external authentication provider](../../../administration/auth/README.md) must be used.
- **Git over HTTP(S)**: When this feature is disabled, a [Personal Access Token](../../profile/personal_access_tokens.md) must be used to authenticate.
## Two-factor authentication
When this feature enabled, all users will have to use the [two-factor authentication](../../profile/account/two_factor_authentication.md).
Once the two-factor authentication is configured as mandatory, the users will be allowed
to skip forced configuration of two-factor authentication for the configurable grace
period in hours.
![Two-factor grace period](img/two_factor_grace_period.png)
## Sign-in information
All users that are not logged-in will be redirected to the page represented by the configured
"Home page URL" if value is not empty.
All users will be redirect to the page represented by the configured "After sign out path"
after sign out if value is not empty.
If a "Sign in text" in Markdown format is provided, then every user will be presented with
this message after logging-in.
## Settings
To access this feature:
1. Navigate to the **Settings > General** in the Admin area.
1. Expand the **Sign-in restrictions** section.
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
one might have when setting this up, or when something is changed, or on upgrading, it's
important to describe those, too. Think of things that may go wrong and include them here.
This is important to minimize requests for support, and to avoid doc comments with
questions that you know someone might ask.
Each scenario can be a third-level heading, e.g. `### Getting error message X`.
If you have none to add when creating a doc, leave this section in place
but commented out to help encourage others to add to it in the future. -->
...@@ -128,6 +128,19 @@ You can choose one of the following options as the first day of the week: ...@@ -128,6 +128,19 @@ You can choose one of the following options as the first day of the week:
If you select **System Default**, the system-wide default setting will be used. If you select **System Default**, the system-wide default setting will be used.
## Integrations
Configure your preferences with third-party services which provide enhancements to your GitLab experience.
### Sourcegraph
NOTE: **Note:**
This setting is only visible if Sourcegraph has been enabled by a GitLab administrator.
Manage the availability of integrated code intelligence features powered by
Sourcegraph. View [the Sourcegraph feature documentation](../../integration/sourcegraph.md#enable-sourcegraph-in-user-preferences)
for more information.
<!-- ## Troubleshooting <!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues Include any troubleshooting steps that you can foresee. If you know beforehand what issues
......
...@@ -1681,6 +1681,7 @@ module API ...@@ -1681,6 +1681,7 @@ module API
expose :verified?, as: :verified expose :verified?, as: :verified
expose :verification_code, as: :verification_code expose :verification_code, as: :verification_code
expose :enabled_until expose :enabled_until
expose :auto_ssl_enabled
expose :certificate, expose :certificate,
as: :certificate_expiration, as: :certificate_expiration,
...@@ -1696,6 +1697,7 @@ module API ...@@ -1696,6 +1697,7 @@ module API
expose :verified?, as: :verified expose :verified?, as: :verified
expose :verification_code, as: :verification_code expose :verification_code, as: :verification_code
expose :enabled_until expose :enabled_until
expose :auto_ssl_enabled
expose :certificate, expose :certificate,
if: ->(pages_domain, _) { pages_domain.certificate? }, if: ->(pages_domain, _) { pages_domain.certificate? },
......
...@@ -92,8 +92,10 @@ module API ...@@ -92,8 +92,10 @@ module API
requires :domain, type: String, desc: 'The domain' requires :domain, type: String, desc: 'The domain'
# rubocop:disable Scalability/FileUploads # rubocop:disable Scalability/FileUploads
# TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960 # TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960
optional :certificate, allow_blank: false, types: [File, String], desc: 'The certificate', as: :user_provided_certificate optional :certificate, types: [File, String], desc: 'The certificate', as: :user_provided_certificate
optional :key, allow_blank: false, types: [File, String], desc: 'The key', as: :user_provided_key optional :key, types: [File, String], desc: 'The key', as: :user_provided_key
optional :auto_ssl_enabled, allow_blank: false, type: Boolean, default: false,
desc: "Enables automatic generation of SSL certificates issued by Let's Encrypt for custom domains."
# rubocop:enable Scalability/FileUploads # rubocop:enable Scalability/FileUploads
all_or_none_of :user_provided_certificate, :user_provided_key all_or_none_of :user_provided_certificate, :user_provided_key
end end
...@@ -116,14 +118,16 @@ module API ...@@ -116,14 +118,16 @@ module API
requires :domain, type: String, desc: 'The domain' requires :domain, type: String, desc: 'The domain'
# rubocop:disable Scalability/FileUploads # rubocop:disable Scalability/FileUploads
# TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960 # TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960
optional :certificate, allow_blank: false, types: [File, String], desc: 'The certificate', as: :user_provided_certificate optional :certificate, types: [File, String], desc: 'The certificate', as: :user_provided_certificate
optional :key, allow_blank: false, types: [File, String], desc: 'The key', as: :user_provided_key optional :key, types: [File, String], desc: 'The key', as: :user_provided_key
optional :auto_ssl_enabled, allow_blank: true, type: Boolean,
desc: "Enables automatic generation of SSL certificates issued by Let's Encrypt for custom domains."
# rubocop:enable Scalability/FileUploads # rubocop:enable Scalability/FileUploads
end end
put ":id/pages/domains/:domain", requirements: PAGES_DOMAINS_ENDPOINT_REQUIREMENTS do put ":id/pages/domains/:domain", requirements: PAGES_DOMAINS_ENDPOINT_REQUIREMENTS do
authorize! :update_pages, user_project authorize! :update_pages, user_project
pages_domain_params = declared(params, include_parent_namespaces: false) pages_domain_params = declared(params, include_parent_namespaces: false, include_missing: false)
# Remove empty private key if certificate is not empty. # Remove empty private key if certificate is not empty.
if pages_domain_params[:user_provided_certificate] && !pages_domain_params[:user_provided_key] if pages_domain_params[:user_provided_certificate] && !pages_domain_params[:user_provided_key]
......
...@@ -136,6 +136,11 @@ module API ...@@ -136,6 +136,11 @@ module API
optional :sign_in_text, type: String, desc: 'The sign in text of the GitLab application' optional :sign_in_text, type: String, desc: 'The sign in text of the GitLab application'
optional :signin_enabled, type: Boolean, desc: 'Flag indicating if password authentication is enabled for the web interface' # support legacy names, can be removed in v5 optional :signin_enabled, type: Boolean, desc: 'Flag indicating if password authentication is enabled for the web interface' # support legacy names, can be removed in v5
optional :signup_enabled, type: Boolean, desc: 'Flag indicating if sign up is enabled' optional :signup_enabled, type: Boolean, desc: 'Flag indicating if sign up is enabled'
optional :sourcegraph_enabled, type: Boolean, desc: 'Enable Sourcegraph'
optional :sourcegraph_public_only, type: Boolean, desc: 'Only allow public projects to communicate with Sourcegraph'
given sourcegraph_enabled: ->(val) { val } do
requires :sourcegraph_url, type: String, desc: 'The configured Sourcegraph instance URL'
end
optional :terminal_max_session_time, type: Integer, desc: 'Maximum time for web terminal websocket connection (in seconds). Set to 0 for unlimited time.' optional :terminal_max_session_time, type: Integer, desc: 'Maximum time for web terminal websocket connection (in seconds). Set to 0 for unlimited time.'
optional :usage_ping_enabled, type: Boolean, desc: 'Every week GitLab will report license usage back to GitLab, Inc.' optional :usage_ping_enabled, type: Boolean, desc: 'Every week GitLab will report license usage back to GitLab, Inc.'
optional :instance_statistics_visibility_private, type: Boolean, desc: 'When set to `true` Instance statistics will only be available to admins' optional :instance_statistics_visibility_private, type: Boolean, desc: 'When set to `true` Instance statistics will only be available to admins'
......
...@@ -25,6 +25,8 @@ module Gitlab ...@@ -25,6 +25,8 @@ module Gitlab
if Sidekiq.server? if Sidekiq.server?
# the pool will be used in a multi-threaded context # the pool will be used in a multi-threaded context
size += Sidekiq.options[:concurrency] size += Sidekiq.options[:concurrency]
elsif defined?(::Puma)
size += Puma.cli_config.options[:max_threads]
end end
size size
......
# frozen_string_literal: true
module Gitlab
class Sourcegraph
class << self
def feature_conditional?
feature.conditional?
end
def feature_available?
# The sourcegraph_bundle feature could be conditionally applied, so check if `!off?`
!feature.off?
end
def feature_enabled?(thing = nil)
feature.enabled?(thing)
end
private
def feature
Feature.get(:sourcegraph)
end
end
end
end
...@@ -8232,10 +8232,10 @@ msgstr "" ...@@ -8232,10 +8232,10 @@ msgstr ""
msgid "GitLabPages|Configure pages" msgid "GitLabPages|Configure pages"
msgstr "" msgstr ""
msgid "GitLabPages|Details" msgid "GitLabPages|Domains"
msgstr "" msgstr ""
msgid "GitLabPages|Domains" msgid "GitLabPages|Edit"
msgstr "" msgstr ""
msgid "GitLabPages|Expired" msgid "GitLabPages|Expired"
...@@ -12541,6 +12541,9 @@ msgstr "" ...@@ -12541,6 +12541,9 @@ msgstr ""
msgid "Preferences|Choose what content you want to see on a project’s overview page." msgid "Preferences|Choose what content you want to see on a project’s overview page."
msgstr "" msgstr ""
msgid "Preferences|Customize integrations with third party services."
msgstr ""
msgid "Preferences|Customize the appearance of the application header and navigation sidebar." msgid "Preferences|Customize the appearance of the application header and navigation sidebar."
msgstr "" msgstr ""
...@@ -12550,9 +12553,15 @@ msgstr "" ...@@ -12550,9 +12553,15 @@ msgstr ""
msgid "Preferences|Display time in 24-hour format" msgid "Preferences|Display time in 24-hour format"
msgstr "" msgstr ""
msgid "Preferences|Enable integrated code intelligence on code views"
msgstr ""
msgid "Preferences|For example: 30 mins ago." msgid "Preferences|For example: 30 mins ago."
msgstr "" msgstr ""
msgid "Preferences|Integrations"
msgstr ""
msgid "Preferences|Layout width" msgid "Preferences|Layout width"
msgstr "" msgstr ""
...@@ -12565,6 +12574,9 @@ msgstr "" ...@@ -12565,6 +12574,9 @@ msgstr ""
msgid "Preferences|Show whitespace in diffs" msgid "Preferences|Show whitespace in diffs"
msgstr "" msgstr ""
msgid "Preferences|Sourcegraph"
msgstr ""
msgid "Preferences|Syntax highlighting theme" msgid "Preferences|Syntax highlighting theme"
msgstr "" msgstr ""
...@@ -16172,6 +16184,51 @@ msgstr "" ...@@ -16172,6 +16184,51 @@ msgstr ""
msgid "Source project cannot be found." msgid "Source project cannot be found."
msgstr "" msgstr ""
msgid "Sourcegraph"
msgstr ""
msgid "SourcegraphAdmin|Block on private and internal projects"
msgstr ""
msgid "SourcegraphAdmin|Configure the URL to a Sourcegraph instance which can read your GitLab projects."
msgstr ""
msgid "SourcegraphAdmin|Enable Sourcegraph"
msgstr ""
msgid "SourcegraphAdmin|Enable code intelligence powered by %{link_start}Sourcegraph%{link_end} on your GitLab instance's code views and merge requests."
msgstr ""
msgid "SourcegraphAdmin|If checked, only public projects will have code intelligence and communicate with Sourcegraph."
msgstr ""
msgid "SourcegraphAdmin|More information"
msgstr ""
msgid "SourcegraphAdmin|Save changes"
msgstr ""
msgid "SourcegraphAdmin|Sourcegraph URL"
msgstr ""
msgid "SourcegraphAdmin|e.g. https://sourcegraph.example.com"
msgstr ""
msgid "SourcegraphPreferences|This feature is experimental and currently limited to certain projects."
msgstr ""
msgid "SourcegraphPreferences|This feature is experimental and limited to public projects."
msgstr ""
msgid "SourcegraphPreferences|This feature is experimental."
msgstr ""
msgid "SourcegraphPreferences|Uses %{link_start}Sourcegraph.com%{link_end}."
msgstr ""
msgid "SourcegraphPreferences|Uses a custom %{link_start}Sourcegraph instance%{link_end}."
msgstr ""
msgid "Spam Logs" msgid "Spam Logs"
msgstr "" msgstr ""
......
[[ "$TRACE" ]] && set -x [[ "$TRACE" ]] && set -x
export TILLER_NAMESPACE="$KUBE_NAMESPACE"
function deploy_exists() { function deploy_exists() {
local namespace="${1}" local namespace="${1}"
...@@ -14,16 +13,18 @@ function deploy_exists() { ...@@ -14,16 +13,18 @@ function deploy_exists() {
} }
function previous_deploy_failed() { function previous_deploy_failed() {
local deploy="${1}" local namespace="${1}"
local deploy="${2}"
echoinfo "Checking for previous deployment of ${deploy}" true echoinfo "Checking for previous deployment of ${deploy}" true
helm status "${deploy}" >/dev/null 2>&1 helm status --tiller-namespace "${namespace}" "${deploy}" >/dev/null 2>&1
local status=$? local status=$?
# if `status` is `0`, deployment exists, has a status # if `status` is `0`, deployment exists, has a status
if [ $status -eq 0 ]; then if [ $status -eq 0 ]; then
echoinfo "Previous deployment found, checking status..." echoinfo "Previous deployment found, checking status..."
deployment_status=$(helm status "${deploy}" | grep ^STATUS | cut -d' ' -f2) deployment_status=$(helm status --tiller-namespace "${namespace}" "${deploy}" | grep ^STATUS | cut -d' ' -f2)
echoinfo "Previous deployment state: ${deployment_status}" echoinfo "Previous deployment state: ${deployment_status}"
if [[ "$deployment_status" == "FAILED" || "$deployment_status" == "PENDING_UPGRADE" || "$deployment_status" == "PENDING_INSTALL" ]]; then if [[ "$deployment_status" == "FAILED" || "$deployment_status" == "PENDING_UPGRADE" || "$deployment_status" == "PENDING_INSTALL" ]]; then
status=0; status=0;
...@@ -37,16 +38,17 @@ function previous_deploy_failed() { ...@@ -37,16 +38,17 @@ function previous_deploy_failed() {
} }
function delete_release() { function delete_release() {
if [ -z "$CI_ENVIRONMENT_SLUG" ]; then local namespace="${KUBE_NAMESPACE}"
local deploy="${CI_ENVIRONMENT_SLUG}"
if [ -z "$deploy" ]; then
echoerr "No release given, aborting the delete!" echoerr "No release given, aborting the delete!"
return return
fi fi
local name="$CI_ENVIRONMENT_SLUG" echoinfo "Deleting release '$deploy'..." true
echoinfo "Deleting release '$name'..." true
helm delete --purge "$name" helm delete --purge --tiller-namespace "${namespace}" "${deploy}"
} }
function delete_failed_release() { function delete_failed_release() {
...@@ -59,7 +61,7 @@ function delete_failed_release() { ...@@ -59,7 +61,7 @@ function delete_failed_release() {
echoinfo "No Review App with ${CI_ENVIRONMENT_SLUG} is currently deployed." echoinfo "No Review App with ${CI_ENVIRONMENT_SLUG} is currently deployed."
else else
# Cleanup and previous installs, as FAILED and PENDING_UPGRADE will cause errors with `upgrade` # Cleanup and previous installs, as FAILED and PENDING_UPGRADE will cause errors with `upgrade`
if previous_deploy_failed "$CI_ENVIRONMENT_SLUG" ; then if previous_deploy_failed "${KUBE_NAMESPACE}" "$CI_ENVIRONMENT_SLUG" ; then
echoinfo "Review App deployment in bad state, cleaning up $CI_ENVIRONMENT_SLUG" echoinfo "Review App deployment in bad state, cleaning up $CI_ENVIRONMENT_SLUG"
delete_release delete_release
else else
...@@ -117,6 +119,7 @@ function ensure_namespace() { ...@@ -117,6 +119,7 @@ function ensure_namespace() {
} }
function install_tiller() { function install_tiller() {
local TILLER_NAMESPACE="$KUBE_NAMESPACE"
echoinfo "Checking deployment/tiller-deploy status in the ${TILLER_NAMESPACE} namespace..." true echoinfo "Checking deployment/tiller-deploy status in the ${TILLER_NAMESPACE} namespace..." true
echoinfo "Initiating the Helm client..." echoinfo "Initiating the Helm client..."
...@@ -131,11 +134,12 @@ function install_tiller() { ...@@ -131,11 +134,12 @@ function install_tiller() {
--override "spec.template.spec.tolerations[0].key"="dedicated" \ --override "spec.template.spec.tolerations[0].key"="dedicated" \
--override "spec.template.spec.tolerations[0].operator"="Equal" \ --override "spec.template.spec.tolerations[0].operator"="Equal" \
--override "spec.template.spec.tolerations[0].value"="helm" \ --override "spec.template.spec.tolerations[0].value"="helm" \
--override "spec.template.spec.tolerations[0].effect"="NoSchedule" --override "spec.template.spec.tolerations[0].effect"="NoSchedule" \
--tiller-namespace "${TILLER_NAMESPACE}"
kubectl rollout status -n "$TILLER_NAMESPACE" -w "deployment/tiller-deploy" kubectl rollout status -n "$TILLER_NAMESPACE" -w "deployment/tiller-deploy"
if ! helm version --debug; then if ! helm version --debug --tiller-namespace "${TILLER_NAMESPACE}"; then
echo "Failed to init Tiller." echo "Failed to init Tiller."
return 1 return 1
fi fi
...@@ -147,7 +151,7 @@ function install_external_dns() { ...@@ -147,7 +151,7 @@ function install_external_dns() {
domain=$(echo "${REVIEW_APPS_DOMAIN}" | awk -F. '{printf "%s.%s", $(NF-1), $NF}') domain=$(echo "${REVIEW_APPS_DOMAIN}" | awk -F. '{printf "%s.%s", $(NF-1), $NF}')
echoinfo "Installing external DNS for domain ${domain}..." true echoinfo "Installing external DNS for domain ${domain}..." true
if ! deploy_exists "${KUBE_NAMESPACE}" "${release_name}" || previous_deploy_failed "${release_name}" ; then if ! deploy_exists "${KUBE_NAMESPACE}" "${release_name}" || previous_deploy_failed "${KUBE_NAMESPACE}" "${release_name}" ; then
echoinfo "Installing external-dns Helm chart" echoinfo "Installing external-dns Helm chart"
helm repo update helm repo update
# Default requested: CPU => 0, memory => 0 # Default requested: CPU => 0, memory => 0
......
# frozen_string_literal: true
require 'spec_helper'
describe SourcegraphGon do
let_it_be(:enabled_user) { create(:user, sourcegraph_enabled: true) }
let_it_be(:disabled_user) { create(:user, sourcegraph_enabled: false) }
let_it_be(:public_project) { create(:project, :public) }
let_it_be(:internal_project) { create(:project, :internal) }
let(:sourcegraph_url) { 'http://sourcegraph.gitlab.com' }
let(:feature_enabled) { true }
let(:sourcegraph_enabled) { true }
let(:sourcegraph_public_only) { false }
let(:format) { :html }
let(:user) { enabled_user }
let(:project) { internal_project }
controller(ApplicationController) do
include SourcegraphGon # rubocop:disable RSpec/DescribedClass
def index
head :ok
end
end
before do
Feature.get(:sourcegraph).enable(feature_enabled)
stub_application_setting(sourcegraph_url: sourcegraph_url, sourcegraph_enabled: sourcegraph_enabled, sourcegraph_public_only: sourcegraph_public_only)
allow(controller).to receive(:project).and_return(project)
Gon.clear
sign_in user if user
end
after do
Feature.get(:sourcegraph).disable
end
subject do
get :index, format: format
Gon.sourcegraph
end
shared_examples 'enabled' do
it { is_expected.to eq({ url: sourcegraph_url }) }
end
shared_examples 'disabled' do
it { is_expected.to be_nil }
end
context 'with feature enabled, application enabled, and user enabled' do
it_behaves_like 'enabled'
end
context 'with feature enabled for specific project' do
let(:feature_enabled) { project }
it_behaves_like 'enabled'
end
context 'with feature enabled for different project' do
let(:feature_enabled) { create(:project) }
it_behaves_like 'disabled'
end
context 'with feature disabled' do
let(:feature_enabled) { false }
it_behaves_like 'disabled'
end
context 'with admin settings disabled' do
let(:sourcegraph_enabled) { false }
it_behaves_like 'disabled'
end
context 'with public only' do
let(:sourcegraph_public_only) { true }
context 'with internal project' do
let(:project) { internal_project }
it_behaves_like 'disabled'
end
context 'with public project' do
let(:project) { public_project }
it_behaves_like 'enabled'
end
end
context 'with user disabled' do
let(:user) { disabled_user }
it_behaves_like 'disabled'
end
context 'with no user' do
let(:user) { nil }
it_behaves_like 'disabled'
end
context 'with non-html format' do
let(:format) { :json }
it_behaves_like 'disabled'
end
end
...@@ -32,10 +32,10 @@ describe Projects::PagesDomainsController do ...@@ -32,10 +32,10 @@ describe Projects::PagesDomainsController do
get(:show, params: request_params.merge(id: pages_domain.domain)) get(:show, params: request_params.merge(id: pages_domain.domain))
end end
it "displays the 'show' page" do it "redirects to the 'edit' page" do
make_request make_request
expect(response).to have_gitlab_http_status(200)
expect(response).to render_template('show') expect(response).to redirect_to(edit_project_pages_domain_path(project, pages_domain.domain))
end end
context 'when user is developer' do context 'when user is developer' do
...@@ -69,7 +69,7 @@ describe Projects::PagesDomainsController do ...@@ -69,7 +69,7 @@ describe Projects::PagesDomainsController do
created_domain = PagesDomain.reorder(:id).last created_domain = PagesDomain.reorder(:id).last
expect(created_domain).to be_present expect(created_domain).to be_present
expect(response).to redirect_to(project_pages_domain_path(project, created_domain)) expect(response).to redirect_to(edit_project_pages_domain_path(project, created_domain))
end end
end end
...@@ -160,7 +160,7 @@ describe Projects::PagesDomainsController do ...@@ -160,7 +160,7 @@ describe Projects::PagesDomainsController do
post :verify, params: params post :verify, params: params
expect(response).to redirect_to project_pages_domain_path(project, pages_domain) expect(response).to redirect_to edit_project_pages_domain_path(project, pages_domain)
expect(flash[:notice]).to eq('Successfully verified domain ownership') expect(flash[:notice]).to eq('Successfully verified domain ownership')
end end
...@@ -169,7 +169,7 @@ describe Projects::PagesDomainsController do ...@@ -169,7 +169,7 @@ describe Projects::PagesDomainsController do
post :verify, params: params post :verify, params: params
expect(response).to redirect_to project_pages_domain_path(project, pages_domain) expect(response).to redirect_to edit_project_pages_domain_path(project, pages_domain)
expect(flash[:alert]).to eq('Failed to verify domain ownership') expect(flash[:alert]).to eq('Failed to verify domain ownership')
end end
......
...@@ -4,7 +4,7 @@ require 'spec_helper' ...@@ -4,7 +4,7 @@ require 'spec_helper'
describe "Pages with Let's Encrypt", :https_pages_enabled do describe "Pages with Let's Encrypt", :https_pages_enabled do
include LetsEncryptHelpers include LetsEncryptHelpers
let(:project) { create(:project) } let(:project) { create(:project, pages_https_only: false) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:role) { :maintainer } let(:role) { :maintainer }
let(:certificate_pem) { attributes_for(:pages_domain)[:certificate] } let(:certificate_pem) { attributes_for(:pages_domain)[:certificate] }
...@@ -34,14 +34,14 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do ...@@ -34,14 +34,14 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do
expect(domain.auto_ssl_enabled).to eq false expect(domain.auto_ssl_enabled).to eq false
expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false' expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false'
expect(page).to have_field 'Certificate (PEM)', type: 'textarea' expect(page).to have_selector '.card-header', text: 'Certificate'
expect(page).to have_field 'Key (PEM)', type: 'textarea' expect(page).to have_text domain.subject
find('.js-auto-ssl-toggle-container .project-feature-toggle').click find('.js-auto-ssl-toggle-container .project-feature-toggle').click
expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true' expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true'
expect(page).not_to have_field 'Certificate (PEM)', type: 'textarea' expect(page).not_to have_selector '.card-header', text: 'Certificate'
expect(page).not_to have_field 'Key (PEM)', type: 'textarea' expect(page).not_to have_text domain.subject
click_on 'Save Changes' click_on 'Save Changes'
...@@ -67,9 +67,6 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do ...@@ -67,9 +67,6 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do
expect(page).to have_field 'Certificate (PEM)', type: 'textarea' expect(page).to have_field 'Certificate (PEM)', type: 'textarea'
expect(page).to have_field 'Key (PEM)', type: 'textarea' expect(page).to have_field 'Key (PEM)', type: 'textarea'
fill_in 'Certificate (PEM)', with: certificate_pem
fill_in 'Key (PEM)', with: certificate_key
click_on 'Save Changes' click_on 'Save Changes'
expect(domain.reload.auto_ssl_enabled).to eq false expect(domain.reload.auto_ssl_enabled).to eq false
...@@ -81,7 +78,8 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do ...@@ -81,7 +78,8 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do
it 'user do not see private key' do it 'user do not see private key' do
visit edit_project_pages_domain_path(project, domain) visit edit_project_pages_domain_path(project, domain)
expect(find_field('Key (PEM)', visible: :all, disabled: :all).value).to be_blank expect(page).not_to have_selector '.card-header', text: 'Certificate'
expect(page).not_to have_text domain.subject
end end
end end
...@@ -100,10 +98,21 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do ...@@ -100,10 +98,21 @@ describe "Pages with Let's Encrypt", :https_pages_enabled do
context 'when certificate is provided by user' do context 'when certificate is provided by user' do
let(:domain) { create(:pages_domain, project: project) } let(:domain) { create(:pages_domain, project: project) }
it 'user sees private key' do it 'user sees certificate subject' do
visit edit_project_pages_domain_path(project, domain)
expect(page).to have_selector '.card-header', text: 'Certificate'
expect(page).to have_text domain.subject
end
it 'user can delete the certificate', :js do
visit edit_project_pages_domain_path(project, domain) visit edit_project_pages_domain_path(project, domain)
expect(find_field('Key (PEM)').value).not_to be_blank expect(page).to have_selector '.card-header', text: 'Certificate'
expect(page).to have_text domain.subject
within('.card') { accept_confirm { click_on 'Remove' } }
expect(page).to have_field 'Certificate (PEM)', with: ''
expect(page).to have_field 'Key (PEM)', with: ''
end end
end end
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
shared_examples 'pages settings editing' do shared_examples 'pages settings editing' do
let(:project) { create(:project) } let_it_be(:project) { create(:project, pages_https_only: false) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:role) { :maintainer } let(:role) { :maintainer }
...@@ -185,6 +185,21 @@ shared_examples 'pages settings editing' do ...@@ -185,6 +185,21 @@ shared_examples 'pages settings editing' do
expect(page).to have_content('my.test.domain.com') expect(page).to have_content('my.test.domain.com')
end end
describe 'with dns verification enabled' do
before do
stub_application_setting(pages_domain_verification_enabled: true)
end
it 'shows the DNS verification record' do
domain = create(:pages_domain, project: project)
visit project_pages_path(project)
within('#content-body') { click_link 'Edit' }
expect(page).to have_field :domain_verification, with: "#{domain.verification_domain} TXT #{domain.keyed_verification_code}"
end
end
describe 'updating the certificate for an existing domain' do describe 'updating the certificate for an existing domain' do
let!(:domain) do let!(:domain) do
create(:pages_domain, project: project) create(:pages_domain, project: project)
...@@ -193,19 +208,22 @@ shared_examples 'pages settings editing' do ...@@ -193,19 +208,22 @@ shared_examples 'pages settings editing' do
it 'allows the certificate to be updated' do it 'allows the certificate to be updated' do
visit project_pages_path(project) visit project_pages_path(project)
within('#content-body') { click_link 'Details' } within('#content-body') { click_link 'Edit' }
click_link 'Edit'
click_button 'Save Changes' click_button 'Save Changes'
expect(page).to have_content('Domain was updated') expect(page).to have_content('Domain was updated')
end end
context 'when the certificate is invalid' do context 'when the certificate is invalid' do
let_it_be(:domain) do
create(:pages_domain, :without_certificate, :without_key, project: project)
end
it 'tells the user what the problem is' do it 'tells the user what the problem is' do
visit project_pages_path(project) visit project_pages_path(project)
within('#content-body') { click_link 'Details' } within('#content-body') { click_link 'Edit' }
click_link 'Edit'
fill_in 'Certificate (PEM)', with: 'invalid data' fill_in 'Certificate (PEM)', with: 'invalid data'
click_button 'Save Changes' click_button 'Save Changes'
...@@ -214,6 +232,27 @@ shared_examples 'pages settings editing' do ...@@ -214,6 +232,27 @@ shared_examples 'pages settings editing' do
expect(page).to have_content("Key doesn't match the certificate") expect(page).to have_content("Key doesn't match the certificate")
end end
end end
it 'allows the certificate to be removed', :js do
visit project_pages_path(project)
within('#content-body') { click_link 'Edit' }
accept_confirm { click_link 'Remove' }
expect(page).to have_field('Certificate (PEM)', with: '')
expect(page).to have_field('Key (PEM)', with: '')
domain.reload
expect(domain.certificate).to be_nil
expect(domain.key).to be_nil
end
it 'shows the DNS CNAME record' do
visit project_pages_path(project)
within('#content-body') { click_link 'Edit' }
expect(page).to have_field :domain_dns, with: "#{domain.domain} CNAME #{domain.project.pages_subdomain}.#{Settings.pages.host}."
end
end end
end end
end end
...@@ -250,7 +289,7 @@ shared_examples 'pages settings editing' do ...@@ -250,7 +289,7 @@ shared_examples 'pages settings editing' do
end end
end end
describe 'HTTPS settings', :js, :https_pages_enabled do describe 'HTTPS settings', :https_pages_enabled do
before do before do
project.namespace.update(owner: user) project.namespace.update(owner: user)
...@@ -358,18 +397,21 @@ shared_examples 'pages settings editing' do ...@@ -358,18 +397,21 @@ shared_examples 'pages settings editing' do
expect(page).to have_link('Remove pages') expect(page).to have_link('Remove pages')
click_link 'Remove pages' accept_confirm { click_link 'Remove pages' }
expect(project.pages_deployed?).to be_falsey expect(page).to have_content('Pages were removed')
expect(project.reload.pages_deployed?).to be_falsey
end end
end end
end end
end end
describe 'Pages' do describe 'Pages', :js do
include LetsEncryptHelpers include LetsEncryptHelpers
include_examples 'pages settings editing' context 'when editing normally' do
include_examples 'pages settings editing'
end
context 'when letsencrypt support is enabled' do context 'when letsencrypt support is enabled' do
before do before do
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
"verified": { "type": "boolean" }, "verified": { "type": "boolean" },
"verification_code": { "type": ["string", "null"] }, "verification_code": { "type": ["string", "null"] },
"enabled_until": { "type": ["date", "null"] }, "enabled_until": { "type": ["date", "null"] },
"auto_ssl_enabled": { "type": "boolean" },
"certificate_expiration": { "certificate_expiration": {
"type": "object", "type": "object",
"properties": { "properties": {
...@@ -17,6 +18,6 @@ ...@@ -17,6 +18,6 @@
"additionalProperties": false "additionalProperties": false
} }
}, },
"required": ["domain", "url", "project_id", "verified", "verification_code", "enabled_until"], "required": ["domain", "url", "project_id", "verified", "verification_code", "enabled_until", "auto_ssl_enabled"],
"additionalProperties": false "additionalProperties": false
} }
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
"verified": { "type": "boolean" }, "verified": { "type": "boolean" },
"verification_code": { "type": ["string", "null"] }, "verification_code": { "type": ["string", "null"] },
"enabled_until": { "type": ["date", "null"] }, "enabled_until": { "type": ["date", "null"] },
"auto_ssl_enabled": { "type": "boolean" },
"certificate": { "certificate": {
"type": "object", "type": "object",
"properties": { "properties": {
...@@ -18,6 +19,6 @@ ...@@ -18,6 +19,6 @@
"additionalProperties": false "additionalProperties": false
} }
}, },
"required": ["domain", "url", "verified", "verification_code", "enabled_until"], "required": ["domain", "url", "verified", "verification_code", "enabled_until", "auto_ssl_enabled"],
"additionalProperties": false "additionalProperties": false
} }
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { normalizeData, resolveCommit, fetchLogsTree } from '~/repository/log_tree'; import { resolveCommit, fetchLogsTree } from '~/repository/log_tree';
const mockData = [ const mockData = [
{ {
...@@ -15,22 +15,6 @@ const mockData = [ ...@@ -15,22 +15,6 @@ const mockData = [
}, },
]; ];
describe('normalizeData', () => {
it('normalizes data into LogTreeCommit object', () => {
expect(normalizeData(mockData)).toEqual([
{
sha: '123',
message: 'testing message',
committedDate: '2019-01-01',
commitPath: 'https://test.com',
fileName: 'index.js',
type: 'blob',
__typename: 'LogTreeCommit',
},
]);
});
});
describe('resolveCommit', () => { describe('resolveCommit', () => {
it('calls resolve when commit found', () => { it('calls resolve when commit found', () => {
const resolver = { const resolver = {
......
import { normalizeData } from '~/repository/utils/commit';
const mockData = [
{
commit: {
id: '123',
message: 'testing message',
committed_date: '2019-01-01',
},
commit_path: `https://test.com`,
file_name: 'index.js',
type: 'blob',
},
];
describe('normalizeData', () => {
it('normalizes data into LogTreeCommit object', () => {
expect(normalizeData(mockData)).toEqual([
{
sha: '123',
message: 'testing message',
committedDate: '2019-01-01',
commitPath: 'https://test.com',
fileName: 'index.js',
type: 'blob',
__typename: 'LogTreeCommit',
},
]);
});
});
# frozen_string_literal: true
require 'spec_helper'
describe SourcegraphHelper do
describe '#sourcegraph_url_message' do
let(:sourcegraph_url) { 'http://sourcegraph.example.com' }
before do
allow(Gitlab::CurrentSettings).to receive(:sourcegraph_url).and_return(sourcegraph_url)
allow(Gitlab::CurrentSettings).to receive(:sourcegraph_url_is_com?).and_return(is_com)
end
subject { helper.sourcegraph_url_message }
context 'with .com sourcegraph url' do
let(:is_com) { true }
it { is_expected.to have_text('Uses Sourcegraph.com') }
it { is_expected.to have_link('Sourcegraph.com', href: sourcegraph_url) }
end
context 'with custom sourcegraph url' do
let(:is_com) { false }
it { is_expected.to have_text('Uses a custom Sourcegraph instance') }
it { is_expected.to have_link('Sourcegraph instance', href: sourcegraph_url) }
context 'with unsafe url' do
let(:sourcegraph_url) { '\" onload=\"alert(1);\"' }
it { is_expected.to have_link('Sourcegraph instance', href: sourcegraph_url) }
end
end
end
context '#sourcegraph_experimental_message' do
let(:feature_conditional) { false }
let(:public_only) { false }
before do
allow(Gitlab::CurrentSettings).to receive(:sourcegraph_public_only).and_return(public_only)
allow(Gitlab::Sourcegraph).to receive(:feature_conditional?).and_return(feature_conditional)
end
subject { helper.sourcegraph_experimental_message }
context 'when not limited by feature or public only' do
it { is_expected.to eq "This feature is experimental." }
end
context 'when limited by feature' do
let(:feature_conditional) { true }
it { is_expected.to eq "This feature is experimental and currently limited to certain projects." }
end
context 'when limited by public only' do
let(:public_only) { true }
it { is_expected.to eq "This feature is experimental and limited to public projects." }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Sourcegraph do
let_it_be(:user) { create(:user) }
let(:feature_scope) { true }
before do
Feature.enable(:sourcegraph, feature_scope)
end
describe '.feature_conditional?' do
subject { described_class.feature_conditional? }
context 'when feature is enabled globally' do
it { is_expected.to be_falsey }
end
context 'when feature is enabled only to a resource' do
let(:feature_scope) { user }
it { is_expected.to be_truthy }
end
end
describe '.feature_available?' do
subject { described_class.feature_available? }
context 'when feature is enabled globally' do
it { is_expected.to be_truthy }
end
context 'when feature is enabled only to a resource' do
let(:feature_scope) { user }
it { is_expected.to be_truthy }
end
end
describe '.feature_enabled?' do
let(:current_user) { nil }
subject { described_class.feature_enabled?(current_user) }
context 'when feature is enabled globally' do
it { is_expected.to be_truthy }
end
context 'when feature is enabled only to a resource' do
let(:feature_scope) { user }
context 'for the same resource' do
let(:current_user) { user }
it { is_expected.to be_truthy }
end
context 'for a different resource' do
let(:current_user) { create(:user) }
it { is_expected.to be_falsey }
end
end
end
end
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
describe ApplicationSetting do describe ApplicationSetting do
using RSpec::Parameterized::TableSyntax
subject(:setting) { described_class.create_from_defaults } subject(:setting) { described_class.create_from_defaults }
it { include(CacheableAttributes) } it { include(CacheableAttributes) }
...@@ -495,6 +497,15 @@ describe ApplicationSetting do ...@@ -495,6 +497,15 @@ describe ApplicationSetting do
it { is_expected.not_to allow_value(nil).for(:static_objects_external_storage_auth_token) } it { is_expected.not_to allow_value(nil).for(:static_objects_external_storage_auth_token) }
end end
end end
context 'sourcegraph settings' do
it 'is invalid if sourcegraph is enabled and no url is provided' do
allow(subject).to receive(:sourcegraph_enabled).and_return(true)
expect(subject.sourcegraph_url).to be_nil
is_expected.to be_invalid
end
end
end end
context 'restrict creating duplicates' do context 'restrict creating duplicates' do
...@@ -583,5 +594,24 @@ describe ApplicationSetting do ...@@ -583,5 +594,24 @@ describe ApplicationSetting do
end end
end end
describe '#sourcegraph_url_is_com?' do
where(:url, :is_com) do
'https://sourcegraph.com' | true
'https://sourcegraph.com/' | true
'https://www.sourcegraph.com' | true
'shttps://www.sourcegraph.com' | false
'https://sourcegraph.example.com/' | false
'https://sourcegraph.org/' | false
end
with_them do
it 'matches the url with sourcegraph.com' do
setting.sourcegraph_url = url
expect(setting.sourcegraph_url_is_com?).to eq(is_com)
end
end
end
it_behaves_like 'application settings examples' it_behaves_like 'application settings examples'
end end
...@@ -3,15 +3,20 @@ ...@@ -3,15 +3,20 @@
require 'spec_helper' require 'spec_helper'
describe API::PagesDomains do describe API::PagesDomains do
set(:project) { create(:project, path: 'my.project', pages_https_only: false) } let_it_be(:project) { create(:project, path: 'my.project', pages_https_only: false) }
set(:user) { create(:user) } let_it_be(:user) { create(:user) }
set(:admin) { create(:admin) } let_it_be(:admin) { create(:admin) }
set(:pages_domain) { create(:pages_domain, :without_key, :without_certificate, domain: 'www.domain.test', project: project) } let_it_be(:pages_domain) { create(:pages_domain, :without_key, :without_certificate, domain: 'www.domain.test', project: project) }
set(:pages_domain_secure) { create(:pages_domain, domain: 'ssl.domain.test', project: project) } let_it_be(:pages_domain_secure) { create(:pages_domain, domain: 'ssl.domain.test', project: project) }
set(:pages_domain_expired) { create(:pages_domain, :with_expired_certificate, domain: 'expired.domain.test', project: project) } let_it_be(:pages_domain_with_letsencrypt) { create(:pages_domain, :letsencrypt, domain: 'letsencrypt.domain.test', project: project) }
let_it_be(:pages_domain_expired) { create(:pages_domain, :with_expired_certificate, domain: 'expired.domain.test', project: project) }
let(:pages_domain_params) { build(:pages_domain, :without_key, :without_certificate, domain: 'www.other-domain.test').slice(:domain) } let(:pages_domain_params) { build(:pages_domain, :without_key, :without_certificate, domain: 'www.other-domain.test').slice(:domain) }
let(:pages_domain_with_letsencrypt_params) do
build(:pages_domain, :without_key, :without_certificate, domain: 'www.other-domain.test', auto_ssl_enabled: true)
.slice(:domain, :auto_ssl_enabled)
end
let(:pages_domain_secure_params) { build(:pages_domain, domain: 'ssl.other-domain.test', project: project).slice(:domain, :certificate, :key) } let(:pages_domain_secure_params) { build(:pages_domain, domain: 'ssl.other-domain.test', project: project).slice(:domain, :certificate, :key) }
let(:pages_domain_secure_key_missmatch_params) {build(:pages_domain, :with_trusted_chain, project: project).slice(:domain, :certificate, :key) } let(:pages_domain_secure_key_missmatch_params) {build(:pages_domain, :with_trusted_chain, project: project).slice(:domain, :certificate, :key) }
let(:pages_domain_secure_missing_chain_params) {build(:pages_domain, :with_missing_chain, project: project).slice(:certificate) } let(:pages_domain_secure_missing_chain_params) {build(:pages_domain, :with_missing_chain, project: project).slice(:certificate) }
...@@ -22,6 +27,7 @@ describe API::PagesDomains do ...@@ -22,6 +27,7 @@ describe API::PagesDomains do
let(:route_secure_domain) { "/projects/#{project.id}/pages/domains/#{pages_domain_secure.domain}" } let(:route_secure_domain) { "/projects/#{project.id}/pages/domains/#{pages_domain_secure.domain}" }
let(:route_expired_domain) { "/projects/#{project.id}/pages/domains/#{pages_domain_expired.domain}" } let(:route_expired_domain) { "/projects/#{project.id}/pages/domains/#{pages_domain_expired.domain}" }
let(:route_vacant_domain) { "/projects/#{project.id}/pages/domains/www.vacant-domain.test" } let(:route_vacant_domain) { "/projects/#{project.id}/pages/domains/www.vacant-domain.test" }
let(:route_letsencrypt_domain) { "/projects/#{project.id}/pages/domains/#{pages_domain_with_letsencrypt.domain}" }
before do before do
allow(Gitlab.config.pages).to receive(:enabled).and_return(true) allow(Gitlab.config.pages).to receive(:enabled).and_return(true)
...@@ -47,9 +53,10 @@ describe API::PagesDomains do ...@@ -47,9 +53,10 @@ describe API::PagesDomains do
expect(response).to match_response_schema('public_api/v4/pages_domain_basics') expect(response).to match_response_schema('public_api/v4/pages_domain_basics')
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.size).to eq(3) expect(json_response.size).to eq(4)
expect(json_response.last).to have_key('domain') expect(json_response.last).to have_key('domain')
expect(json_response.last).to have_key('project_id') expect(json_response.last).to have_key('project_id')
expect(json_response.last).to have_key('auto_ssl_enabled')
expect(json_response.last).to have_key('certificate_expiration') expect(json_response.last).to have_key('certificate_expiration')
expect(json_response.last['certificate_expiration']['expired']).to be true expect(json_response.last['certificate_expiration']['expired']).to be true
expect(json_response.first).not_to have_key('certificate_expiration') expect(json_response.first).not_to have_key('certificate_expiration')
...@@ -73,7 +80,7 @@ describe API::PagesDomains do ...@@ -73,7 +80,7 @@ describe API::PagesDomains do
expect(response).to match_response_schema('public_api/v4/pages_domains') expect(response).to match_response_schema('public_api/v4/pages_domains')
expect(response).to include_pagination_headers expect(response).to include_pagination_headers
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.size).to eq(3) expect(json_response.size).to eq(4)
expect(json_response.map { |pages_domain| pages_domain['domain'] }).to include(pages_domain.domain) expect(json_response.map { |pages_domain| pages_domain['domain'] }).to include(pages_domain.domain)
expect(json_response.last).to have_key('domain') expect(json_response.last).to have_key('domain')
end end
...@@ -166,6 +173,7 @@ describe API::PagesDomains do ...@@ -166,6 +173,7 @@ describe API::PagesDomains do
expect(json_response['url']).to eq(pages_domain_secure.url) expect(json_response['url']).to eq(pages_domain_secure.url)
expect(json_response['certificate']['subject']).to eq(pages_domain_secure.subject) expect(json_response['certificate']['subject']).to eq(pages_domain_secure.subject)
expect(json_response['certificate']['expired']).to be false expect(json_response['certificate']['expired']).to be false
expect(json_response['auto_ssl_enabled']).to be false
end end
it 'returns pages domain with an expired certificate' do it 'returns pages domain with an expired certificate' do
...@@ -175,6 +183,18 @@ describe API::PagesDomains do ...@@ -175,6 +183,18 @@ describe API::PagesDomains do
expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(response).to match_response_schema('public_api/v4/pages_domain/detail')
expect(json_response['certificate']['expired']).to be true expect(json_response['certificate']['expired']).to be true
end end
it 'returns pages domain with letsencrypt' do
get api(route_letsencrypt_domain, user)
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/pages_domain/detail')
expect(json_response['domain']).to eq(pages_domain_with_letsencrypt.domain)
expect(json_response['url']).to eq(pages_domain_with_letsencrypt.url)
expect(json_response['certificate']['subject']).to eq(pages_domain_with_letsencrypt.subject)
expect(json_response['certificate']['expired']).to be false
expect(json_response['auto_ssl_enabled']).to be true
end
end end
context 'when domain is vacant' do context 'when domain is vacant' do
...@@ -246,6 +266,7 @@ describe API::PagesDomains do ...@@ -246,6 +266,7 @@ describe API::PagesDomains do
expect(pages_domain.domain).to eq(params[:domain]) expect(pages_domain.domain).to eq(params[:domain])
expect(pages_domain.certificate).to be_nil expect(pages_domain.certificate).to be_nil
expect(pages_domain.key).to be_nil expect(pages_domain.key).to be_nil
expect(pages_domain.auto_ssl_enabled).to be false
end end
it 'creates a new secure pages domain' do it 'creates a new secure pages domain' do
...@@ -257,6 +278,29 @@ describe API::PagesDomains do ...@@ -257,6 +278,29 @@ describe API::PagesDomains do
expect(pages_domain.domain).to eq(params_secure[:domain]) expect(pages_domain.domain).to eq(params_secure[:domain])
expect(pages_domain.certificate).to eq(params_secure[:certificate]) expect(pages_domain.certificate).to eq(params_secure[:certificate])
expect(pages_domain.key).to eq(params_secure[:key]) expect(pages_domain.key).to eq(params_secure[:key])
expect(pages_domain.auto_ssl_enabled).to be false
end
it 'creates domain with letsencrypt enabled' do
post api(route, user), params: pages_domain_with_letsencrypt_params
pages_domain = PagesDomain.find_by(domain: json_response['domain'])
expect(response).to have_gitlab_http_status(201)
expect(response).to match_response_schema('public_api/v4/pages_domain/detail')
expect(pages_domain.domain).to eq(pages_domain_with_letsencrypt_params[:domain])
expect(pages_domain.auto_ssl_enabled).to be true
end
it 'creates domain with letsencrypt enabled and provided certificate' do
post api(route, user), params: params_secure.merge(auto_ssl_enabled: true)
pages_domain = PagesDomain.find_by(domain: json_response['domain'])
expect(response).to have_gitlab_http_status(201)
expect(response).to match_response_schema('public_api/v4/pages_domain/detail')
expect(pages_domain.domain).to eq(params_secure[:domain])
expect(pages_domain.certificate).to eq(params_secure[:certificate])
expect(pages_domain.key).to eq(params_secure[:key])
expect(pages_domain.auto_ssl_enabled).to be true
end end
it 'fails to create pages domain without key' do it 'fails to create pages domain without key' do
...@@ -323,13 +367,14 @@ describe API::PagesDomains do ...@@ -323,13 +367,14 @@ describe API::PagesDomains do
shared_examples_for 'put pages domain' do shared_examples_for 'put pages domain' do
it 'updates pages domain removing certificate' do it 'updates pages domain removing certificate' do
put api(route_secure_domain, user) put api(route_secure_domain, user), params: { certificate: nil, key: nil }
pages_domain_secure.reload pages_domain_secure.reload
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(response).to match_response_schema('public_api/v4/pages_domain/detail')
expect(pages_domain_secure.certificate).to be_nil expect(pages_domain_secure.certificate).to be_nil
expect(pages_domain_secure.key).to be_nil expect(pages_domain_secure.key).to be_nil
expect(pages_domain_secure.auto_ssl_enabled).to be false
end end
it 'updates pages domain adding certificate' do it 'updates pages domain adding certificate' do
...@@ -342,6 +387,37 @@ describe API::PagesDomains do ...@@ -342,6 +387,37 @@ describe API::PagesDomains do
expect(pages_domain.key).to eq(params_secure[:key]) expect(pages_domain.key).to eq(params_secure[:key])
end end
it 'updates pages domain adding certificate with letsencrypt' do
put api(route_domain, user), params: params_secure.merge(auto_ssl_enabled: true)
pages_domain.reload
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/pages_domain/detail')
expect(pages_domain.certificate).to eq(params_secure[:certificate])
expect(pages_domain.key).to eq(params_secure[:key])
expect(pages_domain.auto_ssl_enabled).to be true
end
it 'updates pages domain enabling letsencrypt' do
put api(route_domain, user), params: { auto_ssl_enabled: true }
pages_domain.reload
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/pages_domain/detail')
expect(pages_domain.auto_ssl_enabled).to be true
end
it 'updates pages domain disabling letsencrypt while preserving the certificate' do
put api(route_letsencrypt_domain, user), params: { auto_ssl_enabled: false }
pages_domain_with_letsencrypt.reload
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/pages_domain/detail')
expect(pages_domain_with_letsencrypt.auto_ssl_enabled).to be false
expect(pages_domain_with_letsencrypt.key).to be
expect(pages_domain_with_letsencrypt.certificate).to be
end
it 'updates pages domain with expired certificate' do it 'updates pages domain with expired certificate' do
put api(route_expired_domain, user), params: params_secure put api(route_expired_domain, user), params: params_secure
pages_domain_expired.reload pages_domain_expired.reload
......
...@@ -19,6 +19,9 @@ describe API::Settings, 'Settings' do ...@@ -19,6 +19,9 @@ describe API::Settings, 'Settings' do
expect(json_response['plantuml_enabled']).to be_falsey expect(json_response['plantuml_enabled']).to be_falsey
expect(json_response['plantuml_url']).to be_nil expect(json_response['plantuml_url']).to be_nil
expect(json_response['default_ci_config_path']).to be_nil expect(json_response['default_ci_config_path']).to be_nil
expect(json_response['sourcegraph_enabled']).to be_falsey
expect(json_response['sourcegraph_url']).to be_nil
expect(json_response['sourcegraph_public_only']).to be_truthy
expect(json_response['default_project_visibility']).to be_a String expect(json_response['default_project_visibility']).to be_a String
expect(json_response['default_snippet_visibility']).to be_a String expect(json_response['default_snippet_visibility']).to be_a String
expect(json_response['default_group_visibility']).to be_a String expect(json_response['default_group_visibility']).to be_a String
...@@ -45,6 +48,7 @@ describe API::Settings, 'Settings' do ...@@ -45,6 +48,7 @@ describe API::Settings, 'Settings' do
storages = Gitlab.config.repositories.storages storages = Gitlab.config.repositories.storages
.merge({ 'custom' => 'tmp/tests/custom_repositories' }) .merge({ 'custom' => 'tmp/tests/custom_repositories' })
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
Feature.get(:sourcegraph).enable
end end
it "updates application settings" do it "updates application settings" do
...@@ -57,6 +61,9 @@ describe API::Settings, 'Settings' do ...@@ -57,6 +61,9 @@ describe API::Settings, 'Settings' do
repository_storages: ['custom'], repository_storages: ['custom'],
plantuml_enabled: true, plantuml_enabled: true,
plantuml_url: 'http://plantuml.example.com', plantuml_url: 'http://plantuml.example.com',
sourcegraph_enabled: true,
sourcegraph_url: 'https://sourcegraph.com',
sourcegraph_public_only: false,
default_snippet_visibility: 'internal', default_snippet_visibility: 'internal',
restricted_visibility_levels: ['public'], restricted_visibility_levels: ['public'],
default_artifacts_expire_in: '2 days', default_artifacts_expire_in: '2 days',
...@@ -89,6 +96,9 @@ describe API::Settings, 'Settings' do ...@@ -89,6 +96,9 @@ describe API::Settings, 'Settings' do
expect(json_response['repository_storages']).to eq(['custom']) expect(json_response['repository_storages']).to eq(['custom'])
expect(json_response['plantuml_enabled']).to be_truthy expect(json_response['plantuml_enabled']).to be_truthy
expect(json_response['plantuml_url']).to eq('http://plantuml.example.com') expect(json_response['plantuml_url']).to eq('http://plantuml.example.com')
expect(json_response['sourcegraph_enabled']).to be_truthy
expect(json_response['sourcegraph_url']).to eq('https://sourcegraph.com')
expect(json_response['sourcegraph_public_only']).to eq(false)
expect(json_response['default_snippet_visibility']).to eq('internal') expect(json_response['default_snippet_visibility']).to eq('internal')
expect(json_response['restricted_visibility_levels']).to eq(['public']) expect(json_response['restricted_visibility_levels']).to eq(['public'])
expect(json_response['default_artifacts_expire_in']).to eq('2 days') expect(json_response['default_artifacts_expire_in']).to eq('2 days')
...@@ -355,5 +365,14 @@ describe API::Settings, 'Settings' do ...@@ -355,5 +365,14 @@ describe API::Settings, 'Settings' do
expect(json_response['domain_blacklist']).to eq(['domain3.com', '*.domain4.com']) expect(json_response['domain_blacklist']).to eq(['domain3.com', '*.domain4.com'])
end end
end end
context "missing sourcegraph_url value when sourcegraph_enabled is true" do
it "returns a blank parameter error message" do
put api("/application/settings", admin), params: { sourcegraph_enabled: true }
expect(response).to have_gitlab_http_status(400)
expect(json_response['error']).to eq('sourcegraph_url is missing')
end
end
end end
end end
# frozen_string_literal: true
require 'spec_helper'
describe 'admin/application_settings/integrations.html.haml' do
let(:app_settings) { build(:application_setting) }
describe 'sourcegraph integration' do
let(:sourcegraph_flag) { true }
before do
assign(:application_setting, app_settings)
allow(Gitlab::Sourcegraph).to receive(:feature_available?).and_return(sourcegraph_flag)
end
context 'when sourcegraph feature is enabled' do
it 'show the form' do
render
expect(rendered).to have_field('application_setting_sourcegraph_enabled')
end
end
context 'when sourcegraph feature is disabled' do
let(:sourcegraph_flag) { false }
it 'show the form' do
render
expect(rendered).not_to have_field('application_setting_sourcegraph_enabled')
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'profiles/preferences/show' do
using RSpec::Parameterized::TableSyntax
let_it_be(:user) { build(:user) }
before do
assign(:user, user)
allow(controller).to receive(:current_user).and_return(user)
end
context 'sourcegraph' do
def have_sourcegraph_field(*args)
have_field('user_sourcegraph_enabled', *args)
end
def have_integrations_section
have_css('.profile-settings-sidebar', { text: 'Integrations' })
end
before do
# Can't use stub_feature_flags because we use Feature.get to check if conditinally applied
Feature.get(:sourcegraph).enable sourcegraph_feature
stub_application_setting(sourcegraph_enabled: sourcegraph_enabled)
end
context 'when not fully enabled' do
where(:feature, :admin_enabled) do
false | false
false | true
true | false
end
with_them do
let(:sourcegraph_feature) { feature }
let(:sourcegraph_enabled) { admin_enabled }
before do
render
end
it 'does not display sourcegraph field' do
expect(rendered).not_to have_sourcegraph_field
end
it 'does not display integrations settings' do
expect(rendered).not_to have_integrations_section
end
end
end
context 'when fully enabled' do
let(:sourcegraph_feature) { true }
let(:sourcegraph_enabled) { true }
before do
render
end
it 'displays the sourcegraph field' do
expect(rendered).to have_sourcegraph_field
end
it 'displays the integrations section' do
expect(rendered).to have_integrations_section
end
end
end
end
...@@ -30,39 +30,5 @@ describe 'projects/pages_domains/show' do ...@@ -30,39 +30,5 @@ describe 'projects/pages_domains/show' do
expect(rendered).to have_content("GitLab is obtaining a Let's Encrypt SSL certificate for this domain. This process can take some time. Please try again later.") expect(rendered).to have_content("GitLab is obtaining a Let's Encrypt SSL certificate for this domain. This process can take some time. Please try again later.")
end end
end end
context 'when certificate is present' do
let(:domain) { create(:pages_domain, :letsencrypt, project: project) }
it 'shows certificate info' do
render
# test just a random part of cert represenations(X509v3 Subject Key Identifier:)
expect(rendered).to have_content("C6:5F:56:4B:10:69:AC:1D:33:D2:26:C9:B3:7A:D7:12:4D:3E:F7:90")
end
end
end
context 'when auto_ssl is disabled' do
context 'when certificate is present' do
let(:domain) { create(:pages_domain, project: project) }
it 'shows certificate info' do
render
# test just a random part of cert represenations(X509v3 Subject Key Identifier:)
expect(rendered).to have_content("C6:5F:56:4B:10:69:AC:1D:33:D2:26:C9:B3:7A:D7:12:4D:3E:F7:90")
end
end
context 'when certificate is absent' do
let(:domain) { create(:pages_domain, :without_certificate, :without_key, project: project) }
it 'shows missing certificate' do
render
expect(rendered).to have_content("missing")
end
end
end end
end end
...@@ -970,6 +970,11 @@ ...@@ -970,6 +970,11 @@
"@sentry/types" "5.7.1" "@sentry/types" "5.7.1"
tslib "^1.9.3" tslib "^1.9.3"
"@sourcegraph/code-host-integration@^0.0.13":
version "0.0.13"
resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.13.tgz#4fd5fe1e0088c63b2a26be231c5a2a4ca79b1596"
integrity sha512-IjF9gb9e8dG8p12DKg5Z7UMOVQO/ClH3AyMCPfX/qH7DH/0b55WH6stYVqZu6y776quFonO4Z9gWYM8pQZjzKw==
"@types/anymatch@*": "@types/anymatch@*":
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.0.tgz#d1d55958d1fccc5527d4aba29fc9c4b942f563ff" resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.0.tgz#d1d55958d1fccc5527d4aba29fc9c4b942f563ff"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment