Commit ec8c9bdf authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera Committed by Mark Florian

Add a new composer installation component

- component
- getters
- new constants
parent 8269fe74
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import { s__ } from '~/locale';
import CodeInstruction from './code_instruction.vue';
import { TrackingActions } from '../constants';
import { mapGetters, mapState } from 'vuex';
export default {
name: 'ComposerInstallation',
components: {
CodeInstruction,
GlLink,
GlSprintf,
},
computed: {
...mapState(['composerHelpPath']),
...mapGetters(['composerRegistryInclude', 'composerPackageInclude']),
},
i18n: {
registryInclude: s__('PackageRegistry|composer.json registry include'),
copyRegistryInclude: s__('PackageRegistry|Copy registry include'),
packageInclude: s__('PackageRegistry|composer.json require package include'),
copyPackageInclude: s__('PackageRegistry|Copy require package include'),
infoLine: s__(
'PackageRegistry|For more information on Composer packages in GitLab, %{linkStart}see the documentation.%{linkEnd}',
),
},
trackingActions: { ...TrackingActions },
};
</script>
<template>
<div>
<p class="gl-mt-3 gl-font-weight-bold" data-testid="registry-include-title">
{{ $options.i18n.registryInclude }}
</p>
<code-instruction
:instruction="composerRegistryInclude"
:copy-text="$options.i18n.copyRegistryInclude"
:tracking-action="$options.trackingActions.COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND"
/>
<p class="gl-mt-3 gl-font-weight-bold" data-testid="package-include-title">
{{ $options.i18n.packageInclude }}
</p>
<code-instruction
:instruction="composerPackageInclude"
:copy-text="$options.i18n.copyPackageInclude"
:tracking-action="$options.trackingActions.COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND"
/>
<span data-testid="help-text">
<gl-sprintf :message="$options.i18n.infoLine">
<template #link="{ content }">
<gl-link :href="composerHelpPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</span>
</div>
</template>
......@@ -4,6 +4,7 @@ import MavenInstallation from './maven_installation.vue';
import NpmInstallation from './npm_installation.vue';
import NugetInstallation from './nuget_installation.vue';
import PypiInstallation from './pypi_installation.vue';
import ComposerInstallation from './composer_installation.vue';
import { PackageType } from '../../shared/constants';
export default {
......@@ -14,6 +15,7 @@ export default {
[PackageType.NPM]: NpmInstallation,
[PackageType.NUGET]: NugetInstallation,
[PackageType.PYPI]: PypiInstallation,
[PackageType.COMPOSER]: ComposerInstallation,
},
props: {
packageEntity: {
......
......@@ -7,6 +7,7 @@ export const TrackingLabels = {
NPM_INSTALLATION: 'npm_installation',
NUGET_INSTALLATION: 'nuget_installation',
PYPI_INSTALLATION: 'pypi_installation',
COMPOSER_INSTALLATION: 'composer_installation',
};
export const TrackingActions = {
......@@ -31,6 +32,9 @@ export const TrackingActions = {
COPY_PIP_INSTALL_COMMAND: 'copy_pip_install_command',
COPY_PYPI_SETUP_COMMAND: 'copy_pypi_setup_command',
COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND: 'copy_composer_registry_include_command',
COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND: 'copy_composer_package_include_command',
};
export const NpmManager = {
......
......@@ -104,3 +104,12 @@ export const pypiSetupCommand = ({ pypiSetupPath }) => `[gitlab]
repository = ${pypiSetupPath}
username = __token__
password = <your personal access token>`;
export const composerRegistryInclude = ({ composerPath }) => {
const base = { type: 'composer', url: composerPath };
return JSON.stringify(base);
};
export const composerPackageInclude = ({ packageEntity }) => {
const base = { package_name: packageEntity.name };
return JSON.stringify(base);
};
......@@ -30,6 +30,10 @@ module PackagesHelper
full_url.sub!('://', '://__token__:<your_personal_token>@')
end
def composer_registry_url(group_id)
expose_url(api_v4_group___packages_composer_packages_path(id: group_id, format: '.json'))
end
def packages_coming_soon_enabled?(resource)
::Feature.enabled?(:packages_coming_soon, resource) && ::Gitlab.dev_env_or_com?
end
......
......@@ -20,4 +20,6 @@
pypi_path: pypi_registry_url(@project.id),
pypi_setup_path: package_registry_project_url(@project.id, :pypi),
pypi_help_path: help_page_path('user/packages/pypi_repository/index'),
composer_path: composer_registry_url(@project&.group&.id),
composer_help_path: help_page_path('user/packages/composer_repository/index'),
project_name: @project.name} }
---
title: Add installation instructions for Composer
merge_request: 38779
author:
type: changed
......@@ -17122,6 +17122,12 @@ msgstr ""
msgid "PackageRegistry|Copy npm setup command"
msgstr ""
msgid "PackageRegistry|Copy registry include"
msgstr ""
msgid "PackageRegistry|Copy require package include"
msgstr ""
msgid "PackageRegistry|Copy yarn command"
msgstr ""
......@@ -17137,6 +17143,9 @@ msgstr ""
msgid "PackageRegistry|Filter by name"
msgstr ""
msgid "PackageRegistry|For more information on Composer packages in GitLab, %{linkStart}see the documentation.%{linkEnd}"
msgstr ""
msgid "PackageRegistry|For more information on the Conan registry, %{linkStart}see the documentation%{linkEnd}."
msgstr ""
......@@ -17257,6 +17266,12 @@ msgstr ""
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|composer.json registry include"
msgstr ""
msgid "PackageRegistry|composer.json require package include"
msgstr ""
msgid "PackageRegistry|npm"
msgstr ""
......
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlSprintf, GlLink } from '@gitlab/ui';
import ComposerInstallation from '~/packages/details/components/composer_installation.vue';
import CodeInstructions from '~/packages/details/components/code_instruction.vue';
import { TrackingActions } from '~/packages/details/constants';
import { registryUrl as composerHelpPath } from 'jest/packages/details/mock_data';
import { composerPackage as packageEntity } from 'jest/packages/mock_data';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('ComposerInstallation', () => {
let wrapper;
const composerRegistryIncludeStr = 'foo/registry';
const composerPackageIncludeStr = 'foo/package';
const store = new Vuex.Store({
state: {
packageEntity,
composerHelpPath,
},
getters: {
composerRegistryInclude: () => composerRegistryIncludeStr,
composerPackageInclude: () => composerPackageIncludeStr,
},
});
const findCodeInstructions = () => wrapper.findAll(CodeInstructions);
const findRegistryIncludeTitle = () => wrapper.find('[data-testid="registry-include-title"]');
const findPackageIncludeTitle = () => wrapper.find('[data-testid="package-include-title"]');
const findHelpText = () => wrapper.find('[data-testid="help-text"]');
const findHelpLink = () => wrapper.find(GlLink);
function createComponent() {
wrapper = shallowMount(ComposerInstallation, {
localVue,
store,
stubs: {
GlSprintf,
},
});
}
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
describe('registry include command', () => {
it('uses code_instructions', () => {
const registryIncludeCommand = findCodeInstructions().at(0);
expect(registryIncludeCommand.exists()).toBe(true);
expect(registryIncludeCommand.props()).toMatchObject({
instruction: composerRegistryIncludeStr,
copyText: 'Copy registry include',
trackingAction: TrackingActions.COPY_COMPOSER_REGISTRY_INCLUDE_COMMAND,
});
});
it('has the correct title', () => {
expect(findRegistryIncludeTitle().text()).toBe('composer.json registry include');
});
});
describe('package include command', () => {
it('uses code_instructions', () => {
const registryIncludeCommand = findCodeInstructions().at(1);
expect(registryIncludeCommand.exists()).toBe(true);
expect(registryIncludeCommand.props()).toMatchObject({
instruction: composerPackageIncludeStr,
copyText: 'Copy require package include',
trackingAction: TrackingActions.COPY_COMPOSER_PACKAGE_INCLUDE_COMMAND,
});
});
it('has the correct title', () => {
expect(findPackageIncludeTitle().text()).toBe('composer.json require package include');
});
it('has the correct help text', () => {
expect(findHelpText().text()).toBe(
'For more information on Composer packages in GitLab, see the documentation.',
);
expect(findHelpLink().attributes()).toMatchObject({
href: composerHelpPath,
target: '_blank',
});
});
});
});
......@@ -6,8 +6,16 @@ import MavenInstallation from '~/packages/details/components/maven_installation.
import ConanInstallation from '~/packages/details/components/conan_installation.vue';
import NugetInstallation from '~/packages/details/components/nuget_installation.vue';
import PypiInstallation from '~/packages/details/components/pypi_installation.vue';
import ComposerInstallation from '~/packages/details/components/composer_installation.vue';
import { conanPackage, mavenPackage, npmPackage, nugetPackage, pypiPackage } from '../../mock_data';
import {
conanPackage,
mavenPackage,
npmPackage,
nugetPackage,
pypiPackage,
composerPackage,
} from '../../mock_data';
describe('InstallationCommands', () => {
let wrapper;
......@@ -23,6 +31,7 @@ describe('InstallationCommands', () => {
const conanInstallation = () => wrapper.find(ConanInstallation);
const nugetInstallation = () => wrapper.find(NugetInstallation);
const pypiInstallation = () => wrapper.find(PypiInstallation);
const composerInstallation = () => wrapper.find(ComposerInstallation);
afterEach(() => {
wrapper.destroy();
......@@ -30,12 +39,13 @@ describe('InstallationCommands', () => {
describe('installation instructions', () => {
describe.each`
packageEntity | selector
${conanPackage} | ${conanInstallation}
${mavenPackage} | ${mavenInstallation}
${npmPackage} | ${npmInstallation}
${nugetPackage} | ${nugetInstallation}
${pypiPackage} | ${pypiInstallation}
packageEntity | selector
${conanPackage} | ${conanInstallation}
${mavenPackage} | ${mavenInstallation}
${npmPackage} | ${npmInstallation}
${nugetPackage} | ${nugetInstallation}
${pypiPackage} | ${pypiInstallation}
${composerPackage} | ${composerInstallation}
`('renders', ({ packageEntity, selector }) => {
it(`${packageEntity.package_type} instructions exist`, () => {
createComponent({ packageEntity });
......
......@@ -44,6 +44,14 @@ RSpec.describe PackagesHelper do
end
end
describe 'composer_registry_url' do
it 'return the composer registry url' do
url = helper.composer_registry_url(1)
expect(url).to eq("#{base_url}group/1/-/packages/composer/packages.json")
end
end
describe 'packages_coming_soon_enabled?' do
it 'returns false when the feature flag is disabled' do
stub_feature_flags(packages_coming_soon: false)
......
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