Merge branch 'master-ce' into check-unique-values-of-pipeline-enum
This commit is contained in:
commit
5b24739eb3
24
CHANGELOG.md
24
CHANGELOG.md
|
@ -2,6 +2,22 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 11.5.2 (2018-12-03)
|
||||
|
||||
### Removed (1 change)
|
||||
|
||||
- Removed Site Statistics optimization as it was causing problems. !23314
|
||||
|
||||
### Fixed (6 changes, 1 of them is from the community)
|
||||
|
||||
- Display impersonation token value only after creation. !22916
|
||||
- Fix not render emoji in filter dropdown. !23112 (Hiroyuki Sato)
|
||||
- Fixes stuck tooltip on stop env button. !23244
|
||||
- Correctly handle data-loss scenarios when encrypting columns. !23306
|
||||
- Clear BatchLoader context between Sidekiq jobs. !23308
|
||||
- Fix handling of filenames with hash characters in tree view. !23368
|
||||
|
||||
|
||||
## 11.5.1 (2018-11-26)
|
||||
|
||||
### Security (17 changes)
|
||||
|
@ -287,6 +303,14 @@ entry.
|
|||
- Disables stop environment button while the deploy is in progress.
|
||||
|
||||
|
||||
## 11.4.9 (2018-12-03)
|
||||
|
||||
### Fixed (2 changes)
|
||||
|
||||
- Display impersonation token value only after creation. !22916
|
||||
- Correctly handle data-loss scenarios when encrypting columns. !23306
|
||||
|
||||
|
||||
## 11.4.8 (2018-11-27)
|
||||
|
||||
### Security (24 changes)
|
||||
|
|
|
@ -181,4 +181,4 @@ This [documentation](doc/development/contributing/merge_request_workflow.md) has
|
|||
|
||||
## Style guides
|
||||
|
||||
This [documentation](doc/development/contributing/design.md) has been moved.
|
||||
This [documentation](doc/development/contributing/style_guides.md) has been moved.
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -82,7 +82,7 @@ gem 'validates_hostname', '~> 1.0.6'
|
|||
gem 'browser', '~> 2.5'
|
||||
|
||||
# GPG
|
||||
gem 'gpgme'
|
||||
gem 'gpgme', '~> 2.0.18'
|
||||
|
||||
# LDAP Auth
|
||||
# GitLab fork with several improvements to original library. For full list of changes
|
||||
|
|
|
@ -313,8 +313,8 @@ GEM
|
|||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (~> 0.7)
|
||||
gpgme (2.0.13)
|
||||
mini_portile2 (~> 2.1)
|
||||
gpgme (2.0.18)
|
||||
mini_portile2 (~> 2.3)
|
||||
grape (1.1.0)
|
||||
activesupport
|
||||
builder
|
||||
|
@ -1016,7 +1016,7 @@ DEPENDENCIES
|
|||
gon (~> 6.2)
|
||||
google-api-client (~> 0.23)
|
||||
google-protobuf (~> 3.6)
|
||||
gpgme
|
||||
gpgme (~> 2.0.18)
|
||||
grape (~> 1.1.0)
|
||||
grape-entity (~> 0.7.1)
|
||||
grape-path-helpers (~> 1.0)
|
||||
|
|
|
@ -310,8 +310,8 @@ GEM
|
|||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (~> 0.7)
|
||||
gpgme (2.0.13)
|
||||
mini_portile2 (~> 2.1)
|
||||
gpgme (2.0.18)
|
||||
mini_portile2 (~> 2.3)
|
||||
grape (1.1.0)
|
||||
activesupport
|
||||
builder
|
||||
|
@ -1007,7 +1007,7 @@ DEPENDENCIES
|
|||
gon (~> 6.2)
|
||||
google-api-client (~> 0.23)
|
||||
google-protobuf (~> 3.6)
|
||||
gpgme
|
||||
gpgme (~> 2.0.18)
|
||||
grape (~> 1.1.0)
|
||||
grape-entity (~> 0.7.1)
|
||||
grape-path-helpers (~> 1.0)
|
||||
|
|
|
@ -88,10 +88,15 @@ export const conditions = [
|
|||
value: 'started',
|
||||
},
|
||||
{
|
||||
url: 'label_name[]=No+Label',
|
||||
url: 'label_name[]=None',
|
||||
tokenKey: 'label',
|
||||
value: 'none',
|
||||
},
|
||||
{
|
||||
url: 'label_name[]=Any',
|
||||
tokenKey: 'any',
|
||||
value: 'any',
|
||||
},
|
||||
{
|
||||
url: 'my_reaction_emoji=None',
|
||||
tokenKey: 'my-reaction',
|
||||
|
|
|
@ -105,7 +105,7 @@ export default {
|
|||
:key="tabView.name"
|
||||
class="h-100"
|
||||
>
|
||||
<component :is="tabView.name" />
|
||||
<component :is="tabView.component || tabView.name" />
|
||||
</div>
|
||||
</resizable-panel>
|
||||
<nav class="ide-activity-bar">
|
||||
|
|
|
@ -30,6 +30,7 @@ export default class MirrorRepos {
|
|||
this.$password.on('input.updateUrl', () => this.debouncedUpdateUrl());
|
||||
|
||||
this.initMirrorSSH();
|
||||
this.updateProtectedBranches();
|
||||
}
|
||||
|
||||
initMirrorSSH() {
|
||||
|
|
|
@ -18,23 +18,19 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
graph() {
|
||||
return this.pipeline.details && this.pipeline.details.stages;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
capitalizeStageName(name) {
|
||||
const escapedName = _.escape(name);
|
||||
return escapedName.charAt(0).toUpperCase() + escapedName.slice(1);
|
||||
},
|
||||
|
||||
isFirstColumn(index) {
|
||||
return index === 0;
|
||||
},
|
||||
|
||||
stageConnectorClass(index, stage) {
|
||||
let className;
|
||||
|
||||
|
@ -48,7 +44,6 @@ export default {
|
|||
|
||||
return className;
|
||||
},
|
||||
|
||||
refreshPipelineGraph() {
|
||||
this.$emit('refreshPipelineGraph');
|
||||
},
|
||||
|
|
|
@ -84,10 +84,6 @@ export default {
|
|||
|
||||
return textBuilder.join(' ');
|
||||
},
|
||||
|
||||
tooltipBoundary() {
|
||||
return this.dropdownLength < 5 ? 'viewport' : null;
|
||||
},
|
||||
/**
|
||||
* Verifies if the provided job has an action path
|
||||
*
|
||||
|
@ -108,7 +104,7 @@ export default {
|
|||
<div class="ci-job-component">
|
||||
<gl-link
|
||||
v-if="status.has_details"
|
||||
v-gl-tooltip="{ boundary: tooltipBoundary }"
|
||||
v-gl-tooltip
|
||||
:href="status.details_path"
|
||||
:title="tooltipText"
|
||||
:class="cssClassJobName"
|
||||
|
|
|
@ -23,11 +23,11 @@ export default class Star {
|
|||
if (isStarred) {
|
||||
$starSpan.removeClass('starred').text(s__('StarProject|Star'));
|
||||
$startIcon.remove();
|
||||
$this.prepend(spriteIcon('star-o'));
|
||||
$this.prepend(spriteIcon('star-o', 'icon'));
|
||||
} else {
|
||||
$starSpan.addClass('starred').text(__('Unstar'));
|
||||
$startIcon.remove();
|
||||
$this.prepend(spriteIcon('star'));
|
||||
$this.prepend(spriteIcon('star', 'icon'));
|
||||
}
|
||||
})
|
||||
.catch(() => Flash('Star toggle failed. Try again later.'));
|
||||
|
|
|
@ -112,7 +112,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mr-widget-heading deploy-heading append-bottom-default">
|
||||
<div class="deploy-heading">
|
||||
<div class="ci-widget media">
|
||||
<div class="media-body">
|
||||
<div class="deploy-body">
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<template>
|
||||
<div class="mr-widget-heading">
|
||||
<div class="mr-widget-content"><slot name="default"></slot></div>
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</template>
|
|
@ -6,6 +6,7 @@ import Icon from '~/vue_shared/components/icon.vue';
|
|||
import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import tooltip from '~/vue_shared/directives/tooltip';
|
||||
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
|
||||
import MrWidgetIcon from './mr_widget_icon.vue';
|
||||
|
||||
export default {
|
||||
name: 'MRWidgetHeader',
|
||||
|
@ -13,6 +14,7 @@ export default {
|
|||
Icon,
|
||||
clipboardButton,
|
||||
TooltipOnTruncate,
|
||||
MrWidgetIcon,
|
||||
},
|
||||
directives: {
|
||||
tooltip,
|
||||
|
@ -76,7 +78,7 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<div class="mr-source-target append-bottom-default">
|
||||
<div class="git-merge-icon-container append-right-default"><icon name="git-merge" /></div>
|
||||
<mr-widget-icon name="git-merge" />
|
||||
<div class="git-merge-container d-flex">
|
||||
<div class="normal">
|
||||
<strong>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<script>
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
|
||||
export default {
|
||||
components: { Icon },
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="circle-icon-container append-right-default"><icon :name="name" /></div>
|
||||
</template>
|
|
@ -79,67 +79,65 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="hasPipeline || hasCIError" class="mr-widget-heading append-bottom-default">
|
||||
<div class="ci-widget media">
|
||||
<template v-if="hasCIError">
|
||||
<div
|
||||
class="add-border ci-status-icon ci-status-icon-failed ci-error
|
||||
js-ci-error append-right-default"
|
||||
>
|
||||
<icon :size="32" name="status_failed_borderless" />
|
||||
</div>
|
||||
<div class="media-body" v-html="errorText"></div>
|
||||
</template>
|
||||
<template v-else-if="hasPipeline">
|
||||
<a :href="status.details_path" class="align-self-start append-right-default">
|
||||
<ci-icon :status="status" :size="32" :borderless="true" class="add-border" />
|
||||
</a>
|
||||
<div class="ci-widget-container d-flex">
|
||||
<div class="ci-widget-content">
|
||||
<div class="media-body">
|
||||
<div class="font-weight-bold">
|
||||
Pipeline
|
||||
<a :href="pipeline.path" class="pipeline-id font-weight-normal pipeline-number"
|
||||
>#{{ pipeline.id }}</a
|
||||
<div v-if="hasPipeline || hasCIError" class="ci-widget media">
|
||||
<template v-if="hasCIError">
|
||||
<div
|
||||
class="add-border ci-status-icon ci-status-icon-failed ci-error
|
||||
js-ci-error append-right-default"
|
||||
>
|
||||
<icon :size="32" name="status_failed_borderless" />
|
||||
</div>
|
||||
<div class="media-body" v-html="errorText"></div>
|
||||
</template>
|
||||
<template v-else-if="hasPipeline">
|
||||
<a :href="status.details_path" class="align-self-start append-right-default">
|
||||
<ci-icon :status="status" :size="32" :borderless="true" class="add-border" />
|
||||
</a>
|
||||
<div class="ci-widget-container d-flex">
|
||||
<div class="ci-widget-content">
|
||||
<div class="media-body">
|
||||
<div class="font-weight-bold">
|
||||
Pipeline
|
||||
<a :href="pipeline.path" class="pipeline-id font-weight-normal pipeline-number"
|
||||
>#{{ pipeline.id }}</a
|
||||
>
|
||||
|
||||
{{ pipeline.details.status.label }}
|
||||
|
||||
<template v-if="hasCommitInfo">
|
||||
for
|
||||
<a
|
||||
:href="pipeline.commit.commit_path"
|
||||
class="commit-sha js-commit-link font-weight-normal"
|
||||
>
|
||||
|
||||
{{ pipeline.details.status.label }}
|
||||
|
||||
<template v-if="hasCommitInfo">
|
||||
for
|
||||
<a
|
||||
:href="pipeline.commit.commit_path"
|
||||
class="commit-sha js-commit-link font-weight-normal"
|
||||
>
|
||||
{{ pipeline.commit.short_id }}</a
|
||||
>
|
||||
on
|
||||
<tooltip-on-truncate
|
||||
:title="sourceBranch"
|
||||
truncate-target="child"
|
||||
class="label-branch label-truncate"
|
||||
v-html="sourceBranchLink"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="pipeline.coverage" class="coverage">Coverage {{ pipeline.coverage }}%</div>
|
||||
{{ pipeline.commit.short_id }}</a
|
||||
>
|
||||
on
|
||||
<tooltip-on-truncate
|
||||
:title="sourceBranch"
|
||||
truncate-target="child"
|
||||
class="label-branch label-truncate"
|
||||
v-html="sourceBranchLink"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="mr-widget-pipeline-graph">
|
||||
<span v-if="hasStages" class="stage-cell">
|
||||
<div
|
||||
v-for="(stage, i) in pipeline.details.stages"
|
||||
:key="i"
|
||||
class="stage-container dropdown js-mini-pipeline-graph mr-widget-pipeline-stages"
|
||||
>
|
||||
<pipeline-stage :stage="stage" />
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
<div v-if="pipeline.coverage" class="coverage">Coverage {{ pipeline.coverage }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div>
|
||||
<span class="mr-widget-pipeline-graph">
|
||||
<span v-if="hasStages" class="stage-cell">
|
||||
<div
|
||||
v-for="(stage, i) in pipeline.details.stages"
|
||||
:key="i"
|
||||
class="stage-container dropdown js-mini-pipeline-graph mr-widget-pipeline-stages"
|
||||
>
|
||||
<pipeline-stage :stage="stage" />
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<script>
|
||||
import Deployment from './deployment.vue';
|
||||
import MrWidgetContainer from './mr_widget_container.vue';
|
||||
import MrWidgetPipeline from './mr_widget_pipeline.vue';
|
||||
|
||||
/**
|
||||
* Renders the pipeline and related deployments from the store.
|
||||
*
|
||||
* | Props | Description
|
||||
* |---------------|-------------
|
||||
* | `mr` | This is the mr_widget store
|
||||
* | `isPostMerge` | If true, show the "post merge" pipeline and deployments
|
||||
*/
|
||||
export default {
|
||||
name: 'MrWidgetPipelineContainer',
|
||||
components: {
|
||||
Deployment,
|
||||
MrWidgetContainer,
|
||||
MrWidgetPipeline,
|
||||
},
|
||||
props: {
|
||||
mr: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isPostMerge: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
pipeline() {
|
||||
return this.isPostMerge ? this.mr.mergePipeline : this.mr.pipeline;
|
||||
},
|
||||
branch() {
|
||||
return this.isPostMerge ? this.mr.targetBranch : this.mr.sourceBranch;
|
||||
},
|
||||
branchLink() {
|
||||
return this.isPostMerge ? this.mr.targetBranch : this.mr.sourceBranchLink;
|
||||
},
|
||||
deployments() {
|
||||
return this.isPostMerge ? this.mr.postMergeDeployments : this.mr.deployments;
|
||||
},
|
||||
deploymentClass() {
|
||||
return this.isPostMerge ? 'js-post-deployment' : 'js-pre-deployment';
|
||||
},
|
||||
hasDeploymentMetrics() {
|
||||
return this.isPostMerge;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<mr-widget-container>
|
||||
<mr-widget-pipeline
|
||||
:pipeline="pipeline"
|
||||
:ci-status="mr.ciStatus"
|
||||
:has-ci="mr.hasCI"
|
||||
:source-branch="branch"
|
||||
:source-branch-link="branchLink"
|
||||
:troubleshooting-docs-path="mr.troubleshootingDocsPath"
|
||||
/>
|
||||
<div v-if="deployments.length" slot="footer" class="mr-widget-extension">
|
||||
<deployment
|
||||
v-for="deployment in deployments"
|
||||
:key="deployment.id"
|
||||
:class="deploymentClass"
|
||||
:deployment="deployment"
|
||||
:show-metrics="hasDeploymentMetrics"
|
||||
/>
|
||||
</div>
|
||||
</mr-widget-container>
|
||||
</template>
|
|
@ -6,7 +6,7 @@ import SmartInterval from '~/smart_interval';
|
|||
import createFlash from '../flash';
|
||||
import WidgetHeader from './components/mr_widget_header.vue';
|
||||
import WidgetMergeHelp from './components/mr_widget_merge_help.vue';
|
||||
import WidgetPipeline from './components/mr_widget_pipeline.vue';
|
||||
import MrWidgetPipelineContainer from './components/mr_widget_pipeline_container.vue';
|
||||
import Deployment from './components/deployment.vue';
|
||||
import WidgetRelatedLinks from './components/mr_widget_related_links.vue';
|
||||
import MergedState from './components/states/mr_widget_merged.vue';
|
||||
|
@ -44,7 +44,7 @@ export default {
|
|||
components: {
|
||||
'mr-widget-header': WidgetHeader,
|
||||
'mr-widget-merge-help': WidgetMergeHelp,
|
||||
'mr-widget-pipeline': WidgetPipeline,
|
||||
MrWidgetPipelineContainer,
|
||||
Deployment,
|
||||
'mr-widget-related-links': WidgetRelatedLinks,
|
||||
'mr-widget-merged': MergedState,
|
||||
|
@ -296,23 +296,12 @@ export default {
|
|||
<template>
|
||||
<div class="mr-state-widget prepend-top-default">
|
||||
<mr-widget-header :mr="mr" />
|
||||
<mr-widget-pipeline
|
||||
<mr-widget-pipeline-container
|
||||
v-if="shouldRenderPipelines"
|
||||
:pipeline="mr.pipeline"
|
||||
:ci-status="mr.ciStatus"
|
||||
:has-ci="mr.hasCI"
|
||||
:source-branch="mr.sourceBranch"
|
||||
:source-branch-link="mr.sourceBranchLink"
|
||||
:troubleshooting-docs-path="mr.troubleshootingDocsPath"
|
||||
class="mr-widget-workflow"
|
||||
:mr="mr"
|
||||
/>
|
||||
<deployment
|
||||
v-for="deployment in mr.deployments"
|
||||
:key="`pre-merge-deploy-${deployment.id}`"
|
||||
class="js-pre-merge-deploy"
|
||||
:deployment="deployment"
|
||||
:show-metrics="false"
|
||||
/>
|
||||
<div class="mr-section-container">
|
||||
<div class="mr-section-container mr-widget-workflow">
|
||||
<grouped-test-reports-app
|
||||
v-if="mr.testResultsPath"
|
||||
class="js-reports-container"
|
||||
|
@ -336,24 +325,11 @@ export default {
|
|||
</div>
|
||||
<div v-if="shouldRenderMergeHelp" class="mr-widget-footer"><mr-widget-merge-help /></div>
|
||||
</div>
|
||||
|
||||
<template v-if="shouldRenderMergedPipeline">
|
||||
<mr-widget-pipeline
|
||||
class="js-post-merge-pipeline prepend-top-default"
|
||||
:pipeline="mr.mergePipeline"
|
||||
:ci-status="mr.ciStatus"
|
||||
:has-ci="mr.hasCI"
|
||||
:source-branch="mr.targetBranch"
|
||||
:source-branch-link="mr.targetBranch"
|
||||
:troubleshooting-docs-path="mr.troubleshootingDocsPath"
|
||||
/>
|
||||
<deployment
|
||||
v-for="postMergeDeployment in mr.postMergeDeployments"
|
||||
:key="`post-merge-deploy-${postMergeDeployment.id}`"
|
||||
:deployment="postMergeDeployment"
|
||||
:show-metrics="true"
|
||||
class="js-post-deployment"
|
||||
/>
|
||||
</template>
|
||||
<mr-widget-pipeline-container
|
||||
v-if="shouldRenderMergedPipeline"
|
||||
class="js-post-merge-pipeline mr-widget-workflow"
|
||||
:mr="mr"
|
||||
:is-post-merge="true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
@import 'bootstrap_migration';
|
||||
@import 'framework/layout';
|
||||
|
||||
@import 'framework/alerts';
|
||||
@import 'framework/animations';
|
||||
@import 'framework/vue_transitions';
|
||||
@import 'framework/avatar';
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
.alert-tip {
|
||||
background-color: $theme-gray-100;
|
||||
color: $theme-gray-900;
|
||||
}
|
|
@ -363,6 +363,12 @@
|
|||
background-color: $white-light;
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.filter-dropdown-container {
|
||||
.dropdown {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
|
@ -372,16 +378,6 @@
|
|||
.dropdown-menu {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.fa-chevron-down {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
padding: 10px;
|
||||
text-align: right;
|
||||
float: left;
|
||||
line-height: 1;
|
||||
|
||||
a {
|
||||
font-family: $monospace-font;
|
||||
|
|
|
@ -80,3 +80,15 @@
|
|||
.user-avatar-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.circle-icon-container {
|
||||
$border-size: 1px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: $border-size solid $theme-gray-400;
|
||||
border-radius: 50%;
|
||||
padding: $gl-padding-8 - $border-size;
|
||||
color: $theme-gray-700;
|
||||
}
|
||||
|
|
|
@ -158,6 +158,10 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-menu-toggle {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
form {
|
||||
display: block;
|
||||
height: auto;
|
||||
|
|
|
@ -50,9 +50,19 @@
|
|||
.mr-widget-heading {
|
||||
position: relative;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 4px;
|
||||
border-radius: $border-radius-default;
|
||||
}
|
||||
|
||||
&:not(.deploy-heading)::before {
|
||||
.mr-widget-extension {
|
||||
border-top: 1px solid $border-color;
|
||||
background-color: $gray-light;
|
||||
}
|
||||
|
||||
.mr-widget-workflow {
|
||||
margin-top: $gl-padding;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
border-left: 1px solid $theme-gray-200;
|
||||
position: absolute;
|
||||
|
@ -68,8 +78,8 @@
|
|||
border-top: 0;
|
||||
}
|
||||
|
||||
.mr-widget-heading,
|
||||
.mr-widget-section,
|
||||
.mr-widget-content,
|
||||
.mr-widget-footer {
|
||||
padding: $gl-padding;
|
||||
}
|
||||
|
@ -560,19 +570,6 @@
|
|||
color: $gl-text-color;
|
||||
}
|
||||
|
||||
.git-merge-icon-container {
|
||||
border: 1px solid $theme-gray-400;
|
||||
border-radius: 50%;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
color: $theme-gray-700;
|
||||
line-height: 28px;
|
||||
|
||||
.ic-git-merge {
|
||||
vertical-align: middle;
|
||||
width: 31px;
|
||||
}
|
||||
}
|
||||
|
||||
.git-merge-container {
|
||||
justify-content: space-between;
|
||||
|
@ -854,11 +851,6 @@
|
|||
}
|
||||
|
||||
.deploy-heading {
|
||||
margin-top: -19px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
background-color: $gray-light;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
padding: $gl-padding-8 $gl-padding;
|
||||
}
|
||||
|
@ -868,6 +860,10 @@
|
|||
font-size: 12px;
|
||||
margin-left: 48px;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
}
|
||||
|
||||
.deploy-body {
|
||||
|
|
|
@ -11,7 +11,7 @@ class Admin::RequestsProfilesController < Admin::ApplicationController
|
|||
profile = Gitlab::RequestProfiler::Profile.find(clean_name)
|
||||
|
||||
if profile
|
||||
render text: profile.content
|
||||
render html: profile.content
|
||||
else
|
||||
redirect_to admin_requests_profiles_path, alert: 'Profile not found'
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ class ChaosController < ActionController::Base
|
|||
duration_taken = (Time.now - start).seconds
|
||||
Kernel.sleep duration_s - duration_taken if duration_s > duration_taken
|
||||
|
||||
render text: "OK", content_type: 'text/plain'
|
||||
render plain: "OK"
|
||||
end
|
||||
|
||||
def cpuspin
|
||||
|
@ -24,14 +24,14 @@ class ChaosController < ActionController::Base
|
|||
|
||||
rand while Time.now < end_time
|
||||
|
||||
render text: "OK", content_type: 'text/plain'
|
||||
render plain: "OK"
|
||||
end
|
||||
|
||||
def sleep
|
||||
duration_s = (params[:duration_s]&.to_i || 30).seconds
|
||||
Kernel.sleep duration_s
|
||||
|
||||
render text: "OK", content_type: 'text/plain'
|
||||
render plain: "OK"
|
||||
end
|
||||
|
||||
def kill
|
||||
|
@ -44,13 +44,13 @@ class ChaosController < ActionController::Base
|
|||
secret = ENV['GITLAB_CHAOS_SECRET']
|
||||
# GITLAB_CHAOS_SECRET is required unless you're running in Development mode
|
||||
if !secret && !Rails.env.development?
|
||||
render text: "chaos misconfigured: please configure GITLAB_CHAOS_SECRET when using GITLAB_ENABLE_CHAOS_ENDPOINTS outside of a development environment", content_type: 'text/plain', status: 500
|
||||
render plain: "chaos misconfigured: please configure GITLAB_CHAOS_SECRET when using GITLAB_ENABLE_CHAOS_ENDPOINTS outside of a development environment", status: :internal_server_error
|
||||
end
|
||||
|
||||
return unless secret
|
||||
|
||||
unless request.headers["HTTP_X_CHAOS_SECRET"] == secret
|
||||
render text: "To experience chaos, please set X-Chaos-Secret header", content_type: 'text/plain', status: 401
|
||||
render plain: "To experience chaos, please set X-Chaos-Secret header", status: :unauthorized
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ class MetricsController < ActionController::Base
|
|||
"# Metrics are disabled, see: #{help_page}\n"
|
||||
end
|
||||
|
||||
render text: response, content_type: 'text/plain; version=0.0.4'
|
||||
render plain: response, content_type: 'text/plain; version=0.0.4'
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -41,12 +41,12 @@ class Profiles::KeysController < Profiles::ApplicationController
|
|||
user = UserFinder.new(params[:username]).find_by_username
|
||||
if user.present?
|
||||
headers['Content-Disposition'] = 'attachment'
|
||||
render text: user.all_ssh_keys.join("\n"), content_type: 'text/plain'
|
||||
render plain: user.all_ssh_keys.join("\n")
|
||||
else
|
||||
return render_404
|
||||
end
|
||||
rescue => e
|
||||
render text: e.message
|
||||
render html: e.message
|
||||
end
|
||||
else
|
||||
return render_404
|
||||
|
|
|
@ -122,7 +122,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
|
|||
set_workhorse_internal_api_content_type
|
||||
render json: Gitlab::Workhorse.terminal_websocket(terminal)
|
||||
else
|
||||
render text: 'Not found', status: :not_found
|
||||
render html: 'Not found', status: :not_found
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ module Ci
|
|||
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
|
||||
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
|
||||
has_many :variables, class_name: 'Ci::PipelineVariable'
|
||||
has_many :deployments, through: :builds
|
||||
has_many :environments, -> { distinct }, through: :deployments
|
||||
|
||||
# Merge requests for which the current pipeline is running against
|
||||
# the merge request's latest commit.
|
||||
|
@ -523,10 +525,6 @@ module Ci
|
|||
yaml_errors.present?
|
||||
end
|
||||
|
||||
def environments
|
||||
builds.where.not(environment: nil).success.pluck(:environment).uniq
|
||||
end
|
||||
|
||||
# Manually set the notes for a Ci::Pipeline
|
||||
# There is no ActiveRecord relation between Ci::Pipeline and notes
|
||||
# as they are related to a commit sha. This method helps importing
|
||||
|
|
|
@ -56,7 +56,11 @@ module Clusters
|
|||
def specification
|
||||
{
|
||||
"ingress" => {
|
||||
"hosts" => [hostname]
|
||||
"hosts" => [hostname],
|
||||
"tls" => [{
|
||||
"hosts" => [hostname],
|
||||
"secretName" => "jupyter-cert"
|
||||
}]
|
||||
},
|
||||
"hub" => {
|
||||
"extraEnv" => {
|
||||
|
|
|
@ -12,13 +12,13 @@ class EnvironmentStatus
|
|||
delegate :deployed_at, to: :deployment, allow_nil: true
|
||||
|
||||
def self.for_merge_request(mr, user)
|
||||
build_environments_status(mr, user, mr.diff_head_sha)
|
||||
build_environments_status(mr, user, mr.actual_head_pipeline)
|
||||
end
|
||||
|
||||
def self.after_merge_request(mr, user)
|
||||
return [] unless mr.merged?
|
||||
|
||||
build_environments_status(mr, user, mr.merge_commit_sha)
|
||||
build_environments_status(mr, user, mr.merge_pipeline)
|
||||
end
|
||||
|
||||
def initialize(environment, merge_request, sha)
|
||||
|
@ -61,13 +61,13 @@ class EnvironmentStatus
|
|||
}
|
||||
end
|
||||
|
||||
def self.build_environments_status(mr, user, sha)
|
||||
Environment.where(project_id: [mr.source_project_id, mr.target_project_id])
|
||||
.available
|
||||
.with_deployment(sha).map do |environment|
|
||||
def self.build_environments_status(mr, user, pipeline)
|
||||
return [] unless pipeline
|
||||
|
||||
pipeline.environments.available.map do |environment|
|
||||
next unless Ability.allowed?(user, :read_environment, environment)
|
||||
|
||||
EnvironmentStatus.new(environment, mr, sha)
|
||||
EnvironmentStatus.new(environment, mr, pipeline.sha)
|
||||
end.compact
|
||||
end
|
||||
private_class_method :build_environments_status
|
||||
|
|
|
@ -5,7 +5,7 @@ class NotificationSetting < ActiveRecord::Base
|
|||
|
||||
ignore_column :events
|
||||
|
||||
enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0, custom: 5 }
|
||||
enum level: { global: 3, watch: 2, participating: 1, mention: 4, disabled: 0, custom: 5 }
|
||||
|
||||
default_value_for :level, NotificationSetting.levels[:global]
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- sorted_by = sort_options_hash[@sort]
|
||||
|
||||
.dropdown.inline.prepend-left-10
|
||||
%button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' } }
|
||||
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' } }
|
||||
= sorted_by
|
||||
= icon('chevron-down')
|
||||
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
- if current_user
|
||||
.dropdown
|
||||
%button.dropdown-toggle{ href: '#', "data-toggle" => "dropdown", 'data-display' => 'static' }
|
||||
= icon('globe')
|
||||
%span.light= _("Visibility:")
|
||||
%button.dropdown-menu-toggle{ href: '#', "data-toggle" => "dropdown", 'data-display' => 'static' }
|
||||
= icon('globe', class: 'mt-1')
|
||||
%span.light.ml-3= _("Visibility:")
|
||||
- if params[:visibility_level].present?
|
||||
= visibility_level_label(params[:visibility_level].to_i)
|
||||
- else
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
spellcheck: false, data: { 'filter-selector' => 'span.namespace-name' }
|
||||
|
||||
.dropdown
|
||||
%button.dropdown-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
|
||||
%button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
|
||||
%span.light sort:
|
||||
- if @sort.present?
|
||||
= sort_options_hash[@sort]
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
= link_to icon('question-circle'), help_page_path('user/project/protected_branches')
|
||||
|
||||
.panel-footer
|
||||
= f.submit _('Mirror repository'), class: 'btn btn-success', name: :update_remote_mirror
|
||||
= f.submit _('Mirror repository'), class: 'btn btn-success js-mirror-submit', name: :update_remote_mirror
|
||||
|
||||
.panel.panel-default
|
||||
.table-responsive
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
= search_field_tag :search, params[:search], { placeholder: s_('TagsPage|Filter by tag name'), id: 'tag-search', class: 'form-control search-text-input input-short', spellcheck: false }
|
||||
|
||||
.dropdown
|
||||
%button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown'} }
|
||||
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown'} }
|
||||
%span.light
|
||||
= tags_sort_options_hash[@sort]
|
||||
= icon('chevron-down')
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- if show_auto_devops_implicitly_enabled_banner?(project)
|
||||
.auto-devops-implicitly-enabled-banner.alert.alert-warning
|
||||
- more_information_link = link_to _('More information'), 'https://docs.gitlab.com/ee/topics/autodevops/', class: 'alert-link'
|
||||
- more_information_link = link_to _('More information'), help_page_path('topics/autodevops/index.md'), target: '_blank', class: 'alert-link'
|
||||
- auto_devops_message = s_("AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found. %{more_information_link}") % { more_information_link: more_information_link }
|
||||
= auto_devops_message.html_safe
|
||||
.alert-link-group
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.dropdown.inline.prepend-left-10
|
||||
%button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown' } }
|
||||
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown' } }
|
||||
%span.light
|
||||
- if @sort.present?
|
||||
= milestone_sort_options_hash[@sort]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
- viewing_issues = controller.controller_name == 'issues' || controller.action_name == 'issues'
|
||||
|
||||
.dropdown.inline.prepend-left-10
|
||||
%button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' } }
|
||||
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' } }
|
||||
= sorted_by
|
||||
= icon('chevron-down')
|
||||
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
- default_sort_by = sort_value_recently_created
|
||||
|
||||
.dropdown.inline.js-group-filter-dropdown-wrap.append-right-10
|
||||
%button.dropdown-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
|
||||
%button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
|
||||
%span.dropdown-label
|
||||
= options_hash[default_sort_by]
|
||||
= icon('chevron-down')
|
||||
|
|
|
@ -95,7 +95,10 @@
|
|||
%ul{ data: { dropdown: true } }
|
||||
%li.filter-dropdown-item{ data: { value: 'none' } }
|
||||
%button.btn.btn-link{ type: 'button' }
|
||||
= _('No Label')
|
||||
= _('None')
|
||||
%li.filter-dropdown-item{ data: { value: 'any' } }
|
||||
%button.btn.btn-link{ type: 'button' }
|
||||
= _('Any')
|
||||
%li.divider.droplab-item-ignore
|
||||
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
|
||||
%li.filter-dropdown-item
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- sort_title = label_sort_options_hash[@sort] || sort_title_name_desc
|
||||
.dropdown.inline
|
||||
%button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown' } }
|
||||
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown' } }
|
||||
= sort_title
|
||||
= icon('chevron-down')
|
||||
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-sort
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Redesign of MR header sections (CE)
|
||||
merge_request: 23465
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Adds Any option to label filters
|
||||
merge_request: 23111
|
||||
author: Jacopo Beschi @jacopo-beschi
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'Fix: Unstar icon button is misaligned'
|
||||
merge_request: 23444
|
||||
author:
|
||||
type: fixed
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Correctly handle data-loss scenarios when encrypting columns
|
||||
merge_request: 23306
|
||||
author:
|
||||
type: fixed
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Removed Site Statistics optimization as it was causing problems
|
||||
merge_request: 23314
|
||||
author:
|
||||
type: removed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix line height of numbers in file blame view
|
||||
merge_request: 23090
|
||||
author: Johann Hubert Sonntagbauer
|
||||
type: fixed
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Fixes stuck tooltip on stop env button
|
||||
merge_request: 23244
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix Order By dropdown menu styling in tablet and mobile screens
|
||||
merge_request: 23446
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Bump gpgme gem version from 2.0.13 to 2.0.18
|
||||
merge_request:
|
||||
author: asaparov
|
||||
type: other
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Display impersonation token value only after creation
|
||||
merge_request: 22916
|
||||
author:
|
||||
type: fixed
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Clear BatchLoader context between Sidekiq jobs
|
||||
merge_request: 23308
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix unrelated deployment status in MR widget
|
||||
merge_request: 23175
|
||||
author:
|
||||
type: fixed
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Fix not render emoji in filter dropdown
|
||||
merge_request: 23112
|
||||
author: Hiroyuki Sato
|
||||
type: fixed
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: 'Auto DevOps: Add echo for each branch of the deploy() function where we run
|
||||
helm upgrade'
|
||||
merge_request: 23499
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: "#52753: HTTPS for JupyterHub installation"
|
||||
merge_request: 23479
|
||||
author: Amit Rathi
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: reorder notification settings by noisy-ness
|
||||
merge_request:
|
||||
author: C.J. Jameson
|
||||
type: changed
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: 'Fix deprecation: render :text is deprecated because it does not actually render
|
||||
a text/plain response'
|
||||
merge_request: 23425
|
||||
author: Jasper Maes
|
||||
type: other
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Fix handling of filenames with hash characters in tree view
|
||||
merge_request: 23368
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix "protected branches only" checkbox not set properly at init
|
||||
merge_request: 23409
|
||||
author:
|
||||
type: fixed
|
|
@ -108,14 +108,18 @@ Get an archive of the repository. This endpoint can be accessed without
|
|||
authentication if the repository is publicly accessible.
|
||||
|
||||
```
|
||||
GET /projects/:id/repository/archive
|
||||
GET /projects/:id/repository/archive[.format]
|
||||
```
|
||||
|
||||
`format` is an optional suffix for the archive format. Default is
|
||||
`tar.gz`. Options are `tar.gz`, `tar.bz2`, `tbz`, 'tbz2`, `tb2`,
|
||||
`bz2`, `tar`, and `zip`. For example, specifying `archive.zip`
|
||||
would send an archive in ZIP format.
|
||||
|
||||
Parameters:
|
||||
|
||||
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
|
||||
- `sha` (optional) - The commit SHA to download. A tag, branch reference or sha can be used. This defaults to the tip of the default branch if not specified
|
||||
- `format` (optional) - The archive format. Default is `tar.gz`. Options are `tar.gz`, `tar.bz2`, `tbz`, `tbz2`, `tb2`, `bz2`, `tar`, `zip`
|
||||
|
||||
## Compare branches, tags or commits
|
||||
|
||||
|
|
|
@ -273,6 +273,8 @@ The `releases` directory will hold all our deployments:
|
|||
echo 'Cloning repository'
|
||||
[ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
|
||||
git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
|
||||
cd {{ $releases_dir }}
|
||||
git reset --hard {{ $commit }}
|
||||
@endtask
|
||||
|
||||
...
|
||||
|
@ -349,6 +351,8 @@ At the end, our `Envoy.blade.php` file will look like this:
|
|||
echo 'Cloning repository'
|
||||
[ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
|
||||
git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
|
||||
cd {{ $releases_dir }}
|
||||
git reset --hard {{ $commit }}
|
||||
@endtask
|
||||
|
||||
@task('run_composer')
|
||||
|
@ -519,7 +523,7 @@ deploy_production:
|
|||
- mkdir -p ~/.ssh
|
||||
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
|
||||
|
||||
- ~/.composer/vendor/bin/envoy run deploy
|
||||
- ~/.composer/vendor/bin/envoy run deploy --commit="$CI_COMMIT_SHA"
|
||||
environment:
|
||||
name: production
|
||||
url: http://192.168.1.1
|
||||
|
|
|
@ -1590,7 +1590,7 @@ Possible values for `when` are:
|
|||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22631) in GitLab 11.5.
|
||||
|
||||
`parallel` allows you to configure how many instances of a job to run in
|
||||
parallel. This value has to be greater than or equal to two (2) and less or equal than 50.
|
||||
parallel. This value has to be greater than or equal to two (2) and less than or equal to 50.
|
||||
|
||||
This creates N instances of the same job that run in parallel. They're named
|
||||
sequentially from `job_name 1/N` to `job_name N/N`.
|
||||
|
|
|
@ -55,7 +55,7 @@ GitLab can be considered to have two layers from a process perspective:
|
|||
|
||||
### gitaly
|
||||
|
||||
- [Omnibus confiugration options](https://gitlab.com/gitlab-org/gitaly/tree/master/doc/configuration)
|
||||
- [Omnibus configuration options](https://gitlab.com/gitlab-org/gitaly/tree/master/doc/configuration)
|
||||
- Layer: Core Service (Data)
|
||||
|
||||
Gitaly is a service designed by GitLab to remove our need for NFS for Git storage in distributed deployments of GitLab. (Think GitLab.com or High Availablity Deployments) As of 11.3.0, This service handles all Git level access in GitLab. You can read more about the project [in the project's readme](https://gitlab.com/gitlab-org/gitaly).
|
||||
|
|
|
@ -479,14 +479,23 @@ no longer be valid as soon as the deployment job finishes. This means that
|
|||
Kubernetes can run the application, but in case it should be restarted or
|
||||
executed somewhere else, it cannot be accessed again.
|
||||
|
||||
#### Migrations
|
||||
|
||||
> [Introduced][ce-21955] in GitLab 11.4
|
||||
|
||||
Database initialization and migrations for PostgreSQL can be configured to run
|
||||
within the application pod by setting the project variables `DB_INITIALIZE` and
|
||||
`DB_MIGRATE` respectively.
|
||||
|
||||
If present, `DB_INITIALIZE` will be run as a shell command within an application pod as a helm
|
||||
post-install hook. Note that this means that if any deploy succeeds,
|
||||
If present, `DB_INITIALIZE` will be run as a shell command within an
|
||||
application pod as a helm post-install hook. As some applications will
|
||||
not run without a successful database initialization step, GitLab will
|
||||
deploy the first release without the application deployment and only the
|
||||
database initialization step. After the database initialization completes,
|
||||
GitLab will deploy a second release with the application deployment as
|
||||
normal.
|
||||
|
||||
Note that a post-install hook means that if any deploy succeeds,
|
||||
`DB_INITIALIZE` will not be processed thereafter.
|
||||
|
||||
If present, `DB_MIGRATE` will be run as a shell command within an application pod as
|
||||
|
|
|
@ -1022,7 +1022,7 @@ A link starting with a `/` is relative to the wiki root.
|
|||
[rouge]: http://rouge.jneen.net/ "Rouge website"
|
||||
[redcarpet]: https://github.com/vmg/redcarpet "Redcarpet website"
|
||||
[katex]: https://github.com/Khan/KaTeX "KaTeX website"
|
||||
[katex-subset]: https://github.com/Khan/KaTeX/wiki/Function-Support-in-KaTeX "Macros supported by KaTeX"
|
||||
[katex-subset]: https://katex.org/docs/supported.html "Macros supported by KaTeX"
|
||||
[asciidoctor-manual]: http://asciidoctor.org/docs/user-manual/#activating-stem-support "Asciidoctor user manual"
|
||||
[commonmarker]: https://github.com/gjtorikian/commonmarker
|
||||
[commonmark-spec]: https://spec.commonmark.org/current/
|
||||
|
|
|
@ -658,6 +658,7 @@ rollout 100%:
|
|||
fi
|
||||
|
||||
if [[ -n "$DB_INITIALIZE" && -z "$(helm ls -q "^$name$")" ]]; then
|
||||
echo "Deploying first release with database initialization..."
|
||||
helm upgrade --install \
|
||||
--wait \
|
||||
--set service.enabled="$service_enabled" \
|
||||
|
@ -680,6 +681,7 @@ rollout 100%:
|
|||
"$name" \
|
||||
chart/
|
||||
|
||||
echo "Deploying second release..."
|
||||
helm upgrade --reuse-values \
|
||||
--wait \
|
||||
--set application.initializeCommand="" \
|
||||
|
@ -688,6 +690,7 @@ rollout 100%:
|
|||
"$name" \
|
||||
chart/
|
||||
else
|
||||
echo "Deploying new release..."
|
||||
helm upgrade --install \
|
||||
--wait \
|
||||
--set service.enabled="$service_enabled" \
|
||||
|
|
|
@ -4297,9 +4297,6 @@ msgstr ""
|
|||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
msgid "No Label"
|
||||
msgstr ""
|
||||
|
||||
msgid "No assignee"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ describe ApplicationController do
|
|||
skip_before_action :authenticate_user!, only: :index
|
||||
|
||||
def index
|
||||
render text: 'authenticated'
|
||||
render html: 'authenticated'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -401,7 +401,7 @@ describe ApplicationController do
|
|||
context 'terms' do
|
||||
controller(described_class) do
|
||||
def index
|
||||
render text: 'authenticated'
|
||||
render html: 'authenticated'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -444,7 +444,7 @@ describe ApplicationController do
|
|||
attr_reader :last_payload
|
||||
|
||||
def index
|
||||
render text: 'authenticated'
|
||||
render html: 'authenticated'
|
||||
end
|
||||
|
||||
def append_info_to_payload(payload)
|
||||
|
|
|
@ -176,7 +176,7 @@ describe 'Issue Boards add issue modal filtering', :js do
|
|||
|
||||
it 'filters by no label' do
|
||||
set_filter('label')
|
||||
click_filter_link('No Label')
|
||||
click_filter_link('None')
|
||||
submit_filter
|
||||
|
||||
page.within('.add-issues-modal') do
|
||||
|
|
|
@ -45,7 +45,8 @@ describe 'Dropdown label', :js do
|
|||
bug_label = create(:label, project: project, title: 'bug-label')
|
||||
init_label_search
|
||||
|
||||
filtered_search.native.send_keys(:down, :down, :enter)
|
||||
# navigate to the bug_label option and selects it
|
||||
filtered_search.native.send_keys(:down, :down, :down, :enter)
|
||||
|
||||
expect_tokens([label_token(bug_label.title)])
|
||||
expect_filtered_search_input_empty
|
||||
|
@ -234,12 +235,20 @@ describe 'Dropdown label', :js do
|
|||
end
|
||||
|
||||
it 'selects `no label`' do
|
||||
find("#{js_dropdown_label} .filter-dropdown-item", text: 'No Label').click
|
||||
find("#{js_dropdown_label} .filter-dropdown-item", text: 'None').click
|
||||
|
||||
expect(page).not_to have_css(js_dropdown_label)
|
||||
expect_tokens([label_token('none', false)])
|
||||
expect_filtered_search_input_empty
|
||||
end
|
||||
|
||||
it 'selects `any label`' do
|
||||
find("#{js_dropdown_label} .filter-dropdown-item", text: 'Any').click
|
||||
|
||||
expect(page).not_to have_css(js_dropdown_label)
|
||||
expect_tokens([label_token('any', false)])
|
||||
expect_filtered_search_input_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe 'input has existing content' do
|
||||
|
|
|
@ -430,10 +430,10 @@ describe 'Filter issues', :js do
|
|||
|
||||
expect_issues_list_count(2)
|
||||
|
||||
sort_toggle = find('.filtered-search-wrapper .dropdown-toggle')
|
||||
sort_toggle = find('.filter-dropdown-container .dropdown-menu-toggle')
|
||||
sort_toggle.click
|
||||
|
||||
find('.filtered-search-wrapper .dropdown-menu li a', text: 'Created date').click
|
||||
find('.filter-dropdown-container .dropdown-menu li a', text: 'Created date').click
|
||||
wait_for_requests
|
||||
|
||||
expect(find('.issues-list .issue:first-of-type .issue-title-text a')).to have_content(new_issue.title)
|
||||
|
|
|
@ -20,7 +20,7 @@ describe "User sorts issues" do
|
|||
end
|
||||
|
||||
it 'keeps the sort option' do
|
||||
find('button.dropdown-toggle').click
|
||||
find('.filter-dropdown-container button.dropdown-menu-toggle').click
|
||||
|
||||
page.within('.content ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link('Milestone')
|
||||
|
@ -40,7 +40,7 @@ describe "User sorts issues" do
|
|||
end
|
||||
|
||||
it "sorts by popularity" do
|
||||
find("button.dropdown-toggle").click
|
||||
find(".filter-dropdown-container button.dropdown-menu-toggle").click
|
||||
|
||||
page.within(".content ul.dropdown-menu.dropdown-menu-right li") do
|
||||
click_link("Popularity")
|
||||
|
|
|
@ -29,6 +29,22 @@ describe 'Merge request > User sees deployment widget', :js do
|
|||
expect(page).to have_content("Deployed to #{environment.name}")
|
||||
expect(find('.js-deploy-time')['data-original-title']).to eq(deployment.created_at.to_time.in_time_zone.to_s(:medium))
|
||||
end
|
||||
|
||||
context 'when a user created a new merge request with the same SHA' do
|
||||
let(:pipeline2) { create(:ci_pipeline_without_jobs, sha: sha, project: project, ref: 'new-patch-1') }
|
||||
let(:build2) { create(:ci_build, :success, pipeline: pipeline2) }
|
||||
let(:environment2) { create(:environment, project: project) }
|
||||
let!(:deployment2) { create(:deployment, environment: environment2, sha: sha, ref: 'new-patch-1', deployable: build2) }
|
||||
|
||||
it 'displays one environment which is related to the pipeline' do
|
||||
visit project_merge_request_path(project, merge_request)
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_selector('.js-deployment-info', count: 1)
|
||||
expect(page).to have_content("#{environment.name}")
|
||||
expect(page).not_to have_content("#{environment2.name}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when deployment failed' do
|
||||
|
|
|
@ -60,7 +60,7 @@ describe 'Merge request > User sees merge widget', :js do
|
|||
it 'shows environments link' do
|
||||
wait_for_requests
|
||||
|
||||
page.within('.js-pre-merge-deploy') do
|
||||
page.within('.js-pre-deployment') do
|
||||
expect(page).to have_content("Deployed to #{environment.name}")
|
||||
expect(find('.js-deploy-url')[:href]).to include(environment.formatted_external_url)
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ describe 'User sorts merge requests' do
|
|||
end
|
||||
|
||||
it 'keeps the sort option' do
|
||||
find('button.dropdown-toggle').click
|
||||
find('.filter-dropdown-container button.dropdown-menu-toggle').click
|
||||
|
||||
page.within('.content ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link('Milestone')
|
||||
|
@ -49,7 +49,7 @@ describe 'User sorts merge requests' do
|
|||
it 'separates remember sorting with issues' do
|
||||
create(:issue, project: project)
|
||||
|
||||
find('button.dropdown-toggle').click
|
||||
find('.filter-dropdown-container button.dropdown-menu-toggle').click
|
||||
|
||||
page.within('.content ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link('Milestone')
|
||||
|
@ -70,7 +70,7 @@ describe 'User sorts merge requests' do
|
|||
end
|
||||
|
||||
it 'sorts by popularity' do
|
||||
find('button.dropdown-toggle').click
|
||||
find('.filter-dropdown-container button.dropdown-menu-toggle').click
|
||||
|
||||
page.within('.content ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link('Popularity')
|
||||
|
|
|
@ -32,7 +32,7 @@ describe 'Issue prioritization' do
|
|||
visit project_issues_path(project, sort: 'label_priority')
|
||||
|
||||
# Ensure we are indicating that issues are sorted by priority
|
||||
expect(page).to have_selector('.dropdown-toggle', text: 'Label priority')
|
||||
expect(page).to have_selector('.dropdown-menu-toggle', text: 'Label priority')
|
||||
|
||||
page.within('.issues-holder') do
|
||||
issue_titles = all('.issues-list .issue-title-text').map(&:text)
|
||||
|
@ -70,7 +70,7 @@ describe 'Issue prioritization' do
|
|||
sign_in user
|
||||
visit project_issues_path(project, sort: 'label_priority')
|
||||
|
||||
expect(page).to have_selector('.dropdown-toggle', text: 'Label priority')
|
||||
expect(page).to have_selector('.dropdown-menu-toggle', text: 'Label priority')
|
||||
|
||||
page.within('.issues-holder') do
|
||||
issue_titles = all('.issues-list .issue-title-text').map(&:text)
|
||||
|
|
|
@ -133,18 +133,49 @@ describe 'Projects > Settings > Repository settings' do
|
|||
expect(page).to have_selector('#mirror_direction')
|
||||
end
|
||||
|
||||
it 'creates a push mirror that mirrors all branches', :js do
|
||||
expect(find('.js-mirror-protected-hidden', visible: false).value).to eq('0')
|
||||
|
||||
fill_in 'url', with: 'ssh://user@localhost/project.git'
|
||||
select 'SSH public key', from: 'Authentication method'
|
||||
|
||||
select_direction
|
||||
|
||||
Sidekiq::Testing.fake! do
|
||||
click_button 'Mirror repository'
|
||||
end
|
||||
|
||||
project.reload
|
||||
|
||||
expect(page).to have_content('Mirroring settings were successfully updated')
|
||||
expect(project.remote_mirrors.first.only_protected_branches).to eq(false)
|
||||
end
|
||||
|
||||
it 'creates a push mirror that only mirrors protected branches', :js do
|
||||
find('#only_protected_branches').click
|
||||
|
||||
expect(find('.js-mirror-protected-hidden', visible: false).value).to eq('1')
|
||||
|
||||
fill_in 'url', with: 'ssh://user@localhost/project.git'
|
||||
select 'SSH public key', from: 'Authentication method'
|
||||
|
||||
select_direction
|
||||
|
||||
Sidekiq::Testing.fake! do
|
||||
click_button 'Mirror repository'
|
||||
end
|
||||
|
||||
project.reload
|
||||
|
||||
expect(page).to have_content('Mirroring settings were successfully updated')
|
||||
expect(project.remote_mirrors.first.only_protected_branches).to eq(true)
|
||||
end
|
||||
|
||||
it 'generates an SSH public key on submission', :js do
|
||||
fill_in 'url', with: 'ssh://user@localhost/project.git'
|
||||
select 'SSH public key', from: 'Authentication method'
|
||||
|
||||
direction_select = find('#mirror_direction')
|
||||
|
||||
# In CE, this select box is disabled, but in EE, it is enabled
|
||||
if direction_select.disabled?
|
||||
expect(direction_select.value).to eq('push')
|
||||
else
|
||||
direction_select.select('Push')
|
||||
end
|
||||
select_direction
|
||||
|
||||
Sidekiq::Testing.fake! do
|
||||
click_button 'Mirror repository'
|
||||
|
@ -153,6 +184,17 @@ describe 'Projects > Settings > Repository settings' do
|
|||
expect(page).to have_content('Mirroring settings were successfully updated')
|
||||
expect(page).to have_selector('[title="Copy SSH public key"]')
|
||||
end
|
||||
|
||||
def select_direction(direction = 'push')
|
||||
direction_select = find('#mirror_direction')
|
||||
|
||||
# In CE, this select box is disabled, but in EE, it is enabled
|
||||
if direction_select.disabled?
|
||||
expect(direction_select.value).to eq(direction)
|
||||
else
|
||||
direction_select.select(direction.capitalize)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,46 +1,154 @@
|
|||
[
|
||||
{
|
||||
"priority": "Unknown",
|
||||
"file": "pom.xml",
|
||||
"cve": "CVE-2012-4387",
|
||||
"url": "http://struts.apache.org/docs/s2-011.html",
|
||||
"message": "Long parameter name DoS for org.apache.struts/struts2-core",
|
||||
"tools": [
|
||||
"gemnasium"
|
||||
"category": "dependency_scanning",
|
||||
"name": "io.netty/netty - CVE-2014-3488",
|
||||
"message": "DoS by CPU exhaustion when using malicious SSL packets",
|
||||
"cve": "app/pom.xml:io.netty/netty@3.9.1.Final:CVE-2014-3488",
|
||||
"severity": "Unknown",
|
||||
"solution": "Upgrade to the latest version",
|
||||
"scanner": {
|
||||
"id": "gemnasium",
|
||||
"name": "Gemnasium"
|
||||
},
|
||||
"location": {
|
||||
"file": "app/pom.xml"
|
||||
},
|
||||
"identifiers": [
|
||||
{
|
||||
"type": "gemnasium",
|
||||
"name": "Gemnasium-d1bf36d9-9f07-46cd-9cfc-8675338ada8f",
|
||||
"value": "d1bf36d9-9f07-46cd-9cfc-8675338ada8f",
|
||||
"url": "https://deps.sec.gitlab.com/packages/maven/io.netty/netty/versions/3.9.1.Final/advisories"
|
||||
},
|
||||
{
|
||||
"type": "cve",
|
||||
"name": "CVE-2014-3488",
|
||||
"value": "CVE-2014-3488",
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3488"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"url": "https://bugzilla.redhat.com/CVE-2014-3488"
|
||||
},
|
||||
{
|
||||
"url": "http://netty.io/news/2014/06/11/3.html"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/netty/netty/issues/2562"
|
||||
}
|
||||
],
|
||||
"priority": "Unknown",
|
||||
"file": "app/pom.xml",
|
||||
"url": "https://bugzilla.redhat.com/CVE-2014-3488",
|
||||
"tool": "gemnasium"
|
||||
},
|
||||
{
|
||||
"priority": "Unknown",
|
||||
"file": "pom.xml",
|
||||
"cve": "CVE-2013-1966",
|
||||
"url": "http://struts.apache.org/docs/s2-014.html",
|
||||
"message": "Remote command execution due to flaw in the includeParams attribute of URL and Anchor tags for org.apache.struts/struts2-core",
|
||||
"tools": [
|
||||
"gemnasium"
|
||||
"category": "dependency_scanning",
|
||||
"name": "Django - CVE-2017-12794",
|
||||
"message": "Possible XSS in traceback section of technical 500 debug page",
|
||||
"cve": "app/requirements.txt:Django@1.11.3:CVE-2017-12794",
|
||||
"severity": "Unknown",
|
||||
"solution": "Upgrade to latest version or apply patch.",
|
||||
"scanner": {
|
||||
"id": "gemnasium",
|
||||
"name": "Gemnasium"
|
||||
},
|
||||
"location": {
|
||||
"file": "app/requirements.txt"
|
||||
},
|
||||
"identifiers": [
|
||||
{
|
||||
"type": "gemnasium",
|
||||
"name": "Gemnasium-6162a015-8635-4a15-8d7c-dc9321db366f",
|
||||
"value": "6162a015-8635-4a15-8d7c-dc9321db366f",
|
||||
"url": "https://deps.sec.gitlab.com/packages/pypi/Django/versions/1.11.3/advisories"
|
||||
},
|
||||
{
|
||||
"type": "cve",
|
||||
"name": "CVE-2017-12794",
|
||||
"value": "CVE-2017-12794",
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-12794"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"url": "https://www.djangoproject.com/weblog/2017/sep/05/security-releases/"
|
||||
}
|
||||
],
|
||||
"priority": "Unknown",
|
||||
"file": "app/requirements.txt",
|
||||
"url": "https://www.djangoproject.com/weblog/2017/sep/05/security-releases/",
|
||||
"tool": "gemnasium"
|
||||
},
|
||||
{
|
||||
"priority": "Unknown",
|
||||
"file": "pom.xml",
|
||||
"cve": "CVE-2013-2115",
|
||||
"url": "http://struts.apache.org/docs/s2-014.html",
|
||||
"message": "Remote command execution due to flaw in the includeParams attribute of URL and Anchor tags for org.apache.struts/struts2-core",
|
||||
"tools": [
|
||||
"gemnasium"
|
||||
"category": "dependency_scanning",
|
||||
"name": "nokogiri - USN-3424-1",
|
||||
"message": "Vulnerabilities in libxml2",
|
||||
"cve": "rails/Gemfile.lock:nokogiri@1.8.0:USN-3424-1",
|
||||
"severity": "Unknown",
|
||||
"solution": "Upgrade to latest version.",
|
||||
"scanner": {
|
||||
"id": "gemnasium",
|
||||
"name": "Gemnasium"
|
||||
},
|
||||
"location": {
|
||||
"file": "rails/Gemfile.lock"
|
||||
},
|
||||
"identifiers": [
|
||||
{
|
||||
"type": "gemnasium",
|
||||
"name": "Gemnasium-06565b64-486d-4326-b906-890d9915804d",
|
||||
"value": "06565b64-486d-4326-b906-890d9915804d",
|
||||
"url": "https://deps.sec.gitlab.com/packages/gem/nokogiri/versions/1.8.0/advisories"
|
||||
},
|
||||
{
|
||||
"type": "usn",
|
||||
"name": "USN-3424-1",
|
||||
"value": "USN-3424-1",
|
||||
"url": "https://usn.ubuntu.com/3424-1/"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"url": "https://github.com/sparklemotion/nokogiri/issues/1673"
|
||||
}
|
||||
],
|
||||
"priority": "Unknown",
|
||||
"file": "rails/Gemfile.lock",
|
||||
"url": "https://github.com/sparklemotion/nokogiri/issues/1673",
|
||||
"tool": "gemnasium"
|
||||
},
|
||||
{
|
||||
"priority": "Unknown",
|
||||
"file": "pom.xml",
|
||||
"cve": "CVE-2013-2134",
|
||||
"url": "http://struts.apache.org/docs/s2-015.html",
|
||||
"message": "Arbitrary OGNL code execution via unsanitized wildcard matching for org.apache.struts/struts2-core",
|
||||
"tools": [
|
||||
"gemnasium"
|
||||
"category": "dependency_scanning",
|
||||
"name": "ffi - CVE-2018-1000201",
|
||||
"message": "ruby-ffi DDL loading issue on Windows OS",
|
||||
"cve": "ffi:1.9.18:CVE-2018-1000201",
|
||||
"severity": "High",
|
||||
"solution": "upgrade to \u003e= 1.9.24",
|
||||
"scanner": {
|
||||
"id": "bundler_audit",
|
||||
"name": "bundler-audit"
|
||||
},
|
||||
"location": {
|
||||
"file": "sast-sample-rails/Gemfile.lock"
|
||||
},
|
||||
"identifiers": [
|
||||
{
|
||||
"type": "cve",
|
||||
"name": "CVE-2018-1000201",
|
||||
"value": "CVE-2018-1000201",
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-1000201"
|
||||
}
|
||||
],
|
||||
"tool": "gemnasium"
|
||||
"links": [
|
||||
{
|
||||
"url": "https://github.com/ffi/ffi/releases/tag/1.9.24"
|
||||
}
|
||||
],
|
||||
"priority": "High",
|
||||
"file": "sast-sample-rails/Gemfile.lock",
|
||||
"url": "https://github.com/ffi/ffi/releases/tag/1.9.24",
|
||||
"tool": "bundler_audit"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,35 +1,154 @@
|
|||
[
|
||||
{
|
||||
"priority": "Unknown",
|
||||
"file": "pom.xml",
|
||||
"cve": "CVE-2012-4386",
|
||||
"url": "http://struts.apache.org/docs/s2-010.html",
|
||||
"message": "CSRF protection bypass for org.apache.struts/struts2-core",
|
||||
"tools": [
|
||||
"gemnasium"
|
||||
"category": "dependency_scanning",
|
||||
"name": "io.netty/netty - CVE-2014-3488",
|
||||
"message": "DoS by CPU exhaustion when using malicious SSL packets",
|
||||
"cve": "app/pom.xml:io.netty/netty@3.9.1.Final:CVE-2014-3488",
|
||||
"severity": "Unknown",
|
||||
"solution": "Upgrade to the latest version",
|
||||
"scanner": {
|
||||
"id": "gemnasium",
|
||||
"name": "Gemnasium"
|
||||
},
|
||||
"location": {
|
||||
"file": "app/pom.xml"
|
||||
},
|
||||
"identifiers": [
|
||||
{
|
||||
"type": "gemnasium",
|
||||
"name": "Gemnasium-d1bf36d9-9f07-46cd-9cfc-8675338ada8f",
|
||||
"value": "d1bf36d9-9f07-46cd-9cfc-8675338ada8f",
|
||||
"url": "https://deps.sec.gitlab.com/packages/maven/io.netty/netty/versions/3.9.1.Final/advisories"
|
||||
},
|
||||
{
|
||||
"type": "cve",
|
||||
"name": "CVE-2014-3488",
|
||||
"value": "CVE-2014-3488",
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3488"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"url": "https://bugzilla.redhat.com/CVE-2014-3488"
|
||||
},
|
||||
{
|
||||
"url": "http://netty.io/news/2014/06/11/3.html"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/netty/netty/issues/2562"
|
||||
}
|
||||
],
|
||||
"priority": "Unknown",
|
||||
"file": "app/pom.xml",
|
||||
"url": "https://bugzilla.redhat.com/CVE-2014-3488",
|
||||
"tool": "gemnasium"
|
||||
},
|
||||
{
|
||||
"priority": "Unknown",
|
||||
"file": "pom.xml",
|
||||
"cve": "CVE-2012-4387",
|
||||
"url": "http://struts.apache.org/docs/s2-011.html",
|
||||
"message": "Long parameter name DoS for org.apache.struts/struts2-core",
|
||||
"tools": [
|
||||
"gemnasium"
|
||||
"category": "dependency_scanning",
|
||||
"name": "Django - CVE-2017-12794",
|
||||
"message": "Possible XSS in traceback section of technical 500 debug page",
|
||||
"cve": "app/requirements.txt:Django@1.11.3:CVE-2017-12794",
|
||||
"severity": "Unknown",
|
||||
"solution": "Upgrade to latest version or apply patch.",
|
||||
"scanner": {
|
||||
"id": "gemnasium",
|
||||
"name": "Gemnasium"
|
||||
},
|
||||
"location": {
|
||||
"file": "app/requirements.txt"
|
||||
},
|
||||
"identifiers": [
|
||||
{
|
||||
"type": "gemnasium",
|
||||
"name": "Gemnasium-6162a015-8635-4a15-8d7c-dc9321db366f",
|
||||
"value": "6162a015-8635-4a15-8d7c-dc9321db366f",
|
||||
"url": "https://deps.sec.gitlab.com/packages/pypi/Django/versions/1.11.3/advisories"
|
||||
},
|
||||
{
|
||||
"type": "cve",
|
||||
"name": "CVE-2017-12794",
|
||||
"value": "CVE-2017-12794",
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-12794"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"url": "https://www.djangoproject.com/weblog/2017/sep/05/security-releases/"
|
||||
}
|
||||
],
|
||||
"priority": "Unknown",
|
||||
"file": "app/requirements.txt",
|
||||
"url": "https://www.djangoproject.com/weblog/2017/sep/05/security-releases/",
|
||||
"tool": "gemnasium"
|
||||
},
|
||||
{
|
||||
"priority": "Unknown",
|
||||
"file": "pom.xml",
|
||||
"cve": "CVE-2013-1966",
|
||||
"url": "http://struts.apache.org/docs/s2-014.html",
|
||||
"message": "Remote command execution due to flaw in the includeParams attribute of URL and Anchor tags for org.apache.struts/struts2-core",
|
||||
"tools": [
|
||||
"gemnasium"
|
||||
"category": "dependency_scanning",
|
||||
"name": "nokogiri - USN-3424-1",
|
||||
"message": "Vulnerabilities in libxml2",
|
||||
"cve": "rails/Gemfile.lock:nokogiri@1.8.0:USN-3424-1",
|
||||
"severity": "Unknown",
|
||||
"solution": "Upgrade to latest version.",
|
||||
"scanner": {
|
||||
"id": "gemnasium",
|
||||
"name": "Gemnasium"
|
||||
},
|
||||
"location": {
|
||||
"file": "rails/Gemfile.lock"
|
||||
},
|
||||
"identifiers": [
|
||||
{
|
||||
"type": "gemnasium",
|
||||
"name": "Gemnasium-06565b64-486d-4326-b906-890d9915804d",
|
||||
"value": "06565b64-486d-4326-b906-890d9915804d",
|
||||
"url": "https://deps.sec.gitlab.com/packages/gem/nokogiri/versions/1.8.0/advisories"
|
||||
},
|
||||
{
|
||||
"type": "usn",
|
||||
"name": "USN-3424-1",
|
||||
"value": "USN-3424-1",
|
||||
"url": "https://usn.ubuntu.com/3424-1/"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"url": "https://github.com/sparklemotion/nokogiri/issues/1673"
|
||||
}
|
||||
],
|
||||
"priority": "Unknown",
|
||||
"file": "rails/Gemfile.lock",
|
||||
"url": "https://github.com/sparklemotion/nokogiri/issues/1673",
|
||||
"tool": "gemnasium"
|
||||
},
|
||||
{
|
||||
"category": "dependency_scanning",
|
||||
"name": "ffi - CVE-2018-1000201",
|
||||
"message": "ruby-ffi DDL loading issue on Windows OS",
|
||||
"cve": "ffi:1.9.18:CVE-2018-1000201",
|
||||
"severity": "High",
|
||||
"solution": "upgrade to \u003e= 1.9.24",
|
||||
"scanner": {
|
||||
"id": "bundler_audit",
|
||||
"name": "bundler-audit"
|
||||
},
|
||||
"location": {
|
||||
"file": "sast-sample-rails/Gemfile.lock"
|
||||
},
|
||||
"identifiers": [
|
||||
{
|
||||
"type": "cve",
|
||||
"name": "CVE-2018-1000201",
|
||||
"value": "CVE-2018-1000201",
|
||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-1000201"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"url": "https://github.com/ffi/ffi/releases/tag/1.9.24"
|
||||
}
|
||||
],
|
||||
"priority": "High",
|
||||
"file": "sast-sample-rails/Gemfile.lock",
|
||||
"url": "https://github.com/ffi/ffi/releases/tag/1.9.24",
|
||||
"tool": "bundler_audit"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -139,57 +139,17 @@ describe('pipeline graph job item', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('tooltip placement', () => {
|
||||
it('does not set tooltip boundary by default', () => {
|
||||
component = mountComponent(JobComponent, {
|
||||
job: mockJob,
|
||||
});
|
||||
|
||||
expect(component.tooltipBoundary).toBeNull();
|
||||
});
|
||||
|
||||
it('sets tooltip boundary to viewport for small dropdowns', () => {
|
||||
component = mountComponent(JobComponent, {
|
||||
job: mockJob,
|
||||
dropdownLength: 1,
|
||||
});
|
||||
|
||||
expect(component.tooltipBoundary).toEqual('viewport');
|
||||
});
|
||||
|
||||
it('does not set tooltip boundary for large lists', () => {
|
||||
component = mountComponent(JobComponent, {
|
||||
job: mockJob,
|
||||
dropdownLength: 7,
|
||||
});
|
||||
|
||||
expect(component.tooltipBoundary).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('for delayed job', () => {
|
||||
beforeEach(() => {
|
||||
const fifteenMinutesInMilliseconds = 900000;
|
||||
spyOn(Date, 'now').and.callFake(
|
||||
() => new Date(delayedJobFixture.scheduled_at).getTime() - fifteenMinutesInMilliseconds,
|
||||
);
|
||||
});
|
||||
|
||||
it('displays remaining time in tooltip', done => {
|
||||
it('displays remaining time in tooltip', () => {
|
||||
component = mountComponent(JobComponent, {
|
||||
job: delayedJobFixture,
|
||||
});
|
||||
|
||||
Vue.nextTick()
|
||||
.then(() => {
|
||||
expect(
|
||||
component.$el
|
||||
.querySelector('.js-pipeline-graph-job-link')
|
||||
.getAttribute('data-original-title'),
|
||||
).toEqual('delayed job - delayed manual action (00:15:00)');
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
expect(
|
||||
component.$el
|
||||
.querySelector('.js-pipeline-graph-job-link')
|
||||
.getAttribute('data-original-title'),
|
||||
).toEqual(`delayed job - delayed manual action (${component.remainingTime})`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import MrWidgetContainer from '~/vue_merge_request_widget/components/mr_widget_container.vue';
|
||||
|
||||
const BODY_HTML = '<div class="test-body">Hello World</div>';
|
||||
const FOOTER_HTML = '<div class="test-footer">Goodbye!</div>';
|
||||
|
||||
describe('MrWidgetContainer', () => {
|
||||
let wrapper;
|
||||
|
||||
const factory = (options = {}) => {
|
||||
const localVue = createLocalVue();
|
||||
|
||||
wrapper = shallowMount(localVue.extend(MrWidgetContainer), {
|
||||
localVue,
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('has layout', () => {
|
||||
factory();
|
||||
|
||||
expect(wrapper.is('.mr-widget-heading')).toBe(true);
|
||||
expect(wrapper.contains('.mr-widget-content')).toBe(true);
|
||||
});
|
||||
|
||||
it('accepts default slot', () => {
|
||||
factory({
|
||||
slots: {
|
||||
default: BODY_HTML,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.contains('.mr-widget-content .test-body')).toBe(true);
|
||||
});
|
||||
|
||||
it('accepts footer slot', () => {
|
||||
factory({
|
||||
slots: {
|
||||
default: BODY_HTML,
|
||||
footer: FOOTER_HTML,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.contains('.mr-widget-content .test-body')).toBe(true);
|
||||
expect(wrapper.contains('.test-footer')).toBe(true);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import MrWidgetIcon from '~/vue_merge_request_widget/components/mr_widget_icon.vue';
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
|
||||
const TEST_ICON = 'commit';
|
||||
|
||||
describe('MrWidgetIcon', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
const localVue = createLocalVue();
|
||||
|
||||
wrapper = shallowMount(localVue.extend(MrWidgetIcon), {
|
||||
propsData: {
|
||||
name: TEST_ICON,
|
||||
},
|
||||
sync: false,
|
||||
localVue,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('renders icon and container', () => {
|
||||
expect(wrapper.is('.circle-icon-container')).toBe(true);
|
||||
expect(wrapper.find(Icon).props('name')).toEqual(TEST_ICON);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,90 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import MrWidgetPipelineContainer from '~/vue_merge_request_widget/components/mr_widget_pipeline_container.vue';
|
||||
import MrWidgetPipeline from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue';
|
||||
import { mockStore } from '../mock_data';
|
||||
|
||||
describe('MrWidgetPipelineContainer', () => {
|
||||
let wrapper;
|
||||
|
||||
const factory = (props = {}) => {
|
||||
const localVue = createLocalVue();
|
||||
|
||||
wrapper = shallowMount(localVue.extend(MrWidgetPipelineContainer), {
|
||||
propsData: {
|
||||
mr: Object.assign({}, mockStore),
|
||||
...props,
|
||||
},
|
||||
localVue,
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('when pre merge', () => {
|
||||
beforeEach(() => {
|
||||
factory();
|
||||
});
|
||||
|
||||
it('renders pipeline', () => {
|
||||
expect(wrapper.find(MrWidgetPipeline).exists()).toBe(true);
|
||||
expect(wrapper.find(MrWidgetPipeline).props()).toEqual(
|
||||
jasmine.objectContaining({
|
||||
pipeline: mockStore.pipeline,
|
||||
ciStatus: mockStore.ciStatus,
|
||||
hasCi: mockStore.hasCI,
|
||||
sourceBranch: mockStore.sourceBranch,
|
||||
sourceBranchLink: mockStore.sourceBranchLink,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('renders deployments', () => {
|
||||
const expectedProps = mockStore.deployments.map(dep =>
|
||||
jasmine.objectContaining({
|
||||
deployment: dep,
|
||||
showMetrics: false,
|
||||
}),
|
||||
);
|
||||
|
||||
const deployments = wrapper.findAll('.mr-widget-extension .js-pre-deployment');
|
||||
|
||||
expect(deployments.wrappers.map(x => x.props())).toEqual(expectedProps);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when post merge', () => {
|
||||
beforeEach(() => {
|
||||
factory({
|
||||
isPostMerge: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders pipeline', () => {
|
||||
expect(wrapper.find(MrWidgetPipeline).exists()).toBe(true);
|
||||
expect(wrapper.find(MrWidgetPipeline).props()).toEqual(
|
||||
jasmine.objectContaining({
|
||||
pipeline: mockStore.mergePipeline,
|
||||
ciStatus: mockStore.ciStatus,
|
||||
hasCi: mockStore.hasCI,
|
||||
sourceBranch: mockStore.targetBranch,
|
||||
sourceBranchLink: mockStore.targetBranch,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('renders deployments', () => {
|
||||
const expectedProps = mockStore.postMergeDeployments.map(dep =>
|
||||
jasmine.objectContaining({
|
||||
deployment: dep,
|
||||
showMetrics: true,
|
||||
}),
|
||||
);
|
||||
|
||||
const deployments = wrapper.findAll('.mr-widget-extension .js-post-deployment');
|
||||
|
||||
expect(deployments.wrappers.map(x => x.props())).toEqual(expectedProps);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -222,3 +222,16 @@ export default {
|
|||
'http://localhost:3000/root/acets-app/commit/53027d060246c8f47e4a9310fb332aa52f221775',
|
||||
troubleshooting_docs_path: 'help',
|
||||
};
|
||||
|
||||
export const mockStore = {
|
||||
pipeline: { id: 0 },
|
||||
mergePipeline: { id: 1 },
|
||||
targetBranch: 'target-branch',
|
||||
sourceBranch: 'source-branch',
|
||||
sourceBranchLink: 'source-branch-link',
|
||||
deployments: [{ id: 0, name: 'bogus' }, { id: 1, name: 'bogus-docs' }],
|
||||
postMergeDeployments: [{ id: 0, name: 'prod' }, { id: 1, name: 'prod-docs' }],
|
||||
troubleshootingDocsPath: 'troubleshooting-docs-path',
|
||||
ciStatus: 'ci-status',
|
||||
hasCI: true,
|
||||
};
|
||||
|
|
|
@ -121,6 +121,8 @@ pipelines:
|
|||
- artifacts
|
||||
- pipeline_schedule
|
||||
- merge_requests
|
||||
- deployments
|
||||
- environments
|
||||
pipeline_variables:
|
||||
- pipeline
|
||||
stages:
|
||||
|
|
|
@ -92,16 +92,12 @@ describe EnvironmentStatus do
|
|||
end
|
||||
|
||||
describe '.build_environments_status' do
|
||||
subject { described_class.send(:build_environments_status, merge_request, user, sha) }
|
||||
subject { described_class.send(:build_environments_status, merge_request, user, pipeline) }
|
||||
|
||||
let!(:build) { create(:ci_build, :deploy_to_production, pipeline: pipeline) }
|
||||
let(:environment) { build.deployment.environment }
|
||||
let(:user) { project.owner }
|
||||
|
||||
before do
|
||||
build.deployment&.update!(sha: sha)
|
||||
end
|
||||
|
||||
context 'when environment is created on a forked project' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:forked) { fork_project(project, user, repository: true) }
|
||||
|
@ -160,6 +156,39 @@ describe EnvironmentStatus do
|
|||
expect(subject.count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when multiple deployments with the same SHA in different environments' do
|
||||
let(:pipeline2) { create(:ci_pipeline, sha: sha, project: project) }
|
||||
let!(:build2) { create(:ci_build, :start_review_app, pipeline: pipeline2) }
|
||||
|
||||
it 'returns deployments related to the head pipeline' do
|
||||
expect(subject.count).to eq(1)
|
||||
expect(subject[0].environment).to eq(environment)
|
||||
expect(subject[0].merge_request).to eq(merge_request)
|
||||
expect(subject[0].sha).to eq(sha)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when multiple deployments in the same pipeline for the same environments' do
|
||||
let!(:build2) { create(:ci_build, :deploy_to_production, pipeline: pipeline) }
|
||||
|
||||
it 'returns unique entries' do
|
||||
expect(subject.count).to eq(1)
|
||||
expect(subject[0].environment).to eq(environment)
|
||||
expect(subject[0].merge_request).to eq(merge_request)
|
||||
expect(subject[0].sha).to eq(sha)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when environment is stopped' do
|
||||
before do
|
||||
environment.stop!
|
||||
end
|
||||
|
||||
it 'does not return environment status' do
|
||||
expect(subject.count).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ module Spec
|
|||
module Features
|
||||
module SortingHelpers
|
||||
def sort_by(value)
|
||||
find('button.dropdown-toggle').click
|
||||
find('.filter-dropdown-container button.dropdown-menu-toggle').click
|
||||
|
||||
page.within('.content ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link(value)
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
module SortingHelper
|
||||
def sorting_by(value)
|
||||
find('button.dropdown-toggle').click
|
||||
find('.filter-dropdown-container button.dropdown-menu-toggle').click
|
||||
page.within('.content ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link value
|
||||
end
|
||||
|
|
|
@ -22,3 +22,4 @@ ingress:
|
|||
enabled: true
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
kubernetes.io/tls-acme: "true"
|
||||
|
|
Loading…
Reference in New Issue