Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-04-15 06:09:49 +00:00
parent b71a496c7a
commit 00a8c64ffd
30 changed files with 736 additions and 44 deletions

View File

@ -45,19 +45,16 @@ export const annotationsYAxis = {
* Fetched list of annotations are parsed into a
* format the eCharts accepts to draw markLines
*
* If Annotation is a single line, the `from` property
* has a value and the `to` is null. Because annotations
* only supports lines the from value does not exist yet.
* If Annotation is a single line, the `starting_at` property
* has a value and the `ending_at` is null. Because annotations
* only supports lines the `ending_at` value does not exist yet.
*
*
* @param {Object} annotation object
* @returns {Object} markLine object
*/
export const parseAnnotations = ({
from: annotationFrom = '',
color = colorValues.primaryColor,
}) => ({
xAxis: annotationFrom,
export const parseAnnotations = ({ starting_at = '', color = colorValues.primaryColor }) => ({
xAxis: starting_at,
lineStyle: {
color,
},
@ -105,7 +102,7 @@ export const generateAnnotationsSeries = ({ deployments = [], annotations = [] }
const annotationsData = annotations.map(annotation => {
return {
name: 'annotations',
value: [annotation.from, annotationsYAxisCoords.pos],
value: [annotation.starting_at, annotationsYAxisCoords.pos],
// style options
symbol: 'none',
// metadata that are accessible in `formatTooltipText` method

View File

@ -4,8 +4,8 @@ query getAnnotations($projectPath: ID!) {
annotations: nodes {
id
description
from
to
starting_at
ending_at
panelId
}
}

View File

@ -2,8 +2,11 @@ import CommitsList from '~/commits';
import GpgBadges from '~/gpg_badges';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import mountCommits from '~/projects/commits';
document.addEventListener('DOMContentLoaded', () => {
new CommitsList(document.querySelector('.js-project-commits-show').dataset.commitsLimit); // eslint-disable-line no-new
new ShortcutsNavigation(); // eslint-disable-line no-new
GpgBadges.fetch();
mountCommits(document.getElementById('js-author-dropdown'));
});

View File

@ -0,0 +1,141 @@
<script>
import { debounce } from 'lodash';
import { mapState, mapActions } from 'vuex';
import {
GlNewDropdown,
GlNewDropdownHeader,
GlNewDropdownItem,
GlSearchBoxByType,
GlNewDropdownDivider,
GlTooltipDirective,
} from '@gitlab/ui';
import { redirectTo } from '~/lib/utils/url_utility';
import { urlParamsToObject } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
const tooltipMessage = __('Searching by both author and message is currently not supported.');
export default {
name: 'AuthorSelect',
components: {
GlNewDropdown,
GlNewDropdownHeader,
GlNewDropdownItem,
GlSearchBoxByType,
GlNewDropdownDivider,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
projectCommitsEl: {
type: HTMLDivElement,
required: true,
},
},
data() {
return {
hasSearchParam: false,
searchTerm: '',
authorInput: '',
currentAuthor: '',
};
},
computed: {
...mapState(['commitsPath', 'commitsAuthors']),
dropdownText() {
return this.currentAuthor || __('Author');
},
tooltipTitle() {
return this.hasSearchParam && tooltipMessage;
},
},
mounted() {
this.fetchAuthors();
const params = urlParamsToObject(window.location.search);
const { search: searchParam, author: authorParam } = params;
const commitsSearchInput = this.projectCommitsEl.querySelector('#commits-search');
if (authorParam) {
commitsSearchInput.setAttribute('disabled', true);
commitsSearchInput.setAttribute('data-toggle', 'tooltip');
commitsSearchInput.setAttribute('title', tooltipMessage);
this.currentAuthor = authorParam;
}
if (searchParam) {
this.hasSearchParam = true;
}
commitsSearchInput.addEventListener(
'keyup',
debounce(event => this.setSearchParam(event.target.value), 500), // keyup & time is to match effect of "filter by commit message"
);
},
methods: {
...mapActions(['fetchAuthors']),
selectAuthor(author) {
const { name: user } = author || {};
// Follow up issue "Remove usage of $.fadeIn from the codebase"
// > https://gitlab.com/gitlab-org/gitlab/-/issues/214395
// Follow up issue "Refactor commit list to a Vue Component"
// To resolving mixing Vue + Vanilla JS
// > https://gitlab.com/gitlab-org/gitlab/-/issues/214010
const commitListElement = this.projectCommitsEl.querySelector('#commits-list');
// To mimick effect of "filter by commit message"
commitListElement.style.opacity = 0.5;
commitListElement.style.transition = 'opacity 200ms';
if (!user) {
return redirectTo(this.commitsPath);
}
return redirectTo(`${this.commitsPath}?author=${user}`);
},
searchAuthors() {
this.fetchAuthors(this.authorInput);
},
setSearchParam(value) {
this.hasSearchParam = Boolean(value);
},
},
};
</script>
<template>
<div ref="dropdownContainer" v-gl-tooltip :title="tooltipTitle" :disabled="!hasSearchParam">
<gl-new-dropdown
:text="dropdownText"
:disabled="hasSearchParam"
class="gl-dropdown w-100 mt-2 mt-sm-0"
>
<gl-new-dropdown-header>
{{ __('Search by author') }}
</gl-new-dropdown-header>
<gl-new-dropdown-divider />
<gl-search-box-by-type
v-model.trim="authorInput"
class="m-2"
:placeholder="__('Search')"
@input="searchAuthors"
/>
<gl-new-dropdown-item :is-checked="!currentAuthor" @click="selectAuthor(null)">
{{ __('Any Author') }}
</gl-new-dropdown-item>
<gl-new-dropdown-divider />
<gl-new-dropdown-item
v-for="author in commitsAuthors"
:key="author.id"
:is-checked="author.name === currentAuthor"
:avatar-url="author.avatar_url"
:secondary-text="author.username"
@click="selectAuthor(author)"
>
{{ author.name }}
</gl-new-dropdown-item>
</gl-new-dropdown>
</div>
</template>

View File

@ -0,0 +1,26 @@
import Vue from 'vue';
import Vuex from 'vuex';
import AuthorSelectApp from './components/author_select.vue';
import store from './store';
Vue.use(Vuex);
export default el => {
if (!el) {
return null;
}
store.dispatch('setInitialData', el.dataset);
return new Vue({
el,
store,
render(h) {
return h(AuthorSelectApp, {
props: {
projectCommitsEl: document.querySelector('.js-project-commits-show'),
},
});
},
});
};

View File

@ -0,0 +1,31 @@
import * as types from './mutation_types';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import { __ } from '~/locale';
export default {
setInitialData({ commit }, data) {
commit(types.SET_INITIAL_DATA, data);
},
receiveAuthorsSuccess({ commit }, authors) {
commit(types.COMMITS_AUTHORS, authors);
},
receiveAuthorsError() {
createFlash(__('An error occurred fetching the project authors.'));
},
fetchAuthors({ dispatch, state }, author = null) {
const { projectId } = state;
const path = '/autocomplete/users.json';
return axios
.get(path, {
params: {
project_id: projectId,
active: true,
search: author,
},
})
.then(({ data }) => dispatch('receiveAuthorsSuccess', data))
.catch(() => dispatch('receiveAuthorsError'));
},
};

View File

@ -0,0 +1,15 @@
import Vue from 'vue';
import Vuex from 'vuex';
import actions from './actions';
import mutations from './mutations';
import state from './state';
Vue.use(Vuex);
export const createStore = () => ({
actions,
mutations,
state: state(),
});
export default new Vuex.Store(createStore());

View File

@ -0,0 +1,2 @@
export const SET_INITIAL_DATA = 'SET_INITIAL_DATA';
export const COMMITS_AUTHORS = 'COMMITS_AUTHORS';

View File

@ -0,0 +1,10 @@
import * as types from './mutation_types';
export default {
[types.SET_INITIAL_DATA](state, data) {
Object.assign(state, data);
},
[types.COMMITS_AUTHORS](state, data) {
state.commitsAuthors = data;
},
};

View File

@ -0,0 +1,5 @@
export default () => ({
commitsPath: null,
projectId: null,
commitsAuthors: [],
});

View File

@ -317,7 +317,10 @@
}
}
.dropdown-item {
// Temporary fix to ensure tick is aligned
// Follow up Issue to remove after the GlNewDropdownItem component is fixed
// > https://gitlab.com/gitlab-org/gitlab/-/issues/213948
li:not(.gl-new-dropdown-item) .dropdown-item {
@include dropdown-link;
}

View File

@ -13,7 +13,8 @@
%ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs
.tree-controls.d-none.d-sm-none.d-md-block<
#js-author-dropdown{ data: { 'commits_path': project_commits_path(@project), 'project_id': @project.id } }
.tree-controls.d-none.d-sm-none.d-md-block
- if @merge_request.present?
.control
= link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn'

View File

@ -0,0 +1,5 @@
---
title: Add ability to filter commits by author
merge_request: 28509
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Add rake task to update x509 signatures
merge_request: 28406
author: Roger Meier
type: added

View File

@ -147,7 +147,12 @@ released.
#### TLS enabled
NOTE: **Note**
This requires GitLab Runner 11.11 or higher.
Requires GitLab Runner 11.11 or later, but is not supported if GitLab
Runner is installed using the [Helm
chart](https://docs.gitlab.com/runner/install/kubernetes.html). See the
[related
issue](https://gitlab.com/gitlab-org/charts/gitlab-runner/issues/83) for
details.
The Docker daemon supports connection over TLS and it's done by default
for Docker 19.03.8 or higher. This is the **suggested** way to use the

View File

@ -1264,7 +1264,9 @@ osx job:
`allow_failure` allows a job to fail without impacting the rest of the CI
suite.
The default value is `false`, except for [manual](#whenmanual) jobs.
The default value is `false`, except for [manual](#whenmanual) jobs using the
`when: manual` syntax, unless using [`rules:`](#rules) syntax, where all jobs
default to false, *including* `when: manual` jobs.
When enabled and the job fails, the job will show an orange warning in the UI.
However, the logical flow of the pipeline will consider the job a
@ -1379,14 +1381,17 @@ manual action by clicking a _play_ button.
When a pipeline is blocked, it will not be merged if Merge When Pipeline Succeeds
is set. Blocked pipelines also do have a special status, called _manual_.
Manual actions are non-blocking by default. If you want to make manual action
blocking, it is necessary to add `allow_failure: false` to the job's definition
in `.gitlab-ci.yml`.
When the `when:manual` syntax is used, manual actions are non-blocking by
default. If you want to make manual action blocking, it is necessary to add
`allow_failure: false` to the job's definition in `.gitlab-ci.yml`.
Optional manual actions have `allow_failure: true` set by default and their
Statuses do not contribute to the overall pipeline status. So, if a manual
action fails, the pipeline will eventually succeed.
NOTE: **Note:**
When using [`rules:`](#rules), `allow_failure` defaults to `false`, including for manual jobs.
Manual actions are considered to be write actions, so permissions for
[protected branches](../../user/project/protected_branches.md) are used when
a user wants to trigger an action. In other words, in order to trigger a manual

View File

@ -36,3 +36,4 @@ The following are available Rake tasks:
| [Uploads sanitize](../administration/raketasks/uploads/sanitize.md) | Remove EXIF data from images uploaded to earlier versions of GitLab. |
| [User management](user_management.md) | Perform user management tasks. |
| [Webhooks administration](web_hooks.md) | Maintain project Webhooks. |
| [X509 signatures](x509_signatures.md) | Update x509 commit signatures, useful if certificate store has changed. |

View File

@ -0,0 +1,22 @@
# X509 signatures
When [signing commits with x509](../user/project/repository/x509_signed_commits/index.md)
the trust anchor might change and the signatures stored within the database have
to be updated.
## Update all x509 signatures
This task loops through all X509 signed commits and updates their verification
based on current certificate store.
**Omnibus Installation**
```shell
sudo gitlab-rake gitlab:x509:update_signatures
```
**Source Installation**
```shell
sudo -u git -H bundle exec rake gitlab:x509:update_signatures RAILS_ENV=production
```

View File

@ -8,8 +8,8 @@ GitLab offers tiers of features. Your subscription determines which tier you hav
GitLab provides special subscriptions to participants in the [GitLab Education Program](https://about.gitlab.com/solutions/education/) and [GitLab Open Source Program](https://about.gitlab.com/solutions/open-source/). For details on obtaining and renewing these subscriptions, see:
- [GitLab Education Program subscriptions](#gitlab-education-program-subscriptions)
- [GitLab Open Source Program subscriptions](#gitlab-open-source-program-subscriptions)
- [GitLab for Education subscriptions](#gitlab-for-education-subscriptions)
- [GitLab for Open Source subscriptions](#gitlab-for-open-source-subscriptions)
## Choosing a GitLab subscription
@ -493,9 +493,9 @@ Learn more about:
- The tiers of [GitLab Support](https://about.gitlab.com/support/).
- [Submit a request via the Support Portal](https://support.gitlab.com/hc/en-us/requests/new).
## GitLab Education Program subscriptions
## GitLab for Education subscriptions
To renew a [GitLab Education Program](https://about.gitlab.com/solutions/education/) subscription, send an email to `education@gitlab.com` with the following information:
To renew a [GitLab for Education](https://about.gitlab.com/solutions/education/) subscription, send an email to `education@gitlab.com` with the following information:
1. The number of seats for the renewal. You can add seats if needed.
1. The use case for the license. Specifically, we need verification that the use meets the conditions of the [End User License Agreement](https://about.gitlab.com/terms/#edu-oss). Note that university infrastructure operations and information technology operations don't fall within the stated terms of the Education Program. For details, see the [Education FAQ](https://about.gitlab.com/solutions/education/#FAQ).
@ -503,9 +503,9 @@ To renew a [GitLab Education Program](https://about.gitlab.com/solutions/educati
After we receive the above information, we will process the request and return a renewal quote for signature. Please allow a minimum of 2 business days for return. Email us at `education@gitlab.com` with any questions.
## GitLab Open Source Program subscriptions
## GitLab for Open Source subscriptions
All requests for our GitLab Open Source program, including subscription renewals, must be made by using the [Open Source Program](https://about.gitlab.com/solutions/open-source/program/) application process. If you have any questions, send an email to `opensource@gitlab.com` for assistance.
All [GitLab for Open Source](https://about.gitlab.com/solutions/open-source/program/) requests, including subscription renewals, must be made by using the application process. If you have any questions, send an email to `opensource@gitlab.com` for assistance.
<!-- ## Troubleshooting

View File

@ -53,8 +53,10 @@ also requires the GitLab Runner 11.5 or later. For earlier versions, use the
This example shows how to run Code Quality on your code by using GitLab CI/CD and Docker.
First, you need GitLab Runner with
[docker-in-docker executor](../../../ci/docker/using_docker_build.md#use-docker-in-docker-workflow-with-docker-executor).
First, you need GitLab Runner with:
- The [docker-in-docker executor](../../../ci/docker/using_docker_build.md#use-docker-in-docker-workflow-with-docker-executor).
- Enough disk space to handle generated Code Quality files. For example on the [GitLab project](https://gitlab.com/gitlab-org/gitlab) the files are approximately 7 GB.
Once you set up the Runner, include the CodeQuality template in your CI config:

View File

@ -2,8 +2,6 @@
module Gitlab
class GitAccessWiki < GitAccess
prepend_if_ee('EE::Gitlab::GitAccessWiki') # rubocop: disable Cop/InjectEnterpriseEditionModule
ERROR_MESSAGES = {
read_only: "You can't push code to a read-only GitLab instance.",
write_to_wiki: "You are not allowed to write to this project's wiki."
@ -33,10 +31,8 @@ module Gitlab
ERROR_MESSAGES[:read_only]
end
private
def repository
project.wiki.repository
def container
project.wiki
end
end
end

View File

@ -0,0 +1,27 @@
require 'logger'
desc "GitLab | X509 | Update signatures when certificate store has changed"
namespace :gitlab do
namespace :x509 do
task update_signatures: :environment do
update_certificates
end
def update_certificates
logger = Logger.new(STDOUT)
unless X509CommitSignature.exists?
logger.info("Unable to find any x509 commit signatures. Exiting.")
return
end
logger.info("Start to update x509 commit signatures")
X509CommitSignature.find_each do |sig|
sig.x509_commit&.update_signature!(sig)
end
logger.info("End update x509 commit signatures")
end
end
end

View File

@ -1289,6 +1289,9 @@ msgstr ""
msgid "Added at"
msgstr ""
msgid "Added for this merge request"
msgstr ""
msgid "Added in this version"
msgstr ""
@ -1855,6 +1858,9 @@ msgstr ""
msgid "An error occurred fetching the dropdown data."
msgstr ""
msgid "An error occurred fetching the project authors."
msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
@ -2173,6 +2179,9 @@ msgstr ""
msgid "Any"
msgstr ""
msgid "Any Author"
msgstr ""
msgid "Any Label"
msgstr ""
@ -14195,6 +14204,9 @@ msgstr ""
msgid "OutdatedBrowser|You can provide feedback %{feedback_link_start}on this issue%{feedback_link_end} or via your usual support channels."
msgstr ""
msgid "Overridden"
msgstr ""
msgid "Overview"
msgstr ""
@ -17691,6 +17703,9 @@ msgstr ""
msgid "Search branches and tags"
msgstr ""
msgid "Search by author"
msgstr ""
msgid "Search files"
msgstr ""
@ -17851,6 +17866,9 @@ msgid_plural "SearchResults|wiki results"
msgstr[0] ""
msgstr[1] ""
msgid "Searching by both author and message is currently not supported."
msgstr ""
msgid "Seat Link"
msgstr ""

View File

@ -213,23 +213,23 @@ export const deploymentData = [
export const annotationsData = [
{
id: 'gid://gitlab/Metrics::Dashboard::Annotation/1',
from: '2020-04-01T12:51:58.373Z',
to: null,
starting_at: '2020-04-01T12:51:58.373Z',
ending_at: null,
panelId: null,
description: 'This is a test annotation',
},
{
id: 'gid://gitlab/Metrics::Dashboard::Annotation/2',
description: 'test annotation 2',
from: '2020-04-02T12:51:58.373Z',
to: null,
starting_at: '2020-04-02T12:51:58.373Z',
ending_at: null,
panelId: null,
},
{
id: 'gid://gitlab/Metrics::Dashboard::Annotation/3',
description: 'test annotation 3',
from: '2020-04-04T12:51:58.373Z',
to: null,
starting_at: '2020-04-04T12:51:58.373Z',
ending_at: null,
panelId: null,
},
];

View File

@ -0,0 +1,216 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import * as urlUtility from '~/lib/utils/url_utility';
import AuthorSelect from '~/projects/commits/components/author_select.vue';
import { createStore } from '~/projects/commits/store';
import {
GlNewDropdown,
GlNewDropdownHeader,
GlSearchBoxByType,
GlNewDropdownItem,
} from '@gitlab/ui';
const localVue = createLocalVue();
localVue.use(Vuex);
const commitsPath = 'author/search/url';
const currentAuthor = 'lorem';
const authors = [
{
id: 1,
name: currentAuthor,
username: 'ipsum',
avatar_url: 'some/url',
},
{
id: 2,
name: 'lorem2',
username: 'ipsum2',
avatar_url: 'some/url/2',
},
];
describe('Author Select', () => {
let store;
let wrapper;
const createComponent = () => {
setFixtures(`
<div class="js-project-commits-show">
<input id="commits-search" type="text" />
<div id="commits-list"></div>
</div>
`);
wrapper = shallowMount(AuthorSelect, {
localVue,
store: new Vuex.Store(store),
propsData: {
projectCommitsEl: document.querySelector('.js-project-commits-show'),
},
});
};
beforeEach(() => {
store = createStore();
store.actions.fetchAuthors = jest.fn();
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
const findDropdownContainer = () => wrapper.find({ ref: 'dropdownContainer' });
const findDropdown = () => wrapper.find(GlNewDropdown);
const findDropdownHeader = () => wrapper.find(GlNewDropdownHeader);
const findSearchBox = () => wrapper.find(GlSearchBoxByType);
const findDropdownItems = () => wrapper.findAll(GlNewDropdownItem);
describe('user is searching via "filter by commit message"', () => {
it('disables dropdown container', () => {
wrapper.setData({ hasSearchParam: true });
return wrapper.vm.$nextTick().then(() => {
expect(findDropdownContainer().attributes('disabled')).toBeFalsy();
});
});
it('has correct tooltip message', () => {
wrapper.setData({ hasSearchParam: true });
return wrapper.vm.$nextTick().then(() => {
expect(findDropdownContainer().attributes('title')).toBe(
'Searching by both author and message is currently not supported.',
);
});
});
it('disables dropdown', () => {
wrapper.setData({ hasSearchParam: false });
return wrapper.vm.$nextTick().then(() => {
expect(findDropdown().attributes('disabled')).toBeFalsy();
});
});
it('hasSearchParam if user types a truthy string', () => {
wrapper.vm.setSearchParam('false');
expect(wrapper.vm.hasSearchParam).toBeTruthy();
});
});
describe('dropdown', () => {
it('displays correct default text', () => {
expect(findDropdown().attributes('text')).toBe('Author');
});
it('displays the current selected author', () => {
wrapper.setData({ currentAuthor });
return wrapper.vm.$nextTick().then(() => {
expect(findDropdown().attributes('text')).toBe(currentAuthor);
});
});
it('displays correct header text', () => {
expect(findDropdownHeader().text()).toBe('Search by author');
});
it('does not have popover text by default', () => {
expect(wrapper.attributes('title')).not.toExist();
});
});
describe('dropdown search box', () => {
it('has correct placeholder', () => {
expect(findSearchBox().attributes('placeholder')).toBe('Search');
});
it('fetch authors on input change', () => {
const authorName = 'lorem';
findSearchBox().vm.$emit('input', authorName);
expect(store.actions.fetchAuthors).toHaveBeenCalledWith(
expect.anything(),
authorName,
undefined,
);
});
});
describe('dropdown list', () => {
beforeEach(() => {
store.state.commitsAuthors = authors;
store.state.commitsPath = commitsPath;
});
it('has a "Any Author" as the first list item', () => {
expect(
findDropdownItems()
.at(0)
.text(),
).toBe('Any Author');
});
it('displays the project authors', () => {
return wrapper.vm.$nextTick().then(() => {
expect(findDropdownItems()).toHaveLength(authors.length + 1);
});
});
it('has the correct props', () => {
const [{ avatar_url, username }] = authors;
const result = {
avatarUrl: avatar_url,
secondaryText: username,
isChecked: true,
};
wrapper.setData({ currentAuthor });
return wrapper.vm.$nextTick().then(() => {
expect(
findDropdownItems()
.at(1)
.props(),
).toEqual(expect.objectContaining(result));
});
});
it("display the author's name", () => {
return wrapper.vm.$nextTick().then(() => {
expect(
findDropdownItems()
.at(1)
.text(),
).toBe(currentAuthor);
});
});
it('passes selected author to redirectPath', () => {
const redirectToUrl = `${commitsPath}?author=${currentAuthor}`;
const spy = jest.spyOn(urlUtility, 'redirectTo');
spy.mockImplementation(() => 'mock');
findDropdownItems()
.at(1)
.vm.$emit('click');
expect(spy).toHaveBeenCalledWith(redirectToUrl);
});
it('does not pass any author to redirectPath', () => {
const redirectToUrl = commitsPath;
const spy = jest.spyOn(urlUtility, 'redirectTo');
spy.mockImplementation();
findDropdownItems()
.at(0)
.vm.$emit('click');
expect(spy).toHaveBeenCalledWith(redirectToUrl);
});
});
});

View File

@ -0,0 +1,69 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import * as types from '~/projects/commits/store/mutation_types';
import testAction from 'helpers/vuex_action_helper';
import actions from '~/projects/commits/store/actions';
import createState from '~/projects/commits/store/state';
import createFlash from '~/flash';
jest.mock('~/flash');
describe('Project commits actions', () => {
let state;
let mock;
beforeEach(() => {
state = createState();
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('setInitialData', () => {
it(`commits ${types.SET_INITIAL_DATA}`, () =>
testAction(actions.setInitialData, undefined, state, [{ type: types.SET_INITIAL_DATA }]));
});
describe('receiveAuthorsSuccess', () => {
it(`commits ${types.COMMITS_AUTHORS}`, () =>
testAction(actions.receiveAuthorsSuccess, undefined, state, [
{ type: types.COMMITS_AUTHORS },
]));
});
describe('shows a flash message when there is an error', () => {
it('creates a flash', () => {
const mockDispatchContext = { dispatch: () => {}, commit: () => {}, state };
actions.receiveAuthorsError(mockDispatchContext);
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith('An error occurred fetching the project authors.');
});
});
describe('fetchAuthors', () => {
it('dispatches request/receive', () => {
const path = '/autocomplete/users.json';
state.projectId = '8';
const data = [{ id: 1 }];
mock.onGet(path).replyOnce(200, data);
testAction(
actions.fetchAuthors,
null,
state,
[],
[{ type: 'receiveAuthorsSuccess', payload: data }],
);
});
it('dispatches request/receive on error', () => {
const path = '/autocomplete/users.json';
mock.onGet(path).replyOnce(500);
testAction(actions.fetchAuthors, null, state, [], [{ type: 'receiveAuthorsError' }]);
});
});
});

View File

@ -0,0 +1,43 @@
import * as types from '~/projects/commits/store/mutation_types';
import mutations from '~/projects/commits/store/mutations';
import createState from '~/projects/commits/store/state';
describe('Project commits mutations', () => {
let state;
beforeEach(() => {
state = createState();
});
afterEach(() => {
state = null;
});
describe(`${types.SET_INITIAL_DATA}`, () => {
it('sets initial data', () => {
state.commitsPath = null;
state.projectId = null;
state.commitsAuthors = [];
const data = {
commitsPath: 'some/path',
projectId: '8',
};
mutations[types.SET_INITIAL_DATA](state, data);
expect(state).toEqual(expect.objectContaining(data));
});
});
describe(`${types.COMMITS_AUTHORS}`, () => {
it('sets commitsAuthors', () => {
const authors = [{ id: 1 }, { id: 2 }];
state.commitsAuthors = [];
mutations[types.COMMITS_AUTHORS](state, authors);
expect(state.commitsAuthors).toEqual(authors);
});
});
});

View File

@ -21,7 +21,7 @@ describe Gitlab::ImportExport::JSON::NdjsonReader do
describe '#exist?' do
subject { ndjson_reader.exist? }
context 'given valid dir_path', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/213843' do
context 'given valid dir_path' do
let(:dir_path) { fixture }
it { is_expected.to be true }

View File

@ -15,15 +15,17 @@ module ImportExport
export_path = [prefix, 'spec', 'fixtures', 'lib', 'gitlab', 'import_export', name].compact
export_path = File.join(*export_path)
extract_archive(export_path, 'tree.tar.gz')
if File.exist?(File.join(export_path, 'tree.tar.gz'))
extract_archive(export_path, 'tree.tar.gz')
end
allow_any_instance_of(Gitlab::ImportExport).to receive(:export_path) { export_path }
end
def extract_archive(path, archive)
if File.exist?(File.join(path, archive))
system("cd #{path}; tar xzvf #{archive} &> /dev/null")
end
output, exit_status = Gitlab::Popen.popen(["cd #{path}; tar xzf #{archive}"])
raise "Failed to extract archive. Output: #{output}" unless exit_status.zero?
end
def cleanup_artifacts_from_extract_archive(name, prefix = nil)
@ -31,7 +33,7 @@ module ImportExport
export_path = File.join(*export_path)
if File.exist?(File.join(export_path, 'tree.tar.gz'))
system("cd #{export_path}; rm -fr tree &> /dev/null")
system("cd #{export_path}; rm -fr tree")
end
end

View File

@ -0,0 +1,42 @@
# frozen_string_literal: true
require 'rake_helper'
describe 'gitlab:x509 namespace rake task' do
before :all do
Rake.application.rake_require 'tasks/gitlab/x509/update'
end
describe 'update_signatures' do
subject { run_rake_task('gitlab:x509:update_signatures') }
let(:project) { create :project, :repository, path: X509Helpers::User1.path }
let(:x509_signed_commit) { project.commit_by(oid: '189a6c924013fc3fe40d6f1ec1dc20214183bc97') }
let(:x509_commit) { Gitlab::X509::Commit.new(x509_signed_commit).signature }
it 'changes from unverified to verified if the certificate store contains the root certificate' do
x509_commit
store = OpenSSL::X509::Store.new
certificate = OpenSSL::X509::Certificate.new X509Helpers::User1.trust_cert
store.add_cert(certificate)
allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
expect(x509_commit.verification_status).to eq('unverified')
expect_any_instance_of(Gitlab::X509::Commit).to receive(:update_signature!).and_call_original
subject
x509_commit.reload
expect(x509_commit.verification_status).to eq('verified')
end
it 'returns if no signature is available' do
expect_any_instance_of(Gitlab::X509::Commit) do |x509_commit|
expect(x509_commit).not_to receive(:update_signature!)
subject
end
end
end
end