Commit 76264b71 authored by Nick Kipling's avatar Nick Kipling Committed by Shinya Maeda

Refactor npm instructions

Changed backend url generation
Updated instructions component
Created getters for npm commands
Updated tests
parent 9afd7128
<script>
import { GlTab, GlTabs } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import { GlLink, GlSprintf, GlTab, GlTabs } from '@gitlab/ui';
import { s__ } from '~/locale';
import CodeInstruction from './code_instruction.vue';
import Tracking from '~/tracking';
import { TrackingActions, TrackingLabels } from '../constants';
import { NpmManager, TrackingActions, TrackingLabels } from '../constants';
import { trackInstallationTabChange } from '../utils';
import { mapGetters, mapState } from 'vuex';
export default {
name: 'NpmInstallation',
components: {
CodeInstruction,
GlLink,
GlSprintf,
GlTab,
GlTabs,
},
......@@ -19,59 +22,27 @@ export default {
}),
trackInstallationTabChange,
],
props: {
name: {
type: String,
required: true,
},
registryUrl: {
type: String,
required: true,
},
helpUrl: {
type: String,
required: true,
},
},
computed: {
packageRegistryUrl() {
if (this.registryUrl.indexOf('package_name') > -1) {
return this.registryUrl.substring(0, this.registryUrl.lastIndexOf('package_name'));
}
return this.registryUrl;
},
npmScope() {
return this.name.substring(0, this.name.indexOf('/'));
},
...mapState(['npmHelpPath']),
...mapGetters(['npmInstallationCommand', 'npmSetupCommand']),
npmCommand() {
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
return `npm i ${this.name}`;
return this.npmInstallationCommand(NpmManager.NPM);
},
npmSetupCommand() {
return `echo ${this.npmScope}:registry=${this.packageRegistryUrl} >> .npmrc`;
npmSetup() {
return this.npmSetupCommand(NpmManager.NPM);
},
yarnCommand() {
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
return `yarn add ${this.name}`;
return this.npmInstallationCommand(NpmManager.YARN);
},
yarnSetupCommand() {
return `echo \\"${this.npmScope}:registry\\" \\"${this.packageRegistryUrl}\\" >> .yarnrc`;
},
helpText() {
return sprintf(
s__(
`PackageRegistry|You may also need to setup authentication using an auth token. %{linkStart}See
the documentation%{linkEnd} to find out more.`,
),
{
linkStart: `<a href="${this.helpUrl}" target="_blank">`,
linkEnd: '</a>',
},
false,
);
return this.npmSetupCommand(NpmManager.YARN);
},
},
i18n: {
helpText: s__(
'PackageRegistry|You may also need to setup authentication using an auth token. %{linkStart}See the documentation%{linkEnd} to find out more.',
),
},
trackingActions: { ...TrackingActions },
};
</script>
......@@ -102,7 +73,7 @@ export default {
<div class="prepend-left-default append-right-default">
<p class="prepend-top-8 font-weight-bold">{{ s__('PackageRegistry|npm') }}</p>
<code-instruction
:instruction="npmSetupCommand"
:instruction="npmSetup"
:copy-text="s__('PackageRegistry|Copy npm setup command')"
class="js-npm-setup"
:tracking-action="$options.trackingActions.COPY_NPM_SETUP_COMMAND"
......@@ -116,7 +87,11 @@ export default {
:tracking-action="$options.trackingActions.COPY_YARN_SETUP_COMMAND"
/>
<p v-html="helpText"></p>
<gl-sprintf :message="$options.i18n.helpText">
<template #link="{ content }">
<gl-link :href="npmHelpPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</div>
</gl-tab>
</gl-tabs>
......
......@@ -26,3 +26,8 @@ export const TrackingActions = {
COPY_NUGET_INSTALL_COMMAND: 'copy_nuget_install_command',
COPY_NUGET_SETUP_COMMAND: 'copy_nuget_setup_command',
};
export const NpmManager = {
NPM: 'npm',
YARN: 'yarn',
};
import { s__ } from '~/locale';
import { generateConanRecipe } from '../utils';
import { NpmManager } from '../constants';
export const packageHasPipeline = ({ packageEntity }) => {
if (packageEntity?.build_info?.pipeline_id) {
......@@ -79,6 +80,23 @@ export const mavenSetupXml = ({ mavenPath }) => `<repositories>
</snapshotRepository>
</distributionManagement>`;
export const npmInstallationCommand = ({ packageEntity }) => (type = NpmManager.NPM) => {
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
const instruction = type === NpmManager.NPM ? 'npm i' : 'yarn add';
return `${instruction} ${packageEntity.name}`;
};
export const npmSetupCommand = ({ packageEntity, npmPath }) => (type = NpmManager.NPM) => {
const scope = packageEntity.name.substring(0, packageEntity.name.indexOf('/'));
if (type === NpmManager.NPM) {
return `echo ${scope}:registry=${npmPath} >> .npmrc`;
}
return `echo \\"${scope}:registry\\" \\"${npmPath}\\" >> .yarnrc`;
};
export const nugetInstallationCommand = ({ packageEntity }) =>
`nuget install ${packageEntity.name} -Source "GitLab"`;
......
......@@ -10,18 +10,14 @@ module EE
::Feature.enabled?(:vue_package_list, subject)
end
def npm_package_registry_url
expose_url(api_v4_packages_npm_package_name_path)
end
def conan_package_registry_url
expose_url("api/#{::API::API.version}/packages/conan")
end
def nuget_package_registry_url(project_id)
expose_url(api_v4_projects_packages_nuget_index_path(id: project_id, format: '.json'))
end
def package_registry_instance_url(registry_type)
expose_url("api/#{::API::API.version}/packages/#{registry_type}")
end
def package_registry_project_url(project_id, registry_type = :maven)
project_api_path = expose_path(api_v4_projects_path(id: project_id))
package_registry_project_path = "#{project_api_path}/packages/#{registry_type}"
......
......@@ -10,11 +10,11 @@
can_delete: can?(current_user, :destroy_package, @project).to_s,
destroy_path: project_package_path(@project, @package),
svg_path: image_path('illustrations/no-packages.svg'),
npm_path: npm_package_registry_url,
npm_path: package_registry_instance_url(:npm),
npm_help_path: help_page_path('user/packages/npm_registry/index'),
maven_path: package_registry_project_url(@project.id, :maven),
maven_help_path: help_page_path('user/packages/maven_repository/index'),
conan_path: conan_package_registry_url,
conan_path: package_registry_instance_url(:conan),
conan_help_path: help_page_path('user/packages/conan_repository/index'),
nuget_path: nuget_package_registry_url(@project.id),
nuget_help_path: help_page_path('user/packages/nuget_repository/index'),
......
import { mount } from '@vue/test-utils';
import Vuex from 'vuex';
import { mount, createLocalVue } from '@vue/test-utils';
import NpmInstallation from 'ee/packages/details/components/npm_installation.vue';
import { TrackingActions, TrackingLabels } from 'ee/packages/details/constants';
import { npmPackage as packageEntity } from '../../mock_data';
import { registryUrl as nugetPath } from '../mock_data';
import Tracking from '~/tracking';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('NpmInstallation', () => {
let wrapper;
const packageScope = '@fake-scope';
const packageName = 'my-package';
const packageScopeName = `${packageScope}/${packageName}`;
const registryUrl = 'https://gitlab.com/api/v4/packages/npm/';
const defaultProps = {
name: packageScopeName,
registryUrl: `${registryUrl}package_name`,
helpUrl: 'foo',
};
const npmInstall = `npm i ${packageScopeName}`;
const npmSetup = `echo ${packageScope}:registry=${registryUrl} >> .npmrc`;
const yarnInstall = `yarn add ${packageScopeName}`;
const yarnSetup = `echo \\"${packageScope}:registry\\" \\"${registryUrl}\\" >> .yarnrc`;
const npmCommandStr = 'npm install';
const npmSetupStr = 'npm setup';
const yarnCommandStr = 'npm install';
const yarnSetupStr = 'npm setup';
const installationTab = () => wrapper.find('.js-installation-tab > a');
const setupTab = () => wrapper.find('.js-setup-tab > a');
const installCommand = type => wrapper.find(`.js-${type}-install > input`);
const setupCommand = type => wrapper.find(`.js-${type}-setup > input`);
function createComponent(props = {}) {
const propsData = {
...defaultProps,
...props,
};
const npmInstallationCommand = () => wrapper.find('.js-npm-install > input');
const npmSetupCommand = () => wrapper.find('.js-npm-setup > input');
const yarnInstallationCommand = () => wrapper.find('.js-yarn-install > input');
const yarnSetupCommand = () => wrapper.find('.js-yarn-setup > input');
function createComponent(yarn = false) {
const store = new Vuex.Store({
state: {
packageEntity,
nugetPath,
},
getters: {
npmInstallationCommand: () => () => (yarn ? yarnCommandStr : npmCommandStr),
npmSetupCommand: () => () => (yarn ? yarnSetupStr : npmSetupStr),
},
});
wrapper = mount(NpmInstallation, {
propsData,
localVue,
store,
});
}
beforeEach(() => {
createComponent();
});
afterEach(() => {
if (wrapper) wrapper.destroy();
});
describe('registry url', () => {
it('creates the correct registry url', () => {
const testRegistryUrl = 'https://foo/baz/';
createComponent({
registryUrl: testRegistryUrl,
});
expect(wrapper.vm.packageRegistryUrl).toBe(testRegistryUrl);
describe('npm commands', () => {
it('renders the correct install command', () => {
expect(npmInstallationCommand().element.value).toBe(npmCommandStr);
});
it('creates the correct registry url when the url already contains package_name', () => {
createComponent({
registryUrl: 'https://package_name/package_name/',
});
expect(wrapper.vm.packageRegistryUrl).toBe('https://package_name/');
it('renders the correct setup command', () => {
expect(npmSetupCommand().element.value).toBe(npmSetupStr);
});
});
describe('installation commands', () => {
describe('yarn commands', () => {
beforeEach(() => {
createComponent();
createComponent(true);
});
it('renders the correct npm commands', () => {
expect(installCommand('npm').element.value).toBe(npmInstall);
expect(setupCommand('npm').element.value).toBe(npmSetup);
it('renders the correct install command', () => {
expect(yarnInstallationCommand().element.value).toBe(yarnCommandStr);
});
it('renders the correct yarn commands', () => {
expect(installCommand('yarn').element.value).toBe(yarnInstall);
expect(setupCommand('yarn').element.value).toBe(yarnSetup);
it('renders the correct setup command', () => {
expect(yarnSetupCommand().element.value).toBe(yarnSetupStr);
});
});
......
......@@ -6,6 +6,8 @@ import {
mavenInstallationXml,
mavenInstallationCommand,
mavenSetupXml,
npmInstallationCommand,
npmSetupCommand,
nugetInstallationCommand,
nugetSetupCommand,
} from 'ee/packages/details/store/getters';
......@@ -23,6 +25,7 @@ import {
registryUrl,
} from '../mock_data';
import { generateConanRecipe } from 'ee/packages/details/utils';
import { NpmManager } from 'ee/packages/details/constants';
describe('Getters PackageDetails Store', () => {
let state;
......@@ -35,6 +38,7 @@ describe('Getters PackageDetails Store', () => {
pipelineError: mockPipelineError,
conanPath: registryUrl,
mavenPath: registryUrl,
npmPath: registryUrl,
nugetPath: registryUrl,
};
......@@ -53,6 +57,11 @@ describe('Getters PackageDetails Store', () => {
const mavenInstallationXmlBlock = generateXmlCodeBlock(packageWithoutBuildInfo.maven_metadatum);
const mavenSetupXmlBlock = generateMavenSetupXml();
const npmInstallStr = `npm i ${npmPackage.name}`;
const npmSetupStr = `echo @Test:registry=${registryUrl} >> .npmrc`;
const yarnInstallStr = `yarn add ${npmPackage.name}`;
const yarnSetupStr = `echo \\"@Test:registry\\" \\"${registryUrl}\\" >> .yarnrc`;
const nugetInstallationCommandStr = `nuget install ${nugetPackage.name} -Source "GitLab"`;
const nugetSetupCommandStr = `nuget source Add -Name "GitLab" -Source "${registryUrl}" -UserName <your_username> -Password <your_token>`;
......@@ -122,6 +131,32 @@ describe('Getters PackageDetails Store', () => {
});
});
describe('npm string getters', () => {
it('gets the correct npmInstallationCommand for NPM', () => {
setupState({ packageEntity: npmPackage });
expect(npmInstallationCommand(state)(NpmManager.NPM)).toEqual(npmInstallStr);
});
it('gets the correct npmSetupCommand for NPM', () => {
setupState({ packageEntity: npmPackage });
expect(npmSetupCommand(state)(NpmManager.NPM)).toEqual(npmSetupStr);
});
it('gets the correct npmInstallationCommand for Yarn', () => {
setupState({ packageEntity: npmPackage });
expect(npmInstallationCommand(state)(NpmManager.YARN)).toEqual(yarnInstallStr);
});
it('gets the correct npmSetupCommand for Yarn', () => {
setupState({ packageEntity: npmPackage });
expect(npmSetupCommand(state)(NpmManager.YARN)).toEqual(yarnSetupStr);
});
});
describe('nuget string getters', () => {
it('gets the correct nugetInstallationCommand', () => {
setupState({ packageEntity: nugetPackage });
......
......@@ -5,6 +5,20 @@ require 'spec_helper'
describe EE::PackagesHelper do
let(:base_url) { "#{Gitlab.config.gitlab.url}/api/v4/" }
describe 'package_registry_instance_url' do
it 'returns conant instance url when registry_type is conant' do
url = helper.package_registry_instance_url(:conan)
expect(url).to eq("#{base_url}packages/conan")
end
it 'returns npm instance url when registry_type is npm' do
url = helper.package_registry_instance_url(:npm)
expect(url).to eq("#{base_url}packages/npm")
end
end
describe 'package_registry_project_url' do
it 'returns maven registry url when registry_type is not provided' do
url = helper.package_registry_project_url(1)
......
......@@ -13474,7 +13474,7 @@ msgstr ""
msgid "PackageRegistry|You are about to delete version %{boldStart}%{version}%{boldEnd} of %{boldStart}%{name}%{boldEnd}. Are you sure?"
msgstr ""
msgid "PackageRegistry|You may also need to setup authentication using an auth token. %{linkStart}See the documentation%{linkEnd} to find out more."
msgid "PackageRegistry|You may also need to setup authentication using an auth token. %{linkStart}See the documentation%{linkEnd} to find out more."
msgstr ""
msgid "PackageRegistry|npm"
......
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