Commit 39bad8e8 authored by Shinya Maeda's avatar Shinya Maeda

Merge branch '201730-refactor-npm-installation-instructions' into 'master'

Refactor npm installation instructions component

See merge request gitlab-org/gitlab!25237
parents 02cbbd21 76264b71
<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,58 +22,26 @@ 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`;
return this.npmSetupCommand(NpmManager.YARN);
},
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,
);
},
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 },
};
......@@ -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,
});
}
afterEach(() => {
if (wrapper) wrapper.destroy();
});
describe('registry url', () => {
it('creates the correct registry url', () => {
const testRegistryUrl = 'https://foo/baz/';
createComponent({
registryUrl: testRegistryUrl,
beforeEach(() => {
createComponent();
});
expect(wrapper.vm.packageRegistryUrl).toBe(testRegistryUrl);
afterEach(() => {
if (wrapper) wrapper.destroy();
});
it('creates the correct registry url when the url already contains package_name', () => {
createComponent({
registryUrl: 'https://package_name/package_name/',
describe('npm commands', () => {
it('renders the correct install command', () => {
expect(npmInstallationCommand().element.value).toBe(npmCommandStr);
});
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)
......
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