Commit 61524f77 authored by Nicolas Dular's avatar Nicolas Dular Committed by Brandon Labuschagne

Add HelloWorld CI Template

This adds a Hello-World CI template that can be used to quickly try out
CI/CD for a project. This CI template gets shown at the empty-pipeline
state experiment in a separate section.
parent 16e74e4e
<script> <script>
import { GlButton } from '@gitlab/ui'; import { GlButton, GlCard, GlSprintf } from '@gitlab/ui';
import { mergeUrlParams } from '~/lib/utils/url_utility'; import { mergeUrlParams } from '~/lib/utils/url_utility';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import { SUGGESTED_CI_TEMPLATES } from '../../constants'; import { SUGGESTED_CI_TEMPLATES, HELLO_WORLD_TEMPLATE_KEY } from '../../constants';
export default { export default {
components: { components: {
GlButton, GlButton,
GlCard,
GlSprintf,
}, },
i18n: { i18n: {
title: s__('Pipelines|Try a sample CI/CD file'),
subtitle: s__(
'Pipelines|Use a sample file to implement GitLab CI/CD based on your project’s language/framework.',
),
cta: s__('Pipelines|Use template'), cta: s__('Pipelines|Use template'),
description: s__( testTemplates: {
'Pipelines|Continuous deployment template to test and deploy your %{name} project.', title: s__('Pipelines|Use a sample CI/CD template'),
), subtitle: s__(
errorMessage: s__('Pipelines|An error occurred. Please try again.'), 'Pipelines|Use a sample %{codeStart}.gitlab-ci.yml%{codeEnd} template file to explore how CI/CD works.',
),
helloWorld: {
title: s__('Pipelines|“Hello world” with GitLab CI/CD'),
description: s__(
'Pipelines|Get familiar with GitLab CI/CD syntax by starting with a simple pipeline that runs a “Hello world” script.',
),
},
},
templates: {
title: s__('Pipelines|Use a CI/CD template'),
subtitle: s__(
"Pipelines|Use a template based on your project's language or framework to get started with GitLab CI/CD.",
),
description: s__('Pipelines|CI/CD template to test and deploy your %{name} project.'),
},
}, },
inject: ['addCiYmlPath'], inject: ['addCiYmlPath'],
data() { data() {
...@@ -26,25 +39,63 @@ export default { ...@@ -26,25 +39,63 @@ export default {
name: key, name: key,
logoPath: SUGGESTED_CI_TEMPLATES[key].logoPath, logoPath: SUGGESTED_CI_TEMPLATES[key].logoPath,
link: mergeUrlParams({ template: key }, this.addCiYmlPath), link: mergeUrlParams({ template: key }, this.addCiYmlPath),
description: sprintf(this.$options.i18n.description, { name: key }), description: sprintf(this.$options.i18n.templates.description, { name: key }),
}; };
}); });
return { return {
templates, templates,
helloWorldTemplateUrl: mergeUrlParams(
{ template: HELLO_WORLD_TEMPLATE_KEY },
this.addCiYmlPath,
),
}; };
}, },
}; };
</script> </script>
<template> <template>
<div> <div>
<h2>{{ $options.i18n.title }}</h2> <h2 class="gl-font-size-h2 gl-text-gray-900">{{ $options.i18n.testTemplates.title }}</h2>
<p>{{ $options.i18n.subtitle }}</p> <p class="gl-text-gray-800 gl-mb-6">
<gl-sprintf :message="$options.i18n.testTemplates.subtitle">
<template #code="{ content }">
<code>{{ content }}</code>
</template>
</gl-sprintf>
</p>
<div class="row gl-mb-8">
<div class="col-lg-3">
<gl-card>
<div class="gl-flex-direction-row">
<div class="gl-py-5"><gl-emoji class="gl-font-size-h2-xl" data-name="wave" /></div>
<div class="gl-mb-3">
<strong class="gl-text-gray-800 gl-mb-2">{{
$options.i18n.testTemplates.helloWorld.title
}}</strong>
</div>
<p class="gl-font-sm">{{ $options.i18n.testTemplates.helloWorld.description }}</p>
</div>
<gl-button
category="primary"
variant="confirm"
:href="helloWorldTemplateUrl"
data-testid="test-template-link"
>
{{ $options.i18n.cta }}
</gl-button>
</gl-card>
</div>
</div>
<h2 class="gl-font-size-h2 gl-text-gray-900">{{ $options.i18n.templates.title }}</h2>
<p class="gl-text-gray-800 gl-mb-6">{{ $options.i18n.templates.subtitle }}</p>
<ul class="gl-list-style-none gl-pl-0"> <ul class="gl-list-style-none gl-pl-0">
<li v-for="template in templates" :key="template.key"> <li v-for="template in templates" :key="template.name">
<div <div
class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-border-b-solid gl-border-b-1 gl-border-b-gray-100 gl-pb-5 gl-pt-5" class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-border-b-solid gl-border-b-1 gl-border-b-gray-100 gl-pb-3 gl-pt-3"
> >
<div class="gl-display-flex gl-flex-direction-row gl-align-items-center"> <div class="gl-display-flex gl-flex-direction-row gl-align-items-center">
<img <img
...@@ -55,8 +106,14 @@ export default { ...@@ -55,8 +106,14 @@ export default {
data-testid="template-logo" data-testid="template-logo"
/> />
<div class="gl-flex-direction-row"> <div class="gl-flex-direction-row">
<strong class="gl-text-gray-800">{{ template.name }}</strong> <div class="gl-mb-3">
<p class="gl-mb-0" data-testid="template-description">{{ template.description }}</p> <strong class="gl-text-gray-800" data-testid="template-name">{{
template.name
}}</strong>
</div>
<p class="gl-mb-0 gl-font-sm" data-testid="template-description">
{{ template.description }}
</p>
</div> </div>
</div> </div>
<gl-button <gl-button
...@@ -64,8 +121,9 @@ export default { ...@@ -64,8 +121,9 @@ export default {
variant="confirm" variant="confirm"
:href="template.link" :href="template.link"
data-testid="template-link" data-testid="template-link"
>{{ $options.i18n.cta }}</gl-button
> >
{{ $options.i18n.cta }}
</gl-button>
</div> </div>
</li> </li>
</ul> </ul>
......
...@@ -36,7 +36,8 @@ export const UNSUPPORTED_DATA = 'unsupported_data'; ...@@ -36,7 +36,8 @@ export const UNSUPPORTED_DATA = 'unsupported_data';
export const CHILD_VIEW = 'child'; export const CHILD_VIEW = 'child';
// The keys of the Object are the same as the `key` value in the template list we get from the API. // The keys of the templates are the same as their filenames
export const HELLO_WORLD_TEMPLATE_KEY = 'Hello-World';
export const SUGGESTED_CI_TEMPLATES = { export const SUGGESTED_CI_TEMPLATES = {
Android: { logoPath: '/assets/illustrations/logos/android.svg' }, Android: { logoPath: '/assets/illustrations/logos/android.svg' },
Bash: { logoPath: '/assets/illustrations/logos/bash.svg' }, Bash: { logoPath: '/assets/illustrations/logos/bash.svg' },
......
---
title: Add Hello World CI Template
merge_request: 58649
author:
type: added
# This file is a template demonstrating the `script` keyword.
# Learn more about this keyword here: https://docs.gitlab.com/ee/ci/yaml/README.html#script
# After committing this template, visit CI/CD > Jobs to see the script output.
job:
script:
# provide a shell script as argument for this keyword.
- echo "Hello World"
...@@ -22908,9 +22908,6 @@ msgstr "" ...@@ -22908,9 +22908,6 @@ msgstr ""
msgid "Pipelines|API" msgid "Pipelines|API"
msgstr "" msgstr ""
msgid "Pipelines|An error occurred. Please try again."
msgstr ""
msgid "Pipelines|Are you sure you want to run this pipeline?" msgid "Pipelines|Are you sure you want to run this pipeline?"
msgstr "" msgstr ""
...@@ -22923,13 +22920,13 @@ msgstr "" ...@@ -22923,13 +22920,13 @@ msgstr ""
msgid "Pipelines|CI lint" msgid "Pipelines|CI lint"
msgstr "" msgstr ""
msgid "Pipelines|Child pipeline" msgid "Pipelines|CI/CD template to test and deploy your %{name} project."
msgstr "" msgstr ""
msgid "Pipelines|Clear runner caches" msgid "Pipelines|Child pipeline"
msgstr "" msgstr ""
msgid "Pipelines|Continuous deployment template to test and deploy your %{name} project." msgid "Pipelines|Clear runner caches"
msgstr "" msgstr ""
msgid "Pipelines|Copy trigger token" msgid "Pipelines|Copy trigger token"
...@@ -22947,6 +22944,9 @@ msgstr "" ...@@ -22947,6 +22944,9 @@ msgstr ""
msgid "Pipelines|Editor" msgid "Pipelines|Editor"
msgstr "" msgstr ""
msgid "Pipelines|Get familiar with GitLab CI/CD syntax by starting with a simple pipeline that runs a “Hello world” script."
msgstr ""
msgid "Pipelines|Get started with CI/CD" msgid "Pipelines|Get started with CI/CD"
msgstr "" msgstr ""
...@@ -23043,10 +23043,16 @@ msgstr "" ...@@ -23043,10 +23043,16 @@ msgstr ""
msgid "Pipelines|Trigger user has insufficient permissions to project" msgid "Pipelines|Trigger user has insufficient permissions to project"
msgstr "" msgstr ""
msgid "Pipelines|Try a sample CI/CD file" msgid "Pipelines|Use a CI/CD template"
msgstr ""
msgid "Pipelines|Use a sample %{codeStart}.gitlab-ci.yml%{codeEnd} template file to explore how CI/CD works."
msgstr "" msgstr ""
msgid "Pipelines|Use a sample file to implement GitLab CI/CD based on your project’s language/framework." msgid "Pipelines|Use a sample CI/CD template"
msgstr ""
msgid "Pipelines|Use a template based on your project's language or framework to get started with GitLab CI/CD."
msgstr "" msgstr ""
msgid "Pipelines|Use template" msgid "Pipelines|Use template"
...@@ -23070,6 +23076,9 @@ msgstr "" ...@@ -23070,6 +23076,9 @@ msgstr ""
msgid "Pipelines|parent" msgid "Pipelines|parent"
msgstr "" msgstr ""
msgid "Pipelines|“Hello world” with GitLab CI/CD"
msgstr ""
msgid "Pipeline|Actions" msgid "Pipeline|Actions"
msgstr "" msgstr ""
......
...@@ -7,16 +7,23 @@ const addCiYmlPath = "/-/new/master?commit_message='Add%20.gitlab-ci.yml'"; ...@@ -7,16 +7,23 @@ const addCiYmlPath = "/-/new/master?commit_message='Add%20.gitlab-ci.yml'";
describe('Pipelines CI Templates', () => { describe('Pipelines CI Templates', () => {
let wrapper; let wrapper;
const GlEmoji = { template: '<img/>' };
const createWrapper = () => { const createWrapper = () => {
return shallowMount(PipelinesCiTemplate, { return shallowMount(PipelinesCiTemplate, {
provide: { provide: {
addCiYmlPath, addCiYmlPath,
}, },
stubs: {
GlEmoji,
},
}); });
}; };
const findTestTemplateLinks = () => wrapper.findAll('[data-testid="test-template-link"]');
const findTemplateDescriptions = () => wrapper.findAll('[data-testid="template-description"]'); const findTemplateDescriptions = () => wrapper.findAll('[data-testid="template-description"]');
const findTemplateLinks = () => wrapper.findAll('[data-testid="template-link"]'); const findTemplateLinks = () => wrapper.findAll('[data-testid="template-link"]');
const findTemplateNames = () => wrapper.findAll('[data-testid="template-name"]');
const findTemplateLogos = () => wrapper.findAll('[data-testid="template-logo"]'); const findTemplateLogos = () => wrapper.findAll('[data-testid="template-logo"]');
afterEach(() => { afterEach(() => {
...@@ -24,7 +31,19 @@ describe('Pipelines CI Templates', () => { ...@@ -24,7 +31,19 @@ describe('Pipelines CI Templates', () => {
wrapper = null; wrapper = null;
}); });
describe('renders templates', () => { describe('renders test template', () => {
beforeEach(() => {
wrapper = createWrapper();
});
it('links to the hello world template', () => {
expect(findTestTemplateLinks().at(0).attributes('href')).toBe(
addCiYmlPath.concat('&template=Hello-World'),
);
});
});
describe('renders template list', () => {
beforeEach(() => { beforeEach(() => {
wrapper = createWrapper(); wrapper = createWrapper();
}); });
...@@ -37,20 +56,24 @@ describe('Pipelines CI Templates', () => { ...@@ -37,20 +56,24 @@ describe('Pipelines CI Templates', () => {
expect(content).toContain(...keys); expect(content).toContain(...keys);
}); });
it('has the correct template name', () => {
expect(findTemplateNames().at(0).text()).toBe('Android');
});
it('links to the correct template', () => { it('links to the correct template', () => {
expect(findTemplateLinks().at(0).attributes('href')).toEqual( expect(findTemplateLinks().at(0).attributes('href')).toBe(
addCiYmlPath.concat('&template=Android'), addCiYmlPath.concat('&template=Android'),
); );
}); });
it('has the description of the template', () => { it('has the description of the template', () => {
expect(findTemplateDescriptions().at(0).text()).toEqual( expect(findTemplateDescriptions().at(0).text()).toBe(
'Continuous deployment template to test and deploy your Android project.', 'CI/CD template to test and deploy your Android project.',
); );
}); });
it('has the right logo of the template', () => { it('has the right logo of the template', () => {
expect(findTemplateLogos().at(0).attributes('src')).toEqual( expect(findTemplateLogos().at(0).attributes('src')).toBe(
'/assets/illustrations/logos/android.svg', '/assets/illustrations/logos/android.svg',
); );
}); });
......
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