From 528bc843128d799b95c611693c420122f4cede62 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 13 Oct 2022 03:09:36 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- GITALY_SERVER_VERSION | 2 +- .../components/cells/runner_owner_cell.vue | 63 ++++++++++ .../runner/components/runner_list.vue | 20 ++++ app/assets/javascripts/runner/constants.js | 1 + .../list/list_item_shared.fragment.graphql | 14 +++ .../concerns/product_analytics_tracking.rb | 9 +- ...32350_add_password_expiration_migration.rb | 12 ++ ...assword_last_changed_at_to_user_details.rb | 9 ++ db/schema_migrations/20221008032350 | 1 + db/schema_migrations/20221012033107 | 1 + db/structure.sql | 12 ++ doc/api/graphql/reference/index.md | 9 ++ doc/ci/variables/predefined_variables.md | 2 + .../documentation/styleguide/word_list.md | 42 ++++--- doc/user/project/releases/index.md | 24 ---- lib/gitlab/tracking/service_ping_context.rb | 25 ++++ locale/gitlab.pot | 9 ++ .../admin/cohorts_controller_spec.rb | 2 +- .../admin/dev_ops_report_controller_spec.rb | 2 +- .../admin/usage_trends_controller_spec.rb | 2 +- .../product_analytics_tracking_spec.rb | 17 +-- .../cycle_analytics_controller_spec.rb | 2 +- .../projects/graphs_controller_spec.rb | 2 +- .../projects/pipelines_controller_spec.rb | 2 +- spec/controllers/search_controller_spec.rb | 2 +- .../cells/runner_owner_cell_spec.js | 111 ++++++++++++++++++ .../runner/components/runner_list_spec.js | 13 +- .../tracking/service_ping_context_spec.rb | 19 +++ ..._add_password_expiration_migration_spec.rb | 19 +++ ...rd_last_changed_at_to_user_details_spec.rb | 33 ++++++ .../snowplow_event_tracking_examples.rb | 12 +- 31 files changed, 432 insertions(+), 61 deletions(-) create mode 100644 app/assets/javascripts/runner/components/cells/runner_owner_cell.vue create mode 100644 db/migrate/20221008032350_add_password_expiration_migration.rb create mode 100644 db/migrate/20221012033107_add_password_last_changed_at_to_user_details.rb create mode 100644 db/schema_migrations/20221008032350 create mode 100644 db/schema_migrations/20221012033107 create mode 100644 lib/gitlab/tracking/service_ping_context.rb create mode 100644 spec/frontend/runner/components/cells/runner_owner_cell_spec.js create mode 100644 spec/lib/gitlab/tracking/service_ping_context_spec.rb create mode 100644 spec/migrations/20221008032350_add_password_expiration_migration_spec.rb create mode 100644 spec/migrations/20221012033107_add_password_last_changed_at_to_user_details_spec.rb diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index a867aa5854f..92f06ddc9eb 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -7a6ddce1d044e41ac9234e30cda62d85cbbc2a54 +d897d27c602d80b247af46a4ce672c2cd9b591ba diff --git a/app/assets/javascripts/runner/components/cells/runner_owner_cell.vue b/app/assets/javascripts/runner/components/cells/runner_owner_cell.vue new file mode 100644 index 00000000000..cb43760b2d6 --- /dev/null +++ b/app/assets/javascripts/runner/components/cells/runner_owner_cell.vue @@ -0,0 +1,63 @@ + + + diff --git a/app/assets/javascripts/runner/components/runner_list.vue b/app/assets/javascripts/runner/components/runner_list.vue index 26f1f3ce08c..d4a3311ff9f 100644 --- a/app/assets/javascripts/runner/components/runner_list.vue +++ b/app/assets/javascripts/runner/components/runner_list.vue @@ -2,15 +2,18 @@ import { GlFormCheckbox, GlTableLite, GlTooltipDirective, GlSkeletonLoader } from '@gitlab/ui'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { s__ } from '~/locale'; +import HelpPopover from '~/vue_shared/components/help_popover.vue'; import checkedRunnerIdsQuery from '../graphql/list/checked_runner_ids.query.graphql'; import { formatJobCount, tableField } from '../utils'; import RunnerStackedSummaryCell from './cells/runner_stacked_summary_cell.vue'; import RunnerStatusPopover from './runner_status_popover.vue'; import RunnerStatusCell from './cells/runner_status_cell.vue'; +import RunnerOwnerCell from './cells/runner_owner_cell.vue'; const defaultFields = [ tableField({ key: 'status', label: s__('Runners|Status'), thClasses: ['gl-w-15p'] }), tableField({ key: 'summary', label: s__('Runners|Runner') }), + tableField({ key: 'owner', label: s__('Runners|Owner'), thClasses: ['gl-w-20p'] }), tableField({ key: 'actions', label: '', thClasses: ['gl-w-15p'] }), ]; @@ -19,9 +22,11 @@ export default { GlFormCheckbox, GlTableLite, GlSkeletonLoader, + HelpPopover, RunnerStatusPopover, RunnerStackedSummaryCell, RunnerStatusCell, + RunnerOwnerCell, }, directives: { GlTooltip: GlTooltipDirective, @@ -140,6 +145,21 @@ export default { + + + + diff --git a/app/assets/javascripts/runner/constants.js b/app/assets/javascripts/runner/constants.js index 5f56151ad35..dfc5f0c4152 100644 --- a/app/assets/javascripts/runner/constants.js +++ b/app/assets/javascripts/runner/constants.js @@ -89,6 +89,7 @@ export const I18N_VERSION_LABEL = s__('Runners|Version %{version}'); export const I18N_LAST_CONTACT_LABEL = s__('Runners|Last contact: %{timeAgo}'); export const I18N_CREATED_AT_LABEL = s__('Runners|Created %{timeAgo}'); export const I18N_SHOW_ONLY_INHERITED = s__('Runners|Show only inherited'); +export const I18N_ADMIN = s__('Runners|Administrator'); // Runner details diff --git a/app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql b/app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql index a12ba7a751a..0dff011daaa 100644 --- a/app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql +++ b/app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql @@ -16,4 +16,18 @@ fragment ListItemShared on CiRunner { updateRunner deleteRunner } + groups(first: 1) { + nodes { + id + name + fullName + webUrl + } + } + ownerProject { + id + name + nameWithNamespace + webUrl + } } diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb index 8e936782e5a..4f96cc5c895 100644 --- a/app/controllers/concerns/product_analytics_tracking.rb +++ b/app/controllers/concerns/product_analytics_tracking.rb @@ -29,7 +29,13 @@ module ProductAnalyticsTracking track_unique_redis_hll_event(name, &block) if destinations.include?(:redis_hll) if destinations.include?(:snowplow) && event_enabled?(name) - Gitlab::Tracking.event(self.class.to_s, name, namespace: tracking_namespace_source, user: current_user) + Gitlab::Tracking.event( + self.class.to_s, + name, + namespace: tracking_namespace_source, + user: current_user, + context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: name).to_context] + ) end end @@ -49,6 +55,7 @@ module ProductAnalyticsTracking user: current_user, property: name, label: label, + context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: name).to_context], **optional_arguments ) end diff --git a/db/migrate/20221008032350_add_password_expiration_migration.rb b/db/migrate/20221008032350_add_password_expiration_migration.rb new file mode 100644 index 00000000000..7dbc73294bb --- /dev/null +++ b/db/migrate/20221008032350_add_password_expiration_migration.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class AddPasswordExpirationMigration < Gitlab::Database::Migration[2.0] + def change + add_column :application_settings, :password_expiration_enabled, :boolean, default: false, null: false, + comment: 'JiHu-specific column' + add_column :application_settings, :password_expires_in_days, :integer, default: 90, null: false, + comment: 'JiHu-specific column' + add_column :application_settings, :password_expires_notice_before_days, :integer, default: 7, null: false, + comment: 'JiHu-specific column' + end +end diff --git a/db/migrate/20221012033107_add_password_last_changed_at_to_user_details.rb b/db/migrate/20221012033107_add_password_last_changed_at_to_user_details.rb new file mode 100644 index 00000000000..db2f411ab92 --- /dev/null +++ b/db/migrate/20221012033107_add_password_last_changed_at_to_user_details.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddPasswordLastChangedAtToUserDetails < Gitlab::Database::Migration[2.0] + enable_lock_retries! + + def change + add_column :user_details, :password_last_changed_at, :datetime_with_timezone, comment: 'JiHu-specific column' + end +end diff --git a/db/schema_migrations/20221008032350 b/db/schema_migrations/20221008032350 new file mode 100644 index 00000000000..8b76b056a77 --- /dev/null +++ b/db/schema_migrations/20221008032350 @@ -0,0 +1 @@ +c5e373b1b416455b67b7bc0affe244295e1f1a2f105fe8ef6efddf8b07da2a86 \ No newline at end of file diff --git a/db/schema_migrations/20221012033107 b/db/schema_migrations/20221012033107 new file mode 100644 index 00000000000..ba1df6370d3 --- /dev/null +++ b/db/schema_migrations/20221012033107 @@ -0,0 +1 @@ +23252a63b8aab6a062cf22db563f8518213d40110449732866e6d8d5092d369e \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 3d607b2ea40..f36419194c8 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -11488,6 +11488,9 @@ CREATE TABLE application_settings ( lock_maven_package_requests_forwarding boolean DEFAULT false NOT NULL, lock_pypi_package_requests_forwarding boolean DEFAULT false NOT NULL, lock_npm_package_requests_forwarding boolean DEFAULT false NOT NULL, + password_expiration_enabled boolean DEFAULT false NOT NULL, + password_expires_in_days integer DEFAULT 90 NOT NULL, + password_expires_notice_before_days integer DEFAULT 7 NOT NULL, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)), CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), @@ -11570,6 +11573,12 @@ COMMENT ON COLUMN application_settings.encrypted_feishu_app_secret IS 'JiHu-spec COMMENT ON COLUMN application_settings.encrypted_feishu_app_secret_iv IS 'JiHu-specific column'; +COMMENT ON COLUMN application_settings.password_expiration_enabled IS 'JiHu-specific column'; + +COMMENT ON COLUMN application_settings.password_expires_in_days IS 'JiHu-specific column'; + +COMMENT ON COLUMN application_settings.password_expires_notice_before_days IS 'JiHu-specific column'; + CREATE SEQUENCE application_settings_id_seq START WITH 1 INCREMENT BY 1 @@ -22079,6 +22088,7 @@ CREATE TABLE user_details ( registration_objective smallint, phone text, requires_credit_card_verification boolean DEFAULT false NOT NULL, + password_last_changed_at timestamp with time zone, CONSTRAINT check_245664af82 CHECK ((char_length(webauthn_xid) <= 100)), CONSTRAINT check_a73b398c60 CHECK ((char_length(phone) <= 50)), CONSTRAINT check_eeeaf8d4f0 CHECK ((char_length(pronouns) <= 50)), @@ -22087,6 +22097,8 @@ CREATE TABLE user_details ( COMMENT ON COLUMN user_details.phone IS 'JiHu-specific column'; +COMMENT ON COLUMN user_details.password_last_changed_at IS 'JiHu-specific column'; + CREATE SEQUENCE user_details_user_id_seq START WITH 1 INCREMENT BY 1 diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 4a9cf3df5fc..67dea28cbd5 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -5861,6 +5861,7 @@ Input type: `WorkItemUpdateInput` | `labelsWidget` | [`WorkItemWidgetLabelsUpdateInput`](#workitemwidgetlabelsupdateinput) | Input for labels widget. | | `startAndDueDateWidget` | [`WorkItemWidgetStartAndDueDateUpdateInput`](#workitemwidgetstartandduedateupdateinput) | Input for start and due date widget. | | `stateEvent` | [`WorkItemStateEvent`](#workitemstateevent) | Close or reopen a work item. | +| `statusWidget` | [`StatusInput`](#statusinput) | Input for status widget. | | `title` | [`String`](#string) | Title of the work item. | | `weightWidget` | [`WorkItemWidgetWeightInput`](#workitemwidgetweightinput) | Input for weight widget. | @@ -23435,6 +23436,14 @@ Represents an action to perform over a snippet file. | `filePath` | [`String!`](#string) | Path of the snippet file. | | `previousPath` | [`String`](#string) | Previous path of the snippet file. | +### `StatusInput` + +#### Arguments + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `status` | [`TestReportState!`](#testreportstate) | Status to assign to the work item. | + ### `Timeframe` A time-frame defined as a closed inclusive range of two dates. diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md index 69536e0fbb7..a2e03ac43b3 100644 --- a/doc/ci/variables/predefined_variables.md +++ b/doc/ci/variables/predefined_variables.md @@ -39,6 +39,7 @@ as it can cause the pipeline to behave unexpectedly. | `CI_COMMIT_SHA` | 9.0 | all | The commit revision the project is built for. | | `CI_COMMIT_SHORT_SHA` | 11.7 | all | The first eight characters of `CI_COMMIT_SHA`. | | `CI_COMMIT_TAG` | 9.0 | 0.5 | The commit tag name. Available only in pipelines for tags. | +| `CI_COMMIT_TAG_MESSAGE` | 15.5 | all | The commit tag message. Avaiable only in pipelines for tags. | | `CI_COMMIT_TIMESTAMP` | 13.4 | all | The timestamp of the commit in the ISO 8601 format. | | `CI_COMMIT_TITLE` | 10.8 | all | The title of the commit. The full first line of the message. | | `CI_CONCURRENT_ID` | all | 11.10 | The unique ID of build execution in a single executor. | @@ -60,6 +61,7 @@ as it can cause the pipeline to behave unexpectedly. | `CI_ENVIRONMENT_URL` | 9.3 | all | The URL of the environment for this job. Available if [`environment:url`](../yaml/index.md#environmenturl) is set. | | `CI_ENVIRONMENT_ACTION` | 13.11 | all | The action annotation specified for this job's environment. Available if [`environment:action`](../yaml/index.md#environmentaction) is set. Can be `start`, `prepare`, or `stop`. | | `CI_ENVIRONMENT_TIER` | 14.0 | all | The [deployment tier of the environment](../environments/index.md#deployment-tier-of-environments) for this job. | +| `CI_RELEASE_DESCRIPTION` | 15.5 | all | The description of the release. Available only on pipelines for tags. Description length is limited to first 1024 characters.| | `CI_GITLAB_FIPS_MODE` | 14.10 | all | The configuration setting for whether FIPS mode is enabled in the GitLab instance. | | `CI_HAS_OPEN_REQUIREMENTS` | 13.1 | all | Only available if the pipeline's project has an open [requirement](../../user/project/requirements/index.md). `true` when available. | | `CI_JOB_ID` | 9.0 | all | The internal ID of the job, unique across all jobs in the GitLab instance. | diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md index 9d99550ad8d..65ad8dea688 100644 --- a/doc/development/documentation/styleguide/word_list.md +++ b/doc/development/documentation/styleguide/word_list.md @@ -513,13 +513,16 @@ For example, **Snowplow Guide**. Instead, speak about the feature itself, and ho When writing about the Guest role: - Use a capital **G**. -- Do not use bold. -- Do not use the phrase, **if you are a guest** to mean someone who is assigned the Guest - role. Instead, write it out. For example, **if you are assigned the Guest role**. -- To describe a situation where the Guest role is the minimum required: +- Write it out: + - Use: if you are assigned the Guest role + - Instead of: if you are a guest + +- When the Guest role is the minimum required role: - Use: at least the Guest role - Instead of: the Guest role or higher +Do not use bold. + Do not use **Guest permissions**. A user who is assigned the Guest role has a set of associated permissions. ## handy @@ -660,13 +663,16 @@ Instead of: When writing about the Maintainer role: - Use a capital **M**. -- Do not use bold. -- Do not use the phrase, **if you are a maintainer** to mean someone who is assigned the Maintainer - role. Instead, write it out. For example, **if you are assigned the Maintainer role**. -- To describe a situation where the Maintainer role is the minimum required: +- Write it out. + - Use: if you are assigned the Maintainer role + - Instead of: if you are a maintainer + +- When the Maintainer role is the minimum required role: - Use: at least the Maintainer role - Instead of: the Maintainer role or higher +Do not use bold. + Do not use **Maintainer permissions**. A user who is assigned the Maintainer role has a set of associated permissions. ## mankind @@ -800,11 +806,14 @@ For example, a log file might overwrite a log file of the same name. When writing about the Owner role: - Use a capital **O**. -- Do not use bold. -- Do not use the phrase, **if you are an owner** to mean someone who is assigned the Owner - role. Instead, write it out. For example, **if you are assigned the Owner role**. +- Write it out. + - Use: if you are assigned the Owner role + - Instead of: if you are an owner +Do not use bold. + Do not use **Owner permissions**. A user who is assigned the Owner role has a set of associated permissions. +An Owner is the highest role a user can have. ## Package Registry @@ -855,13 +864,16 @@ Use **register** instead of **sign up** when talking about creating an account. When writing about the Reporter role: - Use a capital **R**. -- Do not use bold. -- Do not use the phrase, **if you are a reporter** to mean someone who is assigned the Reporter - role. Instead, write it out. For example, **if you are assigned the Reporter role**. -- To describe a situation where the Reporter role is the minimum required: +- Write it out. + - Use: if you are assigned the Reporter role + - Instead of: if you are a reporter + +- When the Reporter role is the minimum required role: - Use: at least the Reporter role - Instead of: the Reporter role or higher +Do not use bold. + Do not use **Reporter permissions**. A user who is assigned the Reporter role has a set of associated permissions. ## Repository Mirroring diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md index cc81b5e0b33..fd01dd451c2 100644 --- a/doc/user/project/releases/index.md +++ b/doc/user/project/releases/index.md @@ -61,7 +61,6 @@ You can create a release: - [Using a job in your CI/CD pipeline](#creating-a-release-by-using-a-cicd-job). - [In the Releases page](#create-a-release-in-the-releases-page). -- [In the Tags page](#create-a-release-in-the-tags-page). - Using the [Releases API](../../../api/releases/index.md#create-a-release). We recommend creating a release as one of the last steps in your CI/CD pipeline. @@ -93,29 +92,6 @@ To create a release in the Releases page: - [Asset links](release_fields.md#links). 1. Select **Create release**. -### Create a release in the Tags page - -To create a release in the Tags page, add release notes to either an existing or a new Git tag. - -To add release notes to a new Git tag: - -1. On the top bar, select **Main menu > Projects** and find your project. -1. On the left sidebar, select **Repository > Tags**. -1. Select **New tag**. -1. Optional. Enter a tag message in the **Message** text box. -1. In the **Release notes** text box, enter the release's description. - You can use Markdown and drag and drop files to this text box. -1. Select **Create tag**. - -To edit release notes of an existing Git tag: - -1. On the top bar, select **Main menu > Projects** and find your project. -1. On the left sidebar, select **Repository > Tags**. -1. Select **Edit release notes** (**{pencil}**). -1. In the **Release notes** text box, enter the release's description. - You can use Markdown and drag and drop files to this text box. -1. Select **Save changes**. - ### Creating a release by using a CI/CD job You can create a release directly as part of the GitLab CI/CD pipeline by using the diff --git a/lib/gitlab/tracking/service_ping_context.rb b/lib/gitlab/tracking/service_ping_context.rb new file mode 100644 index 00000000000..393cd647e7f --- /dev/null +++ b/lib/gitlab/tracking/service_ping_context.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Gitlab + module Tracking + class ServicePingContext + SCHEMA_URL = 'iglu:com.gitlab/gitlab_service_ping/jsonschema/1-0-0' + ALLOWED_SOURCES = %i[redis_hll].freeze + + def initialize(data_source:, event:) + unless ALLOWED_SOURCES.include?(data_source) + raise ArgumentError, "#{data_source} is not acceptable data source for ServicePingContext" + end + + @payload = { + data_source: data_source, + event_name: event + } + end + + def to_context + SnowplowTracker::SelfDescribingJson.new(SCHEMA_URL, @payload) + end + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 8d645180967..5a83c2483ed 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -34575,6 +34575,9 @@ msgstr "" msgid "Runners|Add your feedback in the issue" msgstr "" +msgid "Runners|Administrator" +msgstr "" + msgid "Runners|All" msgstr "" @@ -34781,6 +34784,9 @@ msgstr "" msgid "Runners|Online:" msgstr "" +msgid "Runners|Owner" +msgstr "" + msgid "Runners|Pause from accepting jobs" msgstr "" @@ -34963,6 +34969,9 @@ msgstr "" msgid "Runners|The new view gives you more space and better visibility into your fleet of runners." msgstr "" +msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator." +msgstr "" + msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?" msgstr "" diff --git a/spec/controllers/admin/cohorts_controller_spec.rb b/spec/controllers/admin/cohorts_controller_spec.rb index 766073977c6..50626a5da91 100644 --- a/spec/controllers/admin/cohorts_controller_spec.rb +++ b/spec/controllers/admin/cohorts_controller_spec.rb @@ -14,7 +14,7 @@ RSpec.describe Admin::CohortsController do let(:target_id) { 'i_analytics_cohorts' } end - it_behaves_like 'Snowplow event tracking' do + it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :index } let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } diff --git a/spec/controllers/admin/dev_ops_report_controller_spec.rb b/spec/controllers/admin/dev_ops_report_controller_spec.rb index 5d7a7e089aa..52a46b5e99a 100644 --- a/spec/controllers/admin/dev_ops_report_controller_spec.rb +++ b/spec/controllers/admin/dev_ops_report_controller_spec.rb @@ -29,7 +29,7 @@ RSpec.describe Admin::DevOpsReportController do let(:request_params) { { tab: 'devops-score' } } end - it_behaves_like 'Snowplow event tracking' do + it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :show, format: :html } let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } diff --git a/spec/controllers/admin/usage_trends_controller_spec.rb b/spec/controllers/admin/usage_trends_controller_spec.rb index 356f603bf57..87cf8988b4e 100644 --- a/spec/controllers/admin/usage_trends_controller_spec.rb +++ b/spec/controllers/admin/usage_trends_controller_spec.rb @@ -14,7 +14,7 @@ RSpec.describe Admin::UsageTrendsController do let(:target_id) { 'i_analytics_instance_statistics' } end - it_behaves_like 'Snowplow event tracking' do + it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :index } let(:feature_flag_name) { :route_hll_to_snowplow_phase2 } diff --git a/spec/controllers/concerns/product_analytics_tracking_spec.rb b/spec/controllers/concerns/product_analytics_tracking_spec.rb index 2e734d81ea0..f85b6806f30 100644 --- a/spec/controllers/concerns/product_analytics_tracking_spec.rb +++ b/spec/controllers/concerns/product_analytics_tracking_spec.rb @@ -55,11 +55,19 @@ RSpec.describe ProductAnalyticsTracking, :snowplow do expect(Gitlab::UsageDataCounters::HLLRedisCounter).to have_received(:track_event) .with('g_analytics_valuestream', values: instance_of(String)) + expect_snowplow_tracking(user) + end + + def expect_snowplow_tracking(user) + context = Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'g_analytics_valuestream') + .to_context.to_json + expect_snowplow_event( category: anything, action: 'g_analytics_valuestream', namespace: group, - user: user + user: user, + context: [context] ) end @@ -160,12 +168,7 @@ RSpec.describe ProductAnalyticsTracking, :snowplow do get :show, params: { id: 2 } expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event) - expect_snowplow_event( - category: anything, - action: 'g_analytics_valuestream', - namespace: group, - user: nil - ) + expect_snowplow_tracking(nil) end end end diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb index f5dd8abd67b..034e6104f99 100644 --- a/spec/controllers/projects/cycle_analytics_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb @@ -31,7 +31,7 @@ RSpec.describe Projects::CycleAnalyticsController do let(:target_id) { 'p_analytics_valuestream' } end - it_behaves_like 'Snowplow event tracking' do + it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :show, params: request_params, format: :html } let(:request_params) { { namespace_id: project.namespace, project_id: project } } diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index 9227c7dd70a..3dfc22927cf 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -90,7 +90,7 @@ RSpec.describe Projects::GraphsController do let(:target_id) { 'p_analytics_repo' } end - it_behaves_like 'Snowplow event tracking' do + it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject do sign_in(user) get :charts, params: request_params, format: :html diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index b9acaf65892..6e2de0c4d57 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -859,7 +859,7 @@ RSpec.describe Projects::PipelinesController do let(:target_id) { ['p_analytics_pipelines', tab[:event]] } end - it_behaves_like 'Snowplow event tracking' do + it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :charts, params: request_params, format: :html } let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id, chart: tab[:chart_param] } } diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 4131bd148da..7ab66b04a6e 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -218,7 +218,7 @@ RSpec.describe SearchController do end end - it_behaves_like 'Snowplow event tracking' do + it_behaves_like 'Snowplow event tracking with RedisHLL context' do subject { get :show, params: { group_id: namespace.id, scope: 'blobs', search: 'term' } } let(:project) { nil } diff --git a/spec/frontend/runner/components/cells/runner_owner_cell_spec.js b/spec/frontend/runner/components/cells/runner_owner_cell_spec.js new file mode 100644 index 00000000000..e9965d8855d --- /dev/null +++ b/spec/frontend/runner/components/cells/runner_owner_cell_spec.js @@ -0,0 +1,111 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlLink } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; + +import RunnerOwnerCell from '~/runner/components/cells/runner_owner_cell.vue'; + +import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/runner/constants'; + +describe('RunnerOwnerCell', () => { + let wrapper; + + const findLink = () => wrapper.findComponent(GlLink); + const getLinkTooltip = () => getBinding(findLink().element, 'gl-tooltip').value; + + const createComponent = ({ runner } = {}) => { + wrapper = shallowMount(RunnerOwnerCell, { + directives: { + GlTooltip: createMockDirective(), + }, + propsData: { + runner, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('When its an instance runner', () => { + beforeEach(() => { + createComponent({ + runner: { + runnerType: INSTANCE_TYPE, + }, + }); + }); + + it('shows an administrator label', () => { + expect(findLink().exists()).toBe(false); + expect(wrapper.text()).toBe(s__('Runners|Administrator')); + }); + }); + + describe('When its a group runner', () => { + const mockName = 'Group 2'; + const mockFullName = 'Group 1 / Group 2'; + const mockWebUrl = '/group-1/group-2'; + + beforeEach(() => { + createComponent({ + runner: { + runnerType: GROUP_TYPE, + groups: { + nodes: [ + { + name: mockName, + fullName: mockFullName, + webUrl: mockWebUrl, + }, + ], + }, + }, + }); + }); + + it('Displays a group link', () => { + expect(findLink().attributes('href')).toBe(mockWebUrl); + expect(wrapper.text()).toBe(mockName); + expect(getLinkTooltip()).toBe(mockFullName); + }); + }); + + describe('When its a project runner', () => { + const mockName = 'Project 1'; + const mockNameWithNamespace = 'Group 1 / Project 1'; + const mockWebUrl = '/group-1/project-1'; + + beforeEach(() => { + createComponent({ + runner: { + runnerType: PROJECT_TYPE, + ownerProject: { + name: mockName, + nameWithNamespace: mockNameWithNamespace, + webUrl: mockWebUrl, + }, + }, + }); + }); + + it('Displays a project link', () => { + expect(findLink().attributes('href')).toBe(mockWebUrl); + expect(wrapper.text()).toBe(mockName); + expect(getLinkTooltip()).toBe(mockNameWithNamespace); + }); + }); + + describe('When its an empty runner', () => { + beforeEach(() => { + createComponent({ + runner: {}, + }); + }); + + it('shows no label', () => { + expect(wrapper.text()).toBe(''); + }); + }); +}); diff --git a/spec/frontend/runner/components/runner_list_spec.js b/spec/frontend/runner/components/runner_list_spec.js index 54a9e713721..f20644a9269 100644 --- a/spec/frontend/runner/components/runner_list_spec.js +++ b/spec/frontend/runner/components/runner_list_spec.js @@ -1,12 +1,13 @@ import { GlTableLite, GlSkeletonLoader } from '@gitlab/ui'; +import HelpPopover from '~/vue_shared/components/help_popover.vue'; import { extendedWrapper, shallowMountExtended, mountExtended, } from 'helpers/vue_test_utils_helper'; +import { s__ } from '~/locale'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import RunnerList from '~/runner/components/runner_list.vue'; -import RunnerStatusPopover from '~/runner/components/runner_status_popover.vue'; import { I18N_PROJECT_TYPE, I18N_STATUS_NEVER_CONTACTED } from '~/runner/constants'; import { allRunnersData, onlineContactTimeoutSecs, staleTimeoutSecs } from '../mock_data'; @@ -50,7 +51,7 @@ describe('RunnerList', () => { createComponent( { stubs: { - RunnerStatusPopover: { + HelpPopover: { template: '
', }, }, @@ -60,11 +61,13 @@ describe('RunnerList', () => { const headerLabels = findHeaders().wrappers.map((w) => w.text()); - expect(findHeaders().at(0).findComponent(RunnerStatusPopover).exists()).toBe(true); + expect(findHeaders().at(0).findComponent(HelpPopover).exists()).toBe(true); + expect(findHeaders().at(2).findComponent(HelpPopover).exists()).toBe(true); expect(headerLabels).toEqual([ - 'Status', - 'Runner', + s__('Runners|Status'), + s__('Runners|Runner'), + s__('Runners|Owner'), '', // actions has no label ]); }); diff --git a/spec/lib/gitlab/tracking/service_ping_context_spec.rb b/spec/lib/gitlab/tracking/service_ping_context_spec.rb new file mode 100644 index 00000000000..d70dfaa4e0b --- /dev/null +++ b/spec/lib/gitlab/tracking/service_ping_context_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Tracking::ServicePingContext do + describe '#init' do + it 'does not accept unsupported data sources' do + expect { described_class.new(data_source: :random, event: 'event a') }.to raise_error(ArgumentError) + end + end + + describe '#to_context' do + let(:subject) { described_class.new(data_source: :redis_hll, event: 'sample_event') } + + it 'contains event_name' do + expect(subject.to_context.to_json.dig(:data, :event_name)).to eq('sample_event') + end + end +end diff --git a/spec/migrations/20221008032350_add_password_expiration_migration_spec.rb b/spec/migrations/20221008032350_add_password_expiration_migration_spec.rb new file mode 100644 index 00000000000..05e557f1f52 --- /dev/null +++ b/spec/migrations/20221008032350_add_password_expiration_migration_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe AddPasswordExpirationMigration do + let(:application_setting) { table(:application_settings).create! } + + describe "#up" do + it 'allows to read password expiration fields' do + migrate! + + expect(application_setting.password_expiration_enabled).to eq false + expect(application_setting.password_expires_in_days).to eq 90 + expect(application_setting.password_expires_notice_before_days).to eq 7 + end + end +end diff --git a/spec/migrations/20221012033107_add_password_last_changed_at_to_user_details_spec.rb b/spec/migrations/20221012033107_add_password_last_changed_at_to_user_details_spec.rb new file mode 100644 index 00000000000..46a7b097d02 --- /dev/null +++ b/spec/migrations/20221012033107_add_password_last_changed_at_to_user_details_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe AddPasswordLastChangedAtToUserDetails do + let_it_be(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } + let_it_be(:users) { table(:users) } + let_it_be(:user) { create_user! } + let(:user_detail) { table(:user_details).create!(user_id: user.id, provisioned_by_group_id: namespace.id) } + + describe "#up" do + it 'allows to read password_last_changed_at' do + migrate! + + expect(user_detail.password_last_changed_at).to eq nil + end + end + + private + + def create_user!(name: "Example User", email: "user@example.com", user_type: nil) + users.create!( + name: name, + email: email, + username: name, + projects_limit: 0, + user_type: user_type, + confirmed_at: Time.current + ) + end +end diff --git a/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb b/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb index 4af3c0cc6cc..6749ebd471f 100644 --- a/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb +++ b/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb @@ -32,7 +32,8 @@ RSpec.shared_examples 'Snowplow event tracking' do |overrides: {}| user: try(:user), project: try(:project), label: try(:label), - property: try(:property) + property: try(:property), + context: try(:context) }.merge(overrides).compact.merge(extra) subject @@ -40,3 +41,12 @@ RSpec.shared_examples 'Snowplow event tracking' do |overrides: {}| expect_snowplow_event(**params) end end + +RSpec.shared_examples 'Snowplow event tracking with RedisHLL context' do |overrides: {}| + it_behaves_like 'Snowplow event tracking', overrides: overrides do + let(:context) do + event = try(:property) || action + [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event).to_context.to_json] + end + end +end