Commit 0aefb516 authored by Grzegorz Bizon's avatar Grzegorz Bizon

Merge branch 'master' into backstage/gb/migrate-stages-statuses

* master: (97 commits)
  Bulk update sidebar UI polish
  Fix margin in mini graph for commits box
  Add space between words in language dropdown
  Fix support for old CI API when image or services are not specified
  Short-circuit build coverage extraction for empty regexes
  Update VERSION to 9.5.0-pre
  Update CHANGELOG.md for 9.4.0
  Compress gitlab svg logo
  Fix the gcovr coverage regex by removing line separators before scanning
  Capitalize Sidekiq word in dev doc
  Add 1px to breadcrumbs min height
  Update nginx docs
  Use custom font SVG for logo
  Port spinach tests to rspec feature specs
  Merge branch 'fix-re2-infinite-loop-nick' into 'security-9-3'
  Copy-edit background migrations guidelines
  Add Traditional Chinese in Taiwan translations of Pipeline Schedules
  Fix new project selectors in GitLab QA
  Reword success to passing for pipeline badges
  Rename build to pipeline for status badges
  ...
parents 5505795e 883488e0
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.3-golang-1.8-git-2.7-phantomjs-2.1-node-7.1-postgresql-9.6"
cache:
.default-cache: &default-cache
key: "ruby-233-with-yarn"
paths:
- vendor/ruby
- .yarn-cache/
.push-cache: &push-cache
cache:
<<: *default-cache
policy: push
.pull-cache: &pull-cache
cache:
<<: *default-cache
policy: pull
variables:
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
RAILS_ENV: "test"
......@@ -24,11 +34,11 @@ before_script:
- source scripts/prepare_build.sh
stages:
- build
- prepare
- test
- post-test
- pages
- build
- prepare
- test
- post-test
- pages
# Predefined scopes
.dedicated-runner: &dedicated-runner
......@@ -41,10 +51,6 @@ stages:
SETUP_DB: "false"
USE_BUNDLE_INSTALL: "false"
KNAPSACK_S3_BUCKET: "gitlab-ce-cache"
cache:
key: "knapsack"
paths:
- knapsack/
artifacts:
expire_in: 31d
paths:
......@@ -79,8 +85,9 @@ stages:
- /(^docs[\/-].*|.*-docs$)/
.rspec-knapsack: &rspec-knapsack
stage: test
<<: *dedicated-runner
<<: *pull-cache
stage: test
script:
- JOB_NAME=( $CI_JOB_NAME )
- export CI_NODE_INDEX=${JOB_NAME[-2]}
......@@ -110,8 +117,9 @@ stages:
<<: *except-docs
.spinach-knapsack: &spinach-knapsack
stage: test
<<: *dedicated-runner
<<: *pull-cache
stage: test
script:
- JOB_NAME=( $CI_JOB_NAME )
- export CI_NODE_INDEX=${JOB_NAME[-2]}
......@@ -157,6 +165,7 @@ build-package:
SETUP_DB: "false"
USE_BUNDLE_INSTALL: "false"
stage: build
cache: {}
when: manual
script:
- scripts/trigger-build
......@@ -170,6 +179,11 @@ knapsack:
<<: *dedicated-runner
<<: *except-docs
stage: prepare
cache:
key: knapsack
paths:
- knapsack/
policy: pull
script:
- mkdir -p knapsack/${CI_PROJECT_NAME}/
- wget -O $KNAPSACK_RSPEC_SUITE_REPORT_PATH http://${KNAPSACK_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_RSPEC_SUITE_REPORT_PATH || rm $KNAPSACK_RSPEC_SUITE_REPORT_PATH
......@@ -182,6 +196,11 @@ update-knapsack:
<<: *dedicated-runner
<<: *only-canonical-masters
stage: post-test
cache:
key: knapsack
paths:
- knapsack/
policy: push
script:
- retry gem install fog-aws mime-types
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg_node_*.json
......@@ -194,6 +213,8 @@ setup-test-env:
<<: *dedicated-runner
<<: *except-docs
stage: prepare
cache:
<<: *default-cache
script:
- node --version
- yarn install --pure-lockfile --cache-folder .yarn-cache
......@@ -273,6 +294,7 @@ spinach-mysql 4 5: *spinach-knapsack-mysql
# Static analysis jobs
.ruby-static-analysis: &ruby-static-analysis
<<: *pull-cache
variables:
SIMPLECOV: "false"
SETUP_DB: "false"
......@@ -281,6 +303,7 @@ spinach-mysql 4 5: *spinach-knapsack-mysql
<<: *ruby-static-analysis
<<: *dedicated-runner
<<: *except-docs
<<: *pull-cache
stage: test
script:
- bundle exec rake $CI_JOB_NAME
......@@ -297,9 +320,9 @@ static-analysis:
# - Check validity of relative links
# - Make sure cURL examples in API docs use the full switches
docs lint:
<<: *dedicated-runner
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:nanoc-bootstrap-ruby-2.4-alpine"
stage: test
<<: *dedicated-runner
cache: {}
dependencies: []
before_script: []
......@@ -342,9 +365,10 @@ ee_compat_check:
# DB migration, rollback, and seed jobs
.db-migrate-reset: &db-migrate-reset
stage: test
<<: *dedicated-runner
<<: *except-docs
<<: *pull-cache
stage: test
script:
- bundle exec rake db:migrate:reset
......@@ -357,11 +381,12 @@ db:migrate:reset-mysql:
<<: *use-mysql
.migration-paths: &migration-paths
stage: test
<<: *dedicated-runner
<<: *only-canonical-masters
<<: *pull-cache
stage: test
variables:
SETUP_DB: "false"
<<: *only-canonical-masters
script:
- git fetch origin v8.14.10
- git checkout -f FETCH_HEAD
......@@ -382,9 +407,10 @@ migration:path-mysql:
<<: *use-mysql
.db-rollback: &db-rollback
stage: test
<<: *dedicated-runner
<<: *except-docs
<<: *pull-cache
stage: test
script:
- bundle exec rake db:rollback STEP=120
- bundle exec rake db:migrate
......@@ -398,9 +424,10 @@ db:rollback-mysql:
<<: *use-mysql
.db-seed_fu: &db-seed_fu
stage: test
<<: *dedicated-runner
<<: *except-docs
<<: *pull-cache
stage: test
variables:
SIZE: "1"
SETUP_DB: "false"
......@@ -425,9 +452,10 @@ db:seed_fu-mysql:
# Frontend-related jobs
gitlab:assets:compile:
stage: test
<<: *dedicated-runner
<<: *except-docs
<<: *pull-cache
stage: test
dependencies: []
variables:
NODE_ENV: "production"
......@@ -448,11 +476,12 @@ gitlab:assets:compile:
- webpack-report/
karma:
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.3-golang-1.8-git-2.7-chrome-59.0-node-7.1-postgresql-9.6"
stage: test
<<: *use-pg
<<: *dedicated-runner
<<: *except-docs
<<: *pull-cache
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.3-golang-1.8-git-2.7-chrome-59.0-node-7.1-postgresql-9.6"
stage: test
variables:
BABEL_ENV: "coverage"
CHROME_LOG_FILE: "chrome_debug.log"
......@@ -470,6 +499,7 @@ karma:
codeclimate:
<<: *except-docs
<<: *pull-cache
before_script: []
image: docker:latest
stage: test
......@@ -485,10 +515,11 @@ codeclimate:
paths: [codeclimate.json]
coverage:
stage: post-test
services: []
<<: *dedicated-runner
<<: *except-docs
<<: *pull-cache
stage: post-test
services: []
variables:
SETUP_DB: "false"
USE_BUNDLE_INSTALL: "true"
......@@ -505,7 +536,10 @@ coverage:
lint:javascript:report:
<<: *dedicated-runner
<<: *except-docs
<<: *pull-cache
stage: post-test
dependencies:
- setup-test-env
before_script: []
script:
- find app/ spec/ -name '*.js' -exec sed --in-place 's|/\* eslint-disable .*\*/||' {} \; # run report over all files
......@@ -517,9 +551,10 @@ lint:javascript:report:
- eslint-report.html
pages:
<<: *dedicated-runner
<<: *pull-cache
before_script: []
stage: pages
<<: *dedicated-runner
dependencies:
- coverage
- karma
......@@ -543,6 +578,7 @@ pages:
# rubygems.org in the future.
cache gems:
<<: *dedicated-runner
<<: *pull-cache
only:
- tags
variables:
......@@ -557,8 +593,9 @@ cache gems:
- master@gitlab-org/gitlab-ee
gitlab_git_test:
<<: *pull-cache
<<: *except-docs
variables:
SETUP_DB: "false"
script:
- spec/support/prepare-gitlab-git-test-for-commit --check-for-changes
<<: *except-docs
This diff is collapsed.
......@@ -71,7 +71,7 @@ gem 'gollum-rugged_adapter', '~> 0.4.4', require: false
gem 'github-linguist', '~> 4.7.0', require: 'linguist'
# API
gem 'grape', '~> 0.19.0'
gem 'grape', '~> 0.19.2'
gem 'grape-entity', '~> 0.6.0'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
......@@ -386,7 +386,7 @@ gem 'vmstat', '~> 2.3.0'
gem 'sys-filesystem', '~> 1.1.6'
# Gitaly GRPC client
gem 'gitaly', '~> 0.14.0'
gem 'gitaly', '~> 0.18.0'
gem 'toml-rb', '~> 0.3.15', require: false
......
......@@ -269,7 +269,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly (0.14.0)
gitaly (0.18.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
......@@ -332,13 +332,13 @@ GEM
multi_json (~> 1.11)
os (~> 0.9)
signet (~> 0.7)
grape (0.19.1)
grape (0.19.2)
activesupport
builder
hashie (>= 2.1.0)
multi_json (>= 1.3.2)
multi_xml (>= 0.5.2)
mustermann-grape (~> 0.4.0)
mustermann-grape (~> 1.0.0)
rack (>= 1.3.0)
rack-accept
virtus (>= 1.0.0)
......@@ -463,10 +463,9 @@ GEM
multi_json (1.12.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
mustermann (0.4.0)
tool (~> 0.2)
mustermann-grape (0.4.0)
mustermann (= 0.4.0)
mustermann (1.0.0)
mustermann-grape (1.0.0)
mustermann (~> 1.0.0)
mysql2 (0.4.5)
net-ldap (0.12.1)
netrc (0.11.0)
......@@ -850,7 +849,6 @@ GEM
timfel-krb5-auth (0.8.3)
toml-rb (0.3.15)
citrus (~> 3.0, > 3.0)
tool (0.2.3)
truncato (0.7.8)
htmlentities (~> 4.3.1)
nokogiri (~> 1.6.1)
......@@ -972,7 +970,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
gitaly (~> 0.14.0)
gitaly (~> 0.18.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.5.1)
......@@ -981,7 +979,7 @@ DEPENDENCIES
gollum-rugged_adapter (~> 0.4.4)
gon (~> 6.1.0)
google-api-client (~> 0.8.6)
grape (~> 0.19.0)
grape (~> 0.19.2)
grape-entity (~> 0.6.0)
haml_lint (~> 0.21.0)
hamlit (~> 2.6.1)
......
9.4.0-pre
9.5.0-pre
......@@ -41,7 +41,6 @@ import BlobLinePermalinkUpdater from './blob/blob_line_permalink_updater';
import Landing from './landing';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import UserCallout from './user_callout';
import { ProtectedTagCreate, ProtectedTagEditList } from './protected_tags';
import ShortcutsWiki from './shortcuts_wiki';
import Pipelines from './pipelines';
import BlobViewer from './blob/viewer/index';
......@@ -396,12 +395,6 @@ import PerformanceBar from './performance_bar';
new Search();
break;
case 'projects:settings:repository:show':
// Initialize Protected Branch Settings
new gl.ProtectedBranchCreate();
new gl.ProtectedBranchEditList();
// Initialize Protected Tag Settings
new ProtectedTagCreate();
new ProtectedTagEditList();
// Initialize expandable settings panels
initSettingsPanels();
break;
......
......@@ -2,8 +2,9 @@ import Filter from '~/droplab/plugins/filter';
import './filtered_search_dropdown';
class DropdownHint extends gl.FilteredSearchDropdown {
constructor(droplab, dropdown, input, tokenKeys, filter) {
super(droplab, dropdown, input, filter);
constructor(options = {}) {
const { input, tokenKeys } = options;
super(options);
this.config = {
Filter: {
template: 'hint',
......
......@@ -5,8 +5,9 @@ import Filter from '~/droplab/plugins/filter';
import './filtered_search_dropdown';
class DropdownNonUser extends gl.FilteredSearchDropdown {
constructor(droplab, dropdown, input, tokenKeys, filter, endpoint, symbol) {
super(droplab, dropdown, input, filter);
constructor(options = {}) {
const { input, endpoint, symbol } = options;
super(options);
this.symbol = symbol;
this.config = {
Ajax: {
......
......@@ -5,8 +5,9 @@ import './filtered_search_dropdown';
import { addClassIfElementExists } from '../lib/utils/dom_utils';
class DropdownUser extends gl.FilteredSearchDropdown {
constructor(droplab, dropdown, input, tokenKeys, filter) {
super(droplab, dropdown, input, filter);
constructor(options = {}) {
const { tokenKeys } = options;
super(options);
this.config = {
AjaxFilter: {
endpoint: `${gon.relative_url_root || ''}/autocomplete/users.json`,
......
const DATA_DROPDOWN_TRIGGER = 'data-dropdown-trigger';
class FilteredSearchDropdown {
constructor(droplab, dropdown, input, filter) {
constructor({ droplab, dropdown, input, filter }) {
this.droplab = droplab;
this.hookId = input && input.id;
this.input = input;
......
......@@ -42,13 +42,19 @@ class FilteredSearchDropdownManager {
milestone: {
reference: null,
gl: 'DropdownNonUser',
extraArguments: [`${this.baseEndpoint}/milestones.json`, '%'],
extraArguments: {
endpoint: `${this.baseEndpoint}/milestones.json`,
symbol: '%',
},
element: this.container.querySelector('#js-dropdown-milestone'),
},
label: {
reference: null,
gl: 'DropdownNonUser',
extraArguments: [`${this.baseEndpoint}/labels.json`, '~'],
extraArguments: {
endpoint: `${this.baseEndpoint}/labels.json`,
symbol: '~',
},
element: this.container.querySelector('#js-dropdown-label'),
},
hint: {
......@@ -97,13 +103,19 @@ class FilteredSearchDropdownManager {
let forceShowList = false;
if (!mappingKey.reference) {
const dl = this.droplab;
const defaultArguments =
[null, dl, element, this.filteredSearchInput, this.filteredSearchTokenKeys, key];
const glArguments = defaultArguments.concat(mappingKey.extraArguments || []);
const defaultArguments = {
droplab: this.droplab,
dropdown: element,
input: this.filteredSearchInput,
tokenKeys: this.filteredSearchTokenKeys,
filter: key,
};
const extraArguments = mappingKey.extraArguments || {};
const glArguments = Object.assign({}, defaultArguments, extraArguments);
// Passing glArguments to `new gl[glClass](<arguments>)`
mappingKey.reference = new (Function.prototype.bind.apply(gl[glClass], glArguments))();
mappingKey.reference =
new (Function.prototype.bind.apply(gl[glClass], [null, glArguments]))();
}
if (firstLoad) {
......
......@@ -86,10 +86,23 @@ export default class IssuableBulkUpdateSidebar {
this.toggleCheckboxDisplay(enable);
if (enable) {
this.initAffix();
SidebarHeightManager.init();
}
}
initAffix() {
if (!this.$sidebar.hasClass('affix-top')) {
const offsetTop = $('.scrolling-tabs-container').outerHeight() + $('.sub-nav-scroll').outerHeight();
this.$sidebar.affix({
offset: {
top: offsetTop,
},
});
}
}
updateSelectedIssuableIds() {
this.$issuableIdsInput.val(IssuableBulkUpdateSidebar.getCheckedIssueIds());
}
......
/* eslint-disable no-unused-vars */
import ProtectedBranchCreate from './protected_branch_create';
import ProtectedBranchEditList from './protected_branch_edit_list';
$(() => {
const protectedBranchCreate = new ProtectedBranchCreate();
const protectedBranchEditList = new ProtectedBranchEditList();
});
/* eslint-disable arrow-parens, no-param-reassign, object-shorthand, no-else-return, comma-dangle, max-len */
(global => {
global.gl = global.gl || {};
gl.ProtectedBranchAccessDropdown = class {
export default class ProtectedBranchAccessDropdown {
constructor(options) {
const { $dropdown, data, onSelect } = options;
this.options = options;
this.initDropdown();
}
initDropdown() {
const { $dropdown, data, onSelect } = this.options;
$dropdown.glDropdown({
data: data,
data,
selectable: true,
inputId: $dropdown.data('input-id'),
fieldName: $dropdown.data('field-name'),
toggleLabel(item, el) {
if (el.is('.is-active')) {
toggleLabel(item, $el) {
if ($el.is('.is-active')) {
return item.text;
} else {
return 'Select';
}
return 'Select';
},
clicked(opts) {
const { e } = opts;
e.preventDefault();
clicked(options) {
options.e.preventDefault();
onSelect();
}
},
});
}
};
})(window);
}
/* eslint-disable no-new, arrow-parens, no-param-reassign, comma-dangle, max-len */
/* global ProtectedBranchDropdown */
import ProtectedBranchAccessDropdown from './protected_branch_access_dropdown';
import ProtectedBranchDropdown from './protected_branch_dropdown';
(global => {
global.gl = global.gl || {};
gl.ProtectedBranchCreate = class {
export default class ProtectedBranchCreate {
constructor() {
this.$wrap = this.$form = $('#new_protected_branch');
this.$form = $('.js-new-protected-branch');
this.buildDropdowns();
}
buildDropdowns() {
const $allowedToMergeDropdown = this.$wrap.find('.js-allowed-to-merge');
const $allowedToPushDropdown = this.$wrap.find('.js-allowed-to-push');
const $allowedToMergeDropdown = this.$form.find('.js-allowed-to-merge');
const $allowedToPushDropdown = this.$form.find('.js-allowed-to-push');
// Cache callback
this.onSelectCallback = this.onSelect.bind(this);
// Allowed to Merge dropdown
new gl.ProtectedBranchAccessDropdown({
this.protectedBranchMergeAccessDropdown = new ProtectedBranchAccessDropdown({
$dropdown: $allowedToMergeDropdown,
data: gon.merge_access_levels,
onSelect: this.onSelectCallback
onSelect: this.onSelectCallback,
});
// Allowed to Push dropdown
new gl.ProtectedBranchAccessDropdown({
this.protectedBranchPushAccessDropdown = new ProtectedBranchAccessDropdown({
$dropdown: $allowedToPushDropdown,
data: gon.push_access_levels,
onSelect: this.onSelectCallback
onSelect: this.onSelectCallback,
});
// Select default
......@@ -36,20 +33,19 @@
$allowedToMergeDropdown.data('glDropdown').selectRowAtIndex(0);
// Protected branch dropdown
new ProtectedBranchDropdown({
$dropdown: this.$wrap.find('.js-protected-branch-select'),
onSelect: this.onSelectCallback
this.protectedBranchDropdown = new ProtectedBranchDropdown({
$dropdown: this.$form.find('.js-protected-branch-select'),
onSelect: this.onSelectCallback,
});
}
// This will run after clicked callback
onSelect() {
// Enable submit button
const $branchInput = this.$wrap.find('input[name="protected_branch[name]"]');
const $allowedToMergeInput = this.$wrap.find('input[name="protected_branch[merge_access_levels_attributes][0][access_level]"]');
const $allowedToPushInput = this.$wrap.find('input[name="protected_branch[push_access_levels_attributes][0][access_level]"]');
const $branchInput = this.$form.find('input[name="protected_branch[name]"]');
const $allowedToMergeInput = this.$form.find('input[name="protected_branch[merge_access_levels_attributes][0][access_level]"]');
const $allowedToPushInput = this.$form.find('input[name="protected_branch[push_access_levels_attributes][0][access_level]"]');
this.$form.find('input[type="submit"]').attr('disabled', !($branchInput.val() && $allowedToMergeInput.length && $allowedToPushInput.length));
}
};
})(window);
}
/* eslint-disable comma-dangle, no-unused-vars */
class ProtectedBranchDropdown {
export default class ProtectedBranchDropdown {
/**
* @param {Object} options containing
* `$dropdown` target element
* `onSelect` event callback
* $dropdown must be an element created using `dropdown_branch()` rails helper
*/
constructor(options) {
this.onSelect = options.onSelect;
this.$dropdown = options.$dropdown;
......@@ -12,7 +16,7 @@ class ProtectedBranchDropdown {
this.bindEvents();
// Hide footer
this.$dropdownFooter.addClass('hidden');
this.toggleFooter(true);
}
buildDropdown() {
......@@ -21,7 +25,7 @@ class ProtectedBranchDropdown {
filterable: true,
remote: false,
search: {
fields: ['title']
fields: ['title'],
},
selectable: true,
toggleLabel(selected) {
......@@ -36,10 +40,9 @@ class ProtectedBranchDropdown {
},
onFilter: this.toggleCreateNewButton.bind(this),
clicked: (options) => {
const { $el, e } = options;
e.preventDefault();
options.e.preventDefault();
this.onSelect();
}
},
});
}
......@@ -64,20 +67,22 @@ class ProtectedBranchDropdown {
}
toggleCreateNewButton(branchName) {
if (branchName) {
this.selectedBranch = {
title: branchName,
id: branchName,
text: branchName
text: branchName,
};
if (branchName) {
this.$dropdownContainer
.find('.js-create-new-protected-branch code')
.text(branchName);
}
this.$dropdownFooter.toggleClass('hidden', !branchName);
this.toggleFooter(!branchName);
}
}
window.ProtectedBranchDropdown = ProtectedBranchDropdown;
toggleFooter(toggleState) {
this.$dropdownFooter.toggleClass('hidden', toggleState);
}
}
/* eslint-disable no-new, arrow-parens, no-param-reassign, comma-dangle, max-len */
/* eslint-disable no-new */
/* global Flash */
(global => {
global.gl = global.gl || {};
import ProtectedBranchAccessDropdown from './protected_branch_access_dropdown';
gl.ProtectedBranchEdit = class {
export default class ProtectedBranchEdit {
constructor(options) {
this.$wrap = options.$wrap;
this.$allowedToMergeDropdown = this.$wrap.find('.js-allowed-to-merge');
this.$allowedToPushDropdown = this.$wrap.find('.js-allowed-to-push');
this.onSelectCallback = this.onSelect.bind(this);
this.buildDropdowns();
}
buildDropdowns() {
// Allowed to merge dropdown
new gl.ProtectedBranchAccessDropdown({
this.protectedBranchAccessDropdown = new ProtectedBranchAccessDropdown({
$dropdown: this.$allowedToMergeDropdown,
data: gon.merge_access_levels,
onSelect: this.onSelect.bind(this)
onSelect: this.onSelectCallback,
});
// Allowed to push dropdown
new gl.ProtectedBranchAccessDropdown({
this.protectedBranchAccessDropdown = new ProtectedBranchAccessDropdown({
$dropdown: this.$allowedToPushDropdown,
data: gon.push_access_levels,
onSelect: this.onSelect.bind(this)
onSelect: this.onSelectCallback,
});
}
......@@ -48,22 +48,20 @@
protected_branch: {
merge_access_levels_attributes: [{
id: this.$allowedToMergeDropdown.data('access-level-id'),
access_level: $allowedToMergeInput.val()
access_level: $allowedToMergeInput.val(),
}],
push_access_levels_attributes: [{
id: this.$allowedToPushDropdown.data('access-level-id'),
access_level: $allowedToPushInput.val()
}]
}
access_level: $allowedToPushInput.val(),
}],
},
},
error() {
$.scrollTo(0);
new Flash('Failed to update branch!');
}
new Flash('Failed to update branch!', null, $('.js-protected-branches-list'));
},
}).always(() => {
this.$allowedToMergeDropdown.enable();
this.$allowedToPushDropdown.enable();
});
}
};
})(window);
}
/* eslint-disable arrow-parens, no-param-reassign, no-new, comma-dangle */
/* eslint-disable no-new */
(global => {
global.gl = global.gl || {};
import ProtectedBranchEdit from './protected_branch_edit';
gl.ProtectedBranchEditList = class {
export default class ProtectedBranchEditList {
constructor() {
this.$wrap = $('.protected-branches-list');
this.initEditForm();
}
// Build edit forms
initEditForm() {
this.$wrap.find('.js-protected-branch-edit-form').each((i, el) => {
new gl.ProtectedBranchEdit({
$wrap: $(el)
new ProtectedBranchEdit({
$wrap: $(el),
});
});
}
};
})(window);
}
import './protected_branch_access_dropdown';
import './protected_branch_create';
import './protected_branch_dropdown';
import './protected_branch_edit';
import './protected_branch_edit_list';
export { default as ProtectedTagCreate } from './protected_tag_create';
export { default as ProtectedTagEditList } from './protected_tag_edit_list';
/* eslint-disable no-unused-vars */
import ProtectedTagCreate from './protected_tag_create';
import ProtectedTagEditList from './protected_tag_edit_list';
$(() => {
const protectedtTagCreate = new ProtectedTagCreate();
const protectedtTagEditList = new ProtectedTagEditList();
});
......@@ -190,14 +190,6 @@
display: none;
}
.btn,
.dropdown,
.dropdown-toggle,
input,
form {
height: 35px;
}
input {
display: inline-block;
position: relative;
......
......@@ -92,7 +92,6 @@
@mixin maintain-sidebar-dimensions {
display: block;
width: $gutter-width;
padding: 10px 0;
}
.issues-bulk-update.right-sidebar {
......@@ -104,6 +103,15 @@
&.right-sidebar-expanded {
@include maintain-sidebar-dimensions;
width: $gutter-width;
.issuable-sidebar-header {
// matches `.top-area .nav-controls` for issuable index pages
padding: 11px 0;
}
.block:last-of-type {
border: none;
}
}
&.right-sidebar-collapsed {
......
......@@ -41,10 +41,22 @@ header.navbar-gitlab-new {
}
}
.logo-text {
line-height: initial;
svg {
width: 55px;
height: 15px;
margin: 0;
fill: $white-light;
}
}
&:hover,
&:focus {
color: $tanuki-yellow;
text-decoration: none;
.logo-text svg {
fill: $tanuki-yellow;
}
}
}
}
......@@ -274,7 +286,7 @@ header.navbar-gitlab-new {
.breadcrumbs {
display: flex;
min-height: 60px;
min-height: 61px;
color: $gl-text-color;
border-bottom: 1px solid $border-color;
......
......@@ -23,6 +23,10 @@ $new-sidebar-width: 220px;
position: fixed;
height: 100%;
}
.issues-bulk-update.right-sidebar.right-sidebar-expanded .issuable-sidebar-header {
padding: 10px 0 15px;
}
}
.context-header {
......@@ -165,7 +169,6 @@ $new-sidebar-width: 220px;
> li {
a {
font-size: 12px;
padding: 8px 16px 8px 24px;
&:hover,
......@@ -262,7 +265,7 @@ $new-sidebar-width: 220px;
@media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
// scss-lint:disable DuplicateProperty
height: calc(100vh - 120px);
height: calc(100vh - 180px);
// scss-lint:enable DuplicateProperty
}
}
......
......@@ -54,7 +54,11 @@
.mr-widget-pipeline-graph {
display: inline-block;
vertical-align: middle;
margin: 0 -6px 0 0;
margin-right: 4px;
.stage-cell .stage-container {
margin: 3px 3px 3px 0;
}
.dropdown-menu {
margin-top: 11px;
......
......@@ -742,7 +742,8 @@ pre.light-well {
}
}
.protected-tags-list {
.protected-tags-list,
.protected-branches-list {
.dropdown-menu-toggle {
width: 100%;
max-width: 300px;
......
......@@ -10,9 +10,9 @@ class Admin::HookLogsController < Admin::ApplicationController
end
def retry
status, message = hook.execute(hook_log.request_data, hook_log.trigger)
result = hook.execute(hook_log.request_data, hook_log.trigger)
set_hook_execution_notice(status, message)
set_hook_execution_notice(result)
redirect_to edit_admin_hook_path(@hook)
end
......
......@@ -38,9 +38,9 @@ class Admin::HooksController < Admin::ApplicationController
end
def test
status, message = hook.execute(sample_hook_data, 'system_hooks')
result = TestHooks::SystemService.new(hook, current_user, params[:trigger]).execute
set_hook_execution_notice(status, message)
set_hook_execution_notice(result)
redirect_back_or_default
end
......@@ -66,15 +66,4 @@ class Admin::HooksController < Admin::ApplicationController
:url
)
end
def sample_hook_data
{
event_name: "project_create",
name: "Ruby",
path: "ruby",
project_id: 1,
owner_name: "Someone",
owner_email: "example@gitlabhq.com"
}
end
end
......@@ -3,11 +3,14 @@ module HooksExecution
private
def set_hook_execution_notice(status, message)
if status && status >= 200 && status < 400
flash[:notice] = "Hook executed successfully: HTTP #{status}"
elsif status
flash[:alert] = "Hook executed successfully but returned HTTP #{status} #{message}"
def set_hook_execution_notice(result)
http_status = result[:http_status]
message = result[:message]
if http_status && http_status >= 200 && http_status < 400
flash[:notice] = "Hook executed successfully: HTTP #{http_status}"
elsif http_status
flash[:alert] = "Hook executed successfully but returned HTTP #{http_status} #{message}"
else
flash[:alert] = "Hook execution failed: #{message}"
end
......
......@@ -3,11 +3,11 @@ class Projects::BadgesController < Projects::ApplicationController
before_action :authorize_admin_project!, only: [:index]
before_action :no_cache_headers, except: [:index]
def build
build_status = Gitlab::Badge::Build::Status
def pipeline
pipeline_status = Gitlab::Badge::Pipeline::Status
.new(project, params[:ref])
render_badge build_status
render_badge pipeline_status
end
def coverage
......
......@@ -14,9 +14,9 @@ class Projects::HookLogsController < Projects::ApplicationController
end
def retry
status, message = hook.execute(hook_log.request_data, hook_log.trigger)
result = hook.execute(hook_log.request_data, hook_log.trigger)
set_hook_execution_notice(status, message)
set_hook_execution_notice(result)
redirect_to edit_project_hook_path(@project, @hook)
end
......
......@@ -9,6 +9,10 @@ class Projects::HooksController < Projects::ApplicationController
layout "project_settings"
def index
redirect_to project_settings_integrations_path(@project)
end
def create
@hook = @project.hooks.new(hook_params)
@hook.save
......@@ -33,13 +37,9 @@ class Projects::HooksController < Projects::ApplicationController
end
def test
if !@project.empty_repo?
status, message = TestHookService.new.execute(hook, current_user)
result = TestHooks::ProjectService.new(hook, current_user, params[:trigger]).execute
set_hook_execution_notice(status, message)
else
flash[:alert] = 'Hook execution failed. Ensure the project has commits.'
end
set_hook_execution_notice(result)
redirect_back_or_default(default: { action: 'index' })
end
......
......@@ -35,7 +35,7 @@ module Projects
def define_badges_variables
@ref = params[:ref] || @project.default_branch || 'master'
@badges = [Gitlab::Badge::Build::Status,
@badges = [Gitlab::Badge::Pipeline::Status,
Gitlab::Badge::Coverage::Report]
@badges.map! do |badge|
......
module HooksHelper
def link_to_test_hook(hook, trigger)
path = case hook
when ProjectHook
project = hook.project
test_project_hook_path(project, hook, trigger: trigger)
when SystemHook
test_admin_hook_path(hook, trigger: trigger)
end
trigger_human_name = trigger.to_s.tr('_', ' ').camelize
link_to path, rel: 'nofollow' do
content_tag(:span, trigger_human_name)
end
end
end
......@@ -8,6 +8,6 @@ module TriggersHelper
end
def service_trigger_url(service)
"#{Settings.gitlab.url}/api/v3/projects/#{service.project_id}/services/#{service.to_param}/trigger"
"#{Settings.gitlab.url}/api/v4/projects/#{service.project_id}/services/#{service.to_param}/trigger"
end
end
......@@ -96,6 +96,14 @@ module Ci
BuildSuccessWorker.perform_async(id)
end
end
before_transition any => [:failed] do |build|
next if build.retries_max.zero?
if build.retries_count < build.retries_max
Ci::Build.retry(build, build.user)
end
end
end
def detailed_status(current_user)
......@@ -130,6 +138,14 @@ module Ci
success? || failed? || canceled?
end
def retries_count
pipeline.builds.retried.where(name: self.name).count
end
def retries_max
self.options.fetch(:retry, 0).to_i
end
def latest?
!retried?
end
......
class ProjectHook < WebHook
belongs_to :project
TRIGGERS = {
push_hooks: :push_events,
tag_push_hooks: :tag_push_events,
issue_hooks: :issues_events,
confidential_issue_hooks: :confidential_issues_events,
note_hooks: :note_events,
merge_request_hooks: :merge_requests_events,
job_hooks: :job_events,
pipeline_hooks: :pipeline_events,
wiki_page_hooks: :wiki_page_events
}.freeze
TRIGGERS.each do |trigger, event|
scope trigger, -> { where(event => true) }
end
scope :issue_hooks, -> { where(issues_events: true) }
scope :confidential_issue_hooks, -> { where(confidential_issues_events: true) }
scope :note_hooks, -> { where(note_events: true) }
scope :merge_request_hooks, -> { where(merge_requests_events: true) }
scope :job_hooks, -> { where(job_events: true) }
scope :pipeline_hooks, -> { where(pipeline_events: true) }
scope :wiki_page_hooks, -> { where(wiki_page_events: true) }
belongs_to :project
validates :project, presence: true
end
class ServiceHook < WebHook
belongs_to :service
validates :service, presence: true
def execute(data)
WebHookService.new(self, data, 'service_hook').execute
......
class SystemHook < WebHook
scope :repository_update_hooks, -> { where(repository_update_events: true) }
TRIGGERS = {
repository_update_hooks: :repository_update_events,
push_hooks: :push_events,
tag_push_hooks: :tag_push_events
}.freeze
TRIGGERS.each do |trigger, event|
scope trigger, -> { where(event => true) }
end
default_value_for :push_events, false
default_value_for :repository_update_events, true
......
class WebHook < ActiveRecord::Base
include Sortable
default_value_for :push_events, true
default_value_for :issues_events, false
default_value_for :confidential_issues_events, false
default_value_for :note_events, false
default_value_for :merge_requests_events, false
default_value_for :tag_push_events, false
default_value_for :job_events, false
default_value_for :pipeline_events, false
default_value_for :repository_update_events, false
default_value_for :enable_ssl_verification, true
has_many :web_hook_logs, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
scope :push_hooks, -> { where(push_events: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true) }
validates :url, presence: true, url: true
def execute(data, hook_name)
......
......@@ -4,7 +4,7 @@ class SystemHooksService
end
def execute_hooks(data, hooks_scope = :all)
SystemHook.send(hooks_scope).each do |hook|
SystemHook.public_send(hooks_scope).find_each do |hook|
hook.async_execute(data, 'system_hooks')
end
end
......
class TestHookService
def execute(hook, current_user)
data = Gitlab::DataBuilder::Push.build_sample(hook.project, current_user)
hook.execute(data, 'push_hooks')
end
end
module TestHooks
class BaseService
attr_accessor :hook, :current_user, :trigger
def initialize(hook, current_user, trigger)
@hook = hook
@current_user = current_user
@trigger = trigger
end
def execute
trigger_data_method = "#{trigger}_data"
if !self.respond_to?(trigger_data_method, true) ||
!hook.class::TRIGGERS.value?(trigger.to_sym)
return error('Testing not available for this hook')
end
error_message = catch(:validation_error) do
sample_data = self.__send__(trigger_data_method)
return hook.execute(sample_data, trigger)
end
error(error_message)
end
private
def error(message, http_status = nil)
result = {
message: message,
status: :error
}
result[:http_status] = http_status if http_status
result
end
end
end
module TestHooks
class ProjectService < TestHooks::BaseService
private
def project
@project ||= hook.project
end
def push_events_data
throw(:validation_error, 'Ensure the project has at least one commit.') if project.empty_repo?
Gitlab::DataBuilder::Push.build_sample(project, current_user)
end
alias_method :tag_push_events_data, :push_events_data
def note_events_data
note = project.notes.first
throw(:validation_error, 'Ensure the project has notes.') unless note.present?
Gitlab::DataBuilder::Note.build(note, current_user)
end
def issues_events_data
issue = project.issues.first
throw(:validation_error, 'Ensure the project has issues.') unless issue.present?
issue.to_hook_data(current_user)
end
alias_method :confidential_issues_events_data, :issues_events_data
def merge_requests_events_data
merge_request = project.merge_requests.first
throw(:validation_error, 'Ensure the project has merge requests.') unless merge_request.present?
merge_request.to_hook_data(current_user)
end
def job_events_data
build = project.builds.first
throw(:validation_error, 'Ensure the project has CI jobs.') unless build.present?
Gitlab::DataBuilder::Build.build(build)
end
def pipeline_events_data
pipeline = project.pipelines.first
throw(:validation_error, 'Ensure the project has CI pipelines.') unless pipeline.present?
Gitlab::DataBuilder::Pipeline.build(pipeline)
end
def wiki_page_events_data
page = project.wiki.pages.first
if !project.wiki_enabled? || page.blank?
throw(:validation_error, 'Ensure the wiki is enabled and has pages.')
end
Gitlab::DataBuilder::WikiPage.build(page, current_user, 'create')
end
end
end
module TestHooks
class SystemService < TestHooks::BaseService
private
def project
@project ||= begin
project = Project.first
throw(:validation_error, 'Ensure that at least one project exists.') unless project
project
end
end
def push_events_data
if project.empty_repo?
throw(:validation_error, "Ensure project \"#{project.human_name}\" has commits.")
end
Gitlab::DataBuilder::Push.build_sample(project, current_user)
end
def tag_push_events_data
if project.repository.tags.empty?
throw(:validation_error, "Ensure project \"#{project.human_name}\" has tags.")
end
Gitlab::DataBuilder::Push.build_sample(project, current_user)
end
def repository_update_events_data
commit = project.commit
ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{project.default_branch}"
unless commit
throw(:validation_error, "Ensure project \"#{project.human_name}\" has commits.")
end
change = Gitlab::DataBuilder::Repository.single_change(
commit.parent_id || Gitlab::Git::BLANK_SHA,
commit.id,
ref
)
Gitlab::DataBuilder::Repository.update(project, current_user, [change], [ref])
end
end
end
......@@ -39,7 +39,11 @@ class WebHookService
execution_duration: Time.now - start_time
)
[response.code, response.to_s]
{
status: :success,
http_status: response.code,
message: response.to_s
}
rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e
log_execution(
trigger: hook_name,
......@@ -52,7 +56,10 @@ class WebHookService
Rails.logger.error("WebHook Error => #{e}")
[nil, e.to_s]
{
status: :error,
message: e.to_s
}
end
def async_execute
......
module WikiPages
class BaseService < ::BaseService
def hook_data(page, action)
hook_data = {
object_kind: page.class.name.underscore,
user: current_user.hook_attrs,
project: @project.hook_attrs,
wiki: @project.wiki.hook_attrs,
object_attributes: page.hook_attrs
}
page_url = Gitlab::UrlBuilder.build(page)
hook_data[:object_attributes].merge!(url: page_url, action: action)
hook_data
end
private
def execute_hooks(page, action = 'create')
page_data = hook_data(page, action)
page_data = Gitlab::DataBuilder::WikiPage.build(page, current_user, action)
@project.execute_hooks(page_data, :wiki_page_hooks)
@project.execute_services(page_data, :wiki_page_hooks)
end
......
......@@ -315,7 +315,9 @@
%fieldset
%legend Metrics - Prometheus
%p
Enable a Prometheus metrics endpoint at `#{metrics_path}` to expose a variety of statistics on the health and performance of GitLab. Additional information on authenticating and connecting to the metrics endpoint is available
Enable a Prometheus metrics endpoint at
%code= metrics_path
to expose a variety of statistics on the health and performance of GitLab. Additional information on authenticating and connecting to the metrics endpoint is available
= link_to 'here', admin_health_check_path
\. This setting requires a
= link_to 'restart', help_page_path('administration/restart_gitlab')
......@@ -330,7 +332,10 @@
- unless Gitlab::Metrics.metrics_folder_present?
.help-block
%strong.cred WARNING:
Environment variable `prometheus_multiproc_dir` does not exist or is not pointing to a valid directory.
Environment variable
%code prometheus_multiproc_dir
does not exist or is not pointing to a valid directory.
= link_to icon('question-circle'), help_page_path('administration/monitoring/prometheus/gitlab_metrics', anchor: 'metrics-shared-directory')
%fieldset
%legend Profiling - Performance Bar
......
......@@ -12,7 +12,7 @@
= render partial: 'form', locals: { form: f, hook: @hook }
.form-actions
= f.submit 'Save changes', class: 'btn btn-create'
= link_to 'Test hook', test_admin_hook_path(@hook), class: 'btn btn-default'
= render 'shared/web_hooks/test_button', triggers: SystemHook::TRIGGERS, hook: @hook
= link_to 'Remove', admin_hook_path(@hook), method: :delete, class: 'btn btn-remove pull-right', data: { confirm: 'Are you sure?' }
%hr
......
......@@ -22,12 +22,12 @@
- @hooks.each do |hook|
%li
.controls
= link_to 'Test hook', test_admin_hook_path(hook), class: 'btn btn-sm'
= render 'shared/web_hooks/test_button', triggers: SystemHook::TRIGGERS, hook: hook, button_class: 'btn-small'
= link_to 'Edit', edit_admin_hook_path(hook), class: 'btn btn-sm'
= link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm'
.monospace= hook.url
%div
- %w(repository_update_events push_events tag_push_events issues_events note_events merge_requests_events job_events).each do |trigger|
- if hook.send(trigger)
%span.label.label-gray= trigger.titleize
- SystemHook::TRIGGERS.each_value do |event|
- if hook.public_send(event)
%span.label.label-gray= event.to_s.titleize
%span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'}
......@@ -2,26 +2,6 @@
= render "admin/dashboard/head"
%div{ class: container_class }
%p.prepend-top-default
%span
To register a new Runner you should enter the following registration
token.
With this token the Runner will request a unique Runner token and use
that for future communication.
%br
Registration token is
%code#runners-token= current_application_settings.runners_registration_token
.bs-callout.clearfix
.pull-left
%p
You can reset runners registration token by pressing a button below.
.prepend-top-10
= button_to "Reset runners registration token", reset_runners_token_admin_application_settings_path,
method: :put, class: 'btn btn-default',
data: { confirm: 'Are you sure you want to reset registration token?' }
.bs-callout
%p
A 'Runner' is a process which runs a job.
......@@ -46,6 +26,19 @@
%span.label.label-danger paused
\- Runner will not receive any new jobs
.bs-callout.clearfix
.pull-left
%p
You can reset runners registration token by pressing a button below.
.prepend-top-10
= button_to _("Reset runners registration token"), reset_runners_token_admin_application_settings_path,
method: :put, class: 'btn btn-default',
data: { confirm: _("Are you sure you want to reset registration token?") }
= render partial: 'ci/runner/how_to_setup_runner',
locals: { registration_token: current_application_settings.runners_registration_token,
type: 'shared' }
.append-bottom-20.clearfix
.pull-left
= form_tag admin_runners_path, id: 'runners-search', class: 'form-inline', method: :get do
......
- link = link_to _("GitLab Runner section"), 'https://about.gitlab.com/gitlab-ci/#gitlab-runner', target: '_blank'
.bs-callout.help-callout
%h4= _("How to setup a #{type} Runner for a new project")
%ol
%li
= _("Install a Runner compatible with GitLab CI")
= (_("(checkout the %{link} for information on how to install it).") % { link: link }).html_safe
%li
= _("Specify the following URL during the Runner setup:")
%code= root_url(only_path: false)
%li
= _("Use the following registration token during setup:")
%code#registration_token= registration_token
%li
= _("Start the Runner!")
......@@ -7,6 +7,6 @@
%span.light
- has_icon = provider_has_icon?(provider)
= link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: 'oauth-login' + (has_icon ? ' oauth-image-link' : ' btn'), id: "oauth-login-#{provider}"
%fieldset
%fieldset.prepend-top-10
= check_box_tag :remember_me
= label_tag :remember_me, 'Remember Me'
= label_tag :remember_me, 'Remember me'
......@@ -6,8 +6,8 @@
%h1.title
= link_to root_path, title: 'Dashboard' do
= brand_header_logo
%span.hidden-xs
GitLab
%span.logo-text.hidden-xs
= render 'shared/logo_type.svg'
- if current_user
= render "layouts/nav/new_dashboard"
......
......@@ -13,9 +13,10 @@
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
= f.submit 'Save changes', class: 'btn btn-create'
= link_to 'Test hook', test_project_hook_path(@project, @hook), class: 'btn btn-default'
= render 'shared/web_hooks/test_button', triggers: ProjectHook::TRIGGERS, hook: @hook
= link_to 'Remove', project_hook_path(@project, @hook), method: :delete, class: 'btn btn-remove pull-right', data: { confirm: 'Are you sure?' }
%hr
= render partial: 'projects/hook_logs/index', locals: { hook: @hook, hook_logs: @hook_logs, project: @project }
......@@ -4,7 +4,7 @@
= pipeline_schedule.description
%td.branch-name-cell
= icon('code-fork')
- if pipeline_schedule.ref
- if pipeline_schedule.ref.present?
= link_to pipeline_schedule.ref, project_ref_path(@project, pipeline_schedule.ref), class: "ref-name"
%td
- if pipeline_schedule.last_pipeline
......
.panel.panel-default.protected-branches-list
.panel.panel-default.protected-branches-list.js-protected-branches-list
- if @protected_branches.empty?
.panel-heading
%h3.panel-title
......@@ -23,6 +23,8 @@
- if can_admin_project
%th
%tbody
%tr
%td.flash-container{ colspan: 5 }
= yield
= paginate @protected_branches, theme: 'gitlab'
= form_for [@project.namespace.becomes(Namespace), @project, @protected_branch] do |f|
= form_for [@project.namespace.becomes(Namespace), @project, @protected_branch], html: { class: 'new-protected-branch js-new-protected-branch' } do |f|
.panel.panel-default
.panel-heading
%h3.panel-title
......
.panel.panel-default.protected-tags-list
.panel.panel-default.protected-tags-list.js-protected-tags-list
- if @protected_tags.empty?
.panel-heading
%h3.panel-title
......
%h3 Specific Runners
.bs-callout.help-callout
%h4 How to setup a specific Runner for a new project
%ol
%li
Install a Runner compatible with GitLab CI
(checkout the #{link_to 'GitLab Runner section', 'https://about.gitlab.com/gitlab-ci/#gitlab-runner', target: '_blank'} for information on how to install it).
%li
Specify the following URL during the Runner setup:
%code= root_url(only_path: false)
%li
Use the following registration token during setup:
%code= @project.runners_token
%li
Start the Runner!
= render partial: 'ci/runner/how_to_setup_runner',
locals: { registration_token: @project.runners_token,
type: 'specific' }
- if @project_runners.any?
%h4.underlined-title Runners activated for this project
......
......@@ -3,14 +3,14 @@
.col-md-8.col-lg-7
%strong.light-header= hook.url
%div
- %w(push_events tag_push_events issues_events confidential_issues_events note_events merge_requests_events job_events pipeline_events wiki_page_events).each do |trigger|
- if hook.send(trigger)
%span.label.label-gray.deploy-project-label= trigger.titleize
- ProjectHook::TRIGGERS.each_value do |event|
- if hook.public_send(event)
%span.label.label-gray.deploy-project-label= event.to_s.titleize
.col-md-4.col-lg-5.text-right-lg.prepend-top-5
%span.append-right-10.inline
SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"}
= link_to "Edit", edit_project_hook_path(@project, hook), class: "btn btn-sm"
= link_to "Test", test_project_hook_path(@project, hook), class: "btn btn-sm"
= link_to project_hook_path(@project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-transparent" do
SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'}
= link_to 'Edit', edit_project_hook_path(@project, hook), class: 'btn btn-sm'
= render 'shared/web_hooks/test_button', triggers: ProjectHook::TRIGGERS, hook: hook, button_class: 'btn-small'
= link_to project_hook_path(@project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-transparent' do
%span.sr-only Remove
= icon('trash')
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 617 169"><path d="M315.26 2.97h-21.8l.1 162.5h88.3v-20.1h-66.5l-.1-142.4M465.89 136.95c-5.5 5.7-14.6 11.4-27 11.4-16.6 0-23.3-8.2-23.3-18.9 0-16.1 11.2-23.8 35-23.8 4.5 0 11.7.5 15.4 1.2v30.1h-.1m-22.6-98.5c-17.6 0-33.8 6.2-46.4 16.7l7.7 13.4c8.9-5.2 19.8-10.4 35.5-10.4 17.9 0 25.8 9.2 25.8 24.6v7.9c-3.5-.7-10.7-1.2-15.1-1.2-38.2 0-57.6 13.4-57.6 41.4 0 25.1 15.4 37.7 38.7 37.7 15.7 0 30.8-7.2 36-18.9l4 15.9h15.4v-83.2c-.1-26.3-11.5-43.9-44-43.9M557.63 149.1c-8.2 0-15.4-1-20.8-3.5V70.5c7.4-6.2 16.6-10.7 28.3-10.7 21.1 0 29.2 14.9 29.2 39 0 34.2-13.1 50.3-36.7 50.3m9.2-110.6c-19.5 0-30 13.3-30 13.3v-21l-.1-27.8h-21.3l.1 158.5c10.7 4.5 25.3 6.9 41.2 6.9 40.7 0 60.3-26 60.3-70.9-.1-35.5-18.2-59-50.2-59M77.9 20.6c19.3 0 31.8 6.4 39.9 12.9l9.4-16.3C114.5 6 97.3 0 78.9 0 32.5 0 0 28.3 0 85.4c0 59.8 35.1 83.1 75.2 83.1 20.1 0 37.2-4.7 48.4-9.4l-.5-63.9V75.1H63.6v20.1h38l.5 48.5c-5 2.5-13.6 4.5-25.3 4.5-32.2 0-53.8-20.3-53.8-63-.1-43.5 22.2-64.6 54.9-64.6M231.43 2.95h-21.3l.1 27.3v94.3c0 26.3 11.4 43.9 43.9 43.9 4.5 0 8.9-.4 13.1-1.2v-19.1c-3.1.5-6.4.7-9.9.7-17.9 0-25.8-9.2-25.8-24.6v-65h35.7v-17.8h-35.7l-.1-38.5M155.96 165.47h21.3v-124h-21.3v124M155.96 24.37h21.3V3.07h-21.3v21.3"/></svg>
- type = local_assigns.fetch(:type)
%aside.issues-bulk-update.js-right-sidebar.right-sidebar.affix-top{ data: { "offset-top" => "50", "spy" => "affix" }, "aria-live" => "polite" }
%aside.issues-bulk-update.js-right-sidebar.right-sidebar{ "aria-live" => "polite", data: { 'signed-in': current_user.present? } }
.issuable-sidebar.hidden
= form_tag [:bulk_update, @project.namespace.becomes(Namespace), @project, type], method: :post, class: "bulk-update" do
.block
.block.issuable-sidebar-header
.filter-item.inline.update-issues-btn.pull-left
= button_tag "Update all", class: "btn update-selected-issues btn-info", disabled: true
= button_tag "Cancel", class: "btn btn-default js-bulk-update-menu-hide pull-right"
......
- triggers = local_assigns.fetch(:triggers)
- button_class = local_assigns.fetch(:button_class, '')
- hook = local_assigns.fetch(:hook)
.hook-test-button.dropdown.inline
%button.btn{ 'data-toggle' => 'dropdown', class: button_class }
Test
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right{ role: 'menu' }
- triggers.each_value do |event|
%li
= link_to_test_hook(hook, event)
---
title: Added "created_after" and "created_before" params to issuables
merge_request: 12151
author: Kyle Bishop @kybishop
---
title: "Adding French translations"
merge_request: 12200
author : Erwan "Dremor" Georget
---
title: Display all current broadcast messages, not just the last one
merge_request: 11113
author: rickettm
---
title: Honor the "Remember me" parameter for OAuth-based login
merge_request: 11963
author:
---
title: "#20628 Enable implicit grant in GitLab as OAuth Provider"
merge_request: 12384
author: Mateusz Pytel
---
title: Add coordinator url to admin area runner page
merge_request: 11603
author:
---
title: Replace 'dashboard/new-project.feature' spinach with rspec
merge_request: 12550
author: Alexander Randa (@randaalex)
---
title: Replace 'dashboard/todos' spinach with rspec
merge_request: 12453
author: Alexander Randa (@randaalex)
---
title: Replace 'snippets/snippets.feature' spinach with rspec
merge_request: 12385
author: Alexander Randa @randaalex
---
title: Allow creation of files and directories with spaces through Web UI
merge_request: 12608
author:
---
title: Add blame view age mapping
merge_request: 7198
author: Jeff Stubler
---
title: Update welcome page UX for new users
merge_request: 12662
author:
---
title: Fix mobile view of files view buttons
merge_request:
author:
---
title: Improve members view on mobile
merge_request: 12619
author:
---
title: Disable fork button on project limit
merge_request: 12145
author: Ivan Chernov
---
title: Inserts exact matches of name, username and email to the top of the search
list
merge_request: 12525
author:
---
title: Accept image for avatar in user API
merge_request: 12143
author: Ivan Chernov
---
title: Rename "Slash commands" to "Quick actions" and deprecate "chat commands" in favor
of "slash commands"
merge_request:
author:
---
title: Center dropdown for mini graph
merge_request:
author:
---
title: Fix an email parsing bug where brackets would be inserted in emails from some Outlook clients
merge_request: 9045
author: jneen
---
title: Use fa-chevron-down on dropdown arrows for consistency
merge_request: 9659
author: TM Lee
---
title: Use color inputs for broadcast messages
merge_request:
author:
---
title: Additional Prometheus metrics support
merge_request: 11712
author:
---
title: Moved "Members in a project" menu entry and path locations
merge_request: 11560
---
title: Rollback project repo move if there is an error in Projects::TransferService
merge_request: 11877
author:
---
title: Removes deleted_at and pending_delete occurrences in Project related queries
merge_request: 12091
author:
---
title: Ensures default user limits when external user is unchecked
merge_request: 12218
author:
---
title: Adds realtime feature to job show view header and sidebar info. Updates UX.
merge_request:
author:
---
title: Create responsive mobile view for pipelines table
merge_request:
author:
---
title: Change order of monospace fonts to fix bug on some linux distros
merge_request:
author:
---
title: Fix spacing on runner buttons.
merge_request: !12535
author:
---
title: Add database helpers 'add_timestamps_with_timezone' and 'timestamps_with_timezone'
merge_request: 11229
author: @blackst0ne
---
title: Filter archived project in API v3 only if param present
merge_request: 12245
author: Ivan Chernov
---
title: Allow admins to disable all restricted visibility levels
merge_request: 12649
author:
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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