Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
eccfaf7c24
commit
5ff1b520ba
33 changed files with 948 additions and 35 deletions
|
@ -1,4 +1,4 @@
|
|||
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33"
|
||||
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33"
|
||||
|
||||
stages:
|
||||
- prepare
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
variables:
|
||||
GIT_STRATEGY: none
|
||||
environment:
|
||||
name: review-docs/$CI_COMMIT_REF_SLUG
|
||||
name: review-docs/$DOCS_GITLAB_REPO_SUFFIX-$CI_MERGE_REQUEST_IID
|
||||
# DOCS_REVIEW_APPS_DOMAIN and DOCS_GITLAB_REPO_SUFFIX are CI variables
|
||||
# Discussion: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/14236/diffs#note_40140693
|
||||
url: http://$CI_ENVIRONMENT_SLUG.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
|
||||
url: http://docs-preview-$DOCS_GITLAB_REPO_SUFFIX-$CI_MERGE_REQUEST_IID.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
|
||||
on_stop: review-docs-cleanup
|
||||
before_script:
|
||||
# We don't clone the repo by using GIT_STRATEGY: none and only download the
|
||||
|
@ -39,7 +39,7 @@ review-docs-deploy:
|
|||
review-docs-cleanup:
|
||||
extends: .review-docs
|
||||
environment:
|
||||
name: review-docs/$CI_COMMIT_REF_SLUG
|
||||
name: review-docs/$DOCS_GITLAB_REPO_SUFFIX-$CI_MERGE_REQUEST_IID
|
||||
action: stop
|
||||
script:
|
||||
- ./trigger-build-docs cleanup
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
- .default-before_script
|
||||
- .assets-compile-cache
|
||||
- .only-code-qa-changes
|
||||
image: dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-git-2.22-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-18.06.1
|
||||
image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-git-2.22-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-18.06.1
|
||||
stage: test
|
||||
dependencies: ["setup-test-env"]
|
||||
needs: ["setup-test-env"]
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
- name: redis:alpine
|
||||
|
||||
.use-pg10:
|
||||
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.33"
|
||||
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.33"
|
||||
services:
|
||||
- name: postgres:10.9
|
||||
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||
|
@ -137,7 +137,7 @@
|
|||
- name: docker.elastic.co/elasticsearch/elasticsearch:5.6.12
|
||||
|
||||
.use-pg10-ee:
|
||||
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.33"
|
||||
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.33"
|
||||
services:
|
||||
- name: postgres:10.9
|
||||
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -465,7 +465,7 @@ gem 'lograge', '~> 0.5'
|
|||
gem 'grape_logging', '~> 1.7'
|
||||
|
||||
# DNS Lookup
|
||||
gem 'net-dns', '~> 0.9.0'
|
||||
gem 'gitlab-net-dns', '~> 0.9.1'
|
||||
|
||||
# Countries list
|
||||
gem 'countries', '~> 3.0'
|
||||
|
|
|
@ -370,6 +370,7 @@ GEM
|
|||
redis (> 3.0.0, < 5.0.0)
|
||||
gitlab-license (1.0.0)
|
||||
gitlab-markup (1.7.0)
|
||||
gitlab-net-dns (0.9.1)
|
||||
gitlab-peek (0.0.1)
|
||||
railties (>= 4.0.0)
|
||||
gitlab-sidekiq-fetcher (0.5.2)
|
||||
|
@ -596,7 +597,6 @@ GEM
|
|||
mustermann (~> 1.0.0)
|
||||
nakayoshi_fork (0.0.4)
|
||||
nap (1.1.0)
|
||||
net-dns (0.9.0)
|
||||
net-ldap (0.16.0)
|
||||
net-ntp (2.1.3)
|
||||
net-ssh (5.2.0)
|
||||
|
@ -1173,6 +1173,7 @@ DEPENDENCIES
|
|||
gitlab-labkit (~> 0.5)
|
||||
gitlab-license (~> 1.0)
|
||||
gitlab-markup (~> 1.7.0)
|
||||
gitlab-net-dns (~> 0.9.1)
|
||||
gitlab-peek (~> 0.0.1)
|
||||
gitlab-sidekiq-fetcher (= 0.5.2)
|
||||
gitlab-styles (~> 2.7)
|
||||
|
@ -1222,7 +1223,6 @@ DEPENDENCIES
|
|||
mini_magick
|
||||
minitest (~> 5.11.0)
|
||||
nakayoshi_fork (~> 0.0.4)
|
||||
net-dns (~> 0.9.0)
|
||||
net-ldap
|
||||
net-ntp
|
||||
net-ssh (~> 5.2)
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<script>
|
||||
import { GlLink } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlLink,
|
||||
},
|
||||
props: {
|
||||
artifacts: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<table class="table m-0">
|
||||
<thead class="thead-white text-nowrap">
|
||||
<tr class="d-none d-sm-table-row">
|
||||
<th class="w-0"></th>
|
||||
<th>{{ __('Artifact') }}</th>
|
||||
<th class="w-50"></th>
|
||||
<th>{{ __('Job') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr v-for="item in artifacts" :key="item.text">
|
||||
<td class="w-0"></td>
|
||||
<td>
|
||||
<gl-link :href="item.url" target="_blank">{{ item.text }}</gl-link>
|
||||
</td>
|
||||
<td class="w-0"></td>
|
||||
<td>
|
||||
<gl-link :href="item.job_path">{{ item.job_name }}</gl-link>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
|
@ -0,0 +1,36 @@
|
|||
<script>
|
||||
import { mapActions, mapState, mapGetters } from 'vuex';
|
||||
import ArtifactsList from './artifacts_list.vue';
|
||||
import MrCollapsibleExtension from './mr_collapsible_extension.vue';
|
||||
import createStore from '../stores/artifacts_list';
|
||||
|
||||
export default {
|
||||
store: createStore(),
|
||||
components: {
|
||||
ArtifactsList,
|
||||
MrCollapsibleExtension,
|
||||
},
|
||||
props: {
|
||||
endpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(['artifacts', 'isLoading', 'hasError']),
|
||||
...mapGetters(['title']),
|
||||
},
|
||||
created() {
|
||||
this.setEndpoint(this.endpoint);
|
||||
this.fetchArtifacts();
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['setEndpoint', 'fetchArtifacts']),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<mr-collapsible-extension :title="title" :is-loading="isLoading" :has-error="hasError">
|
||||
<artifacts-list :artifacts="artifacts" />
|
||||
</mr-collapsible-extension>
|
||||
</template>
|
|
@ -0,0 +1,81 @@
|
|||
<script>
|
||||
import { GlButton, GlLink, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlButton,
|
||||
GlLink,
|
||||
GlLoadingIcon,
|
||||
Icon,
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
hasError: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isCollapsed: true,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
arrowIconName() {
|
||||
return this.isCollapsed ? 'angle-right' : 'angle-down';
|
||||
},
|
||||
ariaLabel() {
|
||||
return this.isCollapsed ? __('Expand') : __('Collapse');
|
||||
},
|
||||
isButtonDisabled() {
|
||||
return this.isLoading || this.hasError;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleCollapsed() {
|
||||
this.isCollapsed = !this.isCollapsed;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="mr-widget-extension d-flex align-items-center pl-3">
|
||||
<gl-button
|
||||
class="btn-blank btn s32 square append-right-default"
|
||||
:aria-label="ariaLabel"
|
||||
:disabled="isButtonDisabled"
|
||||
@click="toggleCollapsed"
|
||||
>
|
||||
<gl-loading-icon v-if="isLoading" />
|
||||
<icon v-else :name="arrowIconName" class="js-icon" />
|
||||
</gl-button>
|
||||
<gl-button
|
||||
variant="link"
|
||||
class="js-title"
|
||||
:disabled="isButtonDisabled"
|
||||
:class="{ 'border-0': isButtonDisabled }"
|
||||
@click="toggleCollapsed"
|
||||
>
|
||||
<template v-if="isCollapsed">{{ title }}</template>
|
||||
<template v-else>{{ __('Collapse') }}</template>
|
||||
</gl-button>
|
||||
</div>
|
||||
|
||||
<div v-if="!isCollapsed" class="border-top js-slot-container">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import _ from 'underscore';
|
||||
import ArtifactsApp from './artifacts_list_app.vue';
|
||||
import Deployment from './deployment.vue';
|
||||
import MrWidgetContainer from './mr_widget_container.vue';
|
||||
import MrWidgetPipeline from './mr_widget_pipeline.vue';
|
||||
|
@ -15,6 +16,7 @@ import MrWidgetPipeline from './mr_widget_pipeline.vue';
|
|||
export default {
|
||||
name: 'MrWidgetPipelineContainer',
|
||||
components: {
|
||||
ArtifactsApp,
|
||||
Deployment,
|
||||
MrWidgetContainer,
|
||||
MrWidgetPipeline,
|
||||
|
@ -79,6 +81,9 @@ export default {
|
|||
:troubleshooting-docs-path="mr.troubleshootingDocsPath"
|
||||
/>
|
||||
<template v-slot:footer>
|
||||
<div v-if="mr.exposedArtifactsPath" class="js-exposed-artifacts">
|
||||
<artifacts-app :endpoint="mr.exposedArtifactsPath" />
|
||||
</div>
|
||||
<div v-if="deployments.length" class="mr-widget-extension">
|
||||
<deployment
|
||||
v-for="deployment in deployments"
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
import Visibility from 'visibilityjs';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import Poll from '~/lib/utils/poll';
|
||||
import httpStatusCodes from '~/lib/utils/http_status';
|
||||
|
||||
import * as types from './mutation_types';
|
||||
|
||||
export const setEndpoint = ({ commit }, endpoint) => commit(types.SET_ENDPOINT, endpoint);
|
||||
|
||||
export const requestArtifacts = ({ commit }) => commit(types.REQUEST_ARTIFACTS);
|
||||
|
||||
let eTagPoll;
|
||||
|
||||
export const clearEtagPoll = () => {
|
||||
eTagPoll = null;
|
||||
};
|
||||
|
||||
export const stopPolling = () => {
|
||||
if (eTagPoll) eTagPoll.stop();
|
||||
};
|
||||
|
||||
export const restartPolling = () => {
|
||||
if (eTagPoll) eTagPoll.restart();
|
||||
};
|
||||
|
||||
export const fetchArtifacts = ({ state, dispatch }) => {
|
||||
dispatch('requestArtifacts');
|
||||
|
||||
eTagPoll = new Poll({
|
||||
resource: {
|
||||
getArtifacts(endpoint) {
|
||||
return axios.get(endpoint);
|
||||
},
|
||||
},
|
||||
data: state.endpoint,
|
||||
method: 'getArtifacts',
|
||||
successCallback: ({ data, status }) => {
|
||||
dispatch('receiveArtifactsSuccess', {
|
||||
data,
|
||||
status,
|
||||
});
|
||||
},
|
||||
errorCallback: () => dispatch('receiveArtifactsError'),
|
||||
});
|
||||
|
||||
if (!Visibility.hidden()) {
|
||||
eTagPoll.makeRequest();
|
||||
} else {
|
||||
axios
|
||||
.get(state.endpoint)
|
||||
.then(({ data, status }) => dispatch('receiveArtifactsSuccess', { data, status }))
|
||||
.catch(() => dispatch('receiveArtifactsError'));
|
||||
}
|
||||
|
||||
Visibility.change(() => {
|
||||
if (!Visibility.hidden()) {
|
||||
dispatch('restartPolling');
|
||||
} else {
|
||||
dispatch('stopPolling');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const receiveArtifactsSuccess = ({ commit }, response) => {
|
||||
// With 204 we keep polling and don't update the state
|
||||
if (response.status === httpStatusCodes.OK) {
|
||||
commit(types.RECEIVE_ARTIFACTS_SUCCESS, response.data);
|
||||
}
|
||||
};
|
||||
|
||||
export const receiveArtifactsError = ({ commit }) => commit(types.RECEIVE_ARTIFACTS_ERROR);
|
||||
|
||||
// prevent babel-plugin-rewire from generating an invalid default during karma tests
|
||||
export default () => {};
|
|
@ -0,0 +1,16 @@
|
|||
import { s__, n__ } from '~/locale';
|
||||
|
||||
export const title = state => {
|
||||
if (state.isLoading) {
|
||||
return s__('BuildArtifacts|Loading artifacts');
|
||||
}
|
||||
|
||||
if (state.hasError) {
|
||||
return s__('BuildArtifacts|An error occurred while fetching the artifacts');
|
||||
}
|
||||
|
||||
return n__('View exposed artifact', 'View %d exposed artifacts', state.artifacts.length);
|
||||
};
|
||||
|
||||
// prevent babel-plugin-rewire from generating an invalid default during karma tests
|
||||
export default () => {};
|
|
@ -0,0 +1,16 @@
|
|||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import * as actions from './actions';
|
||||
import mutations from './mutations';
|
||||
import * as getters from './getters';
|
||||
import state from './state';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default () =>
|
||||
new Vuex.Store({
|
||||
actions,
|
||||
mutations,
|
||||
getters,
|
||||
state: state(),
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
export const SET_ENDPOINT = 'SET_ENDPOINT';
|
||||
|
||||
export const REQUEST_ARTIFACTS = 'REQUEST_ARTIFACTS';
|
||||
export const RECEIVE_ARTIFACTS_SUCCESS = 'RECEIVE_ARTIFACTS_SUCCESS';
|
||||
export const RECEIVE_ARTIFACTS_ERROR = 'RECEIVE_ARTIFACTS_ERROR';
|
|
@ -0,0 +1,22 @@
|
|||
import * as types from './mutation_types';
|
||||
|
||||
export default {
|
||||
[types.SET_ENDPOINT](state, endpoint) {
|
||||
state.endpoint = endpoint;
|
||||
},
|
||||
[types.REQUEST_ARTIFACTS](state) {
|
||||
state.isLoading = true;
|
||||
},
|
||||
[types.RECEIVE_ARTIFACTS_SUCCESS](state, response) {
|
||||
state.hasError = false;
|
||||
state.isLoading = false;
|
||||
|
||||
state.artifacts = response;
|
||||
},
|
||||
[types.RECEIVE_ARTIFACTS_ERROR](state) {
|
||||
state.isLoading = false;
|
||||
state.hasError = true;
|
||||
|
||||
state.artifacts = [];
|
||||
},
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
export default () => ({
|
||||
endpoint: null,
|
||||
|
||||
isLoading: false,
|
||||
hasError: false,
|
||||
|
||||
artifacts: [],
|
||||
});
|
|
@ -100,6 +100,7 @@ export default class MergeRequestStore {
|
|||
this.isPipelineBlocked = pipelineStatus ? pipelineStatus.group === 'manual' : false;
|
||||
this.ciStatusFaviconPath = pipelineStatus ? pipelineStatus.favicon : null;
|
||||
this.testResultsPath = data.test_reports_path;
|
||||
this.exposedArtifactsPath = data.exposed_artifacts_path;
|
||||
this.cancelAutoMergePath = data.cancel_auto_merge_path;
|
||||
this.canCancelAutomaticMerge = Boolean(data.cancel_auto_merge_path);
|
||||
|
||||
|
|
|
@ -508,7 +508,6 @@
|
|||
.btn-group
|
||||
%a.btn Edit
|
||||
%a.btn.btn-danger Remove
|
||||
.file-contenta.code
|
||||
= render 'shared/file_highlight', blob: blob
|
||||
|
||||
%h2#markdown Markdown
|
||||
|
|
5
changelogs/unreleased/15018-build-results-fe.yml
Normal file
5
changelogs/unreleased/15018-build-results-fe.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Creates Vue and Vuex app to render exposed artifacts
|
||||
merge_request: 17934
|
||||
author:
|
||||
type: added
|
|
@ -377,6 +377,14 @@ The certificate to be used needs to be installed on all Gitaly nodes and on all
|
|||
client nodes that communicate with it following the procedure described in
|
||||
[GitLab custom certificate configuration](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates).
|
||||
|
||||
NOTE: **Note**
|
||||
The self-signed certificate must specify the address you use to access the
|
||||
Gitaly server. If you are addressing the Gitaly server by a hostname, you can
|
||||
either use the Common Name field for this, or add it as a Subject Alternative
|
||||
Name. If you are addressing the Gitaly server by its IP address, you must add it
|
||||
as a Subject Alternative Name to the certificate.
|
||||
[gRPC does not support using an IP address as Common Name in a certificate](https://github.com/grpc/grpc/issues/2691).
|
||||
|
||||
NOTE: **Note:**
|
||||
It is possible to configure Gitaly servers with both an
|
||||
unencrypted listening address `listen_addr` and an encrypted listening
|
||||
|
|
|
@ -300,17 +300,17 @@ You will need to push a branch to those repositories, it doesn't work for forks.
|
|||
The `review-docs-deploy*` job will:
|
||||
|
||||
1. Create a new branch in the [`gitlab-docs`](https://gitlab.com/gitlab-org/gitlab-docs)
|
||||
project named after the scheme: `$DOCS_GITLAB_REPO_SUFFIX-$CI_ENVIRONMENT_SLUG`,
|
||||
where `DOCS_GITLAB_REPO_SUFFIX` is the suffix for each product, e.g, `ce` for
|
||||
CE, etc.
|
||||
1. Trigger a cross project pipeline and build the docs site with your changes
|
||||
project named after the scheme: `docs-preview-$DOCS_GITLAB_REPO_SUFFIX-$CI_MERGE_REQUEST_IID`,
|
||||
where `DOCS_GITLAB_REPO_SUFFIX` is the suffix for each product, e.g, `ee` for
|
||||
EE, `omnibus` for Omnibus GitLab, etc, and `CI_MERGE_REQUEST_IID` is the ID
|
||||
of the respective merge request.
|
||||
1. Trigger a cross project pipeline and build the docs site with your changes.
|
||||
|
||||
After a few minutes, the Review App will be deployed and you will be able to
|
||||
preview the changes. The docs URL can be found in two places:
|
||||
|
||||
- In the merge request widget
|
||||
- In the output of the `review-docs-deploy*` job, which also includes the
|
||||
triggered pipeline so that you can investigate whether something went wrong
|
||||
In case the review app URL returns 404, this means that either the site is not
|
||||
yet deployed, or something went wrong with the remote pipeline. Give it a few
|
||||
minutes and it should appear online, otherwise you can check the status of the
|
||||
remote pipeline from the link in the merge request's job output.
|
||||
If the pipeline failed or got stuck, drop a line in the `#docs` chat channel.
|
||||
|
||||
TIP: **Tip:**
|
||||
Someone with no merge rights to the GitLab projects (think of forks from
|
||||
|
@ -343,12 +343,11 @@ If you want to know the in-depth details, here's what's really happening:
|
|||
1. The job runs the [`scripts/trigger-build-docs`](https://gitlab.com/gitlab-org/gitlab/blob/master/scripts/trigger-build-docs)
|
||||
script with the `deploy` flag, which in turn:
|
||||
1. Takes your branch name and applies the following:
|
||||
- The slug of the branch name is used to avoid special characters since
|
||||
ultimately this will be used by NGINX.
|
||||
- The `preview-` prefix is added to avoid conflicts if there's a remote branch
|
||||
with the same name that you created in the merge request.
|
||||
- The final branch name is truncated to 42 characters to avoid filesystem
|
||||
limitations with long branch names (> 63 chars).
|
||||
- The `docs-preview-` prefix is added.
|
||||
- The product slug is used to know the project the review app originated
|
||||
from.
|
||||
- The number of the merge request is added so that you can know by the
|
||||
`gitlab-docs` branch name the merge request it originated from.
|
||||
1. The remote branch is then created if it doesn't exist (meaning you can
|
||||
re-run the manual job as many times as you want and this step will be skipped).
|
||||
1. A new cross-project pipeline is triggered in the docs project.
|
||||
|
@ -369,6 +368,7 @@ The following GitLab features are used among others:
|
|||
- [Review Apps](../../ci/review_apps/index.md)
|
||||
- [Artifacts](../../ci/yaml/README.md#artifacts)
|
||||
- [Specific Runner](../../ci/runners/README.md#locking-a-specific-runner-from-being-enabled-for-other-projects)
|
||||
- [Pipelines for merge requests](../../ci/merge_request_pipelines/index.md)
|
||||
|
||||
## Testing
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ The current stages are:
|
|||
## Default image
|
||||
|
||||
The default image is currently
|
||||
`dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33`.
|
||||
`gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33`.
|
||||
It includes Ruby 2.6.3, Go 1.11, Git 2.22, Chrome 73, Node 12, Yarn 1.16,
|
||||
PostgreSQL 9.6, and Graphics Magick 1.3.33.
|
||||
|
||||
|
|
|
@ -1964,6 +1964,9 @@ msgstr ""
|
|||
msgid "Arrange charts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Artifact"
|
||||
msgstr ""
|
||||
|
||||
msgid "Artifact ID"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2661,6 +2664,12 @@ msgstr ""
|
|||
msgid "Browse files"
|
||||
msgstr ""
|
||||
|
||||
msgid "BuildArtifacts|An error occurred while fetching the artifacts"
|
||||
msgstr ""
|
||||
|
||||
msgid "BuildArtifacts|Loading artifacts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Built-in"
|
||||
msgstr ""
|
||||
|
||||
|
@ -18067,6 +18076,11 @@ msgstr ""
|
|||
msgid "View epics list"
|
||||
msgstr ""
|
||||
|
||||
msgid "View exposed artifact"
|
||||
msgid_plural "View %d exposed artifacts"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "View file @ "
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -16,14 +16,12 @@ end
|
|||
GITLAB_DOCS_REPO = 'gitlab-org/gitlab-docs'.freeze
|
||||
|
||||
#
|
||||
# Truncate the remote docs branch name otherwise we hit the filesystem
|
||||
# limit and the directory name where NGINX serves the site won't match
|
||||
# the branch name.
|
||||
# This is the branch that will be created in the gitlab-docs project.
|
||||
# Name it after the product we're previewing and the ID of the MR that
|
||||
# kicked the review app.
|
||||
#
|
||||
def docs_branch
|
||||
# The maximum string length a file can have on a filesystem (ext4)
|
||||
# is 63 characters. CI_ENVIRONMENT_SLUG is limited to 24 characters.
|
||||
ENV["CI_ENVIRONMENT_SLUG"]
|
||||
"docs-preview-#{slug}-#{ENV["CI_MERGE_REQUEST_IID"]}"
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
import { mount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import { TEST_HOST } from 'helpers/test_constants';
|
||||
import ArtifactsListApp from '~/vue_merge_request_widget/components/artifacts_list_app.vue';
|
||||
import createStore from '~/vue_merge_request_widget/stores/artifacts_list';
|
||||
import { artifactsList } from './mock_data';
|
||||
|
||||
describe('Merge Requests Artifacts list app', () => {
|
||||
let wrapper;
|
||||
let mock;
|
||||
const store = createStore();
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
const actionSpies = {
|
||||
fetchArtifacts: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
const createComponent = () => {
|
||||
wrapper = mount(localVue.extend(ArtifactsListApp), {
|
||||
propsData: {
|
||||
endpoint: TEST_HOST,
|
||||
},
|
||||
store,
|
||||
methods: {
|
||||
...actionSpies,
|
||||
},
|
||||
localVue,
|
||||
sync: false,
|
||||
});
|
||||
};
|
||||
|
||||
const findButtons = () => wrapper.findAll('button');
|
||||
const findTitle = () => wrapper.find('.js-title');
|
||||
const findTableRows = () => wrapper.findAll('tbody tr');
|
||||
|
||||
describe('while loading', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
store.dispatch('requestArtifacts');
|
||||
return wrapper.vm.$nextTick();
|
||||
});
|
||||
|
||||
it('renders a loading icon', () => {
|
||||
const loadingIcon = wrapper.find(GlLoadingIcon);
|
||||
expect(loadingIcon.exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders loading text', () => {
|
||||
expect(findTitle().text()).toBe('Loading artifacts');
|
||||
});
|
||||
|
||||
it('renders disabled buttons', () => {
|
||||
const buttons = findButtons();
|
||||
expect(buttons.at(0).attributes('disabled')).toBe('disabled');
|
||||
expect(buttons.at(1).attributes('disabled')).toBe('disabled');
|
||||
});
|
||||
});
|
||||
|
||||
describe('with results', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
mock.onGet(wrapper.vm.$store.state.endpoint).reply(200, artifactsList, {});
|
||||
store.dispatch('receiveArtifactsSuccess', {
|
||||
data: artifactsList,
|
||||
status: 200,
|
||||
});
|
||||
return wrapper.vm.$nextTick();
|
||||
});
|
||||
|
||||
it('renders a title with the number of artifacts', () => {
|
||||
expect(findTitle().text()).toBe('View 2 exposed artifacts');
|
||||
});
|
||||
|
||||
it('renders both buttons enabled', () => {
|
||||
const buttons = findButtons();
|
||||
expect(buttons.at(0).attributes('disabled')).toBe(undefined);
|
||||
expect(buttons.at(1).attributes('disabled')).toBe(undefined);
|
||||
});
|
||||
|
||||
describe('on click', () => {
|
||||
it('renders the list of artifacts', () => {
|
||||
findTitle().trigger('click');
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(findTableRows().length).toEqual(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with error', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
mock.onGet(wrapper.vm.$store.state.endpoint).reply(500, {}, {});
|
||||
store.dispatch('receiveArtifactsError');
|
||||
return wrapper.vm.$nextTick();
|
||||
});
|
||||
|
||||
it('renders the error state', () => {
|
||||
expect(findTitle().text()).toBe('An error occurred while fetching the artifacts');
|
||||
});
|
||||
|
||||
it('renders disabled buttons', () => {
|
||||
const buttons = findButtons();
|
||||
expect(buttons.at(0).attributes('disabled')).toBe('disabled');
|
||||
expect(buttons.at(1).attributes('disabled')).toBe('disabled');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,61 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import { GlLink } from '@gitlab/ui';
|
||||
import ArtifactsList from '~/vue_merge_request_widget/components/artifacts_list.vue';
|
||||
import { artifactsList } from './mock_data';
|
||||
|
||||
describe('Artifacts List', () => {
|
||||
let wrapper;
|
||||
const localVue = createLocalVue();
|
||||
|
||||
const data = {
|
||||
artifacts: artifactsList,
|
||||
};
|
||||
|
||||
const mountComponent = props => {
|
||||
wrapper = shallowMount(localVue.extend(ArtifactsList), {
|
||||
propsData: {
|
||||
...props,
|
||||
},
|
||||
sync: false,
|
||||
localVue,
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mountComponent(data);
|
||||
});
|
||||
|
||||
it('renders list of artifacts', () => {
|
||||
expect(wrapper.findAll('tbody tr').length).toEqual(data.artifacts.length);
|
||||
});
|
||||
|
||||
it('renders link for the artifact', () => {
|
||||
expect(wrapper.find(GlLink).attributes('href')).toEqual(data.artifacts[0].url);
|
||||
});
|
||||
|
||||
it('renders artifact name', () => {
|
||||
expect(wrapper.find(GlLink).text()).toEqual(data.artifacts[0].text);
|
||||
});
|
||||
|
||||
it('renders job url', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.findAll(GlLink)
|
||||
.at(1)
|
||||
.attributes('href'),
|
||||
).toEqual(data.artifacts[0].job_path);
|
||||
});
|
||||
|
||||
it('renders job name', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.findAll(GlLink)
|
||||
.at(1)
|
||||
.text(),
|
||||
).toEqual(data.artifacts[0].job_name);
|
||||
});
|
||||
});
|
15
spec/frontend/vue_mr_widget/components/mock_data.js
Normal file
15
spec/frontend/vue_mr_widget/components/mock_data.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const artifactsList = [
|
||||
{
|
||||
text: 'result.txt',
|
||||
url: 'bar',
|
||||
job_name: 'generate-artifact',
|
||||
job_path: 'bar',
|
||||
},
|
||||
{
|
||||
text: 'foo.txt',
|
||||
url: 'foo',
|
||||
job_name: 'foo-artifact',
|
||||
job_path: 'foo',
|
||||
},
|
||||
];
|
|
@ -0,0 +1,105 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import MrCollapsibleSection from '~/vue_merge_request_widget/components/mr_collapsible_extension.vue';
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
|
||||
describe('Merge Request Collapsible Extension', () => {
|
||||
let wrapper;
|
||||
const data = {
|
||||
title: 'View artifacts',
|
||||
};
|
||||
|
||||
const mountComponent = props => {
|
||||
wrapper = mount(MrCollapsibleSection, {
|
||||
propsData: {
|
||||
...props,
|
||||
},
|
||||
slots: {
|
||||
default: '<div class="js-slot">Foo</div>',
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findTitle = () => wrapper.find('.js-title');
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
describe('while collapsed', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent(data);
|
||||
});
|
||||
|
||||
it('renders provided title', () => {
|
||||
expect(findTitle().text()).toBe(data.title);
|
||||
});
|
||||
|
||||
it('renders angle-right icon', () => {
|
||||
expect(wrapper.vm.arrowIconName).toBe('angle-right');
|
||||
});
|
||||
|
||||
describe('onClick', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('button').trigger('click');
|
||||
});
|
||||
|
||||
it('rendes the provided slot', () => {
|
||||
expect(wrapper.find('.js-slot').isVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders `Collapse` as the title', () => {
|
||||
expect(findTitle().text()).toBe('Collapse');
|
||||
});
|
||||
|
||||
it('renders angle-down icon', () => {
|
||||
expect(wrapper.vm.arrowIconName).toBe('angle-down');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('while loading', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent(Object.assign({}, data, { isLoading: true }));
|
||||
});
|
||||
|
||||
it('renders the buttons disabled', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.findAll('button')
|
||||
.at(0)
|
||||
.attributes('disabled'),
|
||||
).toEqual('disabled');
|
||||
expect(
|
||||
wrapper
|
||||
.findAll('button')
|
||||
.at(1)
|
||||
.attributes('disabled'),
|
||||
).toEqual('disabled');
|
||||
});
|
||||
|
||||
it('renders loading spinner', () => {
|
||||
expect(wrapper.find(GlLoadingIcon).isVisible()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with error', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent(Object.assign({}, data, { hasError: true }));
|
||||
});
|
||||
|
||||
it('renders the buttons disabled', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.findAll('button')
|
||||
.at(0)
|
||||
.attributes('disabled'),
|
||||
).toEqual('disabled');
|
||||
expect(
|
||||
wrapper
|
||||
.findAll('button')
|
||||
.at(1)
|
||||
.attributes('disabled'),
|
||||
).toEqual('disabled');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
import { title } from '~/vue_merge_request_widget/stores/artifacts_list/getters';
|
||||
import state from '~/vue_merge_request_widget/stores/artifacts_list/state';
|
||||
import { artifactsList } from '../../components/mock_data';
|
||||
|
||||
describe('Artifacts Store Getters', () => {
|
||||
let localState;
|
||||
|
||||
beforeEach(() => {
|
||||
localState = state();
|
||||
});
|
||||
|
||||
describe('title', () => {
|
||||
describe('when is loading', () => {
|
||||
it('returns loading message', () => {
|
||||
localState.isLoading = true;
|
||||
expect(title(localState)).toBe('Loading artifacts');
|
||||
});
|
||||
});
|
||||
describe('when has error', () => {
|
||||
it('returns error message', () => {
|
||||
localState.hasError = true;
|
||||
expect(title(localState)).toBe('An error occurred while fetching the artifacts');
|
||||
});
|
||||
});
|
||||
describe('when it has artifacts', () => {
|
||||
it('returns artifacts message', () => {
|
||||
localState.artifacts = artifactsList;
|
||||
expect(title(localState)).toBe('View 2 exposed artifacts');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,78 @@
|
|||
import state from '~/vue_merge_request_widget/stores/artifacts_list/state';
|
||||
import mutations from '~/vue_merge_request_widget/stores/artifacts_list/mutations';
|
||||
import * as types from '~/vue_merge_request_widget/stores/artifacts_list/mutation_types';
|
||||
|
||||
describe('Artifacts Store Mutations', () => {
|
||||
let stateCopy;
|
||||
|
||||
beforeEach(() => {
|
||||
stateCopy = state();
|
||||
});
|
||||
|
||||
describe('SET_ENDPOINT', () => {
|
||||
it('should set endpoint', () => {
|
||||
mutations[types.SET_ENDPOINT](stateCopy, 'endpoint.json');
|
||||
|
||||
expect(stateCopy.endpoint).toEqual('endpoint.json');
|
||||
});
|
||||
});
|
||||
|
||||
describe('REQUEST_ARTIFACTS', () => {
|
||||
it('should set isLoading to true', () => {
|
||||
mutations[types.REQUEST_ARTIFACTS](stateCopy);
|
||||
|
||||
expect(stateCopy.isLoading).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('REECEIVE_ARTIFACTS_SUCCESS', () => {
|
||||
const artifacts = [
|
||||
{
|
||||
text: 'result.txt',
|
||||
url: 'asda',
|
||||
job_name: 'generate-artifact',
|
||||
job_path: 'asda',
|
||||
},
|
||||
{
|
||||
text: 'file.txt',
|
||||
url: 'asda',
|
||||
job_name: 'generate-artifact',
|
||||
job_path: 'asda',
|
||||
},
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
mutations[types.RECEIVE_ARTIFACTS_SUCCESS](stateCopy, artifacts);
|
||||
});
|
||||
|
||||
it('should set isLoading to false', () => {
|
||||
expect(stateCopy.isLoading).toEqual(false);
|
||||
});
|
||||
|
||||
it('should set hasError to false', () => {
|
||||
expect(stateCopy.hasError).toEqual(false);
|
||||
});
|
||||
|
||||
it('should set list of artifacts', () => {
|
||||
expect(stateCopy.artifacts).toEqual(artifacts);
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECEIVE_ARTIFACTS_ERROR', () => {
|
||||
beforeEach(() => {
|
||||
mutations[types.RECEIVE_ARTIFACTS_ERROR](stateCopy);
|
||||
});
|
||||
|
||||
it('should set isLoading to false', () => {
|
||||
expect(stateCopy.isLoading).toEqual(false);
|
||||
});
|
||||
|
||||
it('should set hasError to true', () => {
|
||||
expect(stateCopy.hasError).toEqual(true);
|
||||
});
|
||||
|
||||
it('should set list of artifacts as empty array', () => {
|
||||
expect(stateCopy.artifacts).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,6 +1,7 @@
|
|||
import { mount, 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 ArtifactsApp from '~/vue_merge_request_widget/components/artifacts_list_app.vue';
|
||||
import { mockStore } from '../mock_data';
|
||||
|
||||
describe('MrWidgetPipelineContainer', () => {
|
||||
|
@ -87,4 +88,10 @@ describe('MrWidgetPipelineContainer', () => {
|
|||
expect(deployments.wrappers.map(x => x.props())).toEqual(expectedProps);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with artifacts path', () => {
|
||||
it('renders the artifacts app', () => {
|
||||
expect(wrapper.find(ArtifactsApp).isVisible()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -289,4 +289,5 @@ export const mockStore = {
|
|||
troubleshootingDocsPath: 'troubleshooting-docs-path',
|
||||
ciStatus: 'ci-status',
|
||||
hasCI: true,
|
||||
exposedArtifactsPath: 'exposed_artifacts.json',
|
||||
};
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import {
|
||||
setEndpoint,
|
||||
requestArtifacts,
|
||||
clearEtagPoll,
|
||||
stopPolling,
|
||||
fetchArtifacts,
|
||||
receiveArtifactsSuccess,
|
||||
receiveArtifactsError,
|
||||
} from '~/vue_merge_request_widget/stores/artifacts_list/actions';
|
||||
import state from '~/vue_merge_request_widget/stores/artifacts_list/state';
|
||||
import * as types from '~/vue_merge_request_widget/stores/artifacts_list/mutation_types';
|
||||
import testAction from 'spec/helpers/vuex_action_helper';
|
||||
import { TEST_HOST } from 'spec/test_constants';
|
||||
|
||||
describe('Artifacts App Store Actions', () => {
|
||||
let mockedState;
|
||||
|
||||
beforeEach(() => {
|
||||
mockedState = state();
|
||||
});
|
||||
|
||||
describe('setEndpoint', () => {
|
||||
it('should commit SET_ENDPOINT mutation', done => {
|
||||
testAction(
|
||||
setEndpoint,
|
||||
'endpoint.json',
|
||||
mockedState,
|
||||
[{ type: types.SET_ENDPOINT, payload: 'endpoint.json' }],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('requestArtifacts', () => {
|
||||
it('should commit REQUEST_ARTIFACTS mutation', done => {
|
||||
testAction(
|
||||
requestArtifacts,
|
||||
null,
|
||||
mockedState,
|
||||
[{ type: types.REQUEST_ARTIFACTS }],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchArtifacts', () => {
|
||||
let mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mockedState.endpoint = `${TEST_HOST}/endpoint.json`;
|
||||
mock = new MockAdapter(axios);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mock.restore();
|
||||
stopPolling();
|
||||
clearEtagPoll();
|
||||
});
|
||||
|
||||
describe('success', () => {
|
||||
it('dispatches requestArtifacts and receiveArtifactsSuccess ', done => {
|
||||
mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, [
|
||||
{
|
||||
text: 'result.txt',
|
||||
url: 'asda',
|
||||
job_name: 'generate-artifact',
|
||||
job_path: 'asda',
|
||||
},
|
||||
]);
|
||||
|
||||
testAction(
|
||||
fetchArtifacts,
|
||||
null,
|
||||
mockedState,
|
||||
[],
|
||||
[
|
||||
{
|
||||
type: 'requestArtifacts',
|
||||
},
|
||||
{
|
||||
payload: {
|
||||
data: [
|
||||
{
|
||||
text: 'result.txt',
|
||||
url: 'asda',
|
||||
job_name: 'generate-artifact',
|
||||
job_path: 'asda',
|
||||
},
|
||||
],
|
||||
status: 200,
|
||||
},
|
||||
type: 'receiveArtifactsSuccess',
|
||||
},
|
||||
],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('error', () => {
|
||||
beforeEach(() => {
|
||||
mock.onGet(`${TEST_HOST}/endpoint.json`).reply(500);
|
||||
});
|
||||
|
||||
it('dispatches requestArtifacts and receiveArtifactsError ', done => {
|
||||
testAction(
|
||||
fetchArtifacts,
|
||||
null,
|
||||
mockedState,
|
||||
[],
|
||||
[
|
||||
{
|
||||
type: 'requestArtifacts',
|
||||
},
|
||||
{
|
||||
type: 'receiveArtifactsError',
|
||||
},
|
||||
],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('receiveArtifactsSuccess', () => {
|
||||
it('should commit RECEIVE_ARTIFACTS_SUCCESS mutation with 200', done => {
|
||||
testAction(
|
||||
receiveArtifactsSuccess,
|
||||
{ data: { summary: {} }, status: 200 },
|
||||
mockedState,
|
||||
[{ type: types.RECEIVE_ARTIFACTS_SUCCESS, payload: { summary: {} } }],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
|
||||
it('should not commit RECEIVE_ARTIFACTS_SUCCESS mutation with 204', done => {
|
||||
testAction(
|
||||
receiveArtifactsSuccess,
|
||||
{ data: { summary: {} }, status: 204 },
|
||||
mockedState,
|
||||
[],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('receiveArtifactsError', () => {
|
||||
it('should commit RECEIVE_ARTIFACTS_ERROR mutation', done => {
|
||||
testAction(
|
||||
receiveArtifactsError,
|
||||
null,
|
||||
mockedState,
|
||||
[{ type: types.RECEIVE_ARTIFACTS_ERROR }],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue