Merge branch 'master' into bootstrap4

This commit is contained in:
Clement Ho 2018-04-16 16:19:03 -05:00
commit 7fd3c8da74
25 changed files with 301 additions and 151 deletions

View File

@ -45,4 +45,4 @@ When removing columns, tables, indexes or other structures:
- [ ] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
- [ ] Internationalization required/considered
- [ ] If paid feature, have we considered GitLab.com plan and how it works for groups and is there a design for promoting it to users who aren't on the correct plan
- [ ] End-to-end tests pass (`package-qa` manual pipeline job)
- [ ] End-to-end tests pass (`package-and-qa` manual pipeline job)

View File

@ -206,7 +206,7 @@ GEM
railties (>= 3.0.0)
faraday (0.12.2)
multipart-post (>= 1.2, < 3)
faraday_middleware (0.11.0.1)
faraday_middleware (0.12.2)
faraday (>= 0.7.4, < 1.0)
faraday_middleware-multi_json (0.0.6)
faraday_middleware

View File

@ -1,3 +1,4 @@
<script>
import successSvg from 'icons/_icon_status_success.svg';
import warningSvg from 'icons/_icon_status_warning.svg';
import simplePoll from '~/lib/utils/simple_poll';
@ -7,7 +8,10 @@ import statusIcon from '../mr_widget_status_icon.vue';
import eventHub from '../../event_hub';
export default {
name: 'MRWidgetReadyToMerge',
name: 'ReadyToMerge',
components: {
statusIcon,
},
props: {
mr: { type: Object, required: true },
service: { type: Object, required: true },
@ -26,9 +30,6 @@ export default {
warningSvg,
};
},
components: {
statusIcon,
},
computed: {
shouldShowMergeWhenPipelineSucceedsText() {
return this.mr.isPipelineActive;
@ -217,136 +218,146 @@ export default {
});
},
},
template: `
<div class="mr-widget-body media">
<status-icon :status="iconClass" />
<div class="media-body">
<div class="mr-widget-body-controls media space-children">
<span class="btn-group append-bottom-5">
<button
@click="handleMergeButtonClick()"
:disabled="isMergeButtonDisabled"
:class="mergeButtonClass"
type="button"
class="qa-merge-button">
<i
v-if="isMakingRequest"
class="fa fa-spinner fa-spin"
aria-hidden="true" />
{{mergeButtonText}}
</button>
<button
v-if="shouldShowMergeOptionsDropdown"
:disabled="isMergeButtonDisabled"
type="button"
class="btn btn-sm btn-info dropdown-toggle js-merge-moment"
data-toggle="dropdown"
aria-label="Select merge moment">
<i
class="fa fa-chevron-down"
aria-hidden="true" />
</button>
<ul
v-if="shouldShowMergeOptionsDropdown"
class="dropdown-menu dropdown-menu-right"
role="menu">
<li>
<a
@click.prevent="handleMergeButtonClick(true)"
class="merge_when_pipeline_succeeds"
href="#">
<span class="media">
<span
v-html="successSvg"
class="merge-opt-icon"
aria-hidden="true"></span>
<span class="media-body merge-opt-title">Merge when pipeline succeeds</span>
</span>
</a>
</li>
<li>
<a
@click.prevent="handleMergeButtonClick(false, true)"
class="accept-merge-request"
href="#">
<span class="media">
<span
v-html="warningSvg"
class="merge-opt-icon"
aria-hidden="true"></span>
<span class="media-body merge-opt-title">Merge immediately</span>
</span>
</a>
</li>
</ul>
</span>
<div class="media-body-wrap space-children">
<template v-if="shouldShowMergeControls()">
<label v-if="mr.canRemoveSourceBranch">
<input
id="remove-source-branch-input"
v-model="removeSourceBranch"
class="js-remove-source-branch-checkbox"
:disabled="isRemoveSourceBranchButtonDisabled"
type="checkbox"/> Remove source branch
</label>
};
</script>
<!-- Placeholder for EE extension of this component -->
<squash-before-merge
v-if="shouldShowSquashBeforeMerge"
:mr="mr"
:is-merge-button-disabled="isMergeButtonDisabled" />
<span
v-if="mr.ffOnlyEnabled"
class="js-fast-forward-message">
Fast-forward merge without a merge commit
</span>
<button
v-else
@click="toggleCommitMessageEditor"
:disabled="isMergeButtonDisabled"
class="js-modify-commit-message-button btn btn-default btn-sm"
type="button">
Modify commit message
</button>
</template>
<template v-else>
<span class="bold js-resolve-mr-widget-items-message">
You can only merge once the items above are resolved
</span>
</template>
</div>
</div>
<div
v-if="showCommitMessageEditor"
class="prepend-top-default commit-message-editor">
<div class="form-group clearfix">
<label
class="col-form-label"
for="commit-message">
Commit message
<template>
<div class="mr-widget-body media">
<status-icon :status="iconClass" />
<div class="media-body">
<div class="mr-widget-body-controls media space-children">
<span class="btn-group append-bottom-5">
<button
@click="handleMergeButtonClick()"
:disabled="isMergeButtonDisabled"
:class="mergeButtonClass"
type="button"
class="qa-merge-button">
<i
v-if="isMakingRequest"
class="fa fa-spinner fa-spin"
aria-hidden="true"
></i>
{{ mergeButtonText }}
</button>
<button
v-if="shouldShowMergeOptionsDropdown"
:disabled="isMergeButtonDisabled"
type="button"
class="btn btn-sm btn-info dropdown-toggle js-merge-moment"
data-toggle="dropdown"
aria-label="Select merge moment">
<i
class="fa fa-chevron-down"
aria-hidden="true"
></i>
</button>
<ul
v-if="shouldShowMergeOptionsDropdown"
class="dropdown-menu dropdown-menu-right"
role="menu">
<li>
<a
@click.prevent="handleMergeButtonClick(true)"
class="merge_when_pipeline_succeeds"
href="#">
<span class="media">
<span
v-html="successSvg"
class="merge-opt-icon"
aria-hidden="true"></span>
<span class="media-body merge-opt-title">Merge when pipeline succeeds</span>
</span>
</a>
</li>
<li>
<a
@click.prevent="handleMergeButtonClick(false, true)"
class="accept-merge-request"
href="#">
<span class="media">
<span
v-html="warningSvg"
class="merge-opt-icon"
aria-hidden="true"></span>
<span class="media-body merge-opt-title">Merge immediately</span>
</span>
</a>
</li>
</ul>
</span>
<div class="media-body-wrap space-children">
<template v-if="shouldShowMergeControls()">
<label v-if="mr.canRemoveSourceBranch">
<input
id="remove-source-branch-input"
v-model="removeSourceBranch"
class="js-remove-source-branch-checkbox"
:disabled="isRemoveSourceBranchButtonDisabled"
type="checkbox"/> Remove source branch
</label>
<div class="col-sm-10">
<div class="commit-message-container">
<div class="max-width-marker"></div>
<textarea
v-model="commitMessage"
class="form-control js-commit-message"
required="required"
rows="14"
name="Commit message"></textarea>
</div>
<p class="hint">Try to keep the first line under 52 characters and the others under 72</p>
<div class="hint">
<a
@click.prevent="updateCommitMessage"
href="#">{{commitMessageLinkTitle}}</a>
</div>
<!-- Placeholder for EE extension of this component -->
<squash-before-merge
v-if="shouldShowSquashBeforeMerge"
:mr="mr"
:is-merge-button-disabled="isMergeButtonDisabled" />
<span
v-if="mr.ffOnlyEnabled"
class="js-fast-forward-message">
Fast-forward merge without a merge commit
</span>
<button
v-else
@click="toggleCommitMessageEditor"
:disabled="isMergeButtonDisabled"
class="js-modify-commit-message-button btn btn-default btn-sm"
type="button">
Modify commit message
</button>
</template>
<template v-else>
<span class="bold js-resolve-mr-widget-items-message">
You can only merge once the items above are resolved
</span>
</template>
</div>
</div>
<div
v-if="showCommitMessageEditor"
class="prepend-top-default commit-message-editor">
<div class="form-group clearfix">
<label
class="col-form-label"
for="commit-message">
Commit message
</label>
<div class="col-sm-10">
<div class="commit-message-container">
<div class="max-width-marker"></div>
<textarea
id="commit-message"
v-model="commitMessage"
class="form-control js-commit-message"
required="required"
rows="14"
name="Commit message"></textarea>
</div>
<p class="hint">
Try to keep the first line under 52 characters and the others under 72
</p>
<div class="hint">
<a
@click.prevent="updateCommitMessage"
href="#"
>
{{ commitMessageLinkTitle }}
</a>
</div>
</div>
</div>
</div>
</div>
`,
};
</div>
</template>

View File

@ -27,7 +27,7 @@ export { default as ConflictsState } from './components/states/mr_widget_conflic
export { default as NothingToMergeState } from './components/states/nothing_to_merge.vue';
export { default as MissingBranchState } from './components/states/mr_widget_missing_branch.vue';
export { default as NotAllowedState } from './components/states/mr_widget_not_allowed.vue';
export { default as ReadyToMergeState } from './components/states/mr_widget_ready_to_merge';
export { default as ReadyToMergeState } from './components/states/ready_to_merge.vue';
export { default as ShaMismatchState } from './components/states/sha_mismatch.vue';
export { default as UnresolvedDiscussionsState } from './components/states/unresolved_discussions.vue';
export { default as PipelineBlockedState } from './components/states/mr_widget_pipeline_blocked.vue';

View File

@ -23,9 +23,12 @@ class InternalId < ActiveRecord::Base
#
# The operation locks the record and gathers a `ROW SHARE` lock (in PostgreSQL).
# As such, the increment is atomic and safe to be called concurrently.
def increment_and_save!
#
# If a `maximum_iid` is passed in, this overrides the incremented value if it's
# greater than that. This can be used to correct the increment value if necessary.
def increment_and_save!(maximum_iid)
lock!
self.last_value = (last_value || 0) + 1
self.last_value = [(last_value || 0) + 1, (maximum_iid || 0) + 1].max
save!
last_value
end
@ -89,7 +92,16 @@ class InternalId < ActiveRecord::Base
# and increment its last value
#
# Note this will acquire a ROW SHARE lock on the InternalId record
(lookup || create_record).increment_and_save!
# Note we always calculate the maximum iid present here and
# pass it in to correct the InternalId entry if it's last_value is off.
#
# This can happen in a transition phase where both `AtomicInternalId` and
# `NonatomicInternalId` code runs (e.g. during a deploy).
#
# This is subject to be cleaned up with the 10.8 release:
# https://gitlab.com/gitlab-org/gitlab-ce/issues/45389.
(lookup || create_record).increment_and_save!(maximum_iid)
end
end
@ -115,11 +127,15 @@ class InternalId < ActiveRecord::Base
InternalId.create!(
**scope,
usage: usage_value,
last_value: init.call(subject) || 0
last_value: maximum_iid
)
end
rescue ActiveRecord::RecordNotUnique
lookup
end
def maximum_iid
@maximum_iid ||= init.call(subject) || 0
end
end
end

View File

@ -0,0 +1,5 @@
---
title: Update faraday_middlewar to 0.12.2
merge_request: 18397
author: Takuya Noguchi
type: security

View File

@ -0,0 +1,5 @@
---
title: Move ReadyToMerge vue component
merge_request: 17545
author: George Tsiolis
type: performance

View File

@ -33,6 +33,10 @@ Follow the steps below to set up a custom hook:
For an installation from source the path is usually
`/home/git/gitlab/plugins/`. For Omnibus installs the path is
usually `/opt/gitlab/embedded/service/gitlab-rails/plugins`.
For [highly available] configurations, your hook file should exist on each
application server.
1. Inside the `plugins` directory, create a file with a name of your choice,
without spaces or special characters.
1. Make the hook file executable and make sure it's owned by the git user.
@ -78,3 +82,4 @@ Validating plugins from /plugins directory
[system hooks]: ../system_hooks/system_hooks.md
[webhooks]: ../user/project/integrations/webhooks.md
[highly available]: ./high_availability/README.md

View File

@ -30,6 +30,7 @@ sast:container:
- mv clair-scanner_linux_amd64 clair-scanner
- chmod +x clair-scanner
- touch clair-whitelist.yml
- while( ! wget -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; done
- ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-sast-container-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
artifacts:
paths: [gl-sast-container-report.json]

View File

@ -72,6 +72,18 @@ concurrent: 10
##
checkInterval: 30
## For RBAC support:
rbac:
create: false
## Run the gitlab-bastion container with the ability to deploy/manage containers of jobs
## cluster-wide or only within namespace
clusterWideAccess: false
## Use the following Kubernetes Service Account name if RBAC is disabled in this Helm chart (see rbac.create)
##
# serviceAccountName: default
## Configuration for the Pods that that the runner launches for each new job
##
runners:
@ -116,6 +128,12 @@ runners:
```
### Enabling RBAC support
If your cluster has RBAC enabled, you can choose to either have the chart create its own sevice account or provide one.
To have the chart create the service account for you, set `rbac.create` to true.
### Controlling maximum Runner concurrency
A single GitLab Runner deployed on Kubernetes is able to execute multiple jobs in parallel by automatically starting additional Runner pods. The [`concurrent` setting](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-global-section) controls the maximum number of pods allowed at a single time, and defaults to `10`.

View File

@ -15,6 +15,10 @@ GitLab [administrators](../README.md#administrator-documentation) receive all pe
To add or import a user, you can follow the
[project members documentation](../user/project/members/index.md).
## Principles behind permissions
See our [product handbook on permissions](https://about.gitlab.com/handbook/product#permissions-in-gitlab)
## Project members permissions
The following table depicts the various user permission levels in a project.

View File

@ -45,6 +45,7 @@ and time spent on
templates for issue and merge request description fields for your project
- [Slash commands (quick actions)](quick_actions.md): Textual shortcuts for
common actions on issues or merge requests
- [Web IDE](web_ide/index.md)
**GitLab CI/CD:**

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,34 @@
# Web IDE
> Introduced in [GitLab Ultimate][ee] 10.4.
> Brought to [GitLab CE][ce] in 10.7.
The Web IDE makes it faster and easier to contribute changes to your projects
by providing an advanced editor with commit staging.
## Open the Web IDE
The Web IDE can be opened when viewing a file, from the repository file list,
and from merge requests.
![Open Web IDE](img/open_web_ide.png)
## Commit changes
Changed files are shown on the right in the commit panel. All changes are
automatically staged. To commit your changes, add a commit message and click
the 'Commit Button'.
![Commit changes](img/commit_changes.png)
## Comparing changes
Before you commit your changes, you can compare them with the previous commit
by switching to the review mode or selecting the file from the staged files
list.
An additional review mode is available when you open a merge request, which
shows you a preview of the merge request diff if you commit your changes.
[ee]: https://about.gitlab.com/products/
[ce]: https://about.gitlab.com/products/

View File

@ -2,7 +2,7 @@ module QA
module Page
module MergeRequest
class Show < Page::Base
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js' do
view 'app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue' do
element :merge_button
element :fast_forward_message, 'Fast-forward merge without a merge commit'
end

View File

@ -1,3 +1,18 @@
export default function removeBreakLine (data) {
return data.replace(/\r?\n|\r/g, ' ');
}
/**
* Replaces line break with an empty space
* @param {*} data
*/
export const removeBreakLine = data => data.replace(/\r?\n|\r/g, ' ');
/**
* Removes line breaks, spaces and trims the given text
* @param {String} str
* @returns {String}
*/
export const trimText = str =>
str
.replace(/\r?\n|\r/g, '')
.replace(/\s\s+/g, ' ')
.trim();
export const removeWhitespace = str => str.replace(/\s\s+/g, ' ');

View File

@ -3,6 +3,7 @@ import store from '~/ide/stores';
import listCollapsed from '~/ide/components/commit_sidebar/list_collapsed.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file } from '../../helpers';
import { removeWhitespace } from '../../../helpers/vue_component_helper';
describe('Multi-file editor commit sidebar list collapsed', () => {
let vm;
@ -23,6 +24,6 @@ describe('Multi-file editor commit sidebar list collapsed', () => {
});
it('renders added & modified files count', () => {
expect(vm.$el.textContent.replace(/\s+/g, ' ').trim()).toBe('1 1');
expect(removeWhitespace(vm.$el.textContent).trim()).toBe('1 1');
});
});

View File

@ -1,7 +1,7 @@
import Vue from 'vue';
import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import removeBreakLine from 'spec/helpers/vue_component_helper';
import { removeBreakLine } from 'spec/helpers/vue_component_helper';
describe('MRWidgetConflicts', () => {
let Component;

View File

@ -1,7 +1,7 @@
import Vue from 'vue';
import pipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import removeBreakLine from 'spec/helpers/vue_component_helper';
import { removeBreakLine } from 'spec/helpers/vue_component_helper';
describe('MRWidgetPipelineBlocked', () => {
let vm;

View File

@ -1,12 +1,12 @@
import Vue from 'vue';
import readyToMergeComponent from '~/vue_merge_request_widget/components/states/mr_widget_ready_to_merge';
import ReadyToMerge from '~/vue_merge_request_widget/components/states/ready_to_merge.vue';
import eventHub from '~/vue_merge_request_widget/event_hub';
import * as simplePoll from '~/lib/utils/simple_poll';
const commitMessage = 'This is the commit message';
const commitMessageWithDescription = 'This is the commit message description';
const createComponent = (customConfig = {}) => {
const Component = Vue.extend(readyToMergeComponent);
const Component = Vue.extend(ReadyToMerge);
const mr = {
isPipelineActive: false,
pipeline: null,
@ -36,7 +36,7 @@ const createComponent = (customConfig = {}) => {
});
};
describe('MRWidgetReadyToMerge', () => {
describe('ReadyToMerge', () => {
let vm;
beforeEach(() => {
@ -49,7 +49,7 @@ describe('MRWidgetReadyToMerge', () => {
describe('props', () => {
it('should have props', () => {
const { mr, service } = readyToMergeComponent.props;
const { mr, service } = ReadyToMerge.props;
expect(mr.type instanceof Object).toBeTruthy();
expect(mr.required).toBeTruthy();

View File

@ -1,7 +1,7 @@
import Vue from 'vue';
import ShaMismatch from '~/vue_merge_request_widget/components/states/sha_mismatch.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import removeBreakLine from 'spec/helpers/vue_component_helper';
import { removeBreakLine } from 'spec/helpers/vue_component_helper';
describe('ShaMismatch', () => {
let vm;

View File

@ -5,7 +5,7 @@ describe InternalId do
let(:usage) { :issues }
let(:issue) { build(:issue, project: project) }
let(:scope) { { project: project } }
let(:init) { ->(s) { s.project.issues.size } }
let(:init) { ->(s) { s.project.issues.maximum(:iid) } }
context 'validations' do
it { is_expected.to validate_presence_of(:usage) }
@ -39,6 +39,29 @@ describe InternalId do
end
end
context 'with an InternalId record present and existing issues with a higher internal id' do
# This can happen if the old NonatomicInternalId is still in use
before do
issues = Array.new(rand(1..10)).map { create(:issue, project: project) }
issue = issues.last
issue.iid = issues.map { |i| i.iid }.max + 1
issue.save
end
let(:maximum_iid) { project.issues.map { |i| i.iid }.max }
it 'updates last_value to the maximum internal id present' do
subject
expect(described_class.find_by(project: project, usage: described_class.usages[usage.to_s]).last_value).to eq(maximum_iid + 1)
end
it 'returns next internal id correctly' do
expect(subject).to eq(maximum_iid + 1)
end
end
context 'with concurrent inserts on table' do
it 'looks up the record if it was created concurrently' do
args = { **scope, usage: described_class.usages[usage.to_s] }
@ -81,7 +104,8 @@ describe InternalId do
describe '#increment_and_save!' do
let(:id) { create(:internal_id) }
subject { id.increment_and_save! }
let(:maximum_iid) { nil }
subject { id.increment_and_save!(maximum_iid) }
it 'returns incremented iid' do
value = id.last_value
@ -102,5 +126,14 @@ describe InternalId do
expect(subject).to eq(1)
end
end
context 'with maximum_iid given' do
let(:id) { create(:internal_id, last_value: 1) }
let(:maximum_iid) { id.last_value + 10 }
it 'returns maximum_iid instead' do
expect(subject).to eq(12)
end
end
end
end

View File

@ -315,6 +315,7 @@ production:
mv clair-scanner_linux_amd64 clair-scanner
chmod +x clair-scanner
touch clair-whitelist.yml
while( ! wget -q -O /dev/null http://docker:6060/v1/namespaces ) ; do sleep 1 ; done
./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-sast-container-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
}