Experiment: "Build iOS app guide" email campaign
Compare changes
- Eugie Limpin authored
@@ -31,7+31,7 @@
@@ -44,7+44,7 @@
This MR implements a campaign email experiment.
In !80361 (merged) we introduced a service running in the background to detect if a project is an iOS project. This detection happens every time changes are pushed to the project's main branch (much like repository language detection).
In this MR, when a project is determined to be an iOS project we send an email to the project's members with access_level >= DEVELOPER
that contains a guide on how to build iOS projects within GitLab.
Users::InProductMarketingEmail
is updated so it can be re-used to record sending of campaign emails. Previously, this model was only used to record sending of marketing emails (Users::InProductMarketingEmail
records with track
and series
attribute values) when users accomplish specific tasks during onboarding–e.g. user invites a teammate to a project.
This update comprises the following changes to in_product_marketing_emails
DB table:
NOT NULL
constraints on track
and series
columnscampaign
(text
) column (for now it can only contain 'build_ios_app_guide'
user_id
and campaign
to ensure that a user is sent a campaign email at most oncetrack
and series
are NOT NULL
when campaign IS NULL
OR track
and series
are NULL
when campaign IS NOT NULL
Rollback
$ rails db:rollback
== 20220420034519 AddTextLimitToInProductMarketingEmailCampaign: reverting ====
-- transaction_open?()
-> 0.0000s
-- transaction_open?()
-> 0.0000s
-- execute("ALTER TABLE in_product_marketing_emails\nDROP CONSTRAINT IF EXISTS check_9d8b29f74f\n")
-> 0.0062s
== 20220420034519 AddTextLimitToInProductMarketingEmailCampaign: reverted (0.0217s)
$ rails db:rollback
== 20220401071609 AddCampaignToInProductMarketingEmail: reverting =============
-- transaction_open?()
-> 0.0000s
-- transaction_open?()
-> 0.0000s
-- execute("ALTER TABLE in_product_marketing_emails\nDROP CONSTRAINT IF EXISTS in_product_marketing_emails_track_and_series_or_campaign\n")
-> 0.0012s
-- transaction_open?()
-> 0.0000s
-- index_exists?(:in_product_marketing_emails, [:user_id, :campaign], {:name=>:index_in_product_marketing_emails_on_user_campaign, :algorithm=>:concurrently})
-> 0.0039s
-- execute("SET statement_timeout TO 0")
-> 0.0005s
-- remove_index(:in_product_marketing_emails, {:name=>:index_in_product_marketing_emails_on_user_campaign, :algorithm=>:concurrently, :column=>[:user_id, :campaign]})
-> 0.0046s
-- execute("RESET statement_timeout")
-> 0.0005s
-- remove_column(:in_product_marketing_emails, :campaign, {:if_exists=>true})
-> 0.0022s
== 20220401071609 AddCampaignToInProductMarketingEmail: reverted (0.0305s) ====
Migrate
$ rails db:migrate
== 20220401071609 AddCampaignToInProductMarketingEmail: migrating =============
-- change_column_null(:in_product_marketing_emails, :track, true)
-> 0.0014s
-- change_column_null(:in_product_marketing_emails, :series, true)
-> 0.0008s
-- add_column(:in_product_marketing_emails, :campaign, :text)
-> 0.0037s
-- transaction_open?()
-> 0.0000s
-- index_exists?(:in_product_marketing_emails, [:user_id, :campaign], {:unique=>true, :name=>:index_in_product_marketing_emails_on_user_campaign, :algorithm=>:concurrently})
-> 0.0041s
-- execute("SET statement_timeout TO 0")
-> 0.0005s
-- add_index(:in_product_marketing_emails, [:user_id, :campaign], {:unique=>true, :name=>:index_in_product_marketing_emails_on_user_campaign, :algorithm=>:concurrently})
-> 0.0067s
-- execute("RESET statement_timeout")
-> 0.0005s
-- transaction_open?()
-> 0.0000s
-- current_schema()
-> 0.0003s
-- transaction_open?()
-> 0.0000s
-- execute("ALTER TABLE in_product_marketing_emails\nADD CONSTRAINT in_product_marketing_emails_track_and_series_or_campaign\nCHECK ( (track IS NOT NULL AND series IS NOT NULL AND campaign IS NULL) OR (track IS NULL AND series IS NULL AND campaign IS NOT NULL) )\nNOT VALID;\n")
-> 0.0018s
-- current_schema()
-> 0.0002s
-- execute("ALTER TABLE in_product_marketing_emails VALIDATE CONSTRAINT in_product_marketing_emails_track_and_series_or_campaign;")
-> 0.0010s
== 20220401071609 AddCampaignToInProductMarketingEmail: migrated (0.0444s) ====
$ rails db:migrate
== 20220420034519 AddTextLimitToInProductMarketingEmailCampaign: migrating ====
-- transaction_open?()
-> 0.0000s
-- current_schema()
-> 0.0019s
-- transaction_open?()
-> 0.0000s
-- execute("ALTER TABLE in_product_marketing_emails\nADD CONSTRAINT check_9d8b29f74f\nCHECK ( char_length(campaign) <= 255 )\nNOT VALID;\n")
-> 0.0011s
-- current_schema()
-> 0.0003s
-- execute("ALTER TABLE in_product_marketing_emails VALIDATE CONSTRAINT check_9d8b29f74f;")
-> 0.0008s
== 20220420034519 AddTextLimitToInProductMarketingEmailCampaign: migrated (0.0131s)
Notify.build_ios_app_guide_email('test_recipient@example.com').deliver_now
To test the whole flow:
gitlab.com
. In your terminal, run:
export GITLAB_SIMULATE_SAAS=1 gdk start
Feature.enable(:build_ios_app_guide_email)
user = User.find_by_username('username_of_user')
user.email_opted_in? # should be true. If it's not then just do user.update({email_opted_in: true})
user.can?(:receive_notifications) # should be true
master
) of the project. You can do this by just editing the README.md
file using Web IDE and committing the change to master
branchThis checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.