Commit 32ccde8c authored by Filipa Lacerda's avatar Filipa Lacerda Committed by Phil Hughes

Use Vue component for job artifacts, Commit and Trigger Variables

parent 765686f2
import $ from 'jquery';
export default function handleRevealVariables() {
$('.js-reveal-variables')
.off('click')
.on('click', function click() {
$('.js-build-variables').toggle();
$(this).hide();
});
}
<script> <script>
import TimeagoTooltiop from '~/vue_shared/components/time_ago_tooltip.vue'; import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
export default { export default {
components: { components: {
TimeagoTooltiop, TimeagoTooltip,
}, },
mixins: [
timeagoMixin,
],
props: { props: {
// @build.artifacts_expired? artifact: {
haveArtifactsExpired: { type: Object,
type: Boolean,
required: true, required: true,
}, },
// @build.has_expiring_artifacts? },
willArtifactsExpire: { computed: {
type: Boolean, isExpired() {
required: true, return this.artifact.expired;
},
expireAt: {
type: String,
required: false,
default: null,
},
keepArtifactsPath: {
type: String,
required: false,
default: null,
},
downloadArtifactsPath: {
type: String,
required: false,
default: null,
}, },
browseArtifactsPath: { // Only when the key is `false` we can render this block
type: String, willExpire() {
required: false, return this.artifact.expired === false;
default: null,
}, },
}, },
}; };
...@@ -46,21 +33,22 @@ ...@@ -46,21 +33,22 @@
</div> </div>
<p <p
v-if="haveArtifactsExpired" v-if="isExpired"
class="js-artifacts-removed build-detail-row" class="js-artifacts-removed build-detail-row"
> >
{{ s__('Job|The artifacts were removed') }} {{ s__('Job|The artifacts were removed') }}
</p> </p>
<p <p
v-else-if="willArtifactsExpire" v-else-if="willExpire"
class="js-artifacts-will-be-removed build-detail-row" class="js-artifacts-will-be-removed build-detail-row"
> >
{{ s__('Job|The artifacts will be removed') }} {{ s__('Job|The artifacts will be removed in') }}
</p> </p>
<timeago-tooltiop <timeago-tooltip
v-if="expireAt" v-if="artifact.expire_at"
:time="expireAt" :time="artifact.expire_at"
/> />
<div <div
...@@ -68,8 +56,8 @@ ...@@ -68,8 +56,8 @@
role="group" role="group"
> >
<a <a
v-if="keepArtifactsPath" v-if="artifact.keep_path"
:href="keepArtifactsPath" :href="artifact.keep_path"
class="js-keep-artifacts btn btn-sm btn-default" class="js-keep-artifacts btn btn-sm btn-default"
data-method="post" data-method="post"
> >
...@@ -77,8 +65,8 @@ ...@@ -77,8 +65,8 @@
</a> </a>
<a <a
v-if="downloadArtifactsPath" v-if="artifact.download_path"
:href="downloadArtifactsPath" :href="artifact.download_path"
class="js-download-artifacts btn btn-sm btn-default" class="js-download-artifacts btn btn-sm btn-default"
download download
rel="nofollow" rel="nofollow"
...@@ -87,8 +75,8 @@ ...@@ -87,8 +75,8 @@
</a> </a>
<a <a
v-if="browseArtifactsPath" v-if="artifact.browse_path"
:href="browseArtifactsPath" :href="artifact.browse_path"
class="js-browse-artifacts btn btn-sm btn-default" class="js-browse-artifacts btn btn-sm btn-default"
> >
{{ s__('Job|Browse') }} {{ s__('Job|Browse') }}
......
<script> <script>
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
export default { export default {
components: { components: {
ClipboardButton, ClipboardButton,
},
props: {
pipelineShortSha: {
type: String,
required: true,
}, },
pipelineShaPath: { props: {
type: String, commit: {
required: true, type: Object,
required: true,
},
mergeRequest: {
type: Object,
required: false,
default: null,
},
isLastBlock: {
type: Boolean,
required: true,
},
}, },
mergeRequestReference: { };
type: String,
required: false,
default: null,
},
mergeRequestPath: {
type: String,
required: false,
default: null,
},
gitCommitTitlte: {
type: String,
required: true,
},
},
};
</script> </script>
<template> <template>
<div class="block"> <div
:class="{
'block-last': isLastBlock,
block: !isLastBlock
}">
<p> <p>
{{ __('Commit') }} {{ __('Commit') }}
<a <a
:href="pipelineShaPath" :href="commit.commit_path"
class="js-commit-sha commit-sha link-commit" class="js-commit-sha commit-sha link-commit"
> >{{ commit.short_id }}</a>
{{ pipelineShortSha }}
</a>
<clipboard-button <clipboard-button
:text="pipelineShortSha" :text="commit.short_id"
:title="__('Copy commit SHA to clipboard')" :title="__('Copy commit SHA to clipboard')"
css-class="btn btn-clipboard btn-transparent"
/> />
<a <a
v-if="mergeRequestPath && mergeRequestReference" v-if="mergeRequest"
:href="mergeRequestPath" :href="mergeRequest.path"
class="js-link-commit link-commit" class="js-link-commit link-commit"
> >{{ mergeRequest.iid }}</a>
{{ mergeRequestReference }}
</a>
</p> </p>
<p class="build-light-text append-bottom-0"> <p class="build-light-text append-bottom-0">
{{ gitCommitTitlte }} {{ commit.title }}
</p> </p>
</div> </div>
</template> </template>
<script> <script>
import timeagoMixin from '~/vue_shared/mixins/timeago'; import _ from 'underscore';
import { timeIntervalInWords } from '~/lib/utils/datetime_utility'; import timeagoMixin from '~/vue_shared/mixins/timeago';
import Icon from '~/vue_shared/components/icon.vue'; import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
import DetailRow from './sidebar_detail_row.vue'; import Icon from '~/vue_shared/components/icon.vue';
import DetailRow from './sidebar_detail_row.vue';
import ArtifactsBlock from './artifacts_block.vue';
import TriggerBlock from './trigger_block.vue';
import CommitBlock from './commit_block.vue';
export default { export default {
name: 'SidebarDetailsBlock', name: 'SidebarDetailsBlock',
components: { components: {
DetailRow, ArtifactsBlock,
Icon, CommitBlock,
}, DetailRow,
mixins: [timeagoMixin], Icon,
props: { TriggerBlock,
job: {
type: Object,
required: true,
}, },
isLoading: { mixins: [timeagoMixin],
type: Boolean, props: {
required: true, job: {
type: Object,
required: true,
},
isLoading: {
type: Boolean,
required: true,
},
runnerHelpUrl: {
type: String,
required: false,
default: '',
},
terminalPath: {
type: String,
required: false,
default: null,
},
}, },
runnerHelpUrl: { computed: {
type: String, shouldRenderContent() {
required: false, return !this.isLoading && Object.keys(this.job).length > 0;
default: '', },
}, coverage() {
terminalPath: { return `${this.job.coverage}%`;
type: String, },
required: false, duration() {
default: null, return timeIntervalInWords(this.job.duration);
}, },
}, queued() {
computed: { return timeIntervalInWords(this.job.queued);
shouldRenderContent() { },
return !this.isLoading && Object.keys(this.job).length > 0; runnerId() {
}, return `${this.job.runner.description} (#${this.job.runner.id})`;
coverage() { },
return `${this.job.coverage}%`; retryButtonClass() {
}, let className =
duration() { 'js-retry-button float-right btn btn-retry d-none d-md-block d-lg-block d-xl-block';
return timeIntervalInWords(this.job.duration); className +=
}, this.job.status && this.job.recoverable ? ' btn-primary' : ' btn-inverted-secondary';
queued() { return className;
return timeIntervalInWords(this.job.queued); },
}, hasTimeout() {
runnerId() { return this.job.metadata != null && this.job.metadata.timeout_human_readable !== null;
return `${this.job.runner.description} (#${this.job.runner.id})`; },
}, timeout() {
retryButtonClass() { if (this.job.metadata == null) {
let className = return '';
'js-retry-button float-right btn btn-retry d-none d-md-block d-lg-block d-xl-block'; }
className +=
this.job.status && this.job.recoverable ? ' btn-primary' : ' btn-inverted-secondary';
return className;
},
hasTimeout() {
return this.job.metadata != null && this.job.metadata.timeout_human_readable !== null;
},
timeout() {
if (this.job.metadata == null) {
return '';
}
let t = this.job.metadata.timeout_human_readable; let t = this.job.metadata.timeout_human_readable;
if (this.job.metadata.timeout_source !== '') { if (this.job.metadata.timeout_source !== '') {
t += ` (from ${this.job.metadata.timeout_source})`; t += ` (from ${this.job.metadata.timeout_source})`;
} }
return t; return t;
}, },
renderBlock() { renderBlock() {
return ( return (
this.job.merge_request || this.job.merge_request ||
this.job.duration || this.job.duration ||
this.job.finished_data || this.job.finished_data ||
this.job.erased_at || this.job.erased_at ||
this.job.queued || this.job.queued ||
this.job.runner || this.job.runner ||
this.job.coverage || this.job.coverage ||
this.job.tags.length || this.job.tags.length ||
this.job.cancel_path this.job.cancel_path
); );
},
hasArtifact() {
return !_.isEmpty(this.job.artifact);
},
hasTriggers() {
return !_.isEmpty(this.job.trigger);
},
hasStages() {
return (
this.job &&
this.job.pipeline &&
this.job.pipeline.stages &&
this.job.pipeline.stages.length > 0
) || false;
},
commit() {
return this.job.pipeline.commit || {};
},
}, },
}, };
};
</script> </script>
<template> <template>
<div> <div>
...@@ -229,6 +253,19 @@ export default { ...@@ -229,6 +253,19 @@ export default {
</a> </a>
</div> </div>
</div> </div>
<artifacts-block
v-if="hasArtifact"
:artifact="job.artifact"
/>
<trigger-block
v-if="hasTriggers"
:trigger="job.trigger"
/>
<commit-block
:is-last-block="hasStages"
:commit="commit"
:merge-request="job.merge_request"
/>
</template> </template>
<gl-loading-icon <gl-loading-icon
v-if="isLoading" v-if="isLoading"
......
<script> <script>
export default { export default {
props: { props: {
shortToken: { trigger: {
type: String,
required: false,
default: null,
},
variables: {
type: Object, type: Object,
required: false, required: true,
default: () => ({}),
}, },
}, },
data() { data() {
...@@ -20,7 +13,7 @@ ...@@ -20,7 +13,7 @@
}, },
computed: { computed: {
hasVariables() { hasVariables() {
return Object.keys(this.variables).length > 0; return this.trigger.variables && this.trigger.variables.length > 0;
}, },
}, },
methods: { methods: {
...@@ -38,17 +31,18 @@ ...@@ -38,17 +31,18 @@
</h4> </h4>
<p <p
v-if="shortToken" v-if="trigger.short_token"
class="js-short-token" class="js-short-token"
> >
<span class="build-light-text"> <span class="build-light-text">
{{ __('Token') }} {{ __('Token') }}
</span> </span>
{{ shortToken }} {{ trigger.short_token }}
</p> </p>
<p v-if="hasVariables"> <p v-if="hasVariables">
<button <button
v-if="!areVariablesVisible"
type="button" type="button"
class="btn btn-default group js-reveal-variables" class="btn btn-default group js-reveal-variables"
@click="revealVariables" @click="revealVariables"
...@@ -63,20 +57,20 @@ ...@@ -63,20 +57,20 @@
class="js-build-variables trigger-build-variables" class="js-build-variables trigger-build-variables"
> >
<template <template
v-for="(value, key) in variables" v-for="variable in trigger.variables"
> >
<dt <dt
:key="`${key}-variable`" :key="`${variable.key}-variable`"
class="js-build-variable trigger-build-variable" class="js-build-variable trigger-build-variable"
> >
{{ key }} {{ variable.key }}
</dt> </dt>
<dd <dd
:key="`${key}-value`" :key="`${variable.key}-value`"
class="js-build-value trigger-build-value" class="js-build-value trigger-build-value"
> >
{{ value }} {{ variable.value }}
</dd> </dd>
</template> </template>
</dl> </dl>
......
...@@ -4,7 +4,6 @@ import Poll from '../lib/utils/poll'; ...@@ -4,7 +4,6 @@ import Poll from '../lib/utils/poll';
import JobStore from './stores/job_store'; import JobStore from './stores/job_store';
import JobService from './services/job_service'; import JobService from './services/job_service';
import Job from '../job'; import Job from '../job';
import handleRevealVariables from '../build_variables';
export default class JobMediator { export default class JobMediator {
constructor(options = {}) { constructor(options = {}) {
...@@ -20,7 +19,6 @@ export default class JobMediator { ...@@ -20,7 +19,6 @@ export default class JobMediator {
initBuildClass() { initBuildClass() {
this.build = new Job(); this.build = new Job();
handleRevealVariables();
} }
fetchJob() { fetchJob() {
......
...@@ -3,63 +3,6 @@ ...@@ -3,63 +3,6 @@
.blocks-container .blocks-container
#js-details-block-vue{ data: { terminal_path: can?(current_user, :create_build_terminal, @build) && @build.has_terminal? ? terminal_project_job_path(@project, @build) : nil } } #js-details-block-vue{ data: { terminal_path: can?(current_user, :create_build_terminal, @build) && @build.has_terminal? ? terminal_project_job_path(@project, @build) : nil } }
- if can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?)
.block
.title
Job artifacts
- if @build.artifacts_expired?
%p.build-detail-row
The artifacts were removed
#{time_ago_with_tooltip(@build.artifacts_expire_at)}
- elsif @build.has_expiring_artifacts?
%p.build-detail-row
The artifacts will be removed
#{time_ago_with_tooltip(@build.artifacts_expire_at)}
- if @build.artifacts?
.btn-group.d-flex{ role: :group }
- if @build.has_expiring_artifacts? && can?(current_user, :update_build, @build)
= link_to keep_project_job_artifacts_path(@project, @build), class: 'btn btn-sm btn-default', method: :post do
Keep
= link_to download_project_job_artifacts_path(@project, @build), rel: 'nofollow', download: '', class: 'btn btn-sm btn-default' do
Download
- if @build.browsable_artifacts?
= link_to browse_project_job_artifacts_path(@project, @build), class: 'btn btn-sm btn-default' do
Browse
- if @build.trigger_request
.build-widget.block
%h4.title
Trigger
- if @build.trigger_request&.trigger&.short_token
%p
%span.build-light-text Token:
#{@build.trigger_request.trigger.short_token}
- if @build.trigger_variables.any?
%p
%button.btn.group.js-reveal-variables Reveal Variables
%dl.js-build-variables.trigger-build-variables.hide
- @build.trigger_variables.each do |trigger_variable|
%dt.js-build-variable.trigger-build-variable= trigger_variable[:key]
%dd.js-build-value.trigger-build-value= trigger_variable[:value]
%div{ class: (@build.pipeline.stages_count > 1 ? "block" : "block-last") }
%p
Commit
= link_to @build.pipeline.short_sha, project_commit_path(@project, @build.pipeline.sha), class: 'commit-sha link-commit'
= clipboard_button(text: @build.pipeline.short_sha, title: "Copy commit SHA to clipboard")
- if @build.merge_request
in
= link_to "#{@build.merge_request.to_reference}", merge_request_path(@build.merge_request), class: 'link-commit'
%p.build-light-text.append-bottom-0
#{@build.pipeline.git_commit_title}
- if @build.pipeline.stages_count > 1 - if @build.pipeline.stages_count > 1
.block-last.dropdown.build-dropdown .block-last.dropdown.build-dropdown
%div %div
......
---
title: Use Vue components and new API to render Artifacts, Trigger Variables and Commit blocks on Job page
merge_request: 21777
author:
type: other
...@@ -35,11 +35,15 @@ module Gitlab ...@@ -35,11 +35,15 @@ module Gitlab
request_headers = env_http_headers(env) request_headers = env_http_headers(env)
status, headers, body = @app.call(env) status, headers, body = @app.call(env)
full_body = ''
body.each { |b| full_body << b }
request = OpenStruct.new( request = OpenStruct.new(
url: url, url: url,
status_code: status, status_code: status,
request_headers: request_headers, request_headers: request_headers,
response_headers: headers response_headers: headers,
body: full_body
) )
log_request request log_request request
......
...@@ -3365,7 +3365,7 @@ msgstr "" ...@@ -3365,7 +3365,7 @@ msgstr ""
msgid "Job|The artifacts were removed" msgid "Job|The artifacts were removed"
msgstr "" msgstr ""
msgid "Job|The artifacts will be removed" msgid "Job|The artifacts will be removed in"
msgstr "" msgstr ""
msgid "Job|This job is stuck, because the project doesn't have any runners online assigned to it." msgid "Job|This job is stuck, because the project doesn't have any runners online assigned to it."
......
...@@ -20,23 +20,13 @@ describe "User downloads artifacts" do ...@@ -20,23 +20,13 @@ describe "User downloads artifacts" do
end end
context "via job id" do context "via job id" do
set(:url) { download_project_job_artifacts_path(project, job) } let(:url) { download_project_job_artifacts_path(project, job) }
it_behaves_like "downloading" it_behaves_like "downloading"
end end
context "via branch name and job name" do context "via branch name and job name" do
set(:url) { latest_succeeded_project_artifacts_path(project, "#{pipeline.ref}/download", job: job.name) } let(:url) { latest_succeeded_project_artifacts_path(project, "#{pipeline.ref}/download", job: job.name) }
it_behaves_like "downloading"
end
context "via clicking the `Download` button" do
set(:url) { project_job_path(project, job) }
before do
click_link("Download")
end
it_behaves_like "downloading" it_behaves_like "downloading"
end end
......
...@@ -5,7 +5,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -5,7 +5,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user_access_level) { :developer } let(:user_access_level) { :developer }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project) } let(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit('HEAD').sha) }
let(:job) { create(:ci_build, :trace_live, pipeline: pipeline) } let(:job) { create(:ci_build, :trace_live, pipeline: pipeline) }
let(:job2) { create(:ci_build) } let(:job2) { create(:ci_build) }
...@@ -20,7 +20,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -20,7 +20,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end end
describe "GET /:project/jobs" do describe "GET /:project/jobs" do
let!(:job) { create(:ci_build, pipeline: pipeline) } let!(:job) { create(:ci_build, pipeline: pipeline) }
context "Pending scope" do context "Pending scope" do
before do before do
...@@ -115,22 +115,28 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -115,22 +115,28 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
context "Job from project" do context "Job from project" do
let(:job) { create(:ci_build, :success, :trace_live, pipeline: pipeline) } let(:job) { create(:ci_build, :success, :trace_live, pipeline: pipeline) }
before do it 'shows status name', :js do
visit project_job_path(project, job) visit project_job_path(project, job)
end
it 'shows status name', :js do wait_for_requests
expect(page).to have_css('.ci-status.ci-success', text: 'passed') expect(page).to have_css('.ci-status.ci-success', text: 'passed')
end end
it 'shows commit`s data' do it 'shows commit`s data', :js do
expect(page.status_code).to eq(200) requests = inspect_requests() do
visit project_job_path(project, job)
end
wait_for_requests
expect(requests.first.status_code).to eq(200)
expect(page).to have_content pipeline.sha[0..7] expect(page).to have_content pipeline.sha[0..7]
expect(page).to have_content pipeline.git_commit_message expect(page).to have_content pipeline.commit.title
expect(page).to have_content pipeline.git_author_name
end end
it 'shows active job' do it 'shows active job' do
visit project_job_path(project, job)
expect(page).to have_selector('.build-job.active') expect(page).to have_selector('.build-job.active')
end end
end end
...@@ -199,7 +205,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -199,7 +205,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
it { expect(page.status_code).to eq(404) } it { expect(page.status_code).to eq(404) }
end end
context "Download artifacts" do context "Download artifacts", :js do
before do before do
job.update(legacy_artifacts_file: artifacts_file) job.update(legacy_artifacts_file: artifacts_file)
visit project_job_path(project, job) visit project_job_path(project, job)
...@@ -208,9 +214,22 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -208,9 +214,22 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
it 'has button to download artifacts' do it 'has button to download artifacts' do
expect(page).to have_content 'Download' expect(page).to have_content 'Download'
end end
it 'downloads the zip file when user clicks the download button' do
requests = inspect_requests() do
click_link 'Download'
end
artifact_request = requests.find { |req| req.url.match(%r{artifacts/download}) }
expect(artifact_request.response_headers["Content-Disposition"]).to eq(%Q{attachment; filename="#{job.artifacts_file.filename}"})
expect(artifact_request.response_headers['Content-Transfer-Encoding']).to eq("binary")
expect(artifact_request.response_headers['Content-Type']).to eq("image/gif")
expect(artifact_request.body).to eq(job.artifacts_file.file.read.b)
end
end end
context 'Artifacts expire date' do context 'Artifacts expire date', :js do
before do before do
job.update(legacy_artifacts_file: artifacts_file, job.update(legacy_artifacts_file: artifacts_file,
artifacts_expire_at: expire_at) artifacts_expire_at: expire_at)
...@@ -231,12 +250,12 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -231,12 +250,12 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
context 'when user has ability to update job' do context 'when user has ability to update job' do
it 'keeps artifacts when keep button is clicked' do it 'keeps artifacts when keep button is clicked' do
expect(page).to have_content 'The artifacts will be removed' expect(page).to have_content 'The artifacts will be removed in'
click_link 'Keep' click_link 'Keep'
expect(page).to have_no_link 'Keep' expect(page).to have_no_link 'Keep'
expect(page).to have_no_content 'The artifacts will be removed' expect(page).to have_no_content 'The artifacts will be removed in'
end end
end end
...@@ -314,6 +333,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -314,6 +333,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
shared_examples 'expected variables behavior' do shared_examples 'expected variables behavior' do
it 'shows variable key and value after click', :js do it 'shows variable key and value after click', :js do
expect(page).to have_content('Token')
expect(page).to have_css('.js-reveal-variables') expect(page).to have_css('.js-reveal-variables')
expect(page).not_to have_css('.js-build-variable') expect(page).not_to have_css('.js-build-variable')
expect(page).not_to have_css('.js-build-value') expect(page).not_to have_css('.js-build-value')
...@@ -542,20 +562,26 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -542,20 +562,26 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end end
end end
describe "GET /:project/jobs/:id/download" do describe "GET /:project/jobs/:id/download", :js do
before do before do
job.update(legacy_artifacts_file: artifacts_file) job.update(legacy_artifacts_file: artifacts_file)
visit project_job_path(project, job) visit project_job_path(project, job)
click_link 'Download' click_link 'Download'
end end
context "Build from other project" do context "Build from other project" do
before do before do
job2.update(legacy_artifacts_file: artifacts_file) job2.update(legacy_artifacts_file: artifacts_file)
visit download_project_job_artifacts_path(project, job2)
end end
it { expect(page.status_code).to eq(404) } it do
requests = inspect_requests() do
visit download_project_job_artifacts_path(project, job2)
end
expect(requests.first.status_code).to eq(404)
end
end end
end end
......
...@@ -11,6 +11,19 @@ describe('Artifacts block', () => { ...@@ -11,6 +11,19 @@ describe('Artifacts block', () => {
const timeago = getTimeago(); const timeago = getTimeago();
const formatedDate = timeago.format(expireAt); const formatedDate = timeago.format(expireAt);
const expiredArtifact = {
expire_at: expireAt,
expired: true,
};
const nonExpiredArtifact = {
download_path: '/gitlab-org/gitlab-ce/-/jobs/98314558/artifacts/download',
browse_path: '/gitlab-org/gitlab-ce/-/jobs/98314558/artifacts/browse',
keep_path: '/gitlab-org/gitlab-ce/-/jobs/98314558/artifacts/keep',
expire_at: expireAt,
expired: false,
};
afterEach(() => { afterEach(() => {
vm.$destroy(); vm.$destroy();
}); });
...@@ -18,100 +31,87 @@ describe('Artifacts block', () => { ...@@ -18,100 +31,87 @@ describe('Artifacts block', () => {
describe('with expired artifacts', () => { describe('with expired artifacts', () => {
it('renders expired artifact date and info', () => { it('renders expired artifact date and info', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
haveArtifactsExpired: true, artifact: expiredArtifact,
willArtifactsExpire: false,
expireAt,
}); });
expect(vm.$el.querySelector('.js-artifacts-removed')).not.toBeNull(); expect(vm.$el.querySelector('.js-artifacts-removed')).not.toBeNull();
expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).toBeNull(); expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).toBeNull();
expect(vm.$el.textContent).toContain(formatedDate); expect(vm.$el.textContent).toContain(formatedDate);
expect(vm.$el.querySelector('.js-artifacts-removed').textContent.trim()).toEqual(
'The artifacts were removed',
);
}); });
}); });
describe('with artifacts that will expire', () => { describe('with artifacts that will expire', () => {
it('renders will expire artifact date and info', () => { it('renders will expire artifact date and info', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
haveArtifactsExpired: false, artifact: nonExpiredArtifact,
willArtifactsExpire: true,
expireAt,
}); });
expect(vm.$el.querySelector('.js-artifacts-removed')).toBeNull(); expect(vm.$el.querySelector('.js-artifacts-removed')).toBeNull();
expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).not.toBeNull(); expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).not.toBeNull();
expect(vm.$el.textContent).toContain(formatedDate); expect(vm.$el.textContent).toContain(formatedDate);
expect(vm.$el.querySelector('.js-artifacts-will-be-removed').textContent.trim()).toEqual(
'The artifacts will be removed in',
);
}); });
}); });
describe('when the user can keep the artifacts', () => { describe('with keep path', () => {
it('renders the keep button', () => { it('renders the keep button', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
haveArtifactsExpired: true, artifact: nonExpiredArtifact,
willArtifactsExpire: false,
expireAt,
keepArtifactsPath: '/keep',
}); });
expect(vm.$el.querySelector('.js-keep-artifacts')).not.toBeNull(); expect(vm.$el.querySelector('.js-keep-artifacts')).not.toBeNull();
}); });
}); });
describe('when the user can not keep the artifacts', () => { describe('without keep path', () => {
it('does not render the keep button', () => { it('does not render the keep button', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
haveArtifactsExpired: true, artifact: expiredArtifact,
willArtifactsExpire: false,
expireAt,
}); });
expect(vm.$el.querySelector('.js-keep-artifacts')).toBeNull(); expect(vm.$el.querySelector('.js-keep-artifacts')).toBeNull();
}); });
}); });
describe('when the user can download the artifacts', () => { describe('with download path', () => {
it('renders the download button', () => { it('renders the download button', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
haveArtifactsExpired: true, artifact: nonExpiredArtifact,
willArtifactsExpire: false,
expireAt,
downloadArtifactsPath: '/download',
}); });
expect(vm.$el.querySelector('.js-download-artifacts')).not.toBeNull(); expect(vm.$el.querySelector('.js-download-artifacts')).not.toBeNull();
}); });
}); });
describe('when the user can not download the artifacts', () => { describe('without download path', () => {
it('does not render the keep button', () => { it('does not render the keep button', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
haveArtifactsExpired: true, artifact: expiredArtifact,
willArtifactsExpire: false,
expireAt,
}); });
expect(vm.$el.querySelector('.js-download-artifacts')).toBeNull(); expect(vm.$el.querySelector('.js-download-artifacts')).toBeNull();
}); });
}); });
describe('when the user can browse the artifacts', () => { describe('with browse path', () => {
it('does not render the browse button', () => { it('does not render the browse button', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
haveArtifactsExpired: true, artifact: nonExpiredArtifact,
willArtifactsExpire: false,
expireAt,
browseArtifactsPath: '/browse',
}); });
expect(vm.$el.querySelector('.js-browse-artifacts')).not.toBeNull(); expect(vm.$el.querySelector('.js-browse-artifacts')).not.toBeNull();
}); });
}); });
describe('when the user can not browse the artifacts', () => { describe('without browse path', () => {
it('does not render the browse button', () => { it('does not render the browse button', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
haveArtifactsExpired: true, artifact: expiredArtifact,
willArtifactsExpire: false,
expireAt,
}); });
expect(vm.$el.querySelector('.js-browse-artifacts')).toBeNull(); expect(vm.$el.querySelector('.js-browse-artifacts')).toBeNull();
......
...@@ -7,11 +7,16 @@ describe('Commit block', () => { ...@@ -7,11 +7,16 @@ describe('Commit block', () => {
let vm; let vm;
const props = { const props = {
pipelineShortSha: '1f0fb84f', commit: {
pipelineShaPath: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c', short_id: '1f0fb84f',
mergeRequestReference: '!21244', commit_path: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c',
mergeRequestPath: 'merge_requests/21244', title: 'Update README.md',
gitCommitTitlte: 'Regenerate pot files', },
mergeRequest: {
iid: '!21244',
path: 'merge_requests/21244',
},
isLastBlock: true,
}; };
afterEach(() => { afterEach(() => {
...@@ -26,12 +31,18 @@ describe('Commit block', () => { ...@@ -26,12 +31,18 @@ describe('Commit block', () => {
}); });
it('renders pipeline short sha link', () => { it('renders pipeline short sha link', () => {
expect(vm.$el.querySelector('.js-commit-sha').getAttribute('href')).toEqual(props.pipelineShaPath); expect(vm.$el.querySelector('.js-commit-sha').getAttribute('href')).toEqual(
expect(vm.$el.querySelector('.js-commit-sha').textContent.trim()).toEqual(props.pipelineShortSha); props.commit.commit_path,
);
expect(vm.$el.querySelector('.js-commit-sha').textContent.trim()).toEqual(
props.commit.short_id,
);
}); });
it('renders clipboard button', () => { it('renders clipboard button', () => {
expect(vm.$el.querySelector('button').getAttribute('data-clipboard-text')).toEqual(props.pipelineShortSha); expect(vm.$el.querySelector('button').getAttribute('data-clipboard-text')).toEqual(
props.commit.short_id,
);
}); });
}); });
...@@ -41,17 +52,19 @@ describe('Commit block', () => { ...@@ -41,17 +52,19 @@ describe('Commit block', () => {
...props, ...props,
}); });
expect(vm.$el.querySelector('.js-link-commit').getAttribute('href')).toEqual(props.mergeRequestPath); expect(vm.$el.querySelector('.js-link-commit').getAttribute('href')).toEqual(
expect(vm.$el.querySelector('.js-link-commit').textContent.trim()).toEqual(props.mergeRequestReference); props.mergeRequest.path,
);
expect(vm.$el.querySelector('.js-link-commit').textContent.trim()).toEqual(
props.mergeRequest.iid,
);
}); });
}); });
describe('without merge request', () => { describe('without merge request', () => {
it('does not render merge request', () => { it('does not render merge request', () => {
const copyProps = Object.assign({}, props); const copyProps = Object.assign({}, props);
delete copyProps.mergeRequestPath; delete copyProps.mergeRequest;
delete copyProps.mergeRequestReference;
vm = mountComponent(Component, { vm = mountComponent(Component, {
...copyProps, ...copyProps,
...@@ -67,7 +80,7 @@ describe('Commit block', () => { ...@@ -67,7 +80,7 @@ describe('Commit block', () => {
...props, ...props,
}); });
expect(vm.$el.textContent).toContain(props.gitCommitTitlte); expect(vm.$el.textContent).toContain(props.commit.title);
}); });
}); });
}); });
...@@ -13,7 +13,9 @@ describe('Trigger block', () => { ...@@ -13,7 +13,9 @@ describe('Trigger block', () => {
describe('with short token', () => { describe('with short token', () => {
it('renders short token', () => { it('renders short token', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
shortToken: '0a666b2', trigger: {
short_token: '0a666b2',
},
}); });
expect(vm.$el.querySelector('.js-short-token').textContent).toContain('0a666b2'); expect(vm.$el.querySelector('.js-short-token').textContent).toContain('0a666b2');
...@@ -22,7 +24,7 @@ describe('Trigger block', () => { ...@@ -22,7 +24,7 @@ describe('Trigger block', () => {
describe('without short token', () => { describe('without short token', () => {
it('does not render short token', () => { it('does not render short token', () => {
vm = mountComponent(Component, {}); vm = mountComponent(Component, { trigger: {} });
expect(vm.$el.querySelector('.js-short-token')).toBeNull(); expect(vm.$el.querySelector('.js-short-token')).toBeNull();
}); });
...@@ -32,9 +34,12 @@ describe('Trigger block', () => { ...@@ -32,9 +34,12 @@ describe('Trigger block', () => {
describe('reveal variables', () => { describe('reveal variables', () => {
it('reveals variables on click', done => { it('reveals variables on click', done => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
variables: { trigger: {
key: 'value', short_token: 'bd7e',
variable: 'foo', variables: [
{ key: 'UPLOAD_TO_GCS', value: 'false', public: false },
{ key: 'UPLOAD_TO_S3', value: 'true', public: false },
],
}, },
}); });
...@@ -44,10 +49,10 @@ describe('Trigger block', () => { ...@@ -44,10 +49,10 @@ describe('Trigger block', () => {
.$nextTick() .$nextTick()
.then(() => { .then(() => {
expect(vm.$el.querySelector('.js-build-variables')).not.toBeNull(); expect(vm.$el.querySelector('.js-build-variables')).not.toBeNull();
expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('key'); expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('UPLOAD_TO_GCS');
expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('value'); expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('false');
expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('variable'); expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('UPLOAD_TO_S3');
expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('foo'); expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('true');
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
...@@ -57,7 +62,7 @@ describe('Trigger block', () => { ...@@ -57,7 +62,7 @@ describe('Trigger block', () => {
describe('without variables', () => { describe('without variables', () => {
it('does not render variables', () => { it('does not render variables', () => {
vm = mountComponent(Component); vm = mountComponent(Component, { trigger: {} });
expect(vm.$el.querySelector('.js-reveal-variables')).toBeNull(); expect(vm.$el.querySelector('.js-reveal-variables')).toBeNull();
expect(vm.$el.querySelector('.js-build-variables')).toBeNull(); expect(vm.$el.querySelector('.js-build-variables')).toBeNull();
......
...@@ -188,40 +188,4 @@ describe 'projects/jobs/show' do ...@@ -188,40 +188,4 @@ describe 'projects/jobs/show' do
expect(rendered).not_to have_link('New issue') expect(rendered).not_to have_link('New issue')
end end
end end
context 'when incomplete trigger_request is used' do
before do
build.trigger_request = FactoryBot.build(:ci_trigger_request, trigger: nil)
end
it 'test should not render token block' do
render
expect(rendered).not_to have_content('Token')
end
end
context 'when complete trigger_request is used' do
before do
build.trigger_request = FactoryBot.build(:ci_trigger_request)
end
it 'should render token' do
render
expect(rendered).to have_content('Token')
expect(rendered).to have_content(build.trigger_request.trigger.short_token)
end
end
describe 'commit title in sidebar' do
let(:commit_title) { project.commit.title }
it 'shows commit title and not show commit message' do
render
expect(rendered).to have_css('p.build-light-text.append-bottom-0',
text: /\A\n#{Regexp.escape(commit_title)}\n\Z/)
end
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment