Commit b1ac5ff5 authored by Robert Speicher's avatar Robert Speicher

Merge branch 'lm-add-connection-type' into 'master'

Adds connection fields to template

See merge request gitlab-org/gitlab!46737
parents 002a104d d8658f3e
a77f28ee61f3238c10769ddbd6e428debadfc933
fa974a4ab21aa6acc4c3a00456265248a4d70703
......@@ -26,7 +26,7 @@ export default {
required: false,
default: null,
},
openPath: {
openedPath: {
type: String,
required: false,
default: '',
......@@ -43,7 +43,7 @@ export default {
},
},
computed: {
open() {
opened() {
return this.total - (this.closed + (this.merged || 0));
},
showMerged() {
......@@ -63,8 +63,8 @@ export default {
<span class="gl-white-space-pre-wrap" data-testid="open-stat">
<gl-sprintf :message="__('Open: %{open}')">
<template #open>
<gl-link v-if="openPath" :href="openPath">{{ open }}</gl-link>
<template v-else>{{ open }}</template>
<gl-link v-if="openedPath" :href="openedPath">{{ opened }}</gl-link>
<template v-else>{{ opened }}</template>
</template>
</gl-sprintf>
</span>
......
......@@ -87,9 +87,14 @@ export default {
<release-block-header :release="release" />
<div class="card-body">
<div v-if="shouldRenderMilestoneInfo">
<!-- TODO: Switch open* links to opened* once fields have been updated in GraphQL -->
<release-block-milestone-info
:milestones="milestones"
:open-issues-path="release._links.issuesUrl"
:opened-issues-path="release._links.openedIssuesUrl"
:closed-issues-path="release._links.closedIssuesUrl"
:opened-merge-requests-path="release._links.openedMergeRequestsUrl"
:merged-merge-requests-path="release._links.mergedMergeRequestsUrl"
:closed-merge-requests-path="release._links.closedMergeRequestsUrl"
/>
<hr class="mb-3 mt-0" />
</div>
......
......@@ -20,7 +20,7 @@ export default {
type: Array,
required: true,
},
openIssuesPath: {
openedIssuesPath: {
type: String,
required: false,
default: '',
......@@ -30,7 +30,7 @@ export default {
required: false,
default: '',
},
openMergeRequestsPath: {
openedMergeRequestsPath: {
type: String,
required: false,
default: '',
......@@ -173,7 +173,7 @@ export default {
:label="__('Issues')"
:total="issueCounts.total"
:closed="issueCounts.closed"
:open-path="openIssuesPath"
:opened-path="openedIssuesPath"
:closed-path="closedIssuesPath"
data-testid="issue-stats"
/>
......@@ -183,7 +183,7 @@ export default {
:total="mergeRequestCounts.total"
:merged="mergeRequestCounts.merged"
:closed="mergeRequestCounts.closed"
:open-path="openMergeRequestsPath"
:opened-path="openedMergeRequestsPath"
:merged-path="mergedMergeRequestsPath"
:closed-path="closedMergeRequestsPath"
data-testid="merge-request-stats"
......
......@@ -33,9 +33,12 @@ fragment Release on Release {
}
links {
editUrl
issuesUrl
mergeRequestsUrl
selfUrl
openedIssuesUrl
closedIssuesUrl
openedMergeRequestsUrl
mergedMergeRequestsUrl
closedMergeRequestsUrl
}
commit {
sha
......
......@@ -10,7 +10,9 @@
= notice[:message].html_safe
- if @license.present? && show_license_breakdown?
= render_if_exists 'admin/licenses/breakdown'
.license-panel.gl-mt-5
= render_if_exists 'admin/licenses/summary'
= render_if_exists 'admin/licenses/breakdown'
.admin-dashboard.gl-mt-3
.row
......
- milestone_url = @milestone.project_milestone? ? project_milestone_path(@project, @milestone) : group_milestone_path(@group, @milestone)
%button.js-delete-milestone-button.btn.btn-grouped.btn-danger{ data: { milestone_id: @milestone.id,
%button.js-delete-milestone-button.btn.gl-button.btn-grouped.btn-danger{ data: { milestone_id: @milestone.id,
milestone_title: markdown_field(@milestone, :title),
milestone_url: milestone_url,
milestone_issue_count: @milestone.issues.count,
......
......@@ -11,10 +11,10 @@
.milestone-buttons
- if can?(current_user, :admin_milestone, @group || @project)
= link_to _('Edit'), edit_milestone_path(milestone), class: 'btn btn-grouped'
= link_to _('Edit'), edit_milestone_path(milestone), class: 'btn gl-button btn-grouped'
- if milestone.project_milestone? && milestone.project.group
%button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
%button.js-promote-project-milestone-button.btn.gl-button.btn-grouped{ data: { toggle: 'modal',
target: '#promote-milestone-modal',
milestone_title: milestone.title,
group_name: milestone.project.group.name,
......@@ -26,11 +26,11 @@
#promote-milestone-modal
- if milestone.active?
= link_to _('Close milestone'), update_milestone_path(milestone, { state_event: :close }), method: :put, class: 'btn btn-grouped btn-close'
= link_to _('Close milestone'), update_milestone_path(milestone, { state_event: :close }), method: :put, class: 'btn gl-button btn-grouped btn-close'
- else
= link_to _('Reopen milestone'), update_milestone_path(milestone, { state_event: :activate }), method: :put, class: 'btn btn-grouped btn-reopen'
= link_to _('Reopen milestone'), update_milestone_path(milestone, { state_event: :activate }), method: :put, class: 'btn gl-button btn-grouped btn-reopen'
= render 'shared/milestones/delete_button'
%button.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ type: 'button' }
%button.btn.gl-button.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ type: 'button' }
= sprite_icon('chevron-double-lg-left')
......@@ -8,7 +8,7 @@
= markdown_field(label, :description)
.float-right.d-none.d-lg-block.d-xl-block
= link_to milestones_issues_path(options.merge(state: 'opened')), class: 'btn btn-transparent btn-action' do
= link_to milestones_issues_path(options.merge(state: 'opened')), class: 'btn gl-button btn-default-tertiary btn-action' do
- pluralize milestone_issues_by_label_count(@milestone, label, state: :opened), _('open issue')
= link_to milestones_issues_path(options.merge(state: 'closed')), class: 'btn btn-transparent btn-action' do
= link_to milestones_issues_path(options.merge(state: 'closed')), class: 'btn gl-button btn-default-tertiary btn-action' do
- pluralize milestone_issues_by_label_count(@milestone, label, state: :closed), _('closed issue')
......@@ -46,7 +46,7 @@
.milestone-actions.d-flex.justify-content-sm-start.justify-content-md-end
- if @project # if in milestones list on project level
- if can_admin_group_milestones?
%button.js-promote-project-milestone-button.btn.btn-blank.btn-sm.btn-grouped.has-tooltip{ title: s_('Milestones|Promote to Group Milestone'),
%button.js-promote-project-milestone-button.btn.gl-button.btn-default-tertiary.btn-sm.btn-grouped.has-tooltip{ title: s_('Milestones|Promote to Group Milestone'),
disabled: true,
type: 'button',
data: { url: promote_project_milestone_path(milestone.project, milestone),
......@@ -59,6 +59,6 @@
- if can?(current_user, :admin_milestone, milestone)
- if milestone.closed?
= link_to s_('Milestones|Reopen Milestone'), milestone_path(milestone, milestone: { state_event: :activate }), method: :put, class: "btn btn-sm btn-grouped btn-reopen"
= link_to s_('Milestones|Reopen Milestone'), milestone_path(milestone, milestone: { state_event: :activate }), method: :put, class: "btn gl-button btn-sm btn-grouped btn-reopen"
- else
= link_to s_('Milestones|Close Milestone'), milestone_path(milestone, milestone: { state_event: :close }), method: :put, class: "btn btn-sm btn-grouped btn-close"
= link_to s_('Milestones|Close Milestone'), milestone_path(milestone, milestone: { state_event: :close }), method: :put, class: "btn gl-button btn-warning-secondary btn-sm btn-grouped btn-close"
......@@ -20,4 +20,15 @@ if Gitlab::Runtime.console?
end
puts '-' * 80
# Stop irb from writing a history file by default.
module IrbNoHistory
def init_config(*)
super
IRB.conf[:SAVE_HISTORY] = false
end
end
IRB.singleton_class.prepend(IrbNoHistory)
end
......@@ -133,9 +133,10 @@ Note the following when promoting a secondary:
```
1. Promote the **secondary** node to the **primary** node.
DANGER: **Warning:**
In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
CAUTION: **Caution:**
If the secondary node [has been paused](../../geo/index.md#pausing-and-resuming-replication), this performs
a point-in-time recovery to the last known state.
Data that was created on the primary while the secondary was paused will be lost.
To promote the secondary node to primary along with preflight checks:
......@@ -166,14 +167,16 @@ conjunction with multiple servers, as it can only
perform changes on a **secondary** with only a single machine. Instead, you must
do this manually.
DANGER: **Warning:**
In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
CAUTION: **Caution:**
If the secondary node [has been paused](../../geo/index.md#pausing-and-resuming-replication), this performs
a point-in-time recovery to the last known state.
Data that was created on the primary while the secondary was paused will be lost.
1. SSH in to the database node in the **secondary** and trigger PostgreSQL to
promote to read-write:
```shell
sudo gitlab-pg-ctl promote
sudo gitlab-ctl promote-db
```
In GitLab 12.8 and earlier, see [Message: `sudo: gitlab-pg-ctl: command not found`](../replication/troubleshooting.md#message-sudo-gitlab-pg-ctl-command-not-found).
......@@ -211,9 +214,6 @@ an external PostgreSQL database, as it can only perform changes on a **secondary
node with GitLab and the database on the same machine. As a result, a manual process is
required:
DANGER: **Warning:**
In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
1. Promote the replica database associated with the **secondary** site. This will
set the database to read-write:
- Amazon RDS - [Promoting a Read Replica to Be a Standalone DB Instance](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReadRepl.html#USER_ReadRepl.Promote)
......
......@@ -227,14 +227,15 @@ conjunction with multiple servers, as it can only
perform changes on a **secondary** with only a single machine. Instead, you must
do this manually.
DANGER: **Warning:**
In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
CAUTION: **Caution:**
If the secondary node [has been paused](../../../geo/index.md#pausing-and-resuming-replication), this performs
a point-in-time recovery to the last known state.
Data that was created on the primary while the secondary was paused will be lost.
1. SSH in to the PostgreSQL node in the **secondary** and trigger PostgreSQL to
promote to read-write:
1. SSH in to the PostgreSQL node in the **secondary** and promote PostgreSQL separately:
```shell
sudo gitlab-pg-ctl promote
sudo gitlab-ctl promote-db
```
In GitLab 12.8 and earlier, see [Message: `sudo: gitlab-pg-ctl: command not found`](../../replication/troubleshooting.md#message-sudo-gitlab-pg-ctl-command-not-found).
......
......@@ -196,8 +196,9 @@ For information on how to update your Geo nodes to the latest GitLab version, se
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35913) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
DANGER: **Warning:**
In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
CAUTION: **Caution:**
Pausing and resuming of replication is currently only supported for Geo installations using an
Omnibus GitLab-managed database. External databases are currently not supported.
In some circumstances, like during [upgrades](replication/updating_the_geo_nodes.md) or a [planned failover](disaster_recovery/planned_failover.md), it is desirable to pause replication between the primary and secondary.
......
......@@ -21,9 +21,6 @@ Updating Geo nodes involves performing:
NOTE: **Note:**
These general update steps are not intended for [high-availability deployments](https://docs.gitlab.com/omnibus/update/README.html#multi-node--ha-deployment), and will cause downtime. If you want to avoid downtime, consider using [zero downtime updates](https://docs.gitlab.com/omnibus/update/README.html#zero-downtime-updates).
DANGER: **Warning:**
In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
To update the Geo nodes when a new GitLab version is released, update **primary**
and all **secondary** nodes:
......
......@@ -174,7 +174,7 @@ to authenticate with the API:
- [Container Registry](../user/packages/container_registry/index.md) (`$CI_REGISTRY_PASSWORD` is actually `$CI_JOB_TOKEN`, but this may change in the future)
- [Go Proxy](../user/packages/go_proxy/index.md)
- [Maven Repository](../user/packages/maven_repository/index.md#authenticate-with-a-ci-job-token-in-maven)
- [NPM Repository](../user/packages/npm_registry/index.md#authenticating-with-a-ci-job-token)
- [NPM Repository](../user/packages/npm_registry/index.md#authenticate-with-a-ci-job-token)
- [Nuget Repository](../user/packages/nuget_repository/index.md)
- [PyPI Repository](../user/packages/pypi_repository/index.md#using-gitlab-ci-with-pypi-packages)
- [Generic packages](../user/packages/generic_packages/index.md#publish-a-generic-package-by-using-cicd)
......
......@@ -633,6 +633,8 @@ To enable this feature:
1. Expand the **Permissions, LFS, 2FA** section, and enter IP address ranges into **Allow access to the following IP addresses** field.
1. Click **Save changes**.
![Domain restriction by IP address](img/restrict-by-ip.gif)
#### Allowed domain restriction **(PREMIUM)**
>- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7297) in [GitLab Premium and Silver](https://about.gitlab.com/pricing/) 12.2.
......@@ -661,6 +663,8 @@ To enable this feature:
1. Expand the **Permissions, LFS, 2FA** section, and enter the domain names into **Restrict membership by email** field.
1. Click **Save changes**.
![Domain restriction by email](img/restrict-by-email.gif)
This will enable the domain-checking for all new users added to the group from this moment on.
#### Group file templates **(PREMIUM)**
......
......@@ -4,156 +4,148 @@ 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/#designated-technical-writers
---
# GitLab NPM Registry
# NPM packages in the Package Registry
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5934) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.7.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) to GitLab Core in 13.3.
With the GitLab NPM Registry, every
project can have its own space to store NPM packages.
Publish NPM packages in your project's Package Registry. Then install the
packages whenever you need to use them as a dependency.
![GitLab NPM Registry](img/npm_package_view_v12_5.png)
NOTE: **Note:**
Only [scoped](https://docs.npmjs.com/misc/scope) packages are supported.
## Enabling the NPM Registry
NOTE: **Note:**
This option is available only if your GitLab administrator has
[enabled support for the NPM registry](../../../administration/packages/index.md).
Enabling the NPM registry makes it available for all new projects
by default. To enable it for existing projects, or if you want to disable it:
1. Navigate to your project's **Settings > General > Visibility, project features, permissions**.
1. Find the Packages feature and enable or disable it.
1. Click on **Save changes** for the changes to take effect.
## Build an NPM package
You should then be able to see the **Packages & Registries** section on the left sidebar.
This section covers how to install NPM or Yarn and build a package for your
JavaScript project.
Before proceeding to authenticating with the GitLab NPM Registry, you should
get familiar with the package naming convention.
If you already use NPM and know how to build your own packages, go to
the [next section](#authenticate-to-the-package-registry).
## Getting started
### Install NPM
This section covers how to install NPM (or Yarn) and build a package for your
JavaScript project. This is a quickstart if you are new to NPM packages. If you
are already using NPM and understand how to build your own packages, move on to
the [next section](#authenticating-to-the-gitlab-npm-registry).
Install Node.js and NPM in your local development environment by following
the instructions at [npmjs.com](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).
### Installing NPM
Follow the instructions at [npmjs.com](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) to download and install Node.js and
NPM to your local development environment.
Once installation is complete, verify you can use NPM in your terminal by
When installation is complete, verify you can use NPM in your terminal by
running:
```shell
npm --version
```
You should see the NPM version printed in the output:
The NPM version is shown in the output:
```plaintext
6.10.3
```
### Installing Yarn
### Install Yarn
You may want to install and use Yarn as an alternative to NPM. Follow the
instructions at [yarnpkg.com](https://classic.yarnpkg.com/en/docs/install) to install on
your development environment.
As an alternative to NPM, you can install Yarn in your local environment by following the
instructions at [yarnpkg.com](https://classic.yarnpkg.com/en/docs/install).
Once installed, you can verify that Yarn is available with the following command:
When installation is complete, verify you can use Yarn in your terminal by
running:
```shell
yarn --version
```
You should see the version printed like so:
The Yarn version is shown in the output:
```plaintext
1.19.1
```
### Creating a project
### Create a project
Understanding how to create a full JavaScript project is outside the scope of
this guide but you can initialize a new empty package by creating and navigating
to an empty directory and using the following command:
To create a project:
```shell
npm init
```
1. Create an empty directory.
1. Go to the directory and initialize an empty package by running:
Or if you're using Yarn:
```shell
npm init
```
```shell
yarn init
```
Or if you're using Yarn:
```shell
yarn init
```
This takes you through a series of questions to produce a `package.json`
file, which is required for all NPM packages. The most important question is the
package name. NPM packages must [follow the naming convention](#package-naming-convention)
and be scoped to the project or group where the registry exists.
1. Enter responses to the questions. Ensure the **package name** follows
the [naming convention](#package-naming-convention) and is scoped to the
project or group where the registry exists.
Once you have completed the setup, you are now ready to upload your package to
the GitLab registry. To get started, you need to set up authentication and then
configure GitLab as a remote registry.
A `package.json` file is created.
## Authenticating to the GitLab NPM Registry
## Authenticate to the Package Registry
If a project is private or you want to upload an NPM package to GitLab,
you need to provide credentials for authentication. [Personal access tokens](../../profile/personal_access_tokens.md)
and [deploy tokens](../../project/deploy_tokens/index.md)
are preferred, but support is available for [OAuth tokens](../../../api/oauth2.md#resource-owner-password-credentials-flow).
To authenticate to the Package Registry, you must use one of the following:
CAUTION: **Two-factor authentication (2FA) is only supported with personal access tokens:**
If you have 2FA enabled, you need to use a [personal access token](../../profile/personal_access_tokens.md) with OAuth headers with the scope set to `api` or a [deploy token](../../project/deploy_tokens/index.md) with `read_package_registry` or `write_package_registry` scopes. Standard OAuth tokens cannot authenticate to the GitLab NPM Registry.
- A [personal access token](../../../user/profile/personal_access_tokens.md)
(required for two-factor authentication (2FA)), with the scope set to `api`.
- A [deploy token](./../../project/deploy_tokens/index.md), with the scope set to `read_package_registry`, `write_package_registry`, or both.
- It's not recommended, but you can use [OAuth tokens](../../../api/oauth2.md#resource-owner-password-credentials-flow).
Standard OAuth tokens cannot authenticate to the GitLab NPM Registry. You must use a personal access token with OAuth headers.
- A [CI job token](#authenticate-with-a-ci-job-token).
### Authenticating with a personal access token or deploy token
### Authenticate with a personal access token or deploy token
To authenticate with a [personal access token](../../profile/personal_access_tokens.md) or [deploy token](../../project/deploy_tokens/index.md),
set your NPM configuration:
```shell
# Set URL for your scoped packages.
# For example package with name `@foo/bar` will use this URL for download
npm config set @foo:registry https://gitlab.com/api/v4/packages/npm/
# Set URL for your scoped packages
# For example, a package named `@foo/bar` uses this URL for download
npm config set @foo:registry https://gitlab.example.com/api/v4/packages/npm/
# Add the token for the scoped packages URL. This will allow you to download
# `@foo/` packages from private projects.
npm config set '//gitlab.com/api/v4/packages/npm/:_authToken' "<your_token>"
# Add the token for the scoped packages URL
# Use this to download `@foo/` packages from private projects
npm config set '//gitlab.example.com/api/v4/packages/npm/:_authToken' "<your_token>"
# Add token for uploading to the registry. Replace <your_project_id>
# with the project you want your package to be uploaded to.
npm config set '//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken' "<your_token>"
# Add token for to publish to the package registry
# Replace <your_project_id> with the project you want to publish your package to
npm config set '//gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken' "<your_token>"
```
Replace `<your_project_id>` with your project ID which can be found on the home page
of your project and `<your_token>` with your personal access token or deploy token.
- `<your_project_id>` is your project ID, found on the project's home page.
- `<your_token>` is your personal access token or deploy token.
- Replace `gitlab.example.com` with your domain name.
You should now be able to publish and install NPM packages in your project.
If you encounter an error with [Yarn](https://classic.yarnpkg.com/en/), view
[troubleshooting steps](#troubleshooting).
### Authenticate with a CI job token
If you have a self-managed GitLab installation, replace `gitlab.com` with your
domain name.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9104) in GitLab Premium 12.5.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) to GitLab Core in 13.3.
If you're using NPM with GitLab CI/CD, a CI job token can be used instead of a personal access token or deploy token.
The token inherits the permissions of the user that generates the pipeline.
You should now be able to download and upload NPM packages to your project.
Add a corresponding section to your `.npmrc` file:
NOTE: **Note:**
If you encounter an error message with [Yarn](https://classic.yarnpkg.com/en/), see the
[troubleshooting section](#troubleshooting).
```ini
@foo:registry=https://gitlab.example.com/api/v4/packages/npm/
//gitlab.example.com/api/v4/packages/npm/:_authToken=${CI_JOB_TOKEN}
//gitlab.example.com/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}
```
### Using variables to avoid hard-coding auth token values
#### Use variables to avoid hard-coding auth token values
To avoid hard-coding the `authToken` value, you may use a variables in its place:
To avoid hard-coding the `authToken` value, you may use a variable in its place:
```shell
npm config set '//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken' "${NPM_TOKEN}"
npm config set '//gitlab.com/api/v4/packages/npm/:_authToken' "${NPM_TOKEN}"
npm config set '//gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken' "${NPM_TOKEN}"
npm config set '//gitlab.example.com/api/v4/packages/npm/:_authToken' "${NPM_TOKEN}"
```
Then, you could run `npm publish` either locally or via GitLab CI/CD:
Then, you can run `npm publish` either locally or by using GitLab CI/CD.
- **Locally:** Export `NPM_TOKEN` before publishing:
......@@ -164,174 +156,194 @@ Then, you could run `npm publish` either locally or via GitLab CI/CD:
- **GitLab CI/CD:** Set an `NPM_TOKEN` [variable](../../../ci/variables/README.md)
under your project's **Settings > CI/CD > Variables**.
### Authenticating with a CI job token
## Package naming convention
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9104) in GitLab Premium 12.5.
Your NPM package name must be in the format of `@scope:package-name`.
If you’re using NPM with GitLab CI/CD, a CI job token can be used instead of a personal access token or deploy token.
The token inherits the permissions of the user that generates the pipeline.
- The `@scope` is the root namespace of the GitLab project. It must match exactly, including the case.
- The `package-name` can be whatever you want.
Add a corresponding section to your `.npmrc` file:
For example, if your project is `https://gitlab.example.com/my-org/engineering-group/team-amazing/analytics`,
the root namespace is `my-org`. When you publish a package, it must have `my-org` as the scope.
```ini
@foo:registry=https://gitlab.com/api/v4/packages/npm/
//gitlab.com/api/v4/packages/npm/:_authToken=${CI_JOB_TOKEN}
//gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}
| Project | Package | Supported |
| ---------------------- | ----------------------- | --------- |
| `my-org/bar` | `@my-org/bar` | Yes |
| `my-org/bar/baz` | `@my-org/baz` | Yes |
| `My-org/Bar/baz` | `@My-org/Baz` | Yes |
| `my-org/bar/buz` | `@my-org/anything` | Yes |
| `gitlab-org/gitlab` | `@gitlab-org/gitlab` | Yes |
| `gitlab-org/gitlab` | `@foo/bar` | No |
In GitLab, this regex validates all package names from all package managers:
```plaintext
/\A\@?(([\w\-\.\+]*)\/)*([\w\-\.]+)@?(([\w\-\.\+]*)\/)*([\w\-\.]*)\z/
```
## Uploading packages
This regex allows almost all of the characters that NPM allows, with a few exceptions (for example, `~` is not allowed).
DANGER: **Warning:**
Due to a [bug in NPM](https://github.com/npm/cli/issues/1994), version `7.x` and later do not respect the `publishConfig` entry in the `package.json` file. To publish, you must use an earlier version of NPM, or temporarily set your `.npmrc` scope to `@foo:registry=https://gitlab.example.com/api/v4/projects/<project_id>/packages/npm`.
The regex also allows for capital letters, while NPM does not. Capital letters are needed because the scope must be
identical to the root namespace of the project.
CAUTION: **Caution:**
When you update the path of a user or group, or transfer a subgroup or project,
you must remove any NPM packages first. You cannot update the root namespace
of a project with NPM packages. Make sure you update your `.npmrc` files to follow
the naming convention and run `npm publish` if necessary.
Before you can upload a package, you need to specify the registry
## Publish an NPM package
Before you can publish a package, you must specify the registry
for NPM. To do this, add the following section to the bottom of `package.json`:
```json
"publishConfig": {
"@foo:registry":"https://gitlab.com/api/v4/projects/<your_project_id>/packages/npm/"
"@foo:registry":"https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/"
}
```
Replace `<your_project_id>` with your project ID, which can be found on the home
page of your project, and replace `@foo` with your own scope.
- `<your_project_id>` is your project ID, found on the project's home page.
- `@foo` is your scope.
- Replace `gitlab.example.com` with your domain name.
If you have a self-managed GitLab installation, replace `gitlab.com` with your
domain name.
DANGER: **Warning:**
The `publishConfig` entry in the `package.json` file is not respected, because of a
[bug in NPM](https://github.com/npm/cli/issues/1994) version `7.x` and later. You must
use an earlier version of NPM, or temporarily set your `.npmrc` scope to
`@foo:registry=https://gitlab.example.com/api/v4/projects/<project_id>/packages/npm`.
Once you have enabled it and set up [authentication](#authenticating-to-the-gitlab-npm-registry),
After you have set up [authentication](#authenticate-to-the-package-registry),
you can upload an NPM package to your project:
```shell
npm publish
```
You can then navigate to your project's **Packages & Registries** page and see the uploaded
packages or even delete them.
To view the package, go to your project's **Packages & Registries**.
Attempting to publish a package with a name that already exists within
a given scope causes a `403 Forbidden!` error.
If you try to publish a package [with a name that already exists](#publishing-packages-with-the-same-name-or-version) within
a given scope, you get a `403 Forbidden!` error.
## Uploading a package with the same version twice
## Publish an NPM package by using CI/CD
You cannot upload a package with the same name and version twice, unless you
delete the existing package first. This aligns with npmjs.org's behavior, with
the exception that npmjs.org does not allow users to ever publish the same version
more than once, even if it has been deleted.
## Package naming convention
To work with NPM commands within [GitLab CI/CD](./../../../ci/README.md), you can use
`CI_JOB_TOKEN` in place of the personal access token or deploy token in your commands.
**Packages must be scoped in the root namespace of the project**. The package
name may be anything but it is preferred that the project name be used unless
it is not possible due to a naming collision. For example:
An example `.gitlab-ci.yml` file for publishing NPM packages:
| Project | Package | Supported |
| ---------------------- | ----------------------- | --------- |
| `foo/bar` | `@foo/bar` | Yes |
| `foo/bar/baz` | `@foo/baz` | Yes |
| `foo/bar/buz` | `@foo/anything` | Yes |
| `gitlab-org/gitlab` | `@gitlab-org/gitlab` | Yes |
| `gitlab-org/gitlab` | `@foo/bar` | No |
```yaml
image: node:latest
The regex that is used for naming is validating all package names from all package managers:
stages:
- deploy
```plaintext
/\A\@?(([\w\-\.\+]*)\/)*([\w\-\.]+)@?(([\w\-\.\+]*)\/)*([\w\-\.]*)\z/
deploy:
stage: deploy
script:
- echo "//gitlab.example.com/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}">.npmrc
- npm publish
```
It allows for capital letters, while NPM does not, and allows for almost all of the
characters NPM allows with a few exceptions (`~` is not allowed).
## Publishing packages with the same name or version
NOTE: **Note:**
Capital letters are needed because the scope is required to be
identical to the top level namespace of the project. So, for example, if your
project path is `My-Group/project-foo`, your package must be named `@My-Group/any-package-name`.
`@my-group/any-package-name` will not work.
You cannot publish a package if a package of the same name and version already exists.
You must delete the existing package first.
CAUTION: **When updating the path of a user/group or transferring a (sub)group/project:**
Make sure to remove any NPM packages first. You cannot update the root namespace of a project with NPM packages. Don't forget to update your `.npmrc` files to follow the above naming convention and run `npm publish` if necessary.
This aligns with npmjs.org's behavior. However, npmjs.org does not ever let you publish
the same version more than once, even if it has been deleted.
Now, you can configure your project to authenticate with the GitLab NPM
Registry.
## Install a package
## Installing a package
NPM packages are commonly-installed by using the `npm` or `yarn` commands
in a JavaScript project.
NPM packages are commonly installed using the `npm` or `yarn` commands
inside a JavaScript project. If you haven't already, set the
URL for scoped packages. You can do this with the following command:
1. Set the URL for scoped packages by running:
```shell
npm config set @foo:registry https://gitlab.com/api/v4/packages/npm/
```
```shell
npm config set @foo:registry https://gitlab.example.com/api/v4/packages/npm/
```
Replace `@foo` with your scope.
Replace `@foo` with your scope.
Next, you need to ensure [authentication](#authenticating-to-the-gitlab-npm-registry)
is setup so you can successfully install the package. Once this has been
completed, you can run the following command inside your project to install a
package:
1. Ensure [authentication](#authenticate-to-the-package-registry) is configured.
1. In your project, to install a package, run:
```shell
npm install @my-project-scope/my-package
```
```shell
npm install @my-project-scope/my-package
```
Or if you're using Yarn:
Or if you're using Yarn:
```shell
yarn add @my-project-scope/my-package
```
### Forwarding requests to npmjs.org
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/55344) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.9.
```shell
yarn add @my-project-scope/my-package
```
By default, when an NPM package is not found in the GitLab NPM Registry, the request is forwarded to [npmjs.com](https://www.npmjs.com/).
In [GitLab 12.9 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/55344),
when an NPM package is not found in the Package Registry, the request is forwarded to [npmjs.com](https://www.npmjs.com/).
Administrators can disable this behavior in the [Continuous Integration settings](../../admin_area/settings/continuous_integration.md).
### Installing packages from other organizations
### Install NPM packages from other organizations
You can route package requests to organizations and users outside of GitLab.
To do this, add lines to your `.npmrc` file, replacing `my-org` with the namespace or group that owns your project's repository. The name is case-sensitive and must match the name of your group or namespace exactly.
To do this, add lines to your `.npmrc` file. Replace `my-org` with the namespace or group that owns your project's repository,
and use your organization's URL. The name is case-sensitive and must match the name of your group or namespace exactly.
```shell
@foo:registry=https://gitlab.example.com/api/v4/packages/npm/
//gitlab.com/api/v4/packages/npm/:_authToken= "<your_token>"
//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken= "<your_token>"
//gitlab.example.com/api/v4/packages/npm/:_authToken= "<your_token>"
//gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken= "<your_token>"
@my-other-org:registry=https://gitlab.example.com/api/v4/packages/npm/
//gitlab.com/api/v4/packages/npm/:_authToken= "<your_token>"
//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken= "<your_token>"
//gitlab.example.com/api/v4/packages/npm/:_authToken= "<your_token>"
//gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken= "<your_token>"
```
## Removing a package
### NPM dependencies metadata
In the packages view of your project page, you can delete packages by clicking
the red trash icons or by clicking the **Delete** button on the package details
page.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11867) in GitLab Premium 12.6.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) to GitLab Core in 13.3.
## Publishing a package with CI/CD
In GitLab 12.6 and later, packages published to the Package Registry expose the following attributes to the NPM client:
To work with NPM commands within [GitLab CI/CD](./../../../ci/README.md), you can use
`CI_JOB_TOKEN` in place of the personal access token or deploy token in your commands.
- name
- version
- dist-tags
- dependencies
- dependencies
- devDependencies
- bundleDependencies
- peerDependencies
- deprecated
A simple example `.gitlab-ci.yml` file for publishing NPM packages:
## Add NPM distribution tags
```yaml
image: node:latest
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9425) in GitLab Premium 12.8.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) to GitLab Core in 13.3.
stages:
- deploy
You can add [distribution tags](https://docs.npmjs.com/cli/dist-tag) to newly-published packages.
Tags are optional and can be assigned to only one package at a time.
deploy:
stage: deploy
script:
- echo "//gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}">.npmrc
- npm publish
When you publish a package without a tag, the `latest` tag is added by default.
When you install a package without specifying the tag or version, the `latest` tag is used.
Examples of the supported `dist-tag` commands:
```shell
npm publish @scope/package --tag # Publish a package with new tag
npm dist-tag add @scope/package@version my-tag # Add a tag to an existing package
npm dist-tag ls @scope/package # List all tags under the package
npm dist-tag rm @scope/package@version my-tag # Delete a tag from the package
npm install @scope/package@my-tag # Install a specific tag
```
Learn more about [using `CI_JOB_TOKEN` to authenticate to the GitLab NPM registry](#authenticating-with-a-ci-job-token).
You cannot use your `CI_JOB_TOKEN` or deploy token with the `npm dist-tag` commands.
View [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/258835) for details.
Due to a bug in NPM 6.9.0, deleting distribution tags fails. Make sure your NPM version is 6.9.1 or later.
## Troubleshooting
......@@ -347,7 +359,7 @@ info No lockfile found.
warning XXX: No license field
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
error An unexpected error occurred: "https://gitlab.com/api/v4/projects/XXX/packages/npm/XXX/XXX/-/XXX/XXX-X.X.X.tgz: Request failed \"404 Not Found\"".
error An unexpected error occurred: "https://gitlab.example.com/api/v4/projects/XXX/packages/npm/XXX/XXX/-/XXX/XXX-X.X.X.tgz: Request failed \"404 Not Found\"".
info If you think this is a bug, please open a bug report with the information provided in "/Users/XXX/gitlab-migration/module-util/yarn-error.log".
info Visit https://classic.yarnpkg.com/en/docs/cli/install for documentation about this command
```
......@@ -356,14 +368,14 @@ In this case, try adding this to your `.npmrc` file (and replace `<your_token>`
with your personal access token or deploy token):
```plaintext
//gitlab.com/api/v4/projects/:_authToken=<your_token>
//gitlab.example.com/api/v4/projects/:_authToken=<your_token>
```
You can also use `yarn config` instead of `npm config` when setting your auth-token dynamically:
```shell
yarn config set '//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken' "<your_token>"
yarn config set '//gitlab.com/api/v4/packages/npm/:_authToken' "<your_token>"
yarn config set '//gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken' "<your_token>"
yarn config set '//gitlab.example.com/api/v4/packages/npm/:_authToken' "<your_token>"
```
### `npm publish` targets default NPM registry (`registry.npmjs.org`)
......@@ -379,7 +391,7 @@ should look like:
"version": "1.0.0",
"description": "Example package for GitLab NPM registry",
"publishConfig": {
"@foo:registry":"https://gitlab.com/api/v4/projects/<your_project_id>/packages/npm/"
"@foo:registry":"https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/"
}
}
```
......@@ -387,14 +399,14 @@ should look like:
And the `.npmrc` file should look like:
```ini
//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken=<your_token>
//gitlab.com/api/v4/packages/npm/:_authToken=<your_token>
@foo:registry=https://gitlab.com/api/v4/packages/npm/
//gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken=<your_token>
//gitlab.example.com/api/v4/packages/npm/:_authToken=<your_token>
@foo:registry=https://gitlab.example.com/api/v4/packages/npm/
```
### `npm install` returns `Error: Failed to replace env in config: ${NPM_TOKEN}`
You do not need a token to run `npm install` unless your project is private (the token is only required to publish). If the `.npmrc` file was checked in with a reference to `$NPM_TOKEN`, you can remove it. If you prefer to leave the reference in, you need to set a value prior to running `npm install` or set the value using [GitLab environment variables](./../../../ci/variables/README.md):
You do not need a token to run `npm install` unless your project is private. The token is only required to publish. If the `.npmrc` file was checked in with a reference to `$NPM_TOKEN`, you can remove it. If you prefer to leave the reference in, you must set a value prior to running `npm install` or set the value by using [GitLab environment variables](./../../../ci/variables/README.md):
```shell
NPM_TOKEN=<your_token> npm install
......@@ -402,50 +414,11 @@ NPM_TOKEN=<your_token> npm install
### `npm install` returns `npm ERR! 403 Forbidden`
- Check that your token is not expired and has appropriate permissions.
- Check that [your token does not begin with `-`](https://gitlab.com/gitlab-org/gitlab/-/issues/235473).
- Check if you have attempted to publish a package with a name that already exists within a given scope.
- Ensure the scoped packages URL includes a trailing slash:
- Correct: `//gitlab.com/api/v4/packages/npm/`
- Incorrect: `//gitlab.com/api/v4/packages/npm`
## NPM dependencies metadata
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11867) in GitLab Premium 12.6.
Starting from GitLab 12.6, new packages published to the GitLab NPM Registry expose the following attributes to the NPM client:
- name
- version
- dist-tags
- dependencies
- dependencies
- devDependencies
- bundleDependencies
- peerDependencies
- deprecated
## NPM distribution tags
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9425) in GitLab Premium 12.8.
You can add [distribution tags](https://docs.npmjs.com/cli/dist-tag) for newly published packages.
They follow NPM's convention where they are optional, and each tag can only be assigned to one
package at a time. The `latest` tag is added by default when a package is published without a tag.
The same applies to installing a package without specifying the tag or version.
Examples of the supported `dist-tag` commands and using tags in general:
```shell
npm publish @scope/package --tag # Publish new package with new tag
npm dist-tag add @scope/package@version my-tag # Add a tag to an existing package
npm dist-tag ls @scope/package # List all tags under the package
npm dist-tag rm @scope/package@version my-tag # Delete a tag from the package
npm install @scope/package@my-tag # Install a specific tag
```
NOTE: **Note:**
You cannot use your `CI_JOB_TOKEN` or deploy token with the `npm dist-tag` commands. View [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/258835) for details.
If you get this error, ensure that:
CAUTION: **Warning:**
Due to a bug in NPM 6.9.0, deleting dist tags fails. Make sure your NPM version is greater than 6.9.1.
- Your token is not expired and has appropriate permissions.
- [Your token does not begin with `-`](https://gitlab.com/gitlab-org/gitlab/-/issues/235473).
- A package with the same name doesn't already exist within the given scope.
- The scoped packages URL includes a trailing slash:
- Correct: `//gitlab.example.com/api/v4/packages/npm/`
- Incorrect: `//gitlab.example.com/api/v4/packages/npm`
......@@ -31,7 +31,7 @@ authenticate with GitLab by using the `CI_JOB_TOKEN`.
CI/CD templates, which you can use to get started, are in [this repo](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates).
Learn more about [using CI/CD to build Maven packages](../maven_repository/index.md#create-maven-packages-with-gitlab-cicd), [NPM packages](../npm_registry/index.md#publishing-a-package-with-cicd), [Composer packages](../composer_repository/index.md#publish-a-composer-package-by-using-cicd), [NuGet Packages](../nuget_repository/index.md#publishing-a-nuget-package-with-cicd), [Conan Packages](../conan_repository/index.md#publish-a-conan-package-by-using-cicd), [PyPI packages](../pypi_repository/index.md#using-gitlab-ci-with-pypi-packages), and [generic packages](../generic_packages/index.md#publish-a-generic-package-by-using-cicd).
Learn more about [using CI/CD to build Maven packages](../maven_repository/index.md#create-maven-packages-with-gitlab-cicd), [NPM packages](../npm_registry/index.md#publish-an-npm-package-by-using-cicd), [Composer packages](../composer_repository/index.md#publish-a-composer-package-by-using-cicd), [NuGet Packages](../nuget_repository/index.md#publishing-a-nuget-package-with-cicd), [Conan Packages](../conan_repository/index.md#publish-a-conan-package-by-using-cicd), [PyPI packages](../pypi_repository/index.md#using-gitlab-ci-with-pypi-packages), and [generic packages](../generic_packages/index.md#publish-a-generic-package-by-using-cicd).
If you use CI/CD to build a package, extended activity
information is displayed when you view the package details:
......
......@@ -67,9 +67,9 @@ If you are using NPM, this involves creating an `.npmrc` file and adding the app
to your project using your project ID, then adding a section to your `package.json` file with a similar URL.
Follow
the instructions in the [GitLab NPM Registry documentation](../npm_registry/index.md#authenticating-to-the-gitlab-npm-registry). After
the instructions in the [GitLab NPM Registry documentation](../npm_registry/index.md#authenticate-to-the-package-registry). After
you do this, you can push your NPM package to your project using `npm publish`, as described in the
[uploading packages](../npm_registry/index.md#uploading-packages) section of the docs.
[publishing packages](../npm_registry/index.md#publish-an-npm-package) section of the docs.
#### Maven
......
......@@ -31,7 +31,7 @@ To let your team members organize their own workflows, use
[multiple issue boards](#use-cases-for-multiple-issue-boards). This allows creating multiple issue
boards in the same project.
![GitLab issue board - Core](img/issue_boards_core.png)
![GitLab issue board - Core](img/issue_boards_core_v13_6.png)
Different issue board features are available in different [GitLab tiers](https://about.gitlab.com/pricing/),
as shown in the following table:
......@@ -45,7 +45,7 @@ as shown in the following table:
To learn more, visit [GitLab Enterprise features for issue boards](#gitlab-enterprise-features-for-issue-boards) below.
![GitLab issue board - Premium](img/issue_boards_premium.png)
![GitLab issue board - Premium](img/issue_boards_premium_v13_6.png)
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
Watch a [video presentation](https://youtu.be/vjccjHI7aGI) of
......@@ -69,8 +69,8 @@ For example, let's consider this simplified development workflow:
1. When frontend is complete, the new feature is deployed to a **staging** environment to be tested.
1. When successful, it's deployed to **production**.
If you have the labels "**backend**", "**frontend**", "**staging**", and
"**production**", and an issue board with a list for each, you can:
If you have the labels **Backend**, **Frontend**, **Staging**, and
**Production**, and an issue board with a list for each, you can:
- Visualize the entire flow of implementations since the beginning of the development life cycle
until deployed to production.
......@@ -78,7 +78,7 @@ If you have the labels "**backend**", "**frontend**", "**staging**", and
- Move issues between lists to organize them according to the labels you've set.
- Add multiple issues to lists in the board by selecting one or more existing issues.
![issue card moving](img/issue_board_move_issue_card_list.png)
![issue card moving](img/issue_board_move_issue_card_list_v13_6.png)
### Use cases for multiple issue boards
......@@ -199,7 +199,7 @@ Using the search box at the top of the menu, you can filter the listed boards.
When you have ten or more boards available, a **Recent** section is also shown in the menu, with
shortcuts to your last four visited boards.
![Multiple issue boards](img/issue_boards_multiple.png)
![Multiple issue boards](img/issue_boards_multiple_v13_6.png)
When you're revisiting an issue board in a project or group with multiple boards,
GitLab automatically loads the last board you visited.
......@@ -229,20 +229,16 @@ An issue board can be associated with a GitLab [Milestone](milestones/index.md#m
which automatically filter the board issues accordingly.
This allows you to create unique boards according to your team's need.
![Create scoped board](img/issue_board_creation.png)
![Create scoped board](img/issue_board_creation_v13_6.png)
You can define the scope of your board when creating it or by clicking the "Edit board" button.
Once a milestone, assignee or weight is assigned to an issue board, you can no longer
You can define the scope of your board when creating it or by clicking the **Edit board** button.
After a milestone, assignee or weight is assigned to an issue board, you can no longer
filter through these in the search bar. In order to do that, you need to remove the desired scope
(for example, milestone, assignee, or weight) from the issue board.
![Edit board configuration](img/issue_board_edit_button.png)
If you don't have editing permission in a board, you're still able to see the configuration by
clicking **View scope**.
![Viewing board configuration](img/issue_board_view_scope.png)
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
Watch a [video presentation](https://youtu.be/m5UTNCSqaDk) of
the Configurable Issue Board feature.
......@@ -253,12 +249,8 @@ the Configurable Issue Board feature.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28597) to the Free tier of GitLab.com in 12.10.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212331) to GitLab Core in 13.0.
Click the button at the top right to toggle focus mode on and off. In focus mode, the navigation UI
is hidden, allowing you to focus on issues in the board.
![Board focus mode](img/issue_board_focus_mode.gif)
---
To enable or disable focus mode, select the **Toggle focus mode** button (**{maximize}**) at the top
right. In focus mode, the navigation UI is hidden, allowing you to focus on issues in the board.
### Sum of issue weights **(STARTER)**
......@@ -266,7 +258,7 @@ The top of each list indicates the sum of issue weights for the issues that
belong to that list. This is useful when using boards for capacity allocation,
especially in combination with [assignee lists](#assignee-lists).
![issue board summed weights](img/issue_board_summed_weights.png)
![issue board summed weights](img/issue_board_summed_weights_v13_6.png)
### Group issue boards **(PREMIUM)**
......@@ -279,8 +271,6 @@ group and its descendant subgroups. Similarly, you can only filter by group labe
boards. When updating milestones and labels for an issue through the sidebar update mechanism, again only
group-level objects are available.
![Group issue board](img/group_issue_board.png)
### Assignee lists **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5784) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.0.
......@@ -290,15 +280,15 @@ an assignee list that shows all issues assigned to a user.
You can have a board with both label lists and assignee lists. To add an
assignee list:
1. Click **Add list**.
1. Select the **Add list** dropdown button.
1. Select the **Assignee list** tab.
1. Search and click the user you want to add as an assignee.
1. Search and select the user you want to add as an assignee.
Now that the assignee list is added, you can assign or unassign issues to that user
by [dragging issues](#drag-issues-between-lists) to and from an assignee list.
To remove an assignee list, just as with a label list, click the trash icon.
![Assignee lists](img/issue_board_assignee_lists.png)
![Assignee lists](img/issue_board_assignee_lists_v13_6.png)
### Milestone lists **(PREMIUM)**
......@@ -307,7 +297,7 @@ To remove an assignee list, just as with a label list, click the trash icon.
You're also able to create lists of a milestone. These are lists that filter issues by the assigned
milestone, giving you more freedom and visibility on the issue board. To add a milestone list:
1. Click **Add list**.
1. Select the **Add list** dropdown button.
1. Select the **Milestone** tab.
1. Search and click the milestone.
......@@ -315,7 +305,7 @@ Like the assignee lists, you're able to [drag issues](#drag-issues-between-lists
to and from a milestone list to manipulate the milestone of the dragged issues.
As in other list types, click the trash icon to remove a list.
![Milestone lists](img/issue_board_milestone_lists.png)
![Milestone lists](img/issue_board_milestone_lists_v13_6.png)
## Work In Progress limits **(STARTER)**
......@@ -347,7 +337,7 @@ To set a WIP limit for a list:
If an issue is blocked by another issue, an icon appears next to its title to indicate its blocked
status.
![Blocked issues](img/issue_boards_blocked_icon_v12_8.png)
![Blocked issues](img/issue_boards_blocked_icon_v13_6.png)
## Actions you can take on an issue board
......@@ -381,16 +371,16 @@ have that label.
### Create a new list
Create a new list by clicking the **Add list** button in the upper right corner of the issue board.
Create a new list by clicking the **Add list** dropdown button in the upper right corner of the issue board.
![creating a new list in an issue board](img/issue_board_add_list.png)
![creating a new list in an issue board](img/issue_board_add_list_v13_6.png)
Then, choose the label or user to create the list from. The new list is inserted
at the end of the lists, before **Done**. Moving and reordering lists is as
easy as dragging them around.
Then, choose the label or user to base the new list on. The new list is inserted
at the end of the lists, before **Done**. To move and reorder lists, drag them around.
To create a list for a label that doesn't yet exist, create the label by
choosing **Create new label**. This creates the label immediately and adds it to the dropdown.
choosing **Create project label** or **Create group label**.
This creates the label immediately and adds it to the dropdown.
You can now choose it to create a list.
### Delete a list
......@@ -404,14 +394,14 @@ list view that's removed. You can always restore it later if you need.
### Add issues to a list
You can add issues to a list by clicking the **Add issues** button
present in the upper right corner of the issue board. This opens up a modal
in the top right corner of the issue board. This opens up a modal
window where you can see all the issues that do not belong to any list.
Select one or more issues by clicking the cards and then click **Add issues**
to add them to the selected list. You can limit the issues you want to add to
the list by filtering by author, assignee, milestone, and label.
![Bulk adding issues to lists](img/issue_boards_add_issues_modal.png)
![Bulk adding issues to lists](img/issue_boards_add_issues_modal_v13_6.png)
### Remove an issue from a list
......@@ -419,13 +409,13 @@ Removing an issue from a list can be done by clicking the issue card and then
clicking the **Remove from board** button in the sidebar. The
respective label is removed.
![Remove issue from list](img/issue_boards_remove_issue.png)
![Remove issue from list](img/issue_boards_remove_issue_v13_6.png)
### Filter issues
You should be able to use the filters on top of your issue board to show only
the results you want. It's similar to the filtering used in the issue tracker
since the metadata from the issues and labels are re-used in the issue board.
the results you want. It's similar to the filtering used in the issue tracker,
as the metadata from the issues and labels is re-used in the issue board.
You can filter by author, assignee, milestone, and label.
......@@ -435,13 +425,13 @@ By reordering your lists, you can create workflows. As lists in issue boards are
based on labels, it works out of the box with your existing issues.
So if you've already labeled things with **Backend** and **Frontend**, the issue appears in
the lists as you create them. In addition, this means you can easily move
something between lists by changing a label.
the lists as you create them. In addition, this means you can move something between lists by
changing a label.
A typical workflow of using an issue board would be:
1. You have [created](labels.md#label-management) and [prioritized](labels.md#label-priority)
labels so that you can easily categorize your issues.
labels to categorize your issues.
1. You have a bunch of issues (ideally labeled).
1. You visit the issue board and start [creating lists](#create-a-new-list) to
create a workflow.
......@@ -457,15 +447,15 @@ For example, you can create a list based on the label of **Frontend** and one fo
**Frontend** list. That way, everyone knows that this issue is now being
worked on by the designers.
Then, once they're done, all they have to do is
Then, when they're done, all they have to do is
drag it to the next list, **Backend**. Then, a backend developer can
eventually pick it up. Once they’re done, they move it to **Done**, to close the
eventually pick it up. When they’re done, they move it to **Done**, to close the
issue.
This process can be seen clearly when visiting an issue. With every move
to another list, the label changes and a system note is recorded.
![issue board system notes](img/issue_board_system_notes.png)
![issue board system notes](img/issue_board_system_notes_v13_6.png)
### Drag issues between lists
......@@ -473,16 +463,17 @@ When dragging issues between lists, different behavior occurs depending on the s
| | To Open | To Closed | To label `B` list | To assignee `Bob` list |
|----------------------------|--------------------|--------------|------------------------------|---------------------------------------|
| From Open | - | Issue closed | `B` added | `Bob` assigned |
| From Closed | Issue reopened | - | Issue reopened<br/>`B` added | Issue reopened<br/>`Bob` assigned |
| From label `A` list | `A` removed | Issue closed | `A` removed<br/>`B` added | `Bob` assigned |
| From assignee `Alice` list | `Alice` unassigned | Issue closed | `B` added | `Alice` unassigned<br/>`Bob` assigned |
| **From Open** | - | Issue closed | `B` added | `Bob` assigned |
| **From Closed** | Issue reopened | - | Issue reopened<br/>`B` added | Issue reopened<br/>`Bob` assigned |
| **From label `A` list** | `A` removed | Issue closed | `A` removed<br/>`B` added | `Bob` assigned |
| **From assignee `Alice` list** | `Alice` unassigned | Issue closed | `B` added | `Alice` unassigned<br/>`Bob` assigned |
### Multi-select issue cards
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18954) in GitLab 12.4.
You can select multiple issue cards, then drag the group to another position within the list, or to another list. This makes it faster to reorder many issues at once.
You can select multiple issue cards, then drag the group to another position within the list, or to
another list. This makes it faster to reorder many issues at once.
To select and move multiple cards:
......
......@@ -64,8 +64,8 @@ The Advanced Search Syntax also supports the use of filters. The available filte
- extension: Filters by extension in the filename. Please write the extension without a leading dot. Exact match only.
- blob: Filters by Git `object ID`. Exact match only.
To use them, simply add them to your query in the format `<filter_name>:<value>` without
any spaces between the colon (`:`) and the value.
To use them, add them to your keyword in the format `<filter_name>:<value>` without
any spaces between the colon (`:`) and the value. A keyword or an asterisk (`*`) is required for filter searches and has to be added in front of the filter separated by a space.
Examples:
......
......@@ -17,68 +17,49 @@
- billable_users_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer nofollow">'.html_safe % { url: billable_users_url }
- link_end = '</a>'.html_safe
.license-panel.gl-mt-5
.gl-mb-5.info-well.dark-well
.gl-display-flex.gl-justify-content-space-between.gl-align-items-center.gl-p-5
%div
%h4.gl-mt-0
= _('License overview')
%p.gl-mb-0
= sprite_icon('license', css_class: 'gl-fill-gray-700')
%span.gl-ml-3
= _('Plan:')
%strong= @license.plan.capitalize
%span.gl-ml-5
= render 'admin/licenses/license_status'
%span.gl-ml-5
= _('Licensed to:')
%strong= @license.licensee['Name']
= "(#{@license.licensee['Email']})"
%div
= link_to 'View details', admin_license_path, class: "gl-button btn btn-secondary"
.d-flex.gl-mb-5
.col-sm-6.d-flex.pl-0
.info-well.dark-well.gl-mb-0
.well-segment.well-centered
%h3.center
= _('Users in License:')
= licensed_users
%hr
- if @license.will_expire?
= _('Your license is valid from')
%strong<>
= _(' %{start} to %{end}') % { start: @license.starts_at, end: @license.expires_at }
\.
= _('The %{link_start}true-up model%{link_end} allows having more users, and additional users will incur a retroactive charge on renewal.').html_safe % { link_start: true_up_link_start, link_end: link_end }
= seats_calculation_message(@license)
.col-sm-6.d-flex.pr-0
.info-well.dark-well.gl-mb-0
.well-segment.well-centered
%h3.center
= _('Billable Users:')
= number_with_delimiter current_active_user_count
%hr
%p
= _('This is the number of %{billable_users_link_start}billable users%{link_end} on your installation, and this is the minimum number you need to purchase when you renew your license.').html_safe % { billable_users_link_start: billable_users_link_start, link_end: link_end }
.d-flex.gl-pb-5
.col-sm-6.d-flex.pl-0
.info-well.dark-well.flex-fill.gl-mb-0
.well-segment.well-centered
%h3.center
= _('Maximum Users:')
= number_with_delimiter max_user_count
%hr
= _('This is the highest peak of users on your installation since the license started.')
.col-sm-6.d-flex.pr-0
.info-well.dark-well.gl-mb-0
.well-segment.well-centered
%h3.center
= _('Users over License:')
= number_with_delimiter users_over_license
%hr
- if license_is_over_capacity?
.gl-alert.gl-alert-info.gl-mb-3{ role: 'alert' }
= sprite_icon('information-o', css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
.gl-alert-body
= s_('Your instance has exceeded your subscription\'s licensed user count.')
= _('You\'ll be charged for %{true_up_link_start}users over license%{link_end} on a quartely or annual basis, depending on the terms of your agreement.').html_safe % { true_up_link_start: true_up_link_start, link_end: link_end }
.d-flex.gl-mb-5
.col-sm-6.d-flex.pl-0
.info-well.dark-well.gl-mb-0
.well-segment.well-centered
%h3.center
= _('Users in License:')
= licensed_users
%hr
- if @license.will_expire?
= _('Your license is valid from')
%strong<>
= _(' %{start} to %{end}') % { start: @license.starts_at, end: @license.expires_at }
\.
= _('The %{link_start}true-up model%{link_end} allows having more users, and additional users will incur a retroactive charge on renewal.').html_safe % { link_start: true_up_link_start, link_end: link_end }
= seats_calculation_message(@license)
.col-sm-6.d-flex.pr-0
.info-well.dark-well.gl-mb-0
.well-segment.well-centered
%h3.center
= _('Billable Users:')
= number_with_delimiter current_active_user_count
%hr
%p
= _('This is the number of %{billable_users_link_start}billable users%{link_end} on your installation, and this is the minimum number you need to purchase when you renew your license.').html_safe % { billable_users_link_start: billable_users_link_start, link_end: link_end }
.d-flex.gl-pb-5
.col-sm-6.d-flex.pl-0
.info-well.dark-well.flex-fill.gl-mb-0
.well-segment.well-centered
%h3.center
= _('Maximum Users:')
= number_with_delimiter max_user_count
%hr
= _('This is the highest peak of users on your installation since the license started.')
.col-sm-6.d-flex.pr-0
.info-well.dark-well.gl-mb-0
.well-segment.well-centered
%h3.center
= _('Users over License:')
= number_with_delimiter users_over_license
%hr
- if license_is_over_capacity?
.gl-alert.gl-alert-info.gl-mb-3{ role: 'alert' }
= sprite_icon('information-o', css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
.gl-alert-body
= s_('Your instance has exceeded your subscription\'s licensed user count.')
= _('You\'ll be charged for %{true_up_link_start}users over license%{link_end} on a quartely or annual basis, depending on the terms of your agreement.').html_safe % { true_up_link_start: true_up_link_start, link_end: link_end }
.gl-mb-5.info-well.dark-well
.gl-display-flex.gl-justify-content-space-between.gl-align-items-center.gl-p-5
%div
%h4.gl-mt-0
= _('License overview')
%p.gl-mb-0
= sprite_icon('license', css_class: 'gl-fill-gray-700')
%span.gl-ml-3
= _('Plan:')
%strong= @license.plan.capitalize
%span.gl-ml-5
= render 'admin/licenses/license_status'
%span.gl-ml-5
= _('Licensed to:')
%strong= @license.licensee['Name']
= "(#{@license.licensee['Email']})"
%div
= link_to 'View details', admin_license_path, class: "gl-button btn btn-secondary"
......@@ -18,7 +18,8 @@
- if @license.present?
= render 'info'
= render 'breakdown'
.license-panel.gl-mt-5
= render 'breakdown'
- if @licenses.present?
= render 'license_history'
......@@ -3,7 +3,7 @@
- if message.present? && subscribable.present?
.container-fluid.container-limited.pt-3
.alert.alert-dismissible.gitlab-ee-license-banner.hidden.js-gitlab-ee-license-banner.pb-5.border-width-1px.border-style-solid.border-color-default.border-radius-default{ role: 'alert', data: { license_expiry: subscribable.expires_at } }
.gl-alert.alert-dismissible.gitlab-ee-license-banner.hidden.js-gitlab-ee-license-banner.pb-5.border-width-1px.border-style-solid.border-color-default.border-radius-default{ role: 'alert', data: { license_expiry: subscribable.expires_at } }
%button.close.p-2{ type: 'button', 'aria-label' => 'Dismiss banner', data: { dismiss: 'alert', track_event: 'click_button', track_label: 'dismiss_subscribable_banner' } }
%span{ 'aria-hidden' => 'true' }
= sprite_icon('merge-request-close-m', size: 24)
......
---
title: Remove admin/license page duplicate summary
merge_request: 46827
author:
type: changed
---
title: 'Doc: Introduce new gitlab-ctl promote-db command'
merge_request: 45941
author:
type: fixed
......@@ -15,6 +15,7 @@ RSpec.describe 'admin/licenses/show.html.haml' do
render
expect(rendered).to have_content('Buy License')
expect(rendered).not_to have_content('License overview')
end
end
......
......@@ -218,6 +218,11 @@ module QA
raise "Merge did not appear to be successful" unless merged?
end
def merge_immediately!
click_element(:merge_moment_dropdown)
click_element(:merge_immediately_option)
end
def merged?
has_element?(:merged_status_content, text: 'The changes were merged into', wait: 60)
end
......
# frozen_string_literal: true
require 'faker'
module QA
RSpec.describe 'Verify', :runner do
context 'When pipeline is blocked' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" }
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project-with-blocked-pipeline'
end
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]
end
end
let!(:ci_file) do
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.project = project
commit.commit_message = 'Add .gitlab-ci.yml'
commit.add_files(
[
file_path: '.gitlab-ci.yml',
content: <<~YAML
test_blocked_pipeline:
stage: build
tags: [#{executor}]
script: echo 'OK!'
manual_job:
stage: test
needs: [test_blocked_pipeline]
script: echo do not click me
when: manual
dummy_job:
stage: deploy
needs: [manual_job]
script: echo nothing
YAML
]
)
end
end
let(:merge_request) do
Resource::MergeRequest.fabricate_via_api! do |merge_request|
merge_request.project = project
merge_request.description = Faker::Lorem.sentence
merge_request.target_new_branch = false
merge_request.file_name = 'custom_file.txt'
merge_request.file_content = Faker::Lorem.sentence
end
end
before do
Flow::Login.sign_in
merge_request.visit!
end
after do
runner.remove_via_api!
end
it 'can still merge MR successfully', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/971' do
Page::MergeRequest::Show.perform do |show|
show.wait_until(reload: false) { show.has_pipeline_status?('running') }
show.merge_immediately!
expect(show).to be_merged
end
end
end
end
end
......@@ -5,9 +5,12 @@ Object {
"data": Array [
Object {
"_links": Object {
"closedIssuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.1&scope=all&state=closed",
"closedMergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=closed",
"editUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/edit",
"issuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.1&scope=all&state=opened",
"mergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=opened",
"mergedMergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=merged",
"openedIssuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.1&scope=all&state=opened",
"openedMergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=opened",
"self": "http://localhost/releases-namespace/releases-project/-/releases/v1.1",
"selfUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1",
},
......@@ -130,9 +133,12 @@ exports[`releases/util.js convertOneReleaseGraphQLResponse matches snapshot 1`]
Object {
"data": Object {
"_links": Object {
"closedIssuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.1&scope=all&state=closed",
"closedMergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=closed",
"editUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/edit",
"issuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.1&scope=all&state=opened",
"mergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=opened",
"mergedMergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=merged",
"openedIssuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.1&scope=all&state=opened",
"openedMergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=opened",
"self": "http://localhost/releases-namespace/releases-project/-/releases/v1.1",
"selfUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1",
},
......
......@@ -4,6 +4,6 @@ exports[`~/releases/components/issuable_stats.vue matches snapshot 1`] = `
"<div class=\\"gl-display-flex gl-flex-direction-column gl-flex-shrink-0 gl-mr-6 gl-mb-5\\"><span class=\\"gl-mb-2\\">
Items
<span class=\\"badge badge-muted badge-pill gl-badge sm\\"><!----> 10</span></span>
<div class=\\"gl-display-flex\\"><span data-testid=\\"open-stat\\" class=\\"gl-white-space-pre-wrap\\">Open: <a href=\\"path/to/open/items\\" class=\\"gl-link\\">1</a></span> <span class=\\"gl-mx-2\\">•</span> <span data-testid=\\"merged-stat\\" class=\\"gl-white-space-pre-wrap\\">Merged: <a href=\\"path/to/merged/items\\" class=\\"gl-link\\">7</a></span> <span class=\\"gl-mx-2\\">•</span> <span data-testid=\\"closed-stat\\" class=\\"gl-white-space-pre-wrap\\">Closed: <a href=\\"path/to/closed/items\\" class=\\"gl-link\\">2</a></span></div>
<div class=\\"gl-display-flex\\"><span data-testid=\\"open-stat\\" class=\\"gl-white-space-pre-wrap\\">Open: <a href=\\"path/to/opened/items\\" class=\\"gl-link\\">1</a></span> <span class=\\"gl-mx-2\\">•</span> <span data-testid=\\"merged-stat\\" class=\\"gl-white-space-pre-wrap\\">Merged: <a href=\\"path/to/merged/items\\" class=\\"gl-link\\">7</a></span> <span class=\\"gl-mx-2\\">•</span> <span data-testid=\\"closed-stat\\" class=\\"gl-white-space-pre-wrap\\">Closed: <a href=\\"path/to/closed/items\\" class=\\"gl-link\\">2</a></span></div>
</div>"
`;
......@@ -26,7 +26,7 @@ describe('~/releases/components/issuable_stats.vue', () => {
total: 10,
closed: 2,
merged: 7,
openPath: 'path/to/open/items',
openedPath: 'path/to/opened/items',
closedPath: 'path/to/closed/items',
mergedPath: 'path/to/merged/items',
};
......@@ -72,7 +72,7 @@ describe('~/releases/components/issuable_stats.vue', () => {
const link = findOpenStatLink();
expect(link.exists()).toBe(true);
expect(link.attributes('href')).toBe(defaultProps.openPath);
expect(link.attributes('href')).toBe(defaultProps.openedPath);
});
it('renders the "merged" stat as a link', () => {
......@@ -93,7 +93,7 @@ describe('~/releases/components/issuable_stats.vue', () => {
describe('when path parameters are not provided', () => {
beforeEach(() => {
createComponent({
openPath: undefined,
openedPath: undefined,
closedPath: undefined,
mergedPath: undefined,
});
......
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