Commit 6145b059 authored by Thong Kuah's avatar Thong Kuah

Merge branch 'nicolasdular/refactor-in-product-marketing-emails' into 'master'

Refactor in-product-marketing messages

See merge request gitlab-org/gitlab!60832
parents 6bf98427 fe26fa9e
# frozen_string_literal: true # frozen_string_literal: true
class Groups::EmailCampaignsController < Groups::ApplicationController class Groups::EmailCampaignsController < Groups::ApplicationController
include InProductMarketingHelper
EMAIL_CAMPAIGNS_SCHEMA_URL = 'iglu:com.gitlab/email_campaigns/jsonschema/1-0-0' EMAIL_CAMPAIGNS_SCHEMA_URL = 'iglu:com.gitlab/email_campaigns/jsonschema/1-0-0'
feature_category :navigation feature_category :navigation
...@@ -18,11 +16,13 @@ class Groups::EmailCampaignsController < Groups::ApplicationController ...@@ -18,11 +16,13 @@ class Groups::EmailCampaignsController < Groups::ApplicationController
def track_click def track_click
if Gitlab.com? if Gitlab.com?
message = Gitlab::Email::Message::InProductMarketing.for(@track).new(group: group, series: @series)
data = { data = {
namespace_id: group.id, namespace_id: group.id,
track: @track.to_s, track: @track.to_s,
series: @series, series: @series,
subject_line: subject_line(@track, @series) subject_line: message.subject_line
} }
context = SnowplowTracker::SelfDescribingJson.new(EMAIL_CAMPAIGNS_SCHEMA_URL, data) context = SnowplowTracker::SelfDescribingJson.new(EMAIL_CAMPAIGNS_SCHEMA_URL, data)
......
This diff is collapsed.
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
module Emails module Emails
module InProductMarketing module InProductMarketing
include InProductMarketingHelper
FROM_ADDRESS = 'GitLab <team@gitlab.com>' FROM_ADDRESS = 'GitLab <team@gitlab.com>'
CUSTOM_HEADERS = { CUSTOM_HEADERS = {
from: FROM_ADDRESS, from: FROM_ADDRESS,
...@@ -15,13 +13,11 @@ module Emails ...@@ -15,13 +13,11 @@ module Emails
}.freeze }.freeze
def in_product_marketing_email(recipient_id, group_id, track, series) def in_product_marketing_email(recipient_id, group_id, track, series)
@track = track group = Group.find(group_id)
@series = series email = User.find(recipient_id).notification_email_for(group)
@group = Group.find(group_id) @message = Gitlab::Email::Message::InProductMarketing.for(track).new(group: group, series: series)
email = User.find(recipient_id).notification_email_for(@group) mail_to(to: email, subject: @message.subject_line)
subject = subject_line(track, series)
mail_to(to: email, subject: subject)
end end
private private
...@@ -29,8 +25,17 @@ module Emails ...@@ -29,8 +25,17 @@ module Emails
def mail_to(to:, subject:) def mail_to(to:, subject:)
custom_headers = Gitlab.com? ? CUSTOM_HEADERS : {} custom_headers = Gitlab.com? ? CUSTOM_HEADERS : {}
mail(to: to, subject: subject, **custom_headers) do |format| mail(to: to, subject: subject, **custom_headers) do |format|
format.html { render layout: nil } format.html do
format.text { render layout: nil } @message.format = :html
render layout: nil
end
format.text do
@message.format = :text
render layout: nil
end
end end
end end
end end
......
...@@ -163,43 +163,43 @@ ...@@ -163,43 +163,43 @@
%table{ border: "0", cellpadding: "0", cellspacing: "0", role: "presentation", width: "100%" } %table{ border: "0", cellpadding: "0", cellspacing: "0", role: "presentation", width: "100%" }
%tr %tr
%td{ align: "left", style: "padding: 0 20px;" } %td{ align: "left", style: "padding: 0 20px;" }
= about_link('mailers/in_product_marketing', 'gitlab-logo-gray-rgb.png', 200) = about_link('mailers/in_product_marketing/gitlab-logo-gray-rgb.png', 200)
%tr %tr
%td{ "aria-hidden" => "true", height: "30", style: "font-size: 0; line-height: 0;" } %td{ "aria-hidden" => "true", height: "30", style: "font-size: 0; line-height: 0;" }
%tr{ style: "background-color: #ffffff;" } %tr{ style: "background-color: #ffffff;" }
%td{ style: "color: #424242; padding: 10px 30px; text-align: center; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;font-size: 16px; line-height: 22px; border: 1px solid #dddddd" } %td{ style: "color: #424242; padding: 10px 30px; text-align: center; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;font-size: 16px; line-height: 22px; border: 1px solid #dddddd" }
%p %p
= in_product_marketing_progress(@track, @series, format: :html).html_safe = @message.progress.html_safe
%tr %tr
%td{ bgcolor: "#ffffff", height: "auto", style: "max-width: 600px; width: 100%; text-align: center; height: 200px; padding: 25px 15px; mso-line-height-rule: exactly; min-height: 40px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;", valign: "middle", width: "100%" } %td{ bgcolor: "#ffffff", height: "auto", style: "max-width: 600px; width: 100%; text-align: center; height: 200px; padding: 25px 15px; mso-line-height-rule: exactly; min-height: 40px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;", valign: "middle", width: "100%" }
= in_product_marketing_logo(@track, @series) = inline_image_link(@message.logo_path, { width: '150', style: 'width: 150px;' })
%h1{ style: "font-size: 40px; line-height: 46x; color: #000000; padding: 20px 0 0 0; font-weight: normal;" } %h1{ style: "font-size: 40px; line-height: 46x; color: #000000; padding: 20px 0 0 0; font-weight: normal;" }
= in_product_marketing_title(@track, @series) = @message.title
%h2{ style: "font-size: 28px; line-height: 34px; color: #000000; padding: 0; font-weight: 400;" } %h2{ style: "font-size: 28px; line-height: 34px; color: #000000; padding: 0; font-weight: 400;" }
= in_product_marketing_subtitle(@track, @series) = @message.subtitle
%tr %tr
%td{ style: "padding: 10px 20px 30px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color:#000000; font-size: 18px; line-height: 24px;" } %td{ style: "padding: 10px 20px 30px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color:#000000; font-size: 18px; line-height: 24px;" }
%p{ style: "margin: 0 0 20px 0;" } %p{ style: "margin: 0 0 20px 0;" }
= in_product_marketing_body_line1(@track, @series, format: :html).html_safe = @message.body_line1.html_safe
- in_product_marketing_body_line2(@track, @series, format: :html)&.tap do |line| - @message.body_line2&.tap do |line|
%p{ style: "margin: 0 0 20px 0;" } %p{ style: "margin: 0 0 20px 0;" }
= line.html_safe = line.html_safe
%tr %tr
%td{ align: "center", style: "padding: 10px 20px 80px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" } %td{ align: "center", style: "padding: 10px 20px 80px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" }
.cta_link= cta_link(@track, @series, @group, format: :html) .cta_link= @message.cta_link
%tr{ style: "background-color: #ffffff;" } %tr{ style: "background-color: #ffffff;" }
%td{ align: "center", style: "padding:75px 20px 25px;" } %td{ align: "center", style: "padding:75px 20px 25px;" }
= about_link('', 'gitlab_logo.png', 80) = about_link('gitlab_logo.png', 80)
%tr{ style: "background-color: #ffffff;" } %tr{ style: "background-color: #ffffff;" }
%td{ align: "center", style: "padding:0px ;" } %td{ align: "center", style: "padding:0px ;" }
%tr{ style: "background-color: #ffffff;" } %tr{ style: "background-color: #ffffff;" }
%td{ align: "center", style: "padding:0px 10px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; " } %td{ align: "center", style: "padding:0px 10px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; " }
%span.footernav{ style: "color: #6e49cb; font-size: 16px; line-height: 26px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" } %span.footernav{ style: "color: #6e49cb; font-size: 16px; line-height: 26px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" }
= footer_links(format: :html).join('&nbsp;' * 3 + '|' + '&nbsp;' * 4).html_safe = @message.footer_links.join('&nbsp;' * 3 + '|' + '&nbsp;' * 4).html_safe
%tr{ style: "background-color:#ffffff;" } %tr{ style: "background-color:#ffffff;" }
%td{ align: "center", style: "padding: 40px 30px 20px 30px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" } %td{ align: "center", style: "padding: 40px 30px 20px 30px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" }
.address= address(format: :html) .address= @message.address
%tr{ style: "background-color: #ffffff;" } %tr{ style: "background-color: #ffffff;" }
%td{ align: "left", style: "padding:20px 30px 20px 30px;" } %td{ align: "left", style: "padding:20px 30px 20px 30px;" }
%span.footernav{ style: "color: #6e49cb; font-size: 14px; line-height: 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color:#424242;" } %span.footernav{ style: "color: #6e49cb; font-size: 14px; line-height: 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color:#424242;" }
= unsubscribe(@track, @series, format: :html).html_safe = @message.unsubscribe.html_safe
<%= in_product_marketing_tagline(@track, @series) %> <%= @message.tagline %>
<%= in_product_marketing_title(@track, @series) %> <%= @message.title %>
<%= in_product_marketing_subtitle(@track, @series) %> <%= @message.subtitle %>
<%= in_product_marketing_body_line1(@track, @series) %> <%= @message.body_line1 %>
<%= in_product_marketing_body_line2(@track, @series) %> <%= @message.body_line2 %>
<%= cta_link(@track, @series, @group) %> <%= @message.cta_link %>
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
<%= footer_links %> <%= @message.footer_links %>
<%= address %> <%= @message.address %>
<%= unsubscribe(@track, @series) %> <%= @message.unsubscribe %>
# frozen_string_literal: true
module Gitlab
module Email
module Message
module InProductMarketing
UnknownTrackError = Class.new(StandardError)
TRACKS = [:create, :verify, :team, :trial].freeze
def self.for(track)
raise UnknownTrackError unless TRACKS.include?(track)
"Gitlab::Email::Message::InProductMarketing::#{track.to_s.classify}".constantize
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Email
module Message
module InProductMarketing
class Base
include Gitlab::Email::Message::InProductMarketing::Helper
include Gitlab::Routing
attr_accessor :format
def initialize(group:, series:, format: :html)
raise ArgumentError, "Only #{total_series} series available for this track." unless series.between?(0, total_series - 1)
@group = group
@series = series
@format = format
end
def subject_line
raise NotImplementedError
end
def tagline
raise NotImplementedError
end
def title
raise NotImplementedError
end
def subtitle
raise NotImplementedError
end
def body_line1
raise NotImplementedError
end
def body_line2
raise NotImplementedError
end
def cta_text
raise NotImplementedError
end
def cta_link
case format
when :html
link_to cta_text, group_email_campaigns_url(group, track: track, series: series), target: '_blank', rel: 'noopener noreferrer'
else
[cta_text, group_email_campaigns_url(group, track: track, series: series)].join(' >> ')
end
end
def unsubscribe
parts = Gitlab.com? ? unsubscribe_com : unsubscribe_self_managed(track, series)
case format
when :html
parts.join(' ')
else
parts.join("\n" + ' ' * 16)
end
end
def progress
if Gitlab.com?
s_('InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series.') % { current_series: series + 1, total_series: total_series, track: track.to_s.humanize }
else
s_('InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}.') % { current_series: series + 1, total_series: total_series, track: track.to_s.humanize, unsubscribe_link: unsubscribe_link }
end
end
def address
s_('InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA').html_safe % strong_options
end
def footer_links
links = [
[s_('InProductMarketing|Blog'), 'https://about.gitlab.com/blog'],
[s_('InProductMarketing|Twitter'), 'https://twitter.com/gitlab'],
[s_('InProductMarketing|Facebook'), 'https://www.facebook.com/gitlab'],
[s_('InProductMarketing|YouTube'), 'https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg']
]
case format
when :html
links.map do |text, link|
link_to(text, link)
end
else
'| ' + links.map do |text, link|
[text, link].join(' ')
end.join("\n| ")
end
end
def logo_path
["mailers/in_product_marketing", "#{track}-#{series}.png"].join('/')
end
protected
attr_reader :group, :series
def total_series
3
end
private
def track
self.class.name.demodulize.downcase.to_sym
end
def unsubscribe_com
[
s_('InProductMarketing|If you no longer wish to receive marketing emails from us,'),
s_('InProductMarketing|you may %{unsubscribe_link} at any time.') % { unsubscribe_link: unsubscribe_link }
]
end
def unsubscribe_self_managed(track, series)
[
s_('InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}.') % { unsubscribe_link: unsubscribe_link },
s_("InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}.") % { marketing_preference_link: marketing_preference_link(track, series) }
]
end
def unsubscribe_link
unsubscribe_url = Gitlab.com? ? '%tag_unsubscribe_url%' : profile_notifications_url
link(s_('InProductMarketing|unsubscribe'), unsubscribe_url)
end
def marketing_preference_link(track, series)
params = {
utm_source: 'SM',
utm_medium: 'email',
utm_campaign: 'onboarding',
utm_term: "#{track}_#{series}"
}
preference_link = "https://about.gitlab.com/company/preference-center/?#{params.to_query}"
link(s_('InProductMarketing|update your preferences'), preference_link)
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Email
module Message
module InProductMarketing
class Create < Base
def subject_line
[
s_('InProductMarketing|Create a project in GitLab in 5 minutes'),
s_('InProductMarketing|Import your project and code from GitHub, Bitbucket and others'),
s_('InProductMarketing|Understand repository mirroring')
][series]
end
def tagline
[
s_('InProductMarketing|Get started today'),
s_('InProductMarketing|Get our import guides'),
s_('InProductMarketing|Need an alternative to importing?')
][series]
end
def title
[
s_('InProductMarketing|Take your first steps with GitLab'),
s_('InProductMarketing|Start by importing your projects'),
s_('InProductMarketing|How (and why) mirroring makes sense')
][series]
end
def subtitle
[
s_('InProductMarketing|Dig in and create a project and a repo'),
s_("InProductMarketing|Here's what you need to know"),
s_('InProductMarketing|Try it out')
][series]
end
def body_line1
[
s_("InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}.") % { project_link: project_link, repo_link: repo_link },
s_("InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}.") % { github_link: github_link, bitbucket_link: bitbucket_link },
s_("InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool.") % { mirroring_link: mirroring_link }
][series]
end
def body_line2
[
s_("InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started.") % { basics_link: basics_link },
s_("InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}.") % { import_link: import_link },
s_("InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD.") % { external_repo_link: external_repo_link }
][series]
end
def cta_text
[
s_('InProductMarketing|Create your first project!'),
s_('InProductMarketing|Master the art of importing!'),
s_('InProductMarketing|Understand your project options')
][series]
end
private
def project_link
link(s_('InProductMarketing|create a project'), help_page_url('gitlab-basics/create-project'))
end
def repo_link
link(s_('InProductMarketing|set up a repo'), help_page_url('user/project/repository/index', anchor: 'create-a-repository'))
end
def github_link
link(s_('InProductMarketing|GitHub Enterprise projects to GitLab'), help_page_url('integration/github'))
end
def bitbucket_link
link(s_('InProductMarketing|from Bitbucket'), help_page_url('user/project/import/bitbucket_server'))
end
def mirroring_link
link(s_('InProductMarketing|repository mirroring'), help_page_url('user/project/repository/repository_mirroring'))
end
def basics_link
link(s_('InProductMarketing|Git basics'), help_page_url('gitlab-basics/README'))
end
def import_link
link(s_('InProductMarketing|comprehensive guide'), help_page_url('user/project/import/index'))
end
def external_repo_link
link(s_('InProductMarketing|connect an external repository'), new_project_url(anchor: 'cicd_for_external_repo'))
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Email
module Message
module InProductMarketing
module Helper
include ActionView::Context
include ActionView::Helpers::TagHelper
include ActionView::Helpers::UrlHelper
private
def list(array)
case format
when :html
tag.ul { array.map { |item| tag.li item} }
else
'- ' + array.join("\n- ")
end
end
def strong_options
case format
when :html
{ strong_start: '<b>'.html_safe, strong_end: '</b>'.html_safe }
else
{ strong_start: '', strong_end: '' }
end
end
def link(text, link)
case format
when :html
link_to text, link
else
"#{text} (#{link})"
end
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Email
module Message
module InProductMarketing
class Team < Base
def subject_line
[
s_('InProductMarketing|Working in GitLab = more efficient'),
s_("InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"),
s_('InProductMarketing|Your teams can be more efficient')
][series]
end
def tagline
[
s_('InProductMarketing|Invite your colleagues to join in less than one minute'),
s_('InProductMarketing|Get your team set up on GitLab'),
nil
][series]
end
def title
[
s_('InProductMarketing|Team work makes the dream work'),
s_('InProductMarketing|*GitLab*, noun: a synonym for efficient teams'),
s_('InProductMarketing|Find out how your teams are really doing')
][series]
end
def subtitle
[
s_('InProductMarketing|Actually, GitLab makes the team work (better)'),
s_('InProductMarketing|Our tool brings all the things together'),
s_("InProductMarketing|It's all in the stats")
][series]
end
def body_line1
[
[
s_('InProductMarketing|Did you know teams that use GitLab are far more efficient?'),
list([
s_('InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day'),
s_('InProductMarketing|Ticketmaster decreased their CI build time by 15X')
])
].join("\n"),
s_("InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."),
[
s_('InProductMarketing|Stop wondering and use GitLab to answer questions like:'),
list([
s_('InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?'),
s_('InProductMarketing|How many days does it take our team to complete various tasks?'),
s_('InProductMarketing|What does our value stream timeline look like from product to development to review and production?')
])
].join("\n")
][series]
end
def body_line2
[
s_('InProductMarketing|Invite your colleagues and start shipping code faster.'),
s_("InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."),
s_('InProductMarketing|When your team is on GitLab these answers are a click away.')
][series]
end
def cta_text
[
s_('InProductMarketing|Invite your colleagues today'),
s_('InProductMarketing|Invite your team in less than 60 seconds'),
s_('InProductMarketing|Invite your team now')
][series]
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Email
module Message
module InProductMarketing
class Trial < Base
def subject_line
[
s_('InProductMarketing|Go farther with GitLab'),
s_('InProductMarketing|Automated security scans directly within GitLab'),
s_('InProductMarketing|Take your source code management to the next level')
][series]
end
def tagline
[
s_('InProductMarketing|Start a free trial of GitLab Ultimate – no CC required'),
s_('InProductMarketing|Improve app security with a 30-day trial'),
s_('InProductMarketing|Start with a GitLab Ultimate free trial')
][series]
end
def title
[
s_('InProductMarketing|Give us one minute...'),
s_("InProductMarketing|Security that's integrated into your development lifecycle"),
s_('InProductMarketing|Improve code quality and streamline reviews')
][series]
end
def subtitle
[
s_('InProductMarketing|...and you can get a free trial of GitLab Ultimate'),
s_('InProductMarketing|Try GitLab Ultimate for free'),
s_('InProductMarketing|Better code in less time')
][series]
end
def body_line1
[
[
s_("InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"),
list([
s_('InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels').html_safe % strong_options,
s_('InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals').html_safe % strong_options,
s_('InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection').html_safe % strong_options,
s_('InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream').html_safe % strong_options
])
].join("\n"),
s_('InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance.'),
s_('InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process.')
][series]
end
def body_line2
[
s_('InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required.'),
s_('InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required.'),
s_('InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required.')
][series]
end
def cta_text
[
s_('InProductMarketing|Start a trial'),
s_('InProductMarketing|Beef up your security'),
s_('InProductMarketing|Start your trial now!')
][series]
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Email
module Message
module InProductMarketing
class Verify < Base
def subject_line
[
s_('InProductMarketing|Feel the need for speed?'),
s_('InProductMarketing|3 ways to dive into GitLab CI/CD'),
s_('InProductMarketing|Explore the power of GitLab CI/CD')
][series]
end
def tagline
[
s_('InProductMarketing|Use GitLab CI/CD'),
s_('InProductMarketing|Test, create, deploy'),
s_('InProductMarketing|Are your runners ready?')
][series]
end
def title
[
s_('InProductMarketing|Rapid development, simplified'),
s_('InProductMarketing|Get started with GitLab CI/CD'),
s_('InProductMarketing|Launch GitLab CI/CD in 20 minutes or less')
][series]
end
def subtitle
[
s_('InProductMarketing|How to build and test faster'),
s_('InProductMarketing|Explore the options'),
s_('InProductMarketing|Follow our steps')
][series]
end
def body_line1
[
s_("InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}.") % { ci_link: ci_link },
s_("InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"),
s_("InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy.") % { quick_start_link: quick_start_link }
][series]
end
def body_line2
[
nil,
list([
s_('InProductMarketing|Start by %{performance_link}').html_safe % { performance_link: performance_link },
s_('InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}').html_safe % { ci_template_link: ci_template_link },
s_('InProductMarketing|And finally %{deploy_link} a Python application.').html_safe % { deploy_link: deploy_link }
]),
nil
][series]
end
def cta_text
[
s_('InProductMarketing|Get to know GitLab CI/CD'),
s_('InProductMarketing|Try it yourself'),
s_('InProductMarketing|Explore GitLab CI/CD')
][series]
end
private
def ci_link
link(s_('InProductMarketing|how easy it is to get started'), help_page_url('ci/README'))
end
def quick_start_link
link(s_('InProductMarketing|quick start guide'), help_page_url('ci/quick_start/README'))
end
def performance_link
link(s_('InProductMarketing|testing browser performance'), help_page_url('user/project/merge_requests/browser_performance_testing'))
end
def ci_template_link
link(s_('InProductMarketing|using a CI/CD template'), help_page_url('user/project/pages/getting_started/pages_ci_cd_template'))
end
def deploy_link
link(s_('InProductMarketing|test and deploy'), help_page_url('ci/examples/test-and-deploy-python-application-to-heroku'))
end
end
end
end
end
end
...@@ -17103,10 +17103,10 @@ msgstr "" ...@@ -17103,10 +17103,10 @@ msgstr ""
msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started." msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
msgstr "" msgstr ""
msgid "InProductMarketing|This is email %{series} of 3 in the %{track} series." msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
msgstr "" msgstr ""
msgid "InProductMarketing|This is email %{series} of 3 in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}." msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
msgstr "" msgstr ""
msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X" msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Email::Message::InProductMarketing::Base do
let_it_be(:group) { build(:group) }
let(:series) { 0 }
let(:test_class) { Gitlab::Email::Message::InProductMarketing::Create }
describe 'initialize' do
subject { test_class.new(group: group, series: series) }
context 'when series does not exist' do
let(:series) { 3 }
it 'raises error' do
expect { subject }.to raise_error(ArgumentError)
end
end
context 'when series exists' do
let(:series) { 0 }
it 'does not raise error' do
expect { subject }.not_to raise_error(ArgumentError)
end
end
end
describe '#logo_path' do
subject { test_class.new(group: group, series: series).logo_path }
it { is_expected.to eq('mailers/in_product_marketing/create-0.png') }
end
describe '#unsubscribe' do
subject { test_class.new(group: group, series: series).unsubscribe }
before do
allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
end
context 'on gitlab.com' do
let(:is_gitlab_com) { true }
it { is_expected.to include('%tag_unsubscribe_url%') }
end
context 'not on gitlab.com' do
let(:is_gitlab_com) { false }
it { is_expected.to include(Gitlab::Routing.url_helpers.profile_notifications_url) }
end
end
describe '#cta_link' do
subject(:cta_link) { test_class.new(group: group, series: series).cta_link }
it 'renders link' do
expect(CGI.unescapeHTML(cta_link)).to include(Gitlab::Routing.url_helpers.group_email_campaigns_url(group, track: :create, series: series))
end
end
describe '#progress' do
subject { test_class.new(group: group, series: series).progress }
before do
allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
end
context 'on gitlab.com' do
let(:is_gitlab_com) { true }
it { is_expected.to include('This is email 1 of 3 in the Create series') }
end
context 'not on gitlab.com' do
let(:is_gitlab_com) { false }
it { is_expected.to include('This is email 1 of 3 in the Create series', Gitlab::Routing.url_helpers.profile_notifications_url) }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Email::Message::InProductMarketing::Create do
using RSpec::Parameterized::TableSyntax
let_it_be(:group) { build(:group) }
subject(:message) { described_class.new(group: group, series: series)}
describe "public methods" do
where(series: [0, 1, 2])
with_them do
it 'returns value for series', :aggregate_failures do
expect(message.subject_line).to be_present
expect(message.tagline).to be_present
expect(message.title).to be_present
expect(message.subtitle).to be_present
expect(message.body_line1).to be_present
expect(message.body_line2).to be_present
expect(message.cta_text).to be_present
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Email::Message::InProductMarketing::Team do
using RSpec::Parameterized::TableSyntax
let_it_be(:group) { build(:group) }
subject(:message) { described_class.new(group: group, series: series)}
describe "public methods" do
where(series: [0, 1])
with_them do
it 'returns value for series', :aggregate_failures do
expect(message.subject_line).to be_present
expect(message.tagline).to be_present
expect(message.title).to be_present
expect(message.subtitle).to be_present
expect(message.body_line1).to be_present
expect(message.body_line2).to be_present
expect(message.cta_text).to be_present
end
end
context 'with series 2' do
let(:series) { 2 }
it 'returns value for series', :aggregate_failures do
expect(message.subject_line).to be_present
expect(message.tagline).to be_nil
expect(message.title).to be_present
expect(message.subtitle).to be_present
expect(message.body_line1).to be_present
expect(message.body_line2).to be_present
expect(message.cta_text).to be_present
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Email::Message::InProductMarketing::Trial do
using RSpec::Parameterized::TableSyntax
let_it_be(:group) { build(:group) }
subject(:message) { described_class.new(group: group, series: series)}
describe "public methods" do
where(series: [0, 1, 2])
with_them do
it 'returns value for series', :aggregate_failures do
expect(message.subject_line).to be_present
expect(message.tagline).to be_present
expect(message.title).to be_present
expect(message.subtitle).to be_present
expect(message.body_line1).to be_present
expect(message.body_line2).to be_present
expect(message.cta_text).to be_present
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Email::Message::InProductMarketing::Verify do
let_it_be(:group) { build(:group) }
subject(:message) { described_class.new(group: group, series: series)}
describe "public methods" do
context 'with series 0' do
let(:series) { 0 }
it 'returns value for series', :aggregate_failures do
expect(message.subject_line).to be_present
expect(message.tagline).to be_present
expect(message.title).to be_present
expect(message.subtitle).to be_present
expect(message.body_line1).to be_present
expect(message.body_line2).to be_nil
expect(message.cta_text).to be_present
end
end
context 'with series 1' do
let(:series) { 1 }
it 'returns value for series', :aggregate_failures do
expect(message.subject_line).to be_present
expect(message.tagline).to be_present
expect(message.title).to be_present
expect(message.subtitle).to be_present
expect(message.body_line1).to be_present
expect(message.body_line2).to be_present
expect(message.cta_text).to be_present
end
end
context 'with series 2' do
let(:series) { 2 }
it 'returns value for series', :aggregate_failures do
expect(message.subject_line).to be_present
expect(message.tagline).to be_present
expect(message.title).to be_present
expect(message.subtitle).to be_present
expect(message.body_line1).to be_present
expect(message.body_line2).to be_nil
expect(message.cta_text).to be_present
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Email::Message::InProductMarketing do
describe '.for' do
using RSpec::Parameterized::TableSyntax
subject { described_class.for(track) }
context 'when track exists' do
where(:track, :expected_class) do
:create | described_class::Create
:verify | described_class::Verify
:trial | described_class::Trial
:team | described_class::Team
end
with_them do
it { is_expected.to eq(expected_class) }
end
end
context 'when track does not exist' do
let(:track) { :non_existent }
it 'raises error' do
expect { subject }.to raise_error(described_class::UnknownTrackError)
end
end
end
end
...@@ -5,7 +5,6 @@ require 'email_spec' ...@@ -5,7 +5,6 @@ require 'email_spec'
RSpec.describe Emails::InProductMarketing do RSpec.describe Emails::InProductMarketing do
include EmailSpec::Matchers include EmailSpec::Matchers
include InProductMarketingHelper
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
...@@ -62,11 +61,13 @@ RSpec.describe Emails::InProductMarketing do ...@@ -62,11 +61,13 @@ RSpec.describe Emails::InProductMarketing do
with_them do with_them do
it 'has the correct subject and content' do it 'has the correct subject and content' do
message = Gitlab::Email::Message::InProductMarketing.for(track).new(group: group, series: series)
aggregate_failures do aggregate_failures do
is_expected.to have_subject(subject_line(track, series)) is_expected.to have_subject(message.subject_line)
is_expected.to have_body_text(in_product_marketing_title(track, series)) is_expected.to have_body_text(message.title)
is_expected.to have_body_text(in_product_marketing_subtitle(track, series)) is_expected.to have_body_text(message.subtitle)
is_expected.to have_body_text(in_product_marketing_cta_text(track, series)) is_expected.to have_body_text(CGI.unescapeHTML(message.cta_link))
end end
end end
end end
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Groups::EmailCampaignsController do RSpec.describe Groups::EmailCampaignsController do
include InProductMarketingHelper
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
describe 'GET #index', :snowplow do describe 'GET #index', :snowplow do
...@@ -13,7 +12,7 @@ RSpec.describe Groups::EmailCampaignsController do ...@@ -13,7 +12,7 @@ RSpec.describe Groups::EmailCampaignsController do
let(:track) { 'create' } let(:track) { 'create' }
let(:series) { '0' } let(:series) { '0' }
let(:schema) { described_class::EMAIL_CAMPAIGNS_SCHEMA_URL } let(:schema) { described_class::EMAIL_CAMPAIGNS_SCHEMA_URL }
let(:subject_line_text) { subject_line(track.to_sym, series.to_i) } let(:subject_line_text) { Gitlab::Email::Message::InProductMarketing.for(track.to_sym).new(group: group, series: series.to_i).subject_line }
let(:data) do let(:data) do
{ {
namespace_id: group.id, namespace_id: group.id,
......
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