Commit 1c68c271 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera

Merge branch '334107-npm-registry-setup-step' into 'master'

Enabling switching between project-level and instance-level endpoints when viewing the NPM package registry setup step

See merge request gitlab-org/gitlab!65101
parents de4610f8 12269478
<script> <script>
import { GlLink, GlSprintf } from '@gitlab/ui'; import { GlLink, GlSprintf, GlFormRadioGroup } from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue'; import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue';
...@@ -11,6 +11,8 @@ import { ...@@ -11,6 +11,8 @@ import {
TRACKING_LABEL_CODE_INSTRUCTION, TRACKING_LABEL_CODE_INSTRUCTION,
NPM_PACKAGE_MANAGER, NPM_PACKAGE_MANAGER,
YARN_PACKAGE_MANAGER, YARN_PACKAGE_MANAGER,
PROJECT_PACKAGE_ENDPOINT_TYPE,
INSTANCE_PACKAGE_ENDPOINT_TYPE,
} from '~/packages_and_registries/package_registry/constants'; } from '~/packages_and_registries/package_registry/constants';
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
...@@ -21,8 +23,9 @@ export default { ...@@ -21,8 +23,9 @@ export default {
CodeInstruction, CodeInstruction,
GlLink, GlLink,
GlSprintf, GlSprintf,
GlFormRadioGroup,
}, },
inject: ['npmHelpPath', 'npmPath'], inject: ['npmHelpPath', 'npmPath', 'npmProjectPath'],
props: { props: {
packageEntity: { packageEntity: {
type: Object, type: Object,
...@@ -32,6 +35,7 @@ export default { ...@@ -32,6 +35,7 @@ export default {
data() { data() {
return { return {
instructionType: NPM_PACKAGE_MANAGER, instructionType: NPM_PACKAGE_MANAGER,
packageEndpointType: INSTANCE_PACKAGE_ENDPOINT_TYPE,
}; };
}, },
computed: { computed: {
...@@ -39,13 +43,13 @@ export default { ...@@ -39,13 +43,13 @@ export default {
return this.npmInstallationCommand(NPM_PACKAGE_MANAGER); return this.npmInstallationCommand(NPM_PACKAGE_MANAGER);
}, },
npmSetup() { npmSetup() {
return this.npmSetupCommand(NPM_PACKAGE_MANAGER); return this.npmSetupCommand(NPM_PACKAGE_MANAGER, this.packageEndpointType);
}, },
yarnCommand() { yarnCommand() {
return this.npmInstallationCommand(YARN_PACKAGE_MANAGER); return this.npmInstallationCommand(YARN_PACKAGE_MANAGER);
}, },
yarnSetupCommand() { yarnSetupCommand() {
return this.npmSetupCommand(YARN_PACKAGE_MANAGER); return this.npmSetupCommand(YARN_PACKAGE_MANAGER, this.packageEndpointType);
}, },
showNpm() { showNpm() {
return this.instructionType === NPM_PACKAGE_MANAGER; return this.instructionType === NPM_PACKAGE_MANAGER;
...@@ -58,14 +62,16 @@ export default { ...@@ -58,14 +62,16 @@ export default {
return `${instruction} ${this.packageEntity.name}`; return `${instruction} ${this.packageEntity.name}`;
}, },
npmSetupCommand(type) { npmSetupCommand(type, endpointType) {
const scope = this.packageEntity.name.substring(0, this.packageEntity.name.indexOf('/')); const scope = this.packageEntity.name.substring(0, this.packageEntity.name.indexOf('/'));
const npmPathForEndpoint =
endpointType === INSTANCE_PACKAGE_ENDPOINT_TYPE ? this.npmPath : this.npmProjectPath;
if (type === NPM_PACKAGE_MANAGER) { if (type === NPM_PACKAGE_MANAGER) {
return `echo ${scope}:registry=${this.npmPath}/ >> .npmrc`; return `echo ${scope}:registry=${npmPathForEndpoint}/ >> .npmrc`;
} }
return `echo \\"${scope}:registry\\" \\"${this.npmPath}/\\" >> .yarnrc`; return `echo \\"${scope}:registry\\" \\"${npmPathForEndpoint}/\\" >> .yarnrc`;
}, },
}, },
packageManagers: { packageManagers: {
...@@ -87,6 +93,10 @@ export default { ...@@ -87,6 +93,10 @@ export default {
{ value: NPM_PACKAGE_MANAGER, label: s__('PackageRegistry|Show NPM commands') }, { value: NPM_PACKAGE_MANAGER, label: s__('PackageRegistry|Show NPM commands') },
{ value: YARN_PACKAGE_MANAGER, label: s__('PackageRegistry|Show Yarn commands') }, { value: YARN_PACKAGE_MANAGER, label: s__('PackageRegistry|Show Yarn commands') },
], ],
packageEndpointTypeOptions: [
{ value: INSTANCE_PACKAGE_ENDPOINT_TYPE, text: s__('PackageRegistry|Instance-level') },
{ value: PROJECT_PACKAGE_ENDPOINT_TYPE, text: s__('PackageRegistry|Project-level') },
],
}; };
</script> </script>
...@@ -116,6 +126,12 @@ export default { ...@@ -116,6 +126,12 @@ export default {
<h3 class="gl-font-lg">{{ __('Registry setup') }}</h3> <h3 class="gl-font-lg">{{ __('Registry setup') }}</h3>
<gl-form-radio-group
:options="$options.packageEndpointTypeOptions"
:checked="packageEndpointType"
@change="packageEndpointType = $event"
/>
<code-instruction <code-instruction
v-if="showNpm" v-if="showNpm"
:instruction="npmSetup" :instruction="npmSetup"
......
...@@ -86,3 +86,6 @@ export const PACKAGE_PROCESSING_STATUS = 'PROCESSING'; ...@@ -86,3 +86,6 @@ export const PACKAGE_PROCESSING_STATUS = 'PROCESSING';
export const NPM_PACKAGE_MANAGER = 'npm'; export const NPM_PACKAGE_MANAGER = 'npm';
export const YARN_PACKAGE_MANAGER = 'yarn'; export const YARN_PACKAGE_MANAGER = 'yarn';
export const PROJECT_PACKAGE_ENDPOINT_TYPE = 'project';
export const INSTANCE_PACKAGE_ENDPOINT_TYPE = 'instance';
...@@ -70,6 +70,7 @@ module PackagesHelper ...@@ -70,6 +70,7 @@ module PackagesHelper
can_delete: can?(current_user, :destroy_package, project).to_s, can_delete: can?(current_user, :destroy_package, project).to_s,
svg_path: image_path('illustrations/no-packages.svg'), svg_path: image_path('illustrations/no-packages.svg'),
npm_path: package_registry_instance_url(:npm), npm_path: package_registry_instance_url(:npm),
npm_project_path: package_registry_project_url(project.id, :npm),
npm_help_path: help_page_path('user/packages/npm_registry/index'), npm_help_path: help_page_path('user/packages/npm_registry/index'),
maven_path: package_registry_project_url(project.id, :maven), maven_path: package_registry_project_url(project.id, :maven),
maven_help_path: help_page_path('user/packages/maven_repository/index'), maven_help_path: help_page_path('user/packages/maven_repository/index'),
......
...@@ -370,13 +370,26 @@ in a JavaScript project. You can install a package from the scope of a project o ...@@ -370,13 +370,26 @@ in a JavaScript project. You can install a package from the scope of a project o
If multiple packages have the same name and version, when you install a package, the most recently-published package is retrieved. If multiple packages have the same name and version, when you install a package, the most recently-published package is retrieved.
1. Set the URL for scoped packages by running: 1. Set the URL for scoped packages.
For [instance-level endpoints](#use-the-gitlab-endpoint-for-npm-packages) run:
```shell ```shell
npm config set @foo:registry https://gitlab.example.com/api/v4/packages/npm/ npm config set @foo:registry https://gitlab.example.com/api/v4/packages/npm/
``` ```
Replace `@foo` with your scope. - Replace `@foo` with your scope.
- Replace `gitlab.example.com` with your domain name.
For [project-level endpoints](#use-the-gitlab-endpoint-for-npm-packages) run:
```shell
npm config set @foo:registry https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/
```
- Replace `@foo` with your scope.
- Replace `gitlab.example.com` with your domain name.
- Replace `<your_project_id>` with your project ID, found on the project's home page.
1. Ensure [authentication](#authenticate-to-the-package-registry) is configured. 1. Ensure [authentication](#authenticate-to-the-package-registry) is configured.
......
...@@ -24145,6 +24145,9 @@ msgstr "" ...@@ -24145,6 +24145,9 @@ msgstr ""
msgid "PackageRegistry|Install package version" msgid "PackageRegistry|Install package version"
msgstr "" msgstr ""
msgid "PackageRegistry|Instance-level"
msgstr ""
msgid "PackageRegistry|Invalid Package: failed metadata extraction" msgid "PackageRegistry|Invalid Package: failed metadata extraction"
msgstr "" msgstr ""
...@@ -24190,6 +24193,9 @@ msgstr "" ...@@ -24190,6 +24193,9 @@ msgstr ""
msgid "PackageRegistry|Pip Command" msgid "PackageRegistry|Pip Command"
msgstr "" msgstr ""
msgid "PackageRegistry|Project-level"
msgstr ""
msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}" msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
msgstr "" msgstr ""
......
...@@ -21,6 +21,15 @@ exports[`NpmInstallation renders all the messages 1`] = ` ...@@ -21,6 +21,15 @@ exports[`NpmInstallation renders all the messages 1`] = `
Registry setup Registry setup
</h3> </h3>
<gl-form-radio-group-stub
checked="instance"
disabledfield="disabled"
htmlfield="html"
options="[object Object],[object Object]"
textfield="text"
valuefield="value"
/>
<code-instruction-stub <code-instruction-stub
copytext="Copy npm setup command" copytext="Copy npm setup command"
instruction="echo @gitlab-org:registry=npmPath/ >> .npmrc" instruction="echo @gitlab-org:registry=npmPath/ >> .npmrc"
......
import { GlFormRadioGroup } from '@gitlab/ui';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
...@@ -12,6 +13,8 @@ import { ...@@ -12,6 +13,8 @@ import {
PACKAGE_TYPE_NPM, PACKAGE_TYPE_NPM,
NPM_PACKAGE_MANAGER, NPM_PACKAGE_MANAGER,
YARN_PACKAGE_MANAGER, YARN_PACKAGE_MANAGER,
PROJECT_PACKAGE_ENDPOINT_TYPE,
INSTANCE_PACKAGE_ENDPOINT_TYPE,
} from '~/packages_and_registries/package_registry/constants'; } from '~/packages_and_registries/package_registry/constants';
import CodeInstructions from '~/vue_shared/components/registry/code_instruction.vue'; import CodeInstructions from '~/vue_shared/components/registry/code_instruction.vue';
...@@ -25,12 +28,14 @@ describe('NpmInstallation', () => { ...@@ -25,12 +28,14 @@ describe('NpmInstallation', () => {
const findCodeInstructions = () => wrapper.findAllComponents(CodeInstructions); const findCodeInstructions = () => wrapper.findAllComponents(CodeInstructions);
const findInstallationTitle = () => wrapper.findComponent(InstallationTitle); const findInstallationTitle = () => wrapper.findComponent(InstallationTitle);
const findEndPointTypeSector = () => wrapper.findComponent(GlFormRadioGroup);
function createComponent({ data = {} } = {}) { function createComponent({ data = {} } = {}) {
wrapper = shallowMountExtended(NpmInstallation, { wrapper = shallowMountExtended(NpmInstallation, {
provide: { provide: {
npmHelpPath: 'npmHelpPath', npmHelpPath: 'npmHelpPath',
npmPath: 'npmPath', npmPath: 'npmPath',
npmProjectPath: 'npmProjectPath',
}, },
propsData: { propsData: {
packageEntity, packageEntity,
...@@ -53,6 +58,19 @@ describe('NpmInstallation', () => { ...@@ -53,6 +58,19 @@ describe('NpmInstallation', () => {
expect(wrapper.element).toMatchSnapshot(); expect(wrapper.element).toMatchSnapshot();
}); });
describe('endpoint type selector', () => {
it('has the endpoint type selector', () => {
expect(findEndPointTypeSector().exists()).toBe(true);
expect(findEndPointTypeSector().vm.$attrs.checked).toBe(INSTANCE_PACKAGE_ENDPOINT_TYPE);
expect(findEndPointTypeSector().props()).toMatchObject({
options: [
{ value: INSTANCE_PACKAGE_ENDPOINT_TYPE, text: 'Instance-level' },
{ value: PROJECT_PACKAGE_ENDPOINT_TYPE, text: 'Project-level' },
],
});
});
});
describe('install command switch', () => { describe('install command switch', () => {
it('has the installation title component', () => { it('has the installation title component', () => {
expect(findInstallationTitle().exists()).toBe(true); expect(findInstallationTitle().exists()).toBe(true);
...@@ -96,6 +114,28 @@ describe('NpmInstallation', () => { ...@@ -96,6 +114,28 @@ describe('NpmInstallation', () => {
trackingAction: TRACKING_ACTION_COPY_NPM_SETUP_COMMAND, trackingAction: TRACKING_ACTION_COPY_NPM_SETUP_COMMAND,
}); });
}); });
it('renders the correct setup command for different endpoint types', async () => {
findEndPointTypeSector().vm.$emit('change', PROJECT_PACKAGE_ENDPOINT_TYPE);
await nextTick();
expect(findCodeInstructions().at(1).props()).toMatchObject({
instruction: `echo @gitlab-org:registry=npmProjectPath/ >> .npmrc`,
multiline: false,
trackingAction: TRACKING_ACTION_COPY_NPM_SETUP_COMMAND,
});
findEndPointTypeSector().vm.$emit('change', INSTANCE_PACKAGE_ENDPOINT_TYPE);
await nextTick();
expect(findCodeInstructions().at(1).props()).toMatchObject({
instruction: `echo @gitlab-org:registry=npmPath/ >> .npmrc`,
multiline: false,
trackingAction: TRACKING_ACTION_COPY_NPM_SETUP_COMMAND,
});
});
}); });
describe('yarn', () => { describe('yarn', () => {
...@@ -118,5 +158,27 @@ describe('NpmInstallation', () => { ...@@ -118,5 +158,27 @@ describe('NpmInstallation', () => {
trackingAction: TRACKING_ACTION_COPY_YARN_SETUP_COMMAND, trackingAction: TRACKING_ACTION_COPY_YARN_SETUP_COMMAND,
}); });
}); });
it('renders the correct setup command for different endpoint types', async () => {
findEndPointTypeSector().vm.$emit('change', PROJECT_PACKAGE_ENDPOINT_TYPE);
await nextTick();
expect(findCodeInstructions().at(1).props()).toMatchObject({
instruction: `echo \\"@gitlab-org:registry\\" \\"npmProjectPath/\\" >> .yarnrc`,
multiline: false,
trackingAction: TRACKING_ACTION_COPY_YARN_SETUP_COMMAND,
});
findEndPointTypeSector().vm.$emit('change', INSTANCE_PACKAGE_ENDPOINT_TYPE);
await nextTick();
expect(findCodeInstructions().at(1).props()).toMatchObject({
instruction: 'echo \\"@gitlab-org:registry\\" \\"npmPath/\\" >> .yarnrc',
multiline: false,
trackingAction: TRACKING_ACTION_COPY_YARN_SETUP_COMMAND,
});
});
}); });
}); });
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