Commit 7fd3c8da authored by Clement Ho's avatar Clement Ho

Merge branch 'master' into bootstrap4

parents df1ebe98 c39ad568
...@@ -45,4 +45,4 @@ When removing columns, tables, indexes or other structures: ...@@ -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) - [ ] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
- [ ] Internationalization required/considered - [ ] 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 - [ ] 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)
...@@ -206,7 +206,7 @@ GEM ...@@ -206,7 +206,7 @@ GEM
railties (>= 3.0.0) railties (>= 3.0.0)
faraday (0.12.2) faraday (0.12.2)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
faraday_middleware (0.11.0.1) faraday_middleware (0.12.2)
faraday (>= 0.7.4, < 1.0) faraday (>= 0.7.4, < 1.0)
faraday_middleware-multi_json (0.0.6) faraday_middleware-multi_json (0.0.6)
faraday_middleware faraday_middleware
......
<script>
import successSvg from 'icons/_icon_status_success.svg'; import successSvg from 'icons/_icon_status_success.svg';
import warningSvg from 'icons/_icon_status_warning.svg'; import warningSvg from 'icons/_icon_status_warning.svg';
import simplePoll from '~/lib/utils/simple_poll'; import simplePoll from '~/lib/utils/simple_poll';
...@@ -7,7 +8,10 @@ import statusIcon from '../mr_widget_status_icon.vue'; ...@@ -7,7 +8,10 @@ import statusIcon from '../mr_widget_status_icon.vue';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
export default { export default {
name: 'MRWidgetReadyToMerge', name: 'ReadyToMerge',
components: {
statusIcon,
},
props: { props: {
mr: { type: Object, required: true }, mr: { type: Object, required: true },
service: { type: Object, required: true }, service: { type: Object, required: true },
...@@ -26,9 +30,6 @@ export default { ...@@ -26,9 +30,6 @@ export default {
warningSvg, warningSvg,
}; };
}, },
components: {
statusIcon,
},
computed: { computed: {
shouldShowMergeWhenPipelineSucceedsText() { shouldShowMergeWhenPipelineSucceedsText() {
return this.mr.isPipelineActive; return this.mr.isPipelineActive;
...@@ -217,136 +218,146 @@ export default { ...@@ -217,136 +218,146 @@ export default {
}); });
}, },
}, },
template: ` };
<div class="mr-widget-body media"> </script>
<status-icon :status="iconClass" />
<div class="media-body"> <template>
<div class="mr-widget-body-controls media space-children"> <div class="mr-widget-body media">
<span class="btn-group append-bottom-5"> <status-icon :status="iconClass" />
<button <div class="media-body">
@click="handleMergeButtonClick()" <div class="mr-widget-body-controls media space-children">
:disabled="isMergeButtonDisabled" <span class="btn-group append-bottom-5">
:class="mergeButtonClass" <button
type="button" @click="handleMergeButtonClick()"
class="qa-merge-button"> :disabled="isMergeButtonDisabled"
<i :class="mergeButtonClass"
v-if="isMakingRequest" type="button"
class="fa fa-spinner fa-spin" class="qa-merge-button">
aria-hidden="true" /> <i
{{mergeButtonText}} v-if="isMakingRequest"
</button> 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>
<!-- 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 <button
v-if="shouldShowMergeOptionsDropdown" v-else
@click="toggleCommitMessageEditor"
:disabled="isMergeButtonDisabled" :disabled="isMergeButtonDisabled"
type="button" class="js-modify-commit-message-button btn btn-default btn-sm"
class="btn btn-sm btn-info dropdown-toggle js-merge-moment" type="button">
data-toggle="dropdown" Modify commit message
aria-label="Select merge moment">
<i
class="fa fa-chevron-down"
aria-hidden="true" />
</button> </button>
<ul </template>
v-if="shouldShowMergeOptionsDropdown" <template v-else>
class="dropdown-menu dropdown-menu-right" <span class="bold js-resolve-mr-widget-items-message">
role="menu"> You can only merge once the items above are resolved
<li> </span>
<a </template>
@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>
<!-- 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>
<div </div>
v-if="showCommitMessageEditor" <div
class="prepend-top-default commit-message-editor"> v-if="showCommitMessageEditor"
<div class="form-group clearfix"> class="prepend-top-default commit-message-editor">
<label <div class="form-group clearfix">
class="col-form-label" <label
for="commit-message"> class="col-form-label"
Commit message for="commit-message">
</label> Commit message
<div class="col-sm-10"> </label>
<div class="commit-message-container"> <div class="col-sm-10">
<div class="max-width-marker"></div> <div class="commit-message-container">
<textarea <div class="max-width-marker"></div>
v-model="commitMessage" <textarea
class="form-control js-commit-message" id="commit-message"
required="required" v-model="commitMessage"
rows="14" class="form-control js-commit-message"
name="Commit message"></textarea> required="required"
</div> rows="14"
<p class="hint">Try to keep the first line under 52 characters and the others under 72</p> name="Commit message"></textarea>
<div class="hint"> </div>
<a <p class="hint">
@click.prevent="updateCommitMessage" Try to keep the first line under 52 characters and the others under 72
href="#">{{commitMessageLinkTitle}}</a> </p>
</div> <div class="hint">
<a
@click.prevent="updateCommitMessage"
href="#"
>
{{ commitMessageLinkTitle }}
</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
`, </div>
}; </template>
...@@ -27,7 +27,7 @@ export { default as ConflictsState } from './components/states/mr_widget_conflic ...@@ -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 NothingToMergeState } from './components/states/nothing_to_merge.vue';
export { default as MissingBranchState } from './components/states/mr_widget_missing_branch.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 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 ShaMismatchState } from './components/states/sha_mismatch.vue';
export { default as UnresolvedDiscussionsState } from './components/states/unresolved_discussions.vue'; export { default as UnresolvedDiscussionsState } from './components/states/unresolved_discussions.vue';
export { default as PipelineBlockedState } from './components/states/mr_widget_pipeline_blocked.vue'; export { default as PipelineBlockedState } from './components/states/mr_widget_pipeline_blocked.vue';
......
...@@ -23,9 +23,12 @@ class InternalId < ActiveRecord::Base ...@@ -23,9 +23,12 @@ class InternalId < ActiveRecord::Base
# #
# The operation locks the record and gathers a `ROW SHARE` lock (in PostgreSQL). # 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. # 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! lock!
self.last_value = (last_value || 0) + 1 self.last_value = [(last_value || 0) + 1, (maximum_iid || 0) + 1].max
save! save!
last_value last_value
end end
...@@ -89,7 +92,16 @@ class InternalId < ActiveRecord::Base ...@@ -89,7 +92,16 @@ class InternalId < ActiveRecord::Base
# and increment its last value # and increment its last value
# #
# Note this will acquire a ROW SHARE lock on the InternalId record # 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
end end
...@@ -115,11 +127,15 @@ class InternalId < ActiveRecord::Base ...@@ -115,11 +127,15 @@ class InternalId < ActiveRecord::Base
InternalId.create!( InternalId.create!(
**scope, **scope,
usage: usage_value, usage: usage_value,
last_value: init.call(subject) || 0 last_value: maximum_iid
) )
end end
rescue ActiveRecord::RecordNotUnique rescue ActiveRecord::RecordNotUnique
lookup lookup
end end
def maximum_iid
@maximum_iid ||= init.call(subject) || 0
end
end end
end end
---
title: Update faraday_middlewar to 0.12.2
merge_request: 18397
author: Takuya Noguchi
type: security
---
title: Move ReadyToMerge vue component
merge_request: 17545
author: George Tsiolis
type: performance
...@@ -33,6 +33,10 @@ Follow the steps below to set up a custom hook: ...@@ -33,6 +33,10 @@ Follow the steps below to set up a custom hook:
For an installation from source the path is usually For an installation from source the path is usually
`/home/git/gitlab/plugins/`. For Omnibus installs the path is `/home/git/gitlab/plugins/`. For Omnibus installs the path is
usually `/opt/gitlab/embedded/service/gitlab-rails/plugins`. 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, 1. Inside the `plugins` directory, create a file with a name of your choice,
without spaces or special characters. without spaces or special characters.
1. Make the hook file executable and make sure it's owned by the git user. 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 ...@@ -78,3 +82,4 @@ Validating plugins from /plugins directory
[system hooks]: ../system_hooks/system_hooks.md [system hooks]: ../system_hooks/system_hooks.md
[webhooks]: ../user/project/integrations/webhooks.md [webhooks]: ../user/project/integrations/webhooks.md
[highly available]: ./high_availability/README.md
\ No newline at end of file
...@@ -30,6 +30,7 @@ sast:container: ...@@ -30,6 +30,7 @@ sast:container:
- mv clair-scanner_linux_amd64 clair-scanner - mv clair-scanner_linux_amd64 clair-scanner
- chmod +x clair-scanner - chmod +x clair-scanner
- touch clair-whitelist.yml - 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 - ./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: artifacts:
paths: [gl-sast-container-report.json] paths: [gl-sast-container-report.json]
......
...@@ -72,6 +72,18 @@ concurrent: 10 ...@@ -72,6 +72,18 @@ concurrent: 10
## ##
checkInterval: 30 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 ## Configuration for the Pods that that the runner launches for each new job
## ##
runners: runners:
...@@ -116,6 +128,12 @@ 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 ### 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`. 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`.
......
...@@ -15,6 +15,10 @@ GitLab [administrators](../README.md#administrator-documentation) receive all pe ...@@ -15,6 +15,10 @@ GitLab [administrators](../README.md#administrator-documentation) receive all pe
To add or import a user, you can follow the To add or import a user, you can follow the
[project members documentation](../user/project/members/index.md). [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 ## Project members permissions
The following table depicts the various user permission levels in a project. The following table depicts the various user permission levels in a project.
......
...@@ -45,6 +45,7 @@ and time spent on ...@@ -45,6 +45,7 @@ and time spent on
templates for issue and merge request description fields for your project templates for issue and merge request description fields for your project
- [Slash commands (quick actions)](quick_actions.md): Textual shortcuts for - [Slash commands (quick actions)](quick_actions.md): Textual shortcuts for
common actions on issues or merge requests common actions on issues or merge requests
- [Web IDE](web_ide/index.md)
**GitLab CI/CD:** **GitLab CI/CD:**
......
# 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/
...@@ -2,7 +2,7 @@ module QA ...@@ -2,7 +2,7 @@ module QA
module Page module Page
module MergeRequest module MergeRequest
class Show < Page::Base 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 :merge_button
element :fast_forward_message, 'Fast-forward merge without a merge commit' element :fast_forward_message, 'Fast-forward merge without a merge commit'
end end
......
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, ' ');
...@@ -3,6 +3,7 @@ import store from '~/ide/stores'; ...@@ -3,6 +3,7 @@ import store from '~/ide/stores';
import listCollapsed from '~/ide/components/commit_sidebar/list_collapsed.vue'; import listCollapsed from '~/ide/components/commit_sidebar/list_collapsed.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file } from '../../helpers'; import { file } from '../../helpers';
import { removeWhitespace } from '../../../helpers/vue_component_helper';
describe('Multi-file editor commit sidebar list collapsed', () => { describe('Multi-file editor commit sidebar list collapsed', () => {
let vm; let vm;
...@@ -23,6 +24,6 @@ describe('Multi-file editor commit sidebar list collapsed', () => { ...@@ -23,6 +24,6 @@ describe('Multi-file editor commit sidebar list collapsed', () => {
}); });
it('renders added & modified files count', () => { 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');
}); });
}); });
import Vue from 'vue'; import Vue from 'vue';
import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue'; import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; 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', () => { describe('MRWidgetConflicts', () => {
let Component; let Component;
......
import Vue from 'vue'; import Vue from 'vue';
import pipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.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 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', () => { describe('MRWidgetPipelineBlocked', () => {
let vm; let vm;
......
import Vue from 'vue'; 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 eventHub from '~/vue_merge_request_widget/event_hub';
import * as simplePoll from '~/lib/utils/simple_poll'; import * as simplePoll from '~/lib/utils/simple_poll';
const commitMessage = 'This is the commit message'; const commitMessage = 'This is the commit message';
const commitMessageWithDescription = 'This is the commit message description'; const commitMessageWithDescription = 'This is the commit message description';
const createComponent = (customConfig = {}) => { const createComponent = (customConfig = {}) => {
const Component = Vue.extend(readyToMergeComponent); const Component = Vue.extend(ReadyToMerge);
const mr = { const mr = {
isPipelineActive: false, isPipelineActive: false,
pipeline: null, pipeline: null,
...@@ -36,7 +36,7 @@ const createComponent = (customConfig = {}) => { ...@@ -36,7 +36,7 @@ const createComponent = (customConfig = {}) => {
}); });
}; };
describe('MRWidgetReadyToMerge', () => { describe('ReadyToMerge', () => {
let vm; let vm;
beforeEach(() => { beforeEach(() => {
...@@ -49,7 +49,7 @@ describe('MRWidgetReadyToMerge', () => { ...@@ -49,7 +49,7 @@ describe('MRWidgetReadyToMerge', () => {
describe('props', () => { describe('props', () => {
it('should have props', () => { it('should have props', () => {
const { mr, service } = readyToMergeComponent.props; const { mr, service } = ReadyToMerge.props;
expect(mr.type instanceof Object).toBeTruthy(); expect(mr.type instanceof Object).toBeTruthy();
expect(mr.required).toBeTruthy(); expect(mr.required).toBeTruthy();
......
import Vue from 'vue'; import Vue from 'vue';
import ShaMismatch from '~/vue_merge_request_widget/components/states/sha_mismatch.vue'; import ShaMismatch from '~/vue_merge_request_widget/components/states/sha_mismatch.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; 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', () => { describe('ShaMismatch', () => {
let vm; let vm;
......
...@@ -5,7 +5,7 @@ describe InternalId do ...@@ -5,7 +5,7 @@ describe InternalId do
let(:usage) { :issues } let(:usage) { :issues }
let(:issue) { build(:issue, project: project) } let(:issue) { build(:issue, project: project) }
let(:scope) { { project: project } } let(:scope) { { project: project } }
let(:init) { ->(s) { s.project.issues.size } } let(:init) { ->(s) { s.project.issues.maximum(:iid) } }
context 'validations' do context 'validations' do
it { is_expected.to validate_presence_of(:usage) } it { is_expected.to validate_presence_of(:usage) }
...@@ -39,6 +39,29 @@ describe InternalId do ...@@ -39,6 +39,29 @@ describe InternalId do
end end
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 context 'with concurrent inserts on table' do
it 'looks up the record if it was created concurrently' do it 'looks up the record if it was created concurrently' do
args = { **scope, usage: described_class.usages[usage.to_s] } args = { **scope, usage: described_class.usages[usage.to_s] }
...@@ -81,7 +104,8 @@ describe InternalId do ...@@ -81,7 +104,8 @@ describe InternalId do
describe '#increment_and_save!' do describe '#increment_and_save!' do
let(:id) { create(:internal_id) } 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 it 'returns incremented iid' do
value = id.last_value value = id.last_value
...@@ -102,5 +126,14 @@ describe InternalId do ...@@ -102,5 +126,14 @@ describe InternalId do
expect(subject).to eq(1) expect(subject).to eq(1)
end end
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
end end
...@@ -315,6 +315,7 @@ production: ...@@ -315,6 +315,7 @@ production:
mv clair-scanner_linux_amd64 clair-scanner mv clair-scanner_linux_amd64 clair-scanner
chmod +x clair-scanner chmod +x clair-scanner
touch clair-whitelist.yml 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 ./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
} }
......
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