Commit ad4c2a08 authored by Fatih Acet's avatar Fatih Acet

Merge branch '25374-svg-as-prop' into 'master'

Resolve "Provide SVG as a prop instead of hiding and copy them in environments table"

## What does this MR do?
- Provides SVG as a prop instead of manually manipulate the DOM to show it 
- Uniforms all props names in environments related components, 3 formats were being used and it was error prone
- Adds tests for the new SVG props.

## Why was this MR needed?
Technical debt.

## Does this MR meet the acceptance criteria?

- [x] [Changelog entry](https://docs.gitlab.com/ce/development/changelog.html) added
- [ ] [Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md)
- [ ] API support added
- Tests
  - [x] Added for this feature/bug
  - [ ] All builds are passing
- [x] Conform by the [merge request performance guides](http://docs.gitlab.com/ce/development/merge_request_performance_guidelines.html)
- [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [x] Branch has no merge conflicts with `master` (if it does - rebase it please)
- [x] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)

## What are the relevant issue numbers?
Closes #25374

See merge request !7992
parents e17758c2 2bc6f884
...@@ -74,6 +74,8 @@ ...@@ -74,6 +74,8 @@
projectStoppedEnvironmentsPath: environmentsData.projectStoppedEnvironmentsPath, projectStoppedEnvironmentsPath: environmentsData.projectStoppedEnvironmentsPath,
newEnvironmentPath: environmentsData.newEnvironmentPath, newEnvironmentPath: environmentsData.newEnvironmentPath,
helpPagePath: environmentsData.helpPagePath, helpPagePath: environmentsData.helpPagePath,
commitIconSvg: environmentsData.commitIconSvg,
playIconSvg: environmentsData.playIconSvg,
}; };
}, },
...@@ -227,7 +229,9 @@ ...@@ -227,7 +229,9 @@
:model="model" :model="model"
:toggleRow="toggleRow.bind(model)" :toggleRow="toggleRow.bind(model)"
:can-create-deployment="canCreateDeploymentParsed" :can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"></tr> :can-read-environment="canReadEnvironmentParsed"
:play-icon-svg="playIconSvg"
:commit-icon-svg="commitIconSvg"></tr>
<tr v-if="model.isOpen && model.children && model.children.length > 0" <tr v-if="model.isOpen && model.children && model.children.length > 0"
is="environment-item" is="environment-item"
...@@ -235,7 +239,9 @@ ...@@ -235,7 +239,9 @@
:model="children" :model="children"
:toggleRow="toggleRow.bind(children)" :toggleRow="toggleRow.bind(children)"
:can-create-deployment="canCreateDeploymentParsed" :can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"> :can-read-environment="canReadEnvironmentParsed"
:play-icon-svg="playIconSvg"
:commit-icon-svg="commitIconSvg">
</tr> </tr>
</template> </template>
......
...@@ -12,38 +12,18 @@ ...@@ -12,38 +12,18 @@
required: false, required: false,
default: () => [], default: () => [],
}, },
},
/**
* Appends the svg icon that were render in the index page.
* In order to reuse the svg instead of copy and paste in this template
* we need to render it outside this component using =custom_icon partial.
*
* TODO: Remove this when webpack is merged.
*
*/
mounted() {
const playIcon = document.querySelector('.play-icon-svg.hidden svg');
const dropdownContainer = this.$el.querySelector('.dropdown-play-icon-container');
const actionContainers = this.$el.querySelectorAll('.action-play-icon-container');
// Phantomjs does not have support to iterate a nodelist.
const actionsArray = [].slice.call(actionContainers);
if (playIcon && actionsArray && dropdownContainer) {
dropdownContainer.appendChild(playIcon.cloneNode(true));
actionsArray.forEach((element) => { playIconSvg: {
element.appendChild(playIcon.cloneNode(true)); type: String,
}); required: false,
} },
}, },
template: ` template: `
<div class="inline"> <div class="inline">
<div class="dropdown"> <div class="dropdown">
<a class="dropdown-new btn btn-default" data-toggle="dropdown"> <a class="dropdown-new btn btn-default" data-toggle="dropdown">
<span class="dropdown-play-icon-container"></span> <span class="js-dropdown-play-icon-container" v-html="playIconSvg"></span>
<i class="fa fa-caret-down"></i> <i class="fa fa-caret-down"></i>
</a> </a>
...@@ -53,7 +33,9 @@ ...@@ -53,7 +33,9 @@
data-method="post" data-method="post"
rel="nofollow" rel="nofollow"
class="js-manual-action-link"> class="js-manual-action-link">
<span class="action-play-icon-container"></span>
<span class="js-action-play-icon-container" v-html="playIconSvg"></span>
<span> <span>
{{action.name}} {{action.name}}
</span> </span>
......
...@@ -7,14 +7,14 @@ ...@@ -7,14 +7,14 @@
window.gl.environmentsList.ExternalUrlComponent = Vue.component('external-url-component', { window.gl.environmentsList.ExternalUrlComponent = Vue.component('external-url-component', {
props: { props: {
external_url: { externalUrl: {
type: String, type: String,
default: '', default: '',
}, },
}, },
template: ` template: `
<a class="btn external_url" :href="external_url" target="_blank"> <a class="btn external_url" :href="externalUrl" target="_blank">
<i class="fa fa-external-link"></i> <i class="fa fa-external-link"></i>
</a> </a>
`, `,
......
...@@ -58,6 +58,16 @@ ...@@ -58,6 +58,16 @@
required: false, required: false,
default: false, default: false,
}, },
commitIconSvg: {
type: String,
required: false,
},
playIconSvg: {
type: String,
required: false,
},
}, },
data() { data() {
...@@ -451,11 +461,12 @@ ...@@ -451,11 +461,12 @@
<div v-if="!isFolder && hasLastDeploymentKey" class="js-commit-component"> <div v-if="!isFolder && hasLastDeploymentKey" class="js-commit-component">
<commit-component <commit-component
:tag="commitTag" :tag="commitTag"
:commit_ref="commitRef" :commit-ref="commitRef"
:commit_url="commitUrl" :commit-url="commitUrl"
:short_sha="commitShortSha" :short-sha="commitShortSha"
:title="commitTitle" :title="commitTitle"
:author="commitAuthor"> :author="commitAuthor"
:commit-icon-svg="commitIconSvg">
</commit-component> </commit-component>
</div> </div>
<p v-if="!isFolder && !hasLastDeploymentKey" class="commit-title"> <p v-if="!isFolder && !hasLastDeploymentKey" class="commit-title">
...@@ -476,6 +487,7 @@ ...@@ -476,6 +487,7 @@
<div v-if="hasManualActions && canCreateDeployment" <div v-if="hasManualActions && canCreateDeployment"
class="inline js-manual-actions-container"> class="inline js-manual-actions-container">
<actions-component <actions-component
:play-icon-svg="playIconSvg"
:actions="manualActions"> :actions="manualActions">
</actions-component> </actions-component>
</div> </div>
...@@ -483,22 +495,22 @@ ...@@ -483,22 +495,22 @@
<div v-if="model.external_url && canReadEnvironment" <div v-if="model.external_url && canReadEnvironment"
class="inline js-external-url-container"> class="inline js-external-url-container">
<external-url-component <external-url-component
:external_url="model.external_url"> :external-url="model.external_url">
</external_url-component> </external-url-component>
</div> </div>
<div v-if="isStoppable && canCreateDeployment" <div v-if="isStoppable && canCreateDeployment"
class="inline js-stop-component-container"> class="inline js-stop-component-container">
<stop-component <stop-component
:stop_url="model.stop_path"> :stop-url="model.stop_path">
</stop-component> </stop-component>
</div> </div>
<div v-if="canRetry && canCreateDeployment" <div v-if="canRetry && canCreateDeployment"
class="inline js-rollback-component-container"> class="inline js-rollback-component-container">
<rollback-component <rollback-component
:is_last_deployment="isLastDeployment" :is-last-deployment="isLastDeployment"
:retry_url="retryUrl"> :retry-url="retryUrl">
</rollback-component> </rollback-component>
</div> </div>
</div> </div>
......
...@@ -7,19 +7,20 @@ ...@@ -7,19 +7,20 @@
window.gl.environmentsList.RollbackComponent = Vue.component('rollback-component', { window.gl.environmentsList.RollbackComponent = Vue.component('rollback-component', {
props: { props: {
retry_url: { retryUrl: {
type: String, type: String,
default: '', default: '',
}, },
is_last_deployment: {
isLastDeployment: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
}, },
template: ` template: `
<a class="btn" :href="retry_url" data-method="post" rel="nofollow"> <a class="btn" :href="retryUrl" data-method="post" rel="nofollow">
<span v-if="is_last_deployment"> <span v-if="isLastDeployment">
Re-deploy Re-deploy
</span> </span>
<span v-else> <span v-else>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
window.gl.environmentsList.StopComponent = Vue.component('stop-component', { window.gl.environmentsList.StopComponent = Vue.component('stop-component', {
props: { props: {
stop_url: { stopUrl: {
type: String, type: String,
default: '', default: '',
}, },
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
template: ` template: `
<a class="btn stop-env-link" <a class="btn stop-env-link"
:href="stop_url" :href="stopUrl"
data-confirm="Are you sure you want to stop this environment?" data-confirm="Are you sure you want to stop this environment?"
data-method="post" data-method="post"
rel="nofollow"> rel="nofollow">
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* name * name
* ref_url * ref_url
*/ */
commit_ref: { commitRef: {
type: Object, type: Object,
required: false, required: false,
default: () => ({}), default: () => ({}),
...@@ -32,16 +32,16 @@ ...@@ -32,16 +32,16 @@
/** /**
* Used to link to the commit sha. * Used to link to the commit sha.
*/ */
commit_url: { commitUrl: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
}, },
/** /**
* Used to show the commit short_sha that links to the commit url. * Used to show the commit short sha that links to the commit url.
*/ */
short_sha: { shortSha: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
...@@ -68,6 +68,11 @@ ...@@ -68,6 +68,11 @@
required: false, required: false,
default: () => ({}), default: () => ({}),
}, },
commitIconSvg: {
type: String,
required: false,
},
}, },
computed: { computed: {
...@@ -80,7 +85,7 @@ ...@@ -80,7 +85,7 @@
* @returns {Boolean} * @returns {Boolean}
*/ */
hasCommitRef() { hasCommitRef() {
return this.commit_ref && this.commit_ref.name && this.commit_ref.ref_url; return this.commitRef && this.commitRef.name && this.commitRef.ref_url;
}, },
/** /**
...@@ -110,24 +115,6 @@ ...@@ -110,24 +115,6 @@
}, },
}, },
/**
* In order to reuse the svg instead of copy and paste in this template
* we need to render it outside this component using =custom_icon partial.
* Make sure it has this structure:
* .commit-icon-svg.hidden
* svg
*
* TODO: Find a better way to include SVG
*/
mounted() {
const commitIconContainer = this.$el.querySelector('.commit-icon-container');
const commitIcon = document.querySelector('.commit-icon-svg.hidden svg');
if (commitIconContainer && commitIcon) {
commitIconContainer.appendChild(commitIcon.cloneNode(true));
}
},
template: ` template: `
<div class="branch-commit"> <div class="branch-commit">
...@@ -138,15 +125,15 @@ ...@@ -138,15 +125,15 @@
<a v-if="hasCommitRef" <a v-if="hasCommitRef"
class="monospace branch-name" class="monospace branch-name"
:href="commit_ref.ref_url"> :href="commitRef.ref_url">
{{commit_ref.name}} {{commitRef.name}}
</a> </a>
<div class="icon-container commit-icon commit-icon-container"></div> <div v-html="commitIconSvg" class="commit-icon js-commit-icon"></div>
<a class="commit-id monospace" <a class="commit-id monospace"
:href="commit_url"> :href="commitUrl">
{{short_sha}} {{shortSha}}
</a> </a>
<p class="commit-title"> <p class="commit-title">
...@@ -162,7 +149,7 @@ ...@@ -162,7 +149,7 @@
</a> </a>
<a class="commit-row-message" <a class="commit-row-message"
:href="commit_url"> :href="commitUrl">
{{title}} {{title}}
</a> </a>
</span> </span>
......
...@@ -17,4 +17,6 @@ ...@@ -17,4 +17,6 @@
"project-stopped-environments-path" => project_environments_path(@project, scope: :stopped), "project-stopped-environments-path" => project_environments_path(@project, scope: :stopped),
"new-environment-path" => new_namespace_project_environment_path(@project.namespace, @project), "new-environment-path" => new_namespace_project_environment_path(@project.namespace, @project),
"help-page-path" => help_page_path("ci/environments"), "help-page-path" => help_page_path("ci/environments"),
"css-class" => container_class}} "css-class" => container_class,
"commit-icon-svg" => custom_icon("icon_commit"),
"play-icon-svg" => custom_icon("icon_play")}}
---
title: Resolve "Provide SVG as a prop instead of hiding and copy them in environments table"
merge_request: 7992
author:
...@@ -85,14 +85,14 @@ feature 'Environments page', :feature, :js do ...@@ -85,14 +85,14 @@ feature 'Environments page', :feature, :js do
end end
scenario 'does show a play button' do scenario 'does show a play button' do
find('.dropdown-play-icon-container').click find('.js-dropdown-play-icon-container').click
expect(page).to have_content(manual.name.humanize) expect(page).to have_content(manual.name.humanize)
end end
scenario 'does allow to play manual action', js: true do scenario 'does allow to play manual action', js: true do
expect(manual).to be_skipped expect(manual).to be_skipped
find('.dropdown-play-icon-container').click find('.js-dropdown-play-icon-container').click
expect(page).to have_content(manual.name.humanize) expect(page).to have_content(manual.name.humanize)
expect { click_link(manual.name.humanize) } expect { click_link(manual.name.humanize) }
......
...@@ -8,7 +8,7 @@ describe('Actions Component', () => { ...@@ -8,7 +8,7 @@ describe('Actions Component', () => {
fixture.load('environments/element.html'); fixture.load('environments/element.html');
}); });
it('Should render a dropdown with the provided actions', () => { it('should render a dropdown with the provided actions', () => {
const actionsMock = [ const actionsMock = [
{ {
name: 'bar', name: 'bar',
...@@ -24,6 +24,7 @@ describe('Actions Component', () => { ...@@ -24,6 +24,7 @@ describe('Actions Component', () => {
el: document.querySelector('.test-dom-element'), el: document.querySelector('.test-dom-element'),
propsData: { propsData: {
actions: actionsMock, actions: actionsMock,
playIconSvg: '<svg></svg>',
}, },
}); });
...@@ -34,4 +35,33 @@ describe('Actions Component', () => { ...@@ -34,4 +35,33 @@ describe('Actions Component', () => {
component.$el.querySelector('.dropdown-menu li a').getAttribute('href'), component.$el.querySelector('.dropdown-menu li a').getAttribute('href'),
).toEqual(actionsMock[0].play_path); ).toEqual(actionsMock[0].play_path);
}); });
it('should render a dropdown with the provided svg', () => {
const actionsMock = [
{
name: 'bar',
play_path: 'https://gitlab.com/play',
},
{
name: 'foo',
play_path: '#',
},
];
const component = new window.gl.environmentsList.ActionsComponent({
el: document.querySelector('.test-dom-element'),
propsData: {
actions: actionsMock,
playIconSvg: '<svg></svg>',
},
});
expect(
component.$el.querySelector('.js-dropdown-play-icon-container').children,
).toContain('svg');
expect(
component.$el.querySelector('.js-action-play-icon-container').children,
).toContain('svg');
});
}); });
...@@ -7,12 +7,12 @@ describe('External URL Component', () => { ...@@ -7,12 +7,12 @@ describe('External URL Component', () => {
fixture.load('environments/element.html'); fixture.load('environments/element.html');
}); });
it('should link to the provided external_url', () => { it('should link to the provided externalUrl prop', () => {
const externalURL = 'https://gitlab.com'; const externalURL = 'https://gitlab.com';
const component = new window.gl.environmentsList.ExternalUrlComponent({ const component = new window.gl.environmentsList.ExternalUrlComponent({
el: document.querySelector('.test-dom-element'), el: document.querySelector('.test-dom-element'),
propsData: { propsData: {
external_url: externalURL, externalUrl: externalURL,
}, },
}); });
......
...@@ -9,24 +9,24 @@ describe('Rollback Component', () => { ...@@ -9,24 +9,24 @@ describe('Rollback Component', () => {
fixture.load('environments/element.html'); fixture.load('environments/element.html');
}); });
it('Should link to the provided retry_url', () => { it('Should link to the provided retryUrl', () => {
const component = new window.gl.environmentsList.RollbackComponent({ const component = new window.gl.environmentsList.RollbackComponent({
el: document.querySelector('.test-dom-element'), el: document.querySelector('.test-dom-element'),
propsData: { propsData: {
retry_url: retryURL, retryUrl: retryURL,
is_last_deployment: true, isLastDeployment: true,
}, },
}); });
expect(component.$el.getAttribute('href')).toEqual(retryURL); expect(component.$el.getAttribute('href')).toEqual(retryURL);
}); });
it('Should render Re-deploy label when is_last_deployment is true', () => { it('Should render Re-deploy label when isLastDeployment is true', () => {
const component = new window.gl.environmentsList.RollbackComponent({ const component = new window.gl.environmentsList.RollbackComponent({
el: document.querySelector('.test-dom-element'), el: document.querySelector('.test-dom-element'),
propsData: { propsData: {
retry_url: retryURL, retryUrl: retryURL,
is_last_deployment: true, isLastDeployment: true,
}, },
}); });
...@@ -34,12 +34,12 @@ describe('Rollback Component', () => { ...@@ -34,12 +34,12 @@ describe('Rollback Component', () => {
}); });
it('Should render Rollback label when is_last_deployment is false', () => { it('Should render Rollback label when isLastDeployment is false', () => {
const component = new window.gl.environmentsList.RollbackComponent({ const component = new window.gl.environmentsList.RollbackComponent({
el: document.querySelector('.test-dom-element'), el: document.querySelector('.test-dom-element'),
propsData: { propsData: {
retry_url: retryURL, retryUrl: retryURL,
is_last_deployment: false, isLastDeployment: false,
}, },
}); });
......
...@@ -13,7 +13,7 @@ describe('Stop Component', () => { ...@@ -13,7 +13,7 @@ describe('Stop Component', () => {
component = new window.gl.environmentsList.StopComponent({ component = new window.gl.environmentsList.StopComponent({
el: document.querySelector('.test-dom-element'), el: document.querySelector('.test-dom-element'),
propsData: { propsData: {
stop_url: stopURL, stopUrl: stopURL,
}, },
}); });
}); });
......
...@@ -10,12 +10,12 @@ describe('Commit component', () => { ...@@ -10,12 +10,12 @@ describe('Commit component', () => {
el: document.querySelector('.test-commit-container'), el: document.querySelector('.test-commit-container'),
propsData: { propsData: {
tag: false, tag: false,
commit_ref: { commitRef: {
name: 'master', name: 'master',
ref_url: 'http://localhost/namespace2/gitlabhq/tree/master', ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
}, },
commit_url: 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067', commitUrl: 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067',
short_sha: 'b7836edd', shortSha: 'b7836edd',
title: 'Commit message', title: 'Commit message',
author: { author: {
avatar_url: 'https://gitlab.com/uploads/user/avatar/300478/avatar.png', avatar_url: 'https://gitlab.com/uploads/user/avatar/300478/avatar.png',
...@@ -34,18 +34,19 @@ describe('Commit component', () => { ...@@ -34,18 +34,19 @@ describe('Commit component', () => {
props = { props = {
tag: true, tag: true,
commit_ref: { commitRef: {
name: 'master', name: 'master',
ref_url: 'http://localhost/namespace2/gitlabhq/tree/master', ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
}, },
commit_url: 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067', commitUrl: 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067',
short_sha: 'b7836edd', shortSha: 'b7836edd',
title: 'Commit message', title: 'Commit message',
author: { author: {
avatar_url: 'https://gitlab.com/uploads/user/avatar/300478/avatar.png', avatar_url: 'https://gitlab.com/uploads/user/avatar/300478/avatar.png',
web_url: 'https://gitlab.com/jschatz1', web_url: 'https://gitlab.com/jschatz1',
username: 'jschatz1', username: 'jschatz1',
}, },
commitIconSvg: '<svg></svg>',
}; };
component = new window.gl.CommitComponent({ component = new window.gl.CommitComponent({
...@@ -59,20 +60,24 @@ describe('Commit component', () => { ...@@ -59,20 +60,24 @@ describe('Commit component', () => {
}); });
it('should render a link to the ref url', () => { it('should render a link to the ref url', () => {
expect(component.$el.querySelector('.branch-name').getAttribute('href')).toEqual(props.commit_ref.ref_url); expect(component.$el.querySelector('.branch-name').getAttribute('href')).toEqual(props.commitRef.ref_url);
}); });
it('should render the ref name', () => { it('should render the ref name', () => {
expect(component.$el.querySelector('.branch-name').textContent).toContain(props.commit_ref.name); expect(component.$el.querySelector('.branch-name').textContent).toContain(props.commitRef.name);
}); });
it('should render the commit short sha with a link to the commit url', () => { it('should render the commit short sha with a link to the commit url', () => {
expect(component.$el.querySelector('.commit-id').getAttribute('href')).toEqual(props.commit_url); expect(component.$el.querySelector('.commit-id').getAttribute('href')).toEqual(props.commitUrl);
expect(component.$el.querySelector('.commit-id').textContent).toContain(props.short_sha); expect(component.$el.querySelector('.commit-id').textContent).toContain(props.shortSha);
});
it('should render the given commitIconSvg', () => {
expect(component.$el.querySelector('.js-commit-icon').children).toContain('svg');
}); });
describe('Given commit title and author props', () => { describe('Given commit title and author props', () => {
it('Should render a link to the author profile', () => { it('should render a link to the author profile', () => {
expect( expect(
component.$el.querySelector('.commit-title .avatar-image-container').getAttribute('href'), component.$el.querySelector('.commit-title .avatar-image-container').getAttribute('href'),
).toEqual(props.author.web_url); ).toEqual(props.author.web_url);
...@@ -91,7 +96,7 @@ describe('Commit component', () => { ...@@ -91,7 +96,7 @@ describe('Commit component', () => {
it('should render the commit title', () => { it('should render the commit title', () => {
expect( expect(
component.$el.querySelector('a.commit-row-message').getAttribute('href'), component.$el.querySelector('a.commit-row-message').getAttribute('href'),
).toEqual(props.commit_url); ).toEqual(props.commitUrl);
expect( expect(
component.$el.querySelector('a.commit-row-message').textContent, component.$el.querySelector('a.commit-row-message').textContent,
).toContain(props.title); ).toContain(props.title);
...@@ -99,16 +104,16 @@ describe('Commit component', () => { ...@@ -99,16 +104,16 @@ describe('Commit component', () => {
}); });
describe('When commit title is not provided', () => { describe('When commit title is not provided', () => {
it('Should render default message', () => { it('should render default message', () => {
fixture.set('<div class="test-commit-container"></div>'); fixture.set('<div class="test-commit-container"></div>');
props = { props = {
tag: false, tag: false,
commit_ref: { commitRef: {
name: 'master', name: 'master',
ref_url: 'http://localhost/namespace2/gitlabhq/tree/master', ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
}, },
commit_url: 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067', commitUrl: 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067',
short_sha: 'b7836edd', shortSha: 'b7836edd',
title: null, title: null,
author: {}, author: {},
}; };
......
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