Welcome to mirror list, hosted at ThFree Co, Russian Federation.

event_definer.rb « cli « internal_events « scripts - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 54f81a62dd1c6c7639f507c7eb208989bf3ce1a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# frozen_string_literal: true

require_relative './helpers'

module InternalEventsCli
  class EventDefiner
    include Helpers

    STEPS = [
      'New Event',
      'Description',
      'Name',
      'Context',
      'URL',
      'Group',
      'Tiers',
      'Save files'
    ].freeze

    IDENTIFIER_OPTIONS = {
      %w[project namespace user] => 'Use case: For project-level user actions ' \
                                    '(ex - issue_assignee_changed) [MOST COMMON]',
      %w[namespace user] => 'Use case: For namespace-level user actions (ex - epic_assigned_to_milestone)',
      %w[user] => 'Use case: For user-only actions (ex - admin_impersonated_user)',
      %w[project namespace] => 'Use case: For project-level events without user interaction ' \
                               '(ex - service_desk_request_received)',
      %w[namespace] => 'Use case: For namespace-level events without user interaction ' \
                       '(ex - stale_runners_cleaned_up)',
      %w[] => "Use case: For instance-level events without user interaction [LEAST COMMON]"
    }.freeze

    IDENTIFIER_FORMATTING_BUFFER = "[#{IDENTIFIER_OPTIONS.keys.max_by(&:length).join(', ')}]".length

    attr_reader :cli, :event

    def initialize(cli)
      @cli = cli
      @event = Event.new(milestone: MILESTONE)
    end

    def run
      prompt_for_description
      prompt_for_action
      prompt_for_identifiers
      prompt_for_url
      prompt_for_product_ownership
      prompt_for_tier

      outcome = create_event_file
      display_result(outcome)

      prompt_for_next_steps
    end

    private

    def prompt_for_description
      new_page!(1, 7, STEPS)
      cli.say Text::EVENT_DESCRIPTION_INTRO

      event.description = cli.ask("Describe what the event tracks: #{input_required_text}", **input_opts) do |q|
        q.required true
        q.modify :trim
        q.messages[:required?] = Text::EVENT_DESCRIPTION_HELP
      end
    end

    def prompt_for_action
      new_page!(2, 7, STEPS)
      cli.say Text::EVENT_ACTION_INTRO

      event.action = cli.ask("Define the event name: #{input_required_text}", **input_opts) do |q|
        q.required true
        q.validate ->(input) { input =~ /\A[a-z1-9_]+\z/ && !events_by_filepath.values.map(&:action).include?(input) } # rubocop:disable Rails/NegateInclude -- Not rails
        q.modify :trim
        q.messages[:valid?] = format_warning("Invalid event name. Only lowercase/numbers/underscores allowed. " \
                                             "Ensure %{value} is not an existing event.")
        q.messages[:required?] = Text::EVENT_ACTION_HELP
      end
    end

    def prompt_for_identifiers
      new_page!(3, 7, STEPS)
      cli.say Text::EVENT_IDENTIFIERS_INTRO % event.action

      identifiers = prompt_for_array_selection(
        'Which identifiers are available when the event occurs?',
        IDENTIFIER_OPTIONS.keys
      ) { |choice| format_identifier_choice(choice) }

      event.identifiers = identifiers if identifiers.any?
    end

    def format_identifier_choice(choice)
      formatted_choice = choice.empty? ? 'None' : "[#{choice.sort.join(', ')}]"
      buffer = IDENTIFIER_FORMATTING_BUFFER - formatted_choice.length

      "#{formatted_choice}#{' ' * buffer} -- #{IDENTIFIER_OPTIONS[choice]}"
    end

    def prompt_for_url
      new_page!(4, 7, STEPS)

      event.introduced_by_url = prompt_for_text('Which MR URL will merge the event definition?')
    end

    def prompt_for_product_ownership
      new_page!(5, 7, STEPS)

      ownership = prompt_for_group_ownership({
        product_section: 'Which section will own the event?',
        product_stage: 'Which stage will own the event?',
        product_group: 'Which group will own the event?'
      })

      event.bulk_assign(ownership)
    end

    def prompt_for_tier
      new_page!(6, 7, STEPS)

      event.tiers = prompt_for_array_selection(
        'Which tiers will the event be recorded on?',
        [%w[free premium ultimate], %w[premium ultimate], %w[ultimate]]
      )

      event.distributions = event.tiers.include?('free') ? %w[ce ee] : %w[ee]
    end

    def create_event_file
      new_page!(7, 7, STEPS)

      prompt_to_save_file(event.file_path, event.formatted_output)
    end

    def display_result(outcome)
      new_page!

      cli.say <<~TEXT
        #{divider}
        #{format_info('Done with event definition!')}

        #{outcome || '  No files saved.'}

        #{divider}

          Want to have data reported in Snowplow/Sisense/ServicePing? Add a new metric for your event!

      TEXT
    end

    def prompt_for_next_steps
      next_step = cli.select("How would you like to proceed?", **select_opts) do |menu|
        menu.enum "."

        if File.exist?(event.file_path)
          menu.choice "Create Metric -- define a new metric using #{event.action}.yml", :add_metric
        else
          menu.choice "Save & Create Metric -- save #{event.action}.yml and define a matching metric", :save_and_add
        end

        menu.choice "View Usage -- look at code examples for #{event.action}.yml", :view_usage
        menu.choice 'Exit', :exit
      end

      case next_step
      when :add_metric
        MetricDefiner.new(cli, event.file_path).run
      when :save_and_add
        write_to_file(event.file_path, event.formatted_output, 'create')

        MetricDefiner.new(cli, event.file_path).run
      when :view_usage
        UsageViewer.new(cli, event.file_path, event).run
      when :exit
        cli.say Text::FEEDBACK_NOTICE
      end
    end
  end
end