diff --git a/ee/app/models/remote_development/workspace.rb b/ee/app/models/remote_development/workspace.rb index 690afc94f916c1cc8a835bb9c7e6d3939aef4c33..9c00871587f1e8f452afbc05c4aebbdb294f502b 100644 --- a/ee/app/models/remote_development/workspace.rb +++ b/ee/app/models/remote_development/workspace.rb @@ -6,6 +6,7 @@ module RemoteDevelopment class Workspace < ApplicationRecord include Sortable include RemoteDevelopment::WorkspaceOperations::States + include ::Gitlab::InternalEventsTracking include ::Gitlab::Utils::StrongMemoize include SafelyChangeColumnDefault @@ -100,6 +101,10 @@ class Workspace < ApplicationRecord workspace.new_record? || workspace.actual_state_changed? end + after_save :track_started_workspace, if: -> { + saved_change_to_desired_state? && desired_state == "Running" + } + # @return [RemoteDevelopment::WorkspacesAgentConfig] def workspaces_agent_config unless unversioned_workspaces_agent_config_present? @@ -317,5 +322,18 @@ def touch_actual_state_updated_at # noinspection RubyMismatchedArgumentType - RBS type for #utc is Time, but db field is 'timestamp with time zone' self.actual_state_updated_at = Time.current.utc end + + # @return [void] + def track_started_workspace + track_internal_event( + "track_started_workspaces", + user: user, + project: project, + additional_properties: { + label: previously_new_record? ? "new" : "existing" + } + ) + nil + end end end diff --git a/ee/config/events/track_started_workspaces.yml b/ee/config/events/track_started_workspaces.yml new file mode 100644 index 0000000000000000000000000000000000000000..296123d31442401e0f0ddc84fee581bf78730c02 --- /dev/null +++ b/ee/config/events/track_started_workspaces.yml @@ -0,0 +1,19 @@ +--- +description: Tracks Started New or Exisitng Workspaces +internal_events: true +action: track_started_workspaces +identifiers: +- project +- namespace +- user +additional_properties: + label: + description: new or exisitng workspace +product_group: remote_development +product_categories: +- workspaces +milestone: '18.1' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/191902 +tiers: +- premium +- ultimate diff --git a/ee/config/metrics/counts_all/count_total_existing_workspaces_started.yml b/ee/config/metrics/counts_all/count_total_existing_workspaces_started.yml new file mode 100644 index 0000000000000000000000000000000000000000..4f0c9b66f500b4de5ae6e41e70fcb7ab3679c640 --- /dev/null +++ b/ee/config/metrics/counts_all/count_total_existing_workspaces_started.yml @@ -0,0 +1,24 @@ +--- +key_path: counts.count_total_existing_workspaces_started +description: Count of Total Number of Existing Workspaces Started +product_group: remote_development +product_categories: +- workspaces +performance_indicator_type: [] +value_type: number +status: active +milestone: '18.1' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/191902 +time_frame: +- 28d +- 7d +- all +data_source: internal_events +data_category: optional +tiers: +- premium +- ultimate +events: +- name: track_started_workspaces + filter: + label: existing diff --git a/ee/config/metrics/counts_all/count_total_new_workspaces_started.yml b/ee/config/metrics/counts_all/count_total_new_workspaces_started.yml new file mode 100644 index 0000000000000000000000000000000000000000..9f80c2d204e38e00332a9e8d105def70b907349c --- /dev/null +++ b/ee/config/metrics/counts_all/count_total_new_workspaces_started.yml @@ -0,0 +1,24 @@ +--- +key_path: counts.count_total_new_workspaces_started +description: Count of Total Number of New Workspaces Started +product_group: remote_development +product_categories: +- workspaces +performance_indicator_type: [] +value_type: number +status: active +milestone: '18.1' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/191902 +time_frame: +- 28d +- 7d +- all +data_source: internal_events +data_category: optional +tiers: +- premium +- ultimate +events: +- name: track_started_workspaces + filter: + label: new diff --git a/ee/config/metrics/counts_all/count_total_workspaces_started.yml b/ee/config/metrics/counts_all/count_total_workspaces_started.yml new file mode 100644 index 0000000000000000000000000000000000000000..923110c9b52ffe5a5b2b4acf950f923a04a29b53 --- /dev/null +++ b/ee/config/metrics/counts_all/count_total_workspaces_started.yml @@ -0,0 +1,22 @@ +--- +key_path: counts.count_total_workspaces_started +description: Count of Total Number of Workspaces Started +product_group: remote_development +product_categories: +- workspaces +performance_indicator_type: [] +value_type: number +status: active +milestone: '18.1' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/191902 +time_frame: +- 28d +- 7d +- all +data_source: internal_events +data_category: optional +tiers: +- premium +- ultimate +events: +- name: track_started_workspaces diff --git a/ee/spec/models/remote_development/workspace_spec.rb b/ee/spec/models/remote_development/workspace_spec.rb index ba22055b70096d1bb7d38e4b86322cd6bfe36e59..28b5bcdfef657bea601cc398f8b453f1e4da7198 100644 --- a/ee/spec/models/remote_development/workspace_spec.rb +++ b/ee/spec/models/remote_development/workspace_spec.rb @@ -38,6 +38,9 @@ dns_zone: dns_zone, enabled: workspaces_agent_config_enabled ) + # Some tests would trigger method trigger_update_workspace_to_active_event with HTTPS call + stub_request(:post, "https://events-stg.gitlab.net/com.snowplowanalytics.snowplow/tp2").to_return(status: 200, + body: "", headers: {}) end describe "default values" do @@ -61,7 +64,7 @@ it { is_expected.to belong_to(:user) } it { is_expected.to belong_to(:personal_access_token) } - it 'has correct relation setup' do + it "has correct relation setup" do is_expected .to belong_to(:agent) .class_name("Clusters::Agent") @@ -159,6 +162,52 @@ end end end + + describe "after_save" do + describe "track_started_workspace callback" do + context "when desired_state changes to Running" do + it "triggers the event" do + expect(workspace).to receive(:track_started_workspace) + workspace.update!(desired_state: "Running") + end + + it "triggers internal event with new label on new record" do + expect { workspace.update!(desired_state: "Running") } + .to trigger_internal_events("track_started_workspaces") + .with(user: user, project: project, additional_properties: { + label: "new" + }) + .and increment_usage_metrics("counts.count_total_workspaces_started") + end + + it "triggers internal event with existing label on existing record" do + workspace.save!(desired_state: "Stopped") + expect { workspace.update!(desired_state: "Running") } + .to trigger_internal_events("track_started_workspaces") + .with(user: user, project: project, additional_properties: { + label: "existing" + }) + .and increment_usage_metrics("counts.count_total_workspaces_started") + end + end + + context "when desired_state changes to a value other than Running" do + it "does not trigger the event and metric" do + expect { workspace.update!(desired_state: "Stopped") } + .to not_trigger_internal_events("track_started_workspaces") + .and not_increment_usage_metrics('counts.count_total_workspaces_started') + end + end + + context "when desired_state doesn't change" do + it "does not trigger the event" do + expect { workspace.update!(name: "workspace_new_name") } + .to not_trigger_internal_events("track_started_workspaces") + .and not_increment_usage_metrics('counts.count_total_workspaces_started') + end + end + end + end end describe "validations" do