Commit 39c83bdd authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 13cc2b82 65b8b77c
......@@ -3,10 +3,10 @@ import { throttle } from 'lodash';
import {
GlLoadingIcon,
GlSearchBoxByType,
GlDeprecatedDropdown,
GlDeprecatedDropdownDivider,
GlDeprecatedDropdownHeader,
GlDeprecatedDropdownItem,
GlDropdown,
GlDropdownDivider,
GlDropdownSectionHeader,
GlDropdownItem,
} from '@gitlab/ui';
import httpStatusCodes from '~/lib/utils/http_status';
......@@ -26,10 +26,10 @@ export default {
BoardForm,
GlLoadingIcon,
GlSearchBoxByType,
GlDeprecatedDropdown,
GlDeprecatedDropdownDivider,
GlDeprecatedDropdownHeader,
GlDeprecatedDropdownItem,
GlDropdown,
GlDropdownDivider,
GlDropdownSectionHeader,
GlDropdownItem,
},
props: {
currentBoard: {
......@@ -235,22 +235,17 @@ export default {
<template>
<div class="boards-switcher js-boards-selector gl-mr-3">
<span class="boards-selector-wrapper js-boards-selector-wrapper">
<gl-deprecated-dropdown
<gl-dropdown
data-qa-selector="boards_dropdown"
toggle-class="dropdown-menu-toggle js-dropdown-toggle"
menu-class="flex-column dropdown-extended-height"
:text="board.name"
@show="loadBoards"
>
<div>
<div class="dropdown-title mb-0" @mousedown.prevent>
<p class="gl-new-dropdown-header-top" @mousedown.prevent>
{{ s__('IssueBoards|Switch board') }}
</div>
</div>
<gl-deprecated-dropdown-header class="mt-0">
<gl-search-box-by-type ref="searchBox" v-model="filterTerm" />
</gl-deprecated-dropdown-header>
</p>
<gl-search-box-by-type ref="searchBox" v-model="filterTerm" class="m-2" />
<div
v-if="!loading"
......@@ -259,49 +254,50 @@ export default {
class="dropdown-content flex-fill"
@scroll.passive="throttledSetScrollFade"
>
<gl-deprecated-dropdown-item
<gl-dropdown-item
v-show="filteredBoards.length === 0"
class="gl-pointer-events-none text-secondary"
>
{{ s__('IssueBoards|No matching boards found') }}
</gl-deprecated-dropdown-item>
</gl-dropdown-item>
<h6 v-if="showRecentSection" class="dropdown-bold-header my-0">
<gl-dropdown-section-header v-if="showRecentSection">
{{ __('Recent') }}
</h6>
</gl-dropdown-section-header>
<template v-if="showRecentSection">
<gl-deprecated-dropdown-item
<gl-dropdown-item
v-for="recentBoard in recentBoards"
:key="`recent-${recentBoard.id}`"
class="js-dropdown-item"
:href="`${boardBaseUrl}/${recentBoard.id}`"
>
{{ recentBoard.name }}
</gl-deprecated-dropdown-item>
</gl-dropdown-item>
</template>
<hr v-if="showRecentSection" class="my-1" />
<gl-dropdown-divider v-if="showRecentSection" />
<h6 v-if="showRecentSection" class="dropdown-bold-header my-0">
<gl-dropdown-section-header v-if="showRecentSection">
{{ __('All') }}
</h6>
</gl-dropdown-section-header>
<gl-deprecated-dropdown-item
<gl-dropdown-item
v-for="otherBoard in filteredBoards"
:key="otherBoard.id"
class="js-dropdown-item"
:href="`${boardBaseUrl}/${otherBoard.id}`"
>
{{ otherBoard.name }}
</gl-deprecated-dropdown-item>
<gl-deprecated-dropdown-item v-if="hasMissingBoards" class="small unclickable">
</gl-dropdown-item>
<gl-dropdown-item v-if="hasMissingBoards" class="no-pointer-events">
{{
s__(
'IssueBoards|Some of your boards are hidden, activate a license to see them again.',
)
}}
</gl-deprecated-dropdown-item>
</gl-dropdown-item>
</div>
<div
......@@ -313,25 +309,25 @@ export default {
<gl-loading-icon v-if="loading" />
<div v-if="canAdminBoard">
<gl-deprecated-dropdown-divider />
<gl-dropdown-divider />
<gl-deprecated-dropdown-item
<gl-dropdown-item
v-if="multipleIssueBoardsAvailable"
data-qa-selector="create_new_board_button"
@click.prevent="showPage('new')"
>
{{ s__('IssueBoards|Create new board') }}
</gl-deprecated-dropdown-item>
</gl-dropdown-item>
<gl-deprecated-dropdown-item
<gl-dropdown-item
v-if="showDelete"
class="text-danger js-delete-board"
@click.prevent="showPage('delete')"
>
{{ s__('IssueBoards|Delete board') }}
</gl-deprecated-dropdown-item>
</gl-dropdown-item>
</div>
</gl-deprecated-dropdown>
</gl-dropdown>
<board-form
v-if="currentPage"
......
import Vue from 'vue';
import { GlToast } from '@gitlab/ui';
import { doesHashExistInUrl } from '~/lib/utils/url_utility';
import {
parseBoolean,
historyReplaceState,
buildUrlWithCurrentLocation,
} from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import PipelinesStore from '../../../../pipelines/stores/pipelines_store';
import pipelinesComponent from '../../../../pipelines/components/pipelines_list/pipelines.vue';
import Translate from '../../../../vue_shared/translate';
import { initPipelinesIndex } from '~/pipelines/pipelines_index';
Vue.use(Translate);
Vue.use(GlToast);
document.addEventListener(
'DOMContentLoaded',
() =>
new Vue({
el: '#pipelines-list-vue',
components: {
pipelinesComponent,
},
data() {
return {
store: new PipelinesStore(),
};
},
created() {
this.dataset = document.querySelector(this.$options.el).dataset;
if (doesHashExistInUrl('delete_success')) {
this.$toast.show(__('The pipeline has been deleted'));
historyReplaceState(buildUrlWithCurrentLocation());
}
},
render(createElement) {
return createElement('pipelines-component', {
props: {
store: this.store,
endpoint: this.dataset.endpoint,
pipelineScheduleUrl: this.dataset.pipelineScheduleUrl,
helpPagePath: this.dataset.helpPagePath,
emptyStateSvgPath: this.dataset.emptyStateSvgPath,
errorStateSvgPath: this.dataset.errorStateSvgPath,
noPipelinesSvgPath: this.dataset.noPipelinesSvgPath,
autoDevopsPath: this.dataset.helpAutoDevopsPath,
newPipelinePath: this.dataset.newPipelinePath,
canCreatePipeline: parseBoolean(this.dataset.canCreatePipeline),
hasGitlabCi: parseBoolean(this.dataset.hasGitlabCi),
ciLintPath: this.dataset.ciLintPath,
resetCachePath: this.dataset.resetCachePath,
projectId: this.dataset.projectId,
params: JSON.parse(this.dataset.params),
},
});
},
}),
);
initPipelinesIndex();
......@@ -47,7 +47,7 @@ export default {
class="dropdown-menu-toggle build-content gl-build-content"
>
<div class="gl-display-flex gl-align-items-center gl-justify-content-space-between">
<span class="gl-display-flex gl-align-items-center">
<span class="gl-display-flex gl-align-items-center gl-w-90">
<ci-icon :status="group.status" :size="24" />
<span class="gl-text-truncate mw-70p gl-pl-3 gl-display-inline-block">
......
......@@ -62,7 +62,7 @@ export default {
type: String,
required: true,
},
autoDevopsPath: {
autoDevopsHelpPath: {
type: String,
required: true,
},
......@@ -342,7 +342,7 @@ export default {
:pipelines="state.pipelines"
:pipeline-schedule-url="pipelineScheduleUrl"
:update-graph-dropdown="updateGraphDropdown"
:auto-devops-help-path="autoDevopsPath"
:auto-devops-help-path="autoDevopsHelpPath"
:view-type="viewType"
/>
</div>
......
import Vue from 'vue';
import { GlToast } from '@gitlab/ui';
import { __ } from '~/locale';
import { doesHashExistInUrl } from '~/lib/utils/url_utility';
import {
parseBoolean,
historyReplaceState,
buildUrlWithCurrentLocation,
} from '~/lib/utils/common_utils';
import Translate from '~/vue_shared/translate';
import Pipelines from './components/pipelines_list/pipelines.vue';
import PipelinesStore from './stores/pipelines_store';
Vue.use(Translate);
Vue.use(GlToast);
export const initPipelinesIndex = (selector = '#pipelines-list-vue') => {
const el = document.querySelector(selector);
if (!el) {
return null;
}
const {
endpoint,
pipelineScheduleUrl,
helpPagePath,
emptyStateSvgPath,
errorStateSvgPath,
noPipelinesSvgPath,
autoDevopsHelpPath,
newPipelinePath,
canCreatePipeline,
hasGitlabCi,
ciLintPath,
resetCachePath,
projectId,
params,
} = el.dataset;
return new Vue({
el,
data() {
return {
store: new PipelinesStore(),
};
},
created() {
if (doesHashExistInUrl('delete_success')) {
this.$toast.show(__('The pipeline has been deleted'));
historyReplaceState(buildUrlWithCurrentLocation());
}
},
render(createElement) {
return createElement(Pipelines, {
props: {
store: this.store,
endpoint,
pipelineScheduleUrl,
helpPagePath,
emptyStateSvgPath,
errorStateSvgPath,
noPipelinesSvgPath,
autoDevopsHelpPath,
newPipelinePath,
canCreatePipeline: parseBoolean(canCreatePipeline),
hasGitlabCi: parseBoolean(hasGitlabCi),
ciLintPath,
resetCachePath,
projectId,
params: JSON.parse(params),
},
});
},
});
};
......@@ -139,6 +139,10 @@
width: 186px;
}
.gl-w-90 {
width: 90%;
}
.gl-build-content {
@include build-content();
}
......
......@@ -8,7 +8,7 @@
project_id: @project.id,
params: params.to_json,
"help-page-path" => help_page_path('ci/quick_start/README'),
"help-auto-devops-path" => help_page_path('topics/autodevops/index.md'),
"auto-devops-help-path" => help_page_path('topics/autodevops/index.md'),
"pipeline-schedule-url" => pipeline_schedules_path(@project),
"empty-state-svg-path" => image_path('illustrations/pipelines_empty.svg'),
"error-state-svg-path" => image_path('illustrations/pipelines_failed.svg'),
......
---
title: Fix flex overflow bug
merge_request: 48931
author:
type: fixed
---
title: Replace-GlDeprecatedDropdown-with-GlDropdown-in-app/assets/javascripts/boards
merge_request: 41410
author: nuwe1
type: other
......@@ -43,6 +43,7 @@ The following table lists examples with step-by-step tutorials that are containe
| Parallel testing Ruby & JS | [GitLab CI/CD parallel jobs testing for Ruby & JavaScript projects](https://docs.knapsackpro.com/2019/how-to-run-parallel-jobs-for-rspec-tests-on-gitlab-ci-pipeline-and-speed-up-ruby-javascript-testing). |
| Secrets management with Vault | [Authenticating and Reading Secrets With Hashicorp Vault](authenticating-with-hashicorp-vault/index.md). |
| Multi project pipeline | [Build, test deploy using multi project pipeline](https://gitlab.com/gitlab-examples/upstream-project). |
| NPM with semantic-release | [Publish NPM packages to the GitLab Package Registry using semantic-release](semantic-release.md). |
### Contributing examples
......
---
stage: Package
group: Package
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Publish NPM packages to the GitLab Package Registry using semantic-release
This guide demonstrates how to automatically publish NPM packages to the [GitLab Package Registry](../../user/packages/npm_registry/index.md) by using [semantic-release](https://github.com/semantic-release/semantic-release).
You can also view or fork the complete [example source](https://gitlab.com/gitlab-examples/semantic-release-npm).
## Initialize the module
1. Open a terminal and navigate to the project's repo
1. Run `npm init`. Name the module according to [the Package Registry's naming conventions](../../user/packages/npm_registry/index.md#package-naming-convention). For example, if the project's path is `gitlab-examples/semantic-release-npm`, name the module `@gitlab-examples/semantic-release-npm`.
1. Install the following NPM packages:
```shell
npm install semantic-release @semantic-release/git @semantic-release/gitlab @semantic-release/npm --save-dev
```
1. Add the following properties to the module's `package.json`:
```json
{
"scripts": {
"semantic-release": "semantic-release"
},
"publishConfig": {
"access": "public"
},
"files": [ <path(s) to files here> ]
}
```
1. Update the `files` key with glob pattern(s) that selects all files that should be included in the published module. More information about `files` can be found [in NPM's documentation](https://docs.npmjs.com/cli/v6/configuring-npm/package-json#files).
1. Add a `.gitignore` file to the project to avoid committing `node_modules`:
```plaintext
node_modules
```
## Configure the pipeline
Create a `.gitlab-ci.yml` with the following content:
```yaml
default:
image: node:latest
before_script:
- npm ci --cache .npm --prefer-offline
- |
{
echo "@${CI_PROJECT_ROOT_NAMESPACE}:registry=${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/npm/"
echo "${CI_API_V4_URL#https?}/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=\${CI_JOB_TOKEN}"
} | tee --append .npmrc
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .npm/
workflow:
rules:
- if: $CI_COMMIT_BRANCH
variables:
NPM_TOKEN: ${CI_JOB_TOKEN}
stages:
- release
publish:
stage: release
script:
- npm run semantic-release
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
```
This example configures the pipeline with a single job, `publish`, which runs `semantic-release`. The semantic-release library publishes new versions of the NPM package and creates new GitLab releases (if necessary).
The default `before_script` generates a temporary `.npmrc` that is used to authenticate to the Package Registry during the `publish` job.
## Set up environment variables
As part of publishing a package, semantic-release increases the version number in `package.json`. For semantic-release to commit this change and push it back to GitLab, the pipeline requires a custom environment variable named `GITLAB_TOKEN`. To create this variable:
1. Navigate to **Project > Settings > Access Tokens**.
1. Give the token a name, and select the `api` scope.
1. Click **Create project access token** and copy its value.
1. Navigate to **Project > Settings > CI / CD > Variables**.
1. Click **Add Variable**.
1. In the **Key** field, enter `GITLAB_TOKEN`. In the **Value** field, paste the token created above. Check the **Mask variable** option and click **Add variable**.
## Configure semantic-release
semantic-release pulls its configuration info from a `.releaserc.json` file in the project. Create a `.releaserc.json` at the root of the repository:
```json
{
"branches": ["master"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/gitlab",
"@semantic-release/npm",
[
"@semantic-release/git",
{
"assets": ["package.json"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
]
]
}
```
## Begin publishing releases
Test the pipeline by creating a commit with a message like:
```plaintext
fix: testing patch releases
```
Push the commit to `master`. The pipeline should create a new release (`v1.0.0`) on the project's **Releases** page and publish a new version of the package to the project's **Package Registry** page.
To create a minor release, use a commit message like:
```plaintext
feat: testing minor releases
```
Or, for a breaking change:
```plaintext
feat: testing major releases
BREAKING CHANGE: This is a breaking change.
```
More information about how commit messages are mapped to releases can be found in [semantic-releases's documentation](https://github.com/semantic-release/semantic-release#how-does-it-work).
## Use the module in a project
To use the published module, add an `.npmrc` file to the project that depends on the module. For example, to use [the example project](https://gitlab.com/gitlab-examples/semantic-release-npm)'s module:
```plaintext
@gitlab-examples:registry=https://gitlab.com/api/v4/packages/npm/
```
Then, install the module:
```shell
npm install --save @gitlab-examples/semantic-release-npm
```
......@@ -91,7 +91,7 @@ return new Vue({
},
});
},
}
});
```
> When adding an `id` attribute to mount a Vue application, please make sure this `id` is unique across the codebase
......
This diff is collapsed.
......@@ -277,6 +277,10 @@ deploy:
- npm publish
```
See the
[Publish NPM packages to the GitLab Package Registry using semantic-release](../../../ci/examples/semantic-release.md)
step-by-step guide and demo project for a complete example.
## Publishing packages with the same name or version
You cannot publish a package if a package of the same name and version already exists.
......
<script>
import { GlButton, GlDeprecatedDropdown, GlDeprecatedDropdownItem } from '@gitlab/ui';
import { GlButton, GlDropdown, GlDropdownItem } from '@gitlab/ui';
const ANY_WEIGHT = 'Any weight';
const NO_WEIGHT = 'None';
......@@ -7,8 +7,8 @@ const NO_WEIGHT = 'None';
export default {
components: {
GlButton,
GlDeprecatedDropdown,
GlDeprecatedDropdownItem,
GlDropdown,
GlDropdownItem,
},
props: {
board: {
......@@ -49,17 +49,15 @@ export default {
this.dropdownHidden = false;
this.$refs.dropdown.$children[0].show();
},
selectWeight({ target: { value: weight } }) {
selectWeight(weight) {
this.board.weight = this.weightInt(weight);
this.dropdownHidden = true;
},
weightInt(weight) {
if (weight > 0) {
return parseInt(weight, 10);
if (weight >= 0) {
return weight;
} else if (weight === NO_WEIGHT) {
return -2;
} else if (weight === '0') {
return 0;
}
return -1;
},
......@@ -77,19 +75,21 @@ export default {
</div>
<div :class="valueClass" :hidden="!dropdownHidden" class="value">{{ valueText }}</div>
<gl-deprecated-dropdown
<gl-dropdown
ref="dropdown"
:hidden="dropdownHidden"
:text="valueText"
class="w-100"
menu-class="w-100"
block
toggle-class="d-flex justify-content-between"
>
<div ref="weight-select" @click="selectWeight">
<gl-deprecated-dropdown-item v-for="weight in weights" :key="weight" :value="weight">
<gl-dropdown-item
v-for="weight in weights"
:key="weight"
:value="weight"
@click="selectWeight(weight)"
>
{{ weight }}
</gl-deprecated-dropdown-item>
</div>
</gl-deprecated-dropdown>
</gl-dropdown-item>
</gl-dropdown>
</div>
</template>
import { GlButton, GlDeprecatedDropdown } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import WeightSelect from 'ee/boards/components/weight_select.vue';
import { GlButton, GlDropdown, GlDropdownItem } from '@gitlab/ui';
describe('WeightSelect', () => {
let wrapper;
const editButton = () => wrapper.find(GlButton);
const valueContainer = () => wrapper.find('.value');
const weightDropdown = () => wrapper.find(GlDeprecatedDropdown);
const weightSelect = () => wrapper.find({ ref: 'weight-select' });
const weightDropdown = () => wrapper.find(GlDropdown);
const getWeightItemAtIndex = index =>
weightDropdown()
.findAll(GlDropdownItem)
.at(index);
const defaultProps = {
weights: ['Any', 'None', 0, 1, 2, 3],
board: {
......@@ -81,15 +83,16 @@ describe('WeightSelect', () => {
describe('and a weight has been selected', () => {
beforeEach(() => {
weightSelect().trigger('click');
editButton().trigger('click');
getWeightItemAtIndex(0).vm.$emit('click');
});
it('shows the value text', () => {
expect(valueContainer().isVisible()).toBeTruthy();
expect(valueContainer().isVisible()).toBe(true);
});
it('hides the weight dropdown', () => {
expect(weightDropdown().isVisible()).toBeFalsy();
expect(weightDropdown().isVisible()).toBe(false);
});
});
});
......
import { nextTick } from 'vue';
import { mount } from '@vue/test-utils';
import { GlDeprecatedDropdown, GlLoadingIcon } from '@gitlab/ui';
import { GlDropdown, GlLoadingIcon, GlDropdownSectionHeader } from '@gitlab/ui';
import { TEST_HOST } from 'spec/test_constants';
import BoardsSelector from '~/boards/components/boards_selector.vue';
import boardsStore from '~/boards/stores/boards_store';
......@@ -34,8 +34,9 @@ describe('BoardsSelector', () => {
};
const getDropdownItems = () => wrapper.findAll('.js-dropdown-item');
const getDropdownHeaders = () => wrapper.findAll('.dropdown-bold-header');
const getDropdownHeaders = () => wrapper.findAll(GlDropdownSectionHeader);
const getLoadingIcon = () => wrapper.find(GlLoadingIcon);
const findDropdown = () => wrapper.find(GlDropdown);
beforeEach(() => {
const $apollo = {
......@@ -103,7 +104,7 @@ describe('BoardsSelector', () => {
});
// Emits gl-dropdown show event to simulate the dropdown is opened at initialization time
wrapper.find(GlDeprecatedDropdown).vm.$emit('show');
findDropdown().vm.$emit('show');
});
afterEach(() => {
......
......@@ -31,7 +31,7 @@ describe('Pipelines', () => {
const paths = {
endpoint: 'twitter/flight/pipelines.json',
autoDevopsPath: '/help/topics/autodevops/index.md',
autoDevopsHelpPath: '/help/topics/autodevops/index.md',
helpPagePath: '/help/ci/quick_start/README',
emptyStateSvgPath: '/assets/illustrations/pipelines_empty.svg',
errorStateSvgPath: '/assets/illustrations/pipelines_failed.svg',
......@@ -43,7 +43,7 @@ describe('Pipelines', () => {
const noPermissions = {
endpoint: 'twitter/flight/pipelines.json',
autoDevopsPath: '/help/topics/autodevops/index.md',
autoDevopsHelpPath: '/help/topics/autodevops/index.md',
helpPagePath: '/help/ci/quick_start/README',
emptyStateSvgPath: '/assets/illustrations/pipelines_empty.svg',
errorStateSvgPath: '/assets/illustrations/pipelines_failed.svg',
......
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