summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-11-03 15:11:31 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-03 15:11:31 +0000
commite6fa9529b4922a4c552e8908a2929ff995e8b53d (patch)
tree9ccfea4d253faa8c202f753631961a794af44ad6
parent720cf698151643831bf36e3bd4ccd1c8e9246184 (diff)
downloadgitlab-ce-e6fa9529b4922a4c552e8908a2929ff995e8b53d.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/as-if-jh.gitlab-ci.yml63
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml33
-rw-r--r--.rubocop.yml6
-rw-r--r--.rubocop_todo/graphql/enum_names.yml37
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/boards/components/board_content.vue25
-rw-r--r--app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue84
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue29
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue15
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js1
-rw-r--r--app/assets/stylesheets/framework/variables.scss11
-rw-r--r--app/assets/stylesheets/page_bundles/boards.scss29
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/models/concerns/pg_full_text_searchable.rb2
-rw-r--r--app/services/groups/update_service.rb4
-rw-r--r--app/services/incident_management/timeline_events/create_service.rb3
-rw-r--r--config/feature_flags/development/lazy_load_commits.yml2
-rw-r--r--config/feature_flags/development/refactor_code_quality_extension.yml8
-rw-r--r--config/open_api.yml6
-rw-r--r--doc/api/feature_flags.md2
-rw-r--r--doc/api/releases/index.md12
-rw-r--r--doc/development/ee_features.md2
-rw-r--r--doc/development/pipelines/index.md134
-rw-r--r--doc/development/reusing_abstractions.md3
-rw-r--r--doc/install/installation.md12
-rw-r--r--doc/operations/incident_management/img/timeline_event_for_severity_change_v15_6.pngbin9608 -> 10377 bytes
-rw-r--r--doc/update/index.md4
-rw-r--r--doc/user/public_access.md5
-rw-r--r--lib/api/alert_management_alerts.rb2
-rw-r--r--lib/api/api.rb8
-rw-r--r--lib/api/boards.rb2
-rw-r--r--lib/api/branches.rb2
-rw-r--r--lib/api/ci/job_artifacts.rb2
-rw-r--r--lib/api/ci/jobs.rb2
-rw-r--r--lib/api/ci/pipeline_schedules.rb2
-rw-r--r--lib/api/ci/resource_groups.rb2
-rw-r--r--lib/api/ci/runners.rb4
-rw-r--r--lib/api/ci/secure_files.rb2
-rw-r--r--lib/api/ci/triggers.rb2
-rw-r--r--lib/api/ci/variables.rb2
-rw-r--r--lib/api/clusters/agent_tokens.rb2
-rw-r--r--lib/api/clusters/agents.rb2
-rw-r--r--lib/api/commit_statuses.rb2
-rw-r--r--lib/api/commits.rb2
-rw-r--r--lib/api/container_repositories.rb2
-rw-r--r--lib/api/debian_project_packages.rb2
-rw-r--r--lib/api/entities/basic_release_details.rb12
-rw-r--r--lib/api/entities/feature_flag.rb12
-rw-r--r--lib/api/entities/feature_flag/scope.rb4
-rw-r--r--lib/api/entities/feature_flag/strategy.rb6
-rw-r--r--lib/api/entities/release.rb8
-rw-r--r--lib/api/entities/releases/evidence.rb6
-rw-r--r--lib/api/entities/releases/link.rb20
-rw-r--r--lib/api/entities/releases/source.rb4
-rw-r--r--lib/api/entities/ssh_key.rb11
-rw-r--r--lib/api/entities/user_basic.rb6
-rw-r--r--lib/api/entities/user_public.rb26
-rw-r--r--lib/api/entities/user_safe.rb5
-rw-r--r--lib/api/error_tracking/client_keys.rb2
-rw-r--r--lib/api/error_tracking/collector.rb4
-rw-r--r--lib/api/error_tracking/project_settings.rb2
-rw-r--r--lib/api/feature_flags.rb51
-rw-r--r--lib/api/generic_packages.rb2
-rwxr-xr-xlib/api/go_proxy.rb12
-rw-r--r--lib/api/helpers/packages_helpers.rb30
-rw-r--r--lib/api/integrations.rb4
-rw-r--r--lib/api/issue_links.rb2
-rw-r--r--lib/api/issues.rb2
-rw-r--r--lib/api/keys.rb12
-rw-r--r--lib/api/labels.rb2
-rw-r--r--lib/api/maven_packages.rb2
-rw-r--r--lib/api/merge_request_diffs.rb2
-rw-r--r--lib/api/merge_requests.rb2
-rw-r--r--lib/api/ml/mlflow.rb2
-rw-r--r--lib/api/npm_project_packages.rb2
-rw-r--r--lib/api/nuget_project_packages.rb2
-rw-r--r--lib/api/package_files.rb2
-rw-r--r--lib/api/pages.rb2
-rw-r--r--lib/api/pages_domains.rb2
-rw-r--r--lib/api/project_clusters.rb2
-rw-r--r--lib/api/project_container_repositories.rb2
-rw-r--r--lib/api/project_debian_distributions.rb2
-rw-r--r--lib/api/project_events.rb2
-rw-r--r--lib/api/project_export.rb2
-rw-r--r--lib/api/project_hooks.rb2
-rw-r--r--lib/api/project_import.rb2
-rw-r--r--lib/api/project_milestones.rb2
-rw-r--r--lib/api/project_packages.rb2
-rw-r--r--lib/api/project_repository_storage_moves.rb2
-rw-r--r--lib/api/project_snippets.rb2
-rw-r--r--lib/api/project_statistics.rb2
-rw-r--r--lib/api/project_templates.rb2
-rw-r--r--lib/api/projects.rb2
-rw-r--r--lib/api/protected_branches.rb5
-rw-r--r--lib/api/protected_tags.rb2
-rw-r--r--lib/api/pypi_packages.rb2
-rw-r--r--lib/api/releases.rb187
-rw-r--r--lib/api/remote_mirrors.rb2
-rw-r--r--lib/api/repositories.rb2
-rw-r--r--lib/api/rpm_project_packages.rb2
-rw-r--r--lib/api/search.rb2
-rw-r--r--lib/api/tags.rb2
-rw-r--r--lib/api/terraform/state.rb2
-rw-r--r--lib/api/terraform/state_version.rb2
-rw-r--r--lib/gitlab/gitaly_client.rb2
-rw-r--r--rubocop/cop/graphql/enum_names.rb87
-rwxr-xr-xscripts/setup/as-if-jh.sh28
-rw-r--r--spec/frontend/boards/components/board_content_spec.js36
-rw-r--r--spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js151
-rw-r--r--spec/frontend/reports/codequality_report/store/actions_spec.js1
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js63
-rw-r--r--spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js22
-rw-r--r--spec/lib/api/helpers/packages_helpers_spec.rb119
-rw-r--r--spec/models/concerns/pg_full_text_searchable_spec.rb11
-rw-r--r--spec/models/factories_spec.rb7
-rw-r--r--spec/requests/api/go_proxy_spec.rb13
-rw-r--r--spec/rubocop/cop/graphql/enum_names_spec.rb52
-rw-r--r--spec/scripts/trigger-build_spec.rb1
-rw-r--r--spec/services/groups/update_service_spec.rb9
-rw-r--r--spec/services/incident_management/timeline_events/create_service_spec.rb2
-rw-r--r--spec/tasks/gitlab/gitaly_rake_spec.rb2
-rw-r--r--workhorse/go.mod2
-rw-r--r--workhorse/go.sum3
123 files changed, 1127 insertions, 564 deletions
diff --git a/.gitlab/ci/as-if-jh.gitlab-ci.yml b/.gitlab/ci/as-if-jh.gitlab-ci.yml
new file mode 100644
index 00000000000..6019c8a9649
--- /dev/null
+++ b/.gitlab/ci/as-if-jh.gitlab-ci.yml
@@ -0,0 +1,63 @@
+.shared-as-if-jh:
+ variables:
+ SANDBOX_PROJECT: "gitlab-org-sandbox/gitlab-jh-validation"
+ SANDBOX_REPOSITORY: "https://dummy:${AS_IF_JH_TOKEN}@gitlab.com/${SANDBOX_PROJECT}.git"
+ GITLAB_JH_MIRROR_PROJECT: "33019816"
+ AS_IF_JH_BRANCH: "as-if-jh/${CI_COMMIT_REF_NAME}"
+ JH_FILES_TO_COMMIT: "jh package.json yarn.lock"
+
+add-jh-files:
+ extends:
+ - .shared-as-if-jh
+ - .as-if-jh:rules:prepare-as-if-jh
+ image: ${GITLAB_DEPENDENCY_PROXY}ruby:${RUBY_VERSION}
+ stage: prepare
+ before_script:
+ - source ./scripts/utils.sh
+ - source ./scripts/setup/as-if-jh.sh
+ - install_gitlab_gem
+ script:
+ - prepare_jh_branch
+ - download_jh_path ${JH_FILES_TO_COMMIT}
+ - echoinfo "Changes after downloading JiHu files:"
+ - git diff
+ - git status
+ artifacts:
+ expire_in: 2d
+ paths:
+ # This should match JH_FILES_TO_COMMIT
+ - jh/
+ - package.json
+ - yarn.lock
+
+prepare-as-if-jh-branch:
+ extends:
+ - .shared-as-if-jh
+ - .as-if-jh:rules:prepare-as-if-jh
+ stage: prepare
+ needs:
+ - add-jh-files
+ script:
+ - git checkout -b "${AS_IF_JH_BRANCH}"
+ - git add ${JH_FILES_TO_COMMIT}
+ - git commit -m 'Add JH files' # TODO: Mark which SHA we add
+ # Fetch for the history of the branch so it does not cause the following error:
+ # ! [remote rejected] ref -> ref (shallow update not allowed)
+ - git fetch --unshallow --filter=tree:0 origin "${CI_COMMIT_REF_NAME}"
+ - git push -f "${SANDBOX_REPOSITORY}" "${AS_IF_JH_BRANCH}"
+
+start-as-if-jh:
+ extends:
+ - .shared-as-if-jh
+ - .as-if-jh:rules:start-as-if-jh
+ stage: prepare
+ needs: ["prepare-as-if-jh-branch"]
+ inherit:
+ variables: false
+ variables:
+ AS_IF_EDITION: "jh"
+ FORCE_GITLAB_CI: "true" # TODO: Trigger a merge request pipeline
+ trigger:
+ project: gitlab-org-sandbox/gitlab-jh-validation # ${SANDBOX_PROJECT} does not work here
+ branch: as-if-jh/${CI_COMMIT_REF_NAME} # ${AS_IF_JH_BRANCH} does not work here
+ strategy: depend
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index f3f40256538..c8b1b374b24 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -5,13 +5,17 @@
if: '$CI_PROJECT_NAMESPACE !~ /^gitlab(-org)?($|\/)/'
.if-not-ee: &if-not-ee
- if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/'
+ # Only consider FOSS not EE
+ if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/ && $CI_PROJECT_NAME !~ /^gitlab-jh/'
.if-not-foss: &if-not-foss
if: '$CI_PROJECT_NAME != "gitlab-foss" && $CI_PROJECT_NAME != "gitlab-ce" && $CI_PROJECT_NAME != "gitlabhq"'
.if-jh: &if-jh
- if: '$CI_PROJECT_PATH =~ /^gitlab-(jh|cn)\/.*/'
+ # Example of these projects:
+ # https://jihulab.com/gitlab-cn/gitlab
+ # https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation
+ if: '$CI_PROJECT_PATH =~ /^gitlab-(jh|cn)\/.*/ || $CI_PROJECT_NAME =~ /^gitlab-jh/'
.if-force-ci: &if-force-ci
if: '$FORCE_GITLAB_CI'
@@ -560,6 +564,13 @@
- <<: *if-jh
when: never
+.as-if-jh-default-exclusion-rules:
+ rules:
+ - <<: *if-security-merge-request
+ when: never
+ - <<: *if-merge-request-targeting-stable-branch
+ when: never
+
.rails:rules:minimal-default-rules:
rules:
- <<: *if-merge-request-approved
@@ -2024,3 +2035,21 @@
rules:
- <<: *if-default-refs
changes: *lint-metrics-yaml-patterns
+
+##################
+# as-if-jh rules #
+##################
+.as-if-jh:rules:prepare-as-if-jh:
+ rules:
+ - !reference [".strict-ee-only-rules", rules]
+ - !reference [".as-if-jh-default-exclusion-rules", rules]
+ - <<: *if-merge-request-labels-as-if-jh
+
+# This rule should share the same logic with .as-if-jh:rules:prepare-as-if-jh
+# Because the jobs using this need jobs using the preparation rules
+.as-if-jh:rules:start-as-if-jh:
+ rules:
+ - !reference [".strict-ee-only-rules", rules]
+ - !reference [".as-if-jh-default-exclusion-rules", rules]
+ - <<: *if-merge-request-labels-as-if-jh
+ allow_failure: true # See https://gitlab.com/gitlab-org/gitlab/-/issues/351136
diff --git a/.rubocop.yml b/.rubocop.yml
index 8224f104674..3ae3ce89be0 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -590,6 +590,12 @@ Graphql/Descriptions:
- 'app/graphql/**/*'
- 'ee/app/graphql/**/*'
+Graphql/EnumNames:
+ Enabled: true
+ Include:
+ - 'app/graphql/**/*'
+ - 'ee/app/graphql/**/*'
+
# Cops for upgrade to gitlab-styles 3.1.0
RSpec/ImplicitSubject:
Enabled: false
diff --git a/.rubocop_todo/graphql/enum_names.yml b/.rubocop_todo/graphql/enum_names.yml
new file mode 100644
index 00000000000..18f485b6759
--- /dev/null
+++ b/.rubocop_todo/graphql/enum_names.yml
@@ -0,0 +1,37 @@
+---
+Graphql/EnumNames:
+ Details: grace period
+ Exclude:
+ - 'app/graphql/types/access_level_enum.rb'
+ - 'app/graphql/types/availability_enum.rb'
+ - 'app/graphql/types/ci/pipeline_config_source_enum.rb'
+ - 'app/graphql/types/ci/pipeline_scope_enum.rb'
+ - 'app/graphql/types/ci/pipeline_status_enum.rb'
+ - 'app/graphql/types/container_expiration_policy_cadence_enum.rb'
+ - 'app/graphql/types/container_expiration_policy_keep_enum.rb'
+ - 'app/graphql/types/container_expiration_policy_older_than_enum.rb'
+ - 'app/graphql/types/data_visualization_palette/color_enum.rb'
+ - 'app/graphql/types/data_visualization_palette/weight_enum.rb'
+ - 'app/graphql/types/merge_strategy_enum.rb'
+ - 'app/graphql/types/milestone_state_enum.rb'
+ - 'app/graphql/types/packages/cleanup/keep_duplicated_package_files_enum.rb'
+ - 'app/graphql/types/packages/conan/metadatum_file_type_enum.rb'
+ - 'app/graphql/types/packages/package_type_enum.rb'
+ - 'app/graphql/types/security/report_type_enum.rb'
+ - 'app/graphql/types/snippets/blob_action_enum.rb'
+ - 'app/graphql/types/snippets/type_enum.rb'
+ - 'app/graphql/types/snippets/visibility_scopes_enum.rb'
+ - 'app/graphql/types/sort_direction_enum.rb'
+ - 'app/graphql/types/todo_action_enum.rb'
+ - 'app/graphql/types/todo_state_enum.rb'
+ - 'app/graphql/types/todo_target_enum.rb'
+ - 'app/graphql/types/user_callout_feature_name_enum.rb'
+ - 'app/graphql/types/visibility_levels_enum.rb'
+ - 'ee/app/graphql/types/dast_scan_type_enum.rb'
+ - 'ee/app/graphql/types/dast_site_profile_validation_status_enum.rb'
+ - 'ee/app/graphql/types/dast_site_validation_status_enum.rb'
+ - 'ee/app/graphql/types/dast_site_validation_strategy_enum.rb'
+ - 'ee/app/graphql/types/dast_target_type_enum.rb'
+ - 'ee/app/graphql/types/geo/replication_state_enum.rb'
+ - 'ee/app/graphql/types/geo/verification_state_enum.rb'
+ - 'ee/app/graphql/types/incident_management/oncall_rotation_length_unit_enum.rb'
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index a119dcb32a8..8b4dcdffca0 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-165e1fbd149fd4baec8ce3957e728d3ce3412a15
+b55578ec476e8bc8ecd9775ee7e9960b52e0f6e0
diff --git a/app/assets/javascripts/boards/components/board_content.vue b/app/assets/javascripts/boards/components/board_content.vue
index d99afa8455d..0d2e49c966f 100644
--- a/app/assets/javascripts/boards/components/board_content.vue
+++ b/app/assets/javascripts/boards/components/board_content.vue
@@ -1,6 +1,6 @@
<script>
import { GlAlert } from '@gitlab/ui';
-import { sortBy } from 'lodash';
+import { sortBy, throttle } from 'lodash';
import Draggable from 'vuedraggable';
import { mapState, mapGetters, mapActions } from 'vuex';
import BoardAddNewColumn from 'ee_else_ce/boards/components/board_add_new_column.vue';
@@ -26,6 +26,11 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ boardHeight: null,
+ };
+ },
computed: {
...mapState(['boardLists', 'error', 'addColumnForm']),
...mapGetters(['isSwimlanesOn', 'isEpicBoard', 'isIssueBoard']),
@@ -55,12 +60,28 @@ export default {
return this.canDragColumns ? options : {};
},
},
+ mounted() {
+ this.setBoardHeight();
+
+ this.resizeObserver = new ResizeObserver(
+ throttle(() => {
+ this.setBoardHeight();
+ }, 150),
+ );
+ this.resizeObserver.observe(document.body);
+ },
+ unmounted() {
+ this.resizeObserver.disconnect();
+ },
methods: {
...mapActions(['moveList', 'unsetError']),
afterFormEnters() {
const el = this.canDragColumns ? this.$refs.list.$el : this.$refs.list;
el.scrollTo({ left: el.scrollWidth, behavior: 'smooth' });
},
+ setBoardHeight() {
+ this.boardHeight = `${window.innerHeight - this.$el.getBoundingClientRect().top}px`;
+ },
},
};
</script>
@@ -76,6 +97,7 @@ export default {
ref="list"
v-bind="draggableOptions"
class="boards-list gl-w-full gl-py-5 gl-pr-3 gl-white-space-nowrap gl-overflow-x-scroll"
+ :style="{ height: boardHeight }"
@end="moveList"
>
<board-column
@@ -99,6 +121,7 @@ export default {
:lists="boardListsToUse"
:can-admin-list="canAdminList"
:disabled="disabled"
+ :style="{ height: boardHeight }"
/>
<board-content-sidebar v-if="isIssueBoard" data-testid="issue-boards-sidebar" />
diff --git a/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue b/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue
deleted file mode 100644
index 599e8d35708..00000000000
--- a/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue
+++ /dev/null
@@ -1,84 +0,0 @@
-<script>
-import { mapState, mapActions, mapGetters } from 'vuex';
-import { s__, sprintf } from '~/locale';
-import { componentNames } from '~/reports/components/issue_body';
-import ReportSection from '~/reports/components/report_section.vue';
-import createStore from './store';
-
-export default {
- name: 'GroupedCodequalityReportsApp',
- store: createStore(),
- components: {
- ReportSection,
- },
- props: {
- headBlobPath: {
- type: String,
- required: true,
- },
- baseBlobPath: {
- type: String,
- required: false,
- default: null,
- },
- codequalityReportsPath: {
- type: String,
- required: false,
- default: '',
- },
- codequalityHelpPath: {
- type: String,
- required: true,
- },
- },
- componentNames,
- computed: {
- ...mapState(['newIssues', 'resolvedIssues', 'hasError', 'statusReason']),
- ...mapGetters([
- 'hasCodequalityIssues',
- 'codequalityStatus',
- 'codequalityText',
- 'codequalityPopover',
- ]),
- },
- created() {
- this.setPaths({
- baseBlobPath: this.baseBlobPath,
- headBlobPath: this.headBlobPath,
- reportsPath: this.codequalityReportsPath,
- helpPath: this.codequalityHelpPath,
- });
-
- this.fetchReports();
- },
- methods: {
- ...mapActions(['fetchReports', 'setPaths']),
- },
- loadingText: sprintf(s__('ciReport|Loading %{reportName} report'), {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- reportName: 'Code quality',
- }),
- errorText: sprintf(s__('ciReport|Failed to load %{reportName} report'), {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- reportName: 'Code quality',
- }),
-};
-</script>
-<template>
- <report-section
- :status="codequalityStatus"
- :loading-text="$options.loadingText"
- :error-text="$options.errorText"
- :success-text="codequalityText"
- :unresolved-issues="newIssues"
- :resolved-issues="resolvedIssues"
- :has-issues="hasCodequalityIssues"
- :component="$options.componentNames.CodequalityIssueBody"
- :popover-options="codequalityPopover"
- :show-report-section-status-icon="false"
- track-action="users_expanding_testing_code_quality_report"
- class="js-codequality-widget mr-widget-border-top mr-report"
- >
- <template v-if="hasError" #sub-heading>{{ statusReason }}</template>
- </report-section>
-</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue
index 94359d7d6ac..5111e2609e8 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue
@@ -6,6 +6,7 @@ import { sprintf, __ } from '~/locale';
import Poll from '~/lib/utils/poll';
import ActionButtons from '../action_buttons.vue';
import { EXTENSION_ICONS } from '../../constants';
+import { createTelemetryHub } from '../extensions/telemetry';
import ContentRow from './widget_content_row.vue';
import DynamicContent from './dynamic_content.vue';
import StatusIcon from './status_icon.vue';
@@ -89,6 +90,11 @@ export default {
type: String,
required: true,
},
+ telemetry: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
data() {
return {
@@ -98,6 +104,7 @@ export default {
isLoadingExpandedContent: false,
summaryError: null,
contentError: null,
+ telemetryHub: null,
};
},
computed: {
@@ -113,8 +120,14 @@ export default {
this.$emit('is-loading', newValue);
},
},
+ created() {
+ if (this.telemetry) {
+ this.telemetryHub = createTelemetryHub(this.widgetName);
+ }
+ },
async mounted() {
this.isLoading = true;
+ this.telemetryHub?.viewed();
try {
await this.fetch(this.fetchCollapsedData, FETCH_TYPE_COLLAPSED);
@@ -125,12 +138,21 @@ export default {
this.isLoading = false;
},
methods: {
+ onActionClick(action) {
+ if (action.fullReport) {
+ this.telemetryHub?.fullReportClicked();
+ }
+ },
toggleCollapsed() {
this.isCollapsed = !this.isCollapsed;
- if (this.isExpandedForTheFirstTime && typeof this.fetchExpandedData === 'function') {
- this.isExpandedForTheFirstTime = false;
- this.fetchExpandedContent();
+ if (this.isExpandedForTheFirstTime) {
+ this.telemetryHub?.expanded({ type: this.summaryStatusIcon });
+
+ if (typeof this.fetchExpandedData === 'function') {
+ this.isExpandedForTheFirstTime = false;
+ this.fetchExpandedContent();
+ }
}
},
async fetchExpandedContent() {
@@ -208,6 +230,7 @@ export default {
v-if="actionButtons.length > 0"
:widget="widgetName"
:tertiary-buttons="actionButtons"
+ @clickedAction="onActionClick"
/>
<div
v-if="isCollapsible"
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 62ad22c637b..af0328edb23 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -82,8 +82,6 @@ export default {
MrWidgetAutoMergeFailed: AutoMergeFailed,
MrWidgetRebase: RebaseState,
SourceBranchRemovalStatus,
- GroupedCodequalityReportsApp: () =>
- import('../reports/codequality_report/grouped_codequality_reports_app.vue'),
GroupedTestReportsApp: () =>
import('../reports/grouped_test_report/grouped_test_reports_app.vue'),
MrWidgetApprovals,
@@ -218,9 +216,6 @@ export default {
shouldShowSecurityExtension() {
return window.gon?.features?.refactorSecurityExtension;
},
- shouldShowCodeQualityExtension() {
- return window.gon?.features?.refactorCodeQualityExtension;
- },
shouldShowMergeDetails() {
if (this.mr.state === 'readyToMerge') return true;
@@ -519,7 +514,7 @@ export default {
}
},
registerCodeQualityExtension() {
- if (this.shouldRenderCodeQuality && this.shouldShowCodeQualityExtension) {
+ if (this.shouldRenderCodeQuality) {
registerExtension(codeQualityExtension);
}
},
@@ -592,14 +587,6 @@ export default {
<widget-container v-if="mr" :mr="mr" />
- <grouped-codequality-reports-app
- v-if="shouldRenderCodeQuality && !shouldShowCodeQualityExtension"
- :head-blob-path="mr.headBlobPath"
- :base-blob-path="mr.baseBlobPath"
- :codequality-reports-path="mr.codequalityReportsPath"
- :codequality-help-path="mr.codequalityHelpPath"
- />
-
<security-reports-app
v-if="shouldRenderSecurityReport && !shouldShowSecurityExtension"
:pipeline-id="mr.pipeline.id"
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 731d3886f61..9221b87014b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -299,7 +299,6 @@ export default class MergeRequestStore {
this.headBlobPath = blobPath.head_path || '';
this.baseBlobPath = blobPath.base_path || '';
this.codequalityReportsPath = data.codequality_reports_path;
- this.codequalityHelpPath = data.codequality_help_path;
// Security reports
this.sastComparisonPath = data.sast_comparison_path;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 95e03abbb48..0f2a818d582 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -674,18 +674,7 @@ $ci-skipped-color: #888;
*/
$issue-boards-font-size: 14px;
$issue-boards-card-shadow: rgba(0, 0, 0, 0.1);
-/*
- The following heights are used in boards.scss and are used for calculation of the board height.
- They probably should be derived in a smarter way.
-*/
$issue-boards-filter-height: 68px;
-$issue-boards-filter-height-md: 110px;
-$issue-boards-filter-height-sm: 299px;
-$issue-boards-breadcrumbs-height-xs: 63px;
-$issue-board-list-difference-xs: calc(#{$header-height} + #{$issue-boards-breadcrumbs-height-xs});
-$issue-board-list-difference-sm: calc(#{$header-height} + #{$breadcrumb-min-height});
-$issue-board-list-difference-md: calc(#{$issue-board-list-difference-sm} + #{$issue-boards-filter-height-md});
-$issue-board-list-difference-lg: calc(#{$issue-board-list-difference-sm} + #{$issue-boards-filter-height});
/*
The following heights are used in environment_logs.scss and are used for calculation of the log viewer height.
*/
diff --git a/app/assets/stylesheets/page_bundles/boards.scss b/app/assets/stylesheets/page_bundles/boards.scss
index d45bc865da5..0cc1fb40e4a 100644
--- a/app/assets/stylesheets/page_bundles/boards.scss
+++ b/app/assets/stylesheets/page_bundles/boards.scss
@@ -18,38 +18,9 @@
.boards-list,
.board-swimlanes {
- height: calc(100vh - #{$issue-board-list-difference-xs});
overflow-x: scroll;
min-height: 200px;
border-left: 8px solid var(--gray-10, $white);
-
- @include media-breakpoint-only(sm) {
- height: calc(100vh - #{$issue-board-list-difference-sm});
- }
-
- @include media-breakpoint-up(md) {
- height: calc(100vh - #{$issue-board-list-difference-md});
- }
-
- @include media-breakpoint-up(lg) {
- height: calc(100vh - #{$issue-board-list-difference-lg});
- }
-
- .with-performance-bar & {
- height: calc(100vh - #{$issue-board-list-difference-xs} - #{$performance-bar-height});
-
- @include media-breakpoint-only(sm) {
- height: calc(100vh - #{$issue-board-list-difference-sm} - #{$performance-bar-height});
- }
-
- @include media-breakpoint-up(md) {
- height: calc(100vh - #{$issue-board-list-difference-md} - #{$performance-bar-height});
- }
-
- @include media-breakpoint-up(lg) {
- height: calc(100vh - #{$issue-board-list-difference-lg} - #{$performance-bar-height});
- }
- }
}
.board {
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 3251b1483c3..cfc565a8b56 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -34,7 +34,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action only: [:show] do
push_frontend_feature_flag(:merge_request_widget_graphql, project)
push_frontend_feature_flag(:core_security_mr_widget_counts, project)
- push_frontend_feature_flag(:refactor_code_quality_extension, project)
push_frontend_feature_flag(:refactor_mr_widget_test_summary, project)
push_frontend_feature_flag(:issue_assignees_widget, @project)
push_frontend_feature_flag(:realtime_labels, project)
diff --git a/app/models/concerns/pg_full_text_searchable.rb b/app/models/concerns/pg_full_text_searchable.rb
index f533791c2ee..562c8cf23f3 100644
--- a/app/models/concerns/pg_full_text_searchable.rb
+++ b/app/models/concerns/pg_full_text_searchable.rb
@@ -25,7 +25,7 @@ module PgFullTextSearchable
TSVECTOR_MAX_LENGTH = 1.megabyte.freeze
TEXT_SEARCH_DICTIONARY = 'english'
URL_SCHEME_REGEX = %r{(?<=\A|\W)\w+://(?=\w+)}.freeze
- TSQUERY_DISALLOWED_CHARACTERS_REGEX = %r{[^a-zA-Z0-9 .@/\-"]}.freeze
+ TSQUERY_DISALLOWED_CHARACTERS_REGEX = %r{[^a-zA-Z0-9 .@/\-_"]}.freeze
def update_search_data!
tsvector_sql_nodes = self.class.pg_full_text_searchable_columns.map do |column, weight|
diff --git a/app/services/groups/update_service.rb b/app/services/groups/update_service.rb
index 2135892a95a..925a2acbb58 100644
--- a/app/services/groups/update_service.rb
+++ b/app/services/groups/update_service.rb
@@ -10,6 +10,8 @@ module Groups
reject_parent_id!
remove_unallowed_params
+ before_assignment_hook(group, params)
+
if renaming_group_with_container_registry_images?
group.errors.add(:base, container_images_error)
return false
@@ -25,8 +27,6 @@ module Groups
handle_changes
- before_assignment_hook(group, params)
-
handle_namespace_settings
group.assign_attributes(params)
diff --git a/app/services/incident_management/timeline_events/create_service.rb b/app/services/incident_management/timeline_events/create_service.rb
index c625b0d15bd..ef6f48bd741 100644
--- a/app/services/incident_management/timeline_events/create_service.rb
+++ b/app/services/incident_management/timeline_events/create_service.rb
@@ -52,7 +52,8 @@ module IncidentManagement
def change_severity(incident, user)
return if Feature.disabled?(:incident_timeline_events_for_severity, incident.project)
- note = "@#{user.username} changed the incident severity to **#{incident.severity.humanize}**"
+ severity_label = IssuableSeverity::SEVERITY_LABELS[incident.severity.to_sym]
+ note = "@#{user.username} changed the incident severity to **#{severity_label}**"
occurred_at = incident.updated_at
action = 'severity'
diff --git a/config/feature_flags/development/lazy_load_commits.yml b/config/feature_flags/development/lazy_load_commits.yml
index d4764907211..6140b88c3c2 100644
--- a/config/feature_flags/development/lazy_load_commits.yml
+++ b/config/feature_flags/development/lazy_load_commits.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/342497
milestone: '14.4'
type: development
group: group::source code
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/refactor_code_quality_extension.yml b/config/feature_flags/development/refactor_code_quality_extension.yml
deleted file mode 100644
index c6eb7c19a6e..00000000000
--- a/config/feature_flags/development/refactor_code_quality_extension.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: refactor_code_quality_extension
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88865
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/363845
-milestone: '15.1'
-type: development
-group: group::secure
-default_enabled: false
diff --git a/config/open_api.yml b/config/open_api.yml
index 331a90a8710..a3e9bd44a16 100644
--- a/config/open_api.yml
+++ b/config/open_api.yml
@@ -29,6 +29,8 @@ metadata:
description: Operations related to environments
- name: feature_flags_user_lists
description: Operations related to accessing GitLab feature flag user lists
+ - name: feature_flags
+ description: Operations related to feature flags
- name: features
description: Operations related to managing Flipper-based feature flags
- name: freeze_periods
@@ -39,5 +41,7 @@ metadata:
description: Operations related to metadata of the GitLab instance
- name: release_links
description: Operations related to release assets (links)
+ - name: releases
+ description: Operations related to releases
- name: suggestions
- description: Operations related to suggestions \ No newline at end of file
+ description: Operations related to suggestions
diff --git a/doc/api/feature_flags.md b/doc/api/feature_flags.md
index 55eb62f9a0d..1aec1006610 100644
--- a/doc/api/feature_flags.md
+++ b/doc/api/feature_flags.md
@@ -144,7 +144,7 @@ POST /projects/:id/feature_flags
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
| `name` | string | yes | The name of the feature flag. |
-| `version` | string | yes | The version of the feature flag. Must be `new_version_flag`. Omit or set to `legacy_flag` to create a Legacy feature flag. |
+| `version` | string | yes | The version of the feature flag. Must be `new_version_flag`. Omit to create a Legacy feature flag. |
| `description` | string | no | The description of the feature flag. |
| `active` | boolean | no | The active state of the flag. Defaults to true. [Supported](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38350) in GitLab 13.3 and later. |
| `strategies` | JSON | no | The feature flag [strategies](../operations/feature_flags.md#feature-flag-strategies). |
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index e3b1d9230f6..64af547e6d2 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -28,7 +28,7 @@ For authentication, the Releases API accepts either:
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
-Paginated list of Releases, sorted by `released_at`.
+Returns a paginated list of releases, sorted by `released_at`.
```plaintext
GET /projects/:id/releases
@@ -235,7 +235,7 @@ Example response:
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
-Get a Release for the given tag.
+Gets a release for the given tag.
```plaintext
GET /projects/:id/releases/:tag_name
@@ -366,7 +366,7 @@ Example response:
## Create a release
-Create a release. Developer level access to the project is required to create a release.
+Creates a release. Developer level access to the project is required to create a release.
```plaintext
POST /projects/:id/releases
@@ -516,7 +516,7 @@ adding milestones for ancestor groups raises an error.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199065) in GitLab 12.10.
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
-Create Evidence for an existing Release.
+Creates an evidence for an existing release.
```plaintext
POST /projects/:id/releases/:tag_name/evidence
@@ -543,7 +543,7 @@ Example response:
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
-Update a release. Developer level access to the project is required to update a release.
+Updates a release. Developer level access to the project is required to update a release.
```plaintext
PUT /projects/:id/releases/:tag_name
@@ -652,7 +652,7 @@ Example response:
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
-Delete a release. Deleting a release doesn't delete the associated tag. Maintainer level access to the project is required to delete a release.
+Deletes a release. Deleting a release doesn't delete the associated tag. Maintainer level access to the project is required to delete a release.
```plaintext
DELETE /projects/:id/releases/:tag_name
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index 9b17b694194..162b313b531 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -693,7 +693,7 @@ module EE
prepended do
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
# ...
diff --git a/doc/development/pipelines/index.md b/doc/development/pipelines/index.md
index 56a36395afd..26b3c7558cf 100644
--- a/doc/development/pipelines/index.md
+++ b/doc/development/pipelines/index.md
@@ -257,27 +257,31 @@ set and get the `ee/` folder removed before the tests start running.
The intent is to ensure that a change doesn't introduce a failure after `gitlab-org/gitlab` is synced to `gitlab-org/gitlab-foss`.
-## As-if-JH jobs
+## As-if-JH cross project downstream pipeline
-NOTE:
-This is disabled for now.
-
-The `* as-if-jh` jobs run the GitLab test suite "as if JiHu", meaning as if the jobs would run in the context
-of [GitLab JH](../jh_features_review.md). These jobs are only created in the following cases:
+The `start-as-if-jh` job triggers a cross project downstream pipeline which
+runs the GitLab test suite "as if JiHu", meaning as if the pipeline would run
+in the context of [GitLab JH](../jh_features_review.md). These jobs are only
+created in the following cases:
- when the `pipeline:run-as-if-jh` label is set on the merge request
-- when the `pipeline:run-all-rspec` label is set on the merge request
-- when any code or backstage file is changed
-- when any startup CSS file is changed
-The `* as-if-jh` jobs are run in addition to the regular EE-context jobs. The `jh/` folder is added before the tests start running.
+This pipeline runs under the context of a generated branch in the
+[GitLab JH validation](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation)
+project, which is a mirror of the
+[GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab).
-The intent is to ensure that a change doesn't introduce a failure after `gitlab-org/gitlab` is synced to [GitLab JH](https://jihulab.com/gitlab-cn/gitlab).
+The generated branch name is prefixed with `as-if-jh/` along with the branch
+name in the merge request. This generated branch is based on the merge request
+branch, additionally adding changes downloaded from the
+[corresponding JH branch](#corresponding-jh-branch) on top to turn the whole
+pipeline as if JiHu.
-### When to consider applying `pipeline:run-as-if-jh` label
+The intent is to ensure that a change doesn't introduce a failure after
+[GitLab](https://gitlab.com/gitlab-org/gitlab) is synchronized to
+[GitLab JH](https://jihulab.com/gitlab-cn/gitlab).
-NOTE:
-This is disabled for now.
+### When to consider applying `pipeline:run-as-if-jh` label
If a Ruby file is renamed and there's a corresponding [`prepend_mod` line](../jh_features_review.md#jh-features-based-on-ce-or-ee-features),
it's likely that GitLab JH is relying on it and requires a corresponding
@@ -285,17 +289,109 @@ change to rename the module or class it's prepending.
### Corresponding JH branch
-NOTE:
-This is disabled for now.
-
You can create a corresponding JH branch on [GitLab JH](https://jihulab.com/gitlab-cn/gitlab) by
appending `-jh` to the branch name. If a corresponding JH branch is found,
-`* as-if-jh` jobs grab the `jh` folder from the respective branch,
-rather than from the default branch `main-jh`.
+as-if-jh pipeline grabs files from the respective branch, rather than from the
+default branch `main-jh`.
NOTE:
For now, CI will try to fetch the branch on the [GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab), so it might take some time for the new JH branch to propagate to the mirror.
+NOTE:
+While [GitLab JH validation](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation) is a mirror of
+[GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab),
+it does not include any corresponding JH branch beside the default `main-jh`.
+This is why when we want to fetch corresponding JH branch we should fetch it
+from the main mirror, rather than the validation project.
+
+### How as-if-JH pipeline was configured
+
+The whole process looks like this:
+
+```mermaid
+flowchart TD
+ subgraph "JiHuLab.com"
+ JH["gitlab-cn/gitlab"]
+ end
+
+ subgraph "GitLab.com"
+ Mirror["gitlab-org/gitlab-jh-mirrors/gitlab"]
+ Validation["gitlab-org-sandbox/gitlab-jh-validation"]
+
+ subgraph MR["gitlab-org/gitlab merge request"]
+ Add["add-jh-files job"]
+ Prepare["prepare-as-if-jh-branch job"]
+ Add --"download artifacts"--> Prepare
+ end
+
+ Mirror --"pull mirror with master and main-jh"--> Validation
+ Mirror --"download JiHu files with ADD_JH_FILES_TOKEN"--> Add
+ Prepare --"push as-if-jh branches with AS_IF_JH_TOKEN"--> Validation
+ Validation --> Pipeline["as-if-jh pipeline"]
+ end
+
+ JH --"pull mirror with corresponding JH branches"--> Mirror
+```
+
+#### Tokens set in the project variables
+
+- `ADD_JH_FILES_TOKEN`: This is a [GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab)
+ project token with `read_api` permission, to be able to download JiHu files.
+- `AS_IF_JH_TOKEN`: This is a [GitLab JH validation](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation)
+ project token with `write_repository` permission, to push generated `as-if-jh/*` branch.
+
+#### How we generate the as-if-JH branch
+
+First `add-jh-files` job will download the required JiHu files from the
+corresponding JH branch, saving in artifacts. Next `prepare-as-if-jh-branch`
+job will create a new branch from the merge request branch, commit the
+changes, and finally push the branch to the
+[validation project](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation).
+
+#### How we trigger and run the as-if-JH pipeline
+
+After having the `as-if-jh/*` branch, `start-as-if-jh` job will trigger a pipeline
+in the [validation project](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation)
+to run the cross-project downstream pipeline.
+
+#### How the GitLab JH mirror project is set up
+
+The [GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab) project is private and CI is disabled.
+
+It's a pull mirror pulling from [GitLab JH](https://jihulab.com/gitlab-cn/gitlab),
+mirroring all branches, overriding divergent refs, triggering no pipelines
+when mirror is updated.
+
+The pulling user is [`@gitlab-jh-bot`](https://gitlab.com/gitlab-jh-bot), who
+is a maintainer in the project. The credentials can be found in the 1password
+engineering vault.
+
+No password is used from mirroring because GitLab JH is a public project.
+
+#### How the GitLab JH validation project is set up
+
+This [GitLab JH validation](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation) project is public and CI is enabled, without any project variables.
+
+It's a pull mirror pulling from [GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab),
+mirroring only protected branches, `master` and `main-jh`, overriding
+divergent refs, triggering no pipelines when mirror is updated.
+
+The pulling user is [`@gitlab-jh-validation-bot`](https://gitlab.com/gitlab-jh-validation-bot), who is a maintainer in the project, and also a
+reporter in the
+[GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab).
+The credentials can be found in the 1password engineering vault.
+
+A personal access token from `@gitlab-jh-validation-bot` with
+`write_repository` permission is used as the password to pull changes from
+the GitLab JH mirror. Username is set with `gitlab-jh-validation-bot`.
+
+There is also a [pipeline schedule](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation/-/pipeline_schedules)
+to run maintenance pipelines with variable `SCHEDULE_TYPE` set to `maintenance`
+running every day, updating cache.
+
+The default CI/CD configuration file is also set at `jh/.gitlab-ci.yml` so it
+runs exactly like [GitLab JH](https://jihulab.com/gitlab-cn/gitlab/-/blob/main-jh/jh/.gitlab-ci.yml).
+
## Ruby 3.0 jobs
You can add the `pipeline:run-in-ruby3` label to the merge request to switch
diff --git a/doc/development/reusing_abstractions.md b/doc/development/reusing_abstractions.md
index 2701192137c..58d1e20394c 100644
--- a/doc/development/reusing_abstractions.md
+++ b/doc/development/reusing_abstractions.md
@@ -151,7 +151,8 @@ When implementing a service class, consider:
developer's discretion, such as: `issue`, `project`, `merge_request`.
1. When service represents an action initiated by a user or executed in the
context of a user, the initializer must have the `current_user:` keyword argument.
- Services with `current_user:` argument run high-level business logic.
+ Services with the `current_user:` argument run high-level business logic
+ and must validate user authorization to perform their operations.
1. When service does not have a user context and it's not directly initiated
by a user (like background service or side-effects), the `current_user:`
argument is not needed. This describes low-level domain logic or instance-wide logic.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 6108ec8d0e0..5149ae9c1e1 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -46,12 +46,12 @@ If the highest number stable branch is unclear, check the [GitLab blog](https://
## Software requirements
-| Software | Minimum version | Notes |
-| -------- | --------------- | ----- |
-| [Ruby](#2-ruby) | `2.7` | From GitLab 13.6, Ruby 2.7 is required. Ruby 3.0 is not supported yet (see [the relevant epic](https://gitlab.com/groups/gitlab-org/-/epics/5149) for the current status). You must use the standard MRI implementation of Ruby. We love [JRuby](https://www.jruby.org/) and [Rubinius](https://github.com/rubinius/rubinius#the-rubinius-language-platform), but GitLab needs several Gems that have native extensions. |
-| [Go](#3-go) | `1.17` | From GitLab 15.2, Go 1.17 or later is required. |
-| [Git](#git) | `2.33.x` | From GitLab 14.4, Git 2.33.x and later is required. It's highly recommended that you use the [Git version provided by Gitaly](#git). |
-| [Node.js](#4-node) | `14.15.0` | GitLab uses [webpack](https://webpack.js.org/) to compile frontend assets. Node.js 16.x is recommended, as it's faster. You can check which version you're running with `node -v`. You must update it to a newer version if needed. |
+| Software | Minimum version | Notes |
+| ------------------ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| [Ruby](#2-ruby) | `2.7` | From GitLab 13.6, Ruby 2.7 is required. Ruby 3.0 is not supported yet (see [the relevant epic](https://gitlab.com/groups/gitlab-org/-/epics/5149) for the current status). You must use the standard MRI implementation of Ruby. We love [JRuby](https://www.jruby.org/) and [Rubinius](https://github.com/rubinius/rubinius#the-rubinius-language-platform), but GitLab needs several Gems that have native extensions. |
+| [Go](#3-go) | `1.17` | From GitLab 15.2, Go 1.17 or later is required. |
+| [Git](#git) | `2.37.x` | From GitLab 15.6, Git 2.37.x and later is required. It's highly recommended that you use the [Git version provided by Gitaly](#git). |
+| [Node.js](#4-node) | `14.15.0` | GitLab uses [webpack](https://webpack.js.org/) to compile frontend assets. Node.js 16.x is recommended, as it's faster. You can check which version you're running with `node -v`. You must update it to a newer version if needed. |
## GitLab directory structure
diff --git a/doc/operations/incident_management/img/timeline_event_for_severity_change_v15_6.png b/doc/operations/incident_management/img/timeline_event_for_severity_change_v15_6.png
index 121cc4b23cb..ae9d446f8b5 100644
--- a/doc/operations/incident_management/img/timeline_event_for_severity_change_v15_6.png
+++ b/doc/operations/incident_management/img/timeline_event_for_severity_change_v15_6.png
Binary files differ
diff --git a/doc/update/index.md b/doc/update/index.md
index 38c0df68fc5..2d381d955d1 100644
--- a/doc/update/index.md
+++ b/doc/update/index.md
@@ -467,6 +467,10 @@ NOTE:
Specific information that follow related to Ruby and Git versions do not apply to [Omnibus installations](https://docs.gitlab.com/omnibus/)
and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with appropriate Ruby and Git versions and are not using system binaries for Ruby and Git. There is no need to install Ruby or Git when utilizing these two approaches.
+### 15.6.0
+
+- Git 2.37.0 and later is required by Gitaly. For installations from source, we recommend you use the [Git version provided by Gitaly](../install/installation.md#git).
+
### 15.4.0
- GitLab 15.4.0 includes a [batched background migration](#batched-background-migrations) to [remove incorrect values from `expire_at` in `ci_job_artifacts` table](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89318).
diff --git a/doc/user/public_access.md b/doc/user/public_access.md
index fbab9d9bb51..24b3387e5c6 100644
--- a/doc/user/public_access.md
+++ b/doc/user/public_access.md
@@ -78,11 +78,12 @@ Prerequisite:
## Change group visibility
-Prerequisite:
+Prerequisites:
- You must have the Owner role for a group.
- Subgroups and projects must already have visibility settings that are at least as
- restrictive as the new setting of the parent group.
+ restrictive as the new setting of the parent group. For example, you cannot set a group
+ to private if a subgroup or project in that group is public.
1. On the top bar, select **Main menu > Groups** and find your project.
1. On the left sidebar, select **Settings > General**.
diff --git a/lib/api/alert_management_alerts.rb b/lib/api/alert_management_alerts.rb
index f03f133f6f7..f57b7d00c81 100644
--- a/lib/api/alert_management_alerts.rb
+++ b/lib/api/alert_management_alerts.rb
@@ -6,7 +6,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :alert_iid, type: Integer, desc: 'The IID of the Alert'
end
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 3400e15394d..0f90ca7c845 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -182,11 +182,14 @@ module API
mount ::API::Deployments
mount ::API::Environments
mount ::API::FeatureFlagsUserLists
+ mount ::API::FeatureFlags
mount ::API::Features
mount ::API::FreezePeriods
- mount ::API::MergeRequestDiffs
+ mount ::API::Keys
mount ::API::Metadata
+ mount ::API::MergeRequestDiffs
mount ::API::ProjectRepositoryStorageMoves
+ mount ::API::Releases
mount ::API::Release::Links
mount ::API::ResourceAccessTokens
mount ::API::ProtectedTags
@@ -238,7 +241,6 @@ module API
mount ::API::ErrorTracking::Collector
mount ::API::ErrorTracking::ProjectSettings
mount ::API::Events
- mount ::API::FeatureFlags
mount ::API::Files
mount ::API::GenericPackages
mount ::API::Geo
@@ -263,7 +265,6 @@ module API
mount ::API::Invitations
mount ::API::IssueLinks
mount ::API::Issues
- mount ::API::Keys
mount ::API::Labels
mount ::API::Lint
mount ::API::Markdown
@@ -301,7 +302,6 @@ module API
mount ::API::Projects
mount ::API::ProtectedTags
mount ::API::PypiPackages
- mount ::API::Releases
mount ::API::RemoteMirrors
mount ::API::Repositories
mount ::API::ResourceLabelEvents
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index 6e3005ce676..0e0f6441da7 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -19,7 +19,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
segment ':id/boards' do
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 7e6b0214c03..51c9a4e53df 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -29,7 +29,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a project repository branches' do
diff --git a/lib/api/ci/job_artifacts.rb b/lib/api/ci/job_artifacts.rb
index b3a0a9ef54a..352ad04c982 100644
--- a/lib/api/ci/job_artifacts.rb
+++ b/lib/api/ci/job_artifacts.rb
@@ -19,7 +19,7 @@ module API
prepend_mod_with('API::Ci::JobArtifacts') # rubocop: disable Cop/InjectEnterpriseEditionModule
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Download the artifacts archive from a job' do
diff --git a/lib/api/ci/jobs.rb b/lib/api/ci/jobs.rb
index 0de915c22e0..770420f8f93 100644
--- a/lib/api/ci/jobs.rb
+++ b/lib/api/ci/jobs.rb
@@ -11,7 +11,7 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
helpers do
diff --git a/lib/api/ci/pipeline_schedules.rb b/lib/api/ci/pipeline_schedules.rb
index 886c3509c51..ab2a76a05d3 100644
--- a/lib/api/ci/pipeline_schedules.rb
+++ b/lib/api/ci/pipeline_schedules.rb
@@ -11,7 +11,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all pipeline schedules' do
diff --git a/lib/api/ci/resource_groups.rb b/lib/api/ci/resource_groups.rb
index ea6d3cc8fd4..3ec2d08158e 100644
--- a/lib/api/ci/resource_groups.rb
+++ b/lib/api/ci/resource_groups.rb
@@ -11,7 +11,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all resource groups for this project' do
diff --git a/lib/api/ci/runners.rb b/lib/api/ci/runners.rb
index 5250a9bca2c..988c3f4f566 100644
--- a/lib/api/ci/runners.rb
+++ b/lib/api/ci/runners.rb
@@ -256,7 +256,9 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_admin_project }
diff --git a/lib/api/ci/secure_files.rb b/lib/api/ci/secure_files.rb
index 511b6e06cd3..e04718b72f0 100644
--- a/lib/api/ci/secure_files.rb
+++ b/lib/api/ci/secure_files.rb
@@ -16,7 +16,7 @@ module API
default_format :json
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/ci/triggers.rb b/lib/api/ci/triggers.rb
index 0531b17cf97..2cda597430c 100644
--- a/lib/api/ci/triggers.rb
+++ b/lib/api/ci/triggers.rb
@@ -11,7 +11,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Trigger a GitLab project pipeline' do
diff --git a/lib/api/ci/variables.rb b/lib/api/ci/variables.rb
index 25a06719783..b5eecc844d5 100644
--- a/lib/api/ci/variables.rb
+++ b/lib/api/ci/variables.rb
@@ -13,7 +13,7 @@ module API
helpers ::API::Helpers::VariablesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/clusters/agent_tokens.rb b/lib/api/clusters/agent_tokens.rb
index 02d3fcdf5ea..6ccd41c53a8 100644
--- a/lib/api/clusters/agent_tokens.rb
+++ b/lib/api/clusters/agent_tokens.rb
@@ -10,7 +10,7 @@ module API
feature_category :kubernetes_management
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
diff --git a/lib/api/clusters/agents.rb b/lib/api/clusters/agents.rb
index b93ad2a946b..62d4fb009c6 100644
--- a/lib/api/clusters/agents.rb
+++ b/lib/api/clusters/agents.rb
@@ -11,7 +11,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'List the agents for a project' do
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 7d8b58fd7b6..859cbd1ce60 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -8,7 +8,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
include PaginationParams
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 50d0687ba75..b141e3edc71 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -27,7 +27,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS, urgency: :low do
desc 'Get a project repository commits' do
diff --git a/lib/api/container_repositories.rb b/lib/api/container_repositories.rb
index d4fa6153a92..f2dd1fa21fd 100644
--- a/lib/api/container_repositories.rb
+++ b/lib/api/container_repositories.rb
@@ -14,7 +14,7 @@ module API
namespace 'registry' do
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :repositories, requirements: { id: /[0-9]*/ } do
desc 'Get a container repository' do
diff --git a/lib/api/debian_project_packages.rb b/lib/api/debian_project_packages.rb
index 03f0f97b805..1c7b29ab0b9 100644
--- a/lib/api/debian_project_packages.rb
+++ b/lib/api/debian_project_packages.rb
@@ -34,7 +34,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
namespace ':id/packages/debian' do
diff --git a/lib/api/entities/basic_release_details.rb b/lib/api/entities/basic_release_details.rb
index d13080f32f4..dba19b3abd7 100644
--- a/lib/api/entities/basic_release_details.rb
+++ b/lib/api/entities/basic_release_details.rb
@@ -5,12 +5,12 @@ module API
class BasicReleaseDetails < Grape::Entity
include ::API::Helpers::Presentable
- expose :name
- expose :tag, as: :tag_name
- expose :description
- expose :created_at
- expose :released_at
- expose :upcoming_release?, as: :upcoming_release
+ expose :name, documentation: { type: 'string', example: 'Release v1.0' }
+ expose :tag, documentation: { type: 'string', example: 'v1.0' }, as: :tag_name
+ expose :description, documentation: { type: 'string', example: 'Finally released v1.0' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-01-03T01:56:19.539Z' }
+ expose :released_at, documentation: { type: 'dateTime', example: '2019-01-03T01:56:19.539Z' }
+ expose :upcoming_release?, documentation: { type: 'boolean' }, as: :upcoming_release
end
end
end
diff --git a/lib/api/entities/feature_flag.rb b/lib/api/entities/feature_flag.rb
index 9dec3873504..273307357a2 100644
--- a/lib/api/entities/feature_flag.rb
+++ b/lib/api/entities/feature_flag.rb
@@ -3,12 +3,12 @@
module API
module Entities
class FeatureFlag < Grape::Entity
- expose :name
- expose :description
- expose :active
- expose :version
- expose :created_at
- expose :updated_at
+ expose :name, documentation: { type: 'string', example: 'merge_train' }
+ expose :description, documentation: { type: 'string', example: 'merge train feature flag' }
+ expose :active, documentation: { type: 'boolean' }
+ expose :version, documentation: { type: 'string', example: 'new_version_flag' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-11-04T08:13:51.423Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2019-11-04T08:13:51.423Z' }
expose :scopes do |_ff|
[]
end
diff --git a/lib/api/entities/feature_flag/scope.rb b/lib/api/entities/feature_flag/scope.rb
index 906fe718257..e29793c250a 100644
--- a/lib/api/entities/feature_flag/scope.rb
+++ b/lib/api/entities/feature_flag/scope.rb
@@ -4,8 +4,8 @@ module API
module Entities
class FeatureFlag < Grape::Entity
class Scope < Grape::Entity
- expose :id
- expose :environment_scope
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :environment_scope, documentation: { type: 'string', example: 'production' }
end
end
end
diff --git a/lib/api/entities/feature_flag/strategy.rb b/lib/api/entities/feature_flag/strategy.rb
index 32699be0ee3..62178420370 100644
--- a/lib/api/entities/feature_flag/strategy.rb
+++ b/lib/api/entities/feature_flag/strategy.rb
@@ -4,9 +4,9 @@ module API
module Entities
class FeatureFlag < Grape::Entity
class Strategy < Grape::Entity
- expose :id
- expose :name
- expose :parameters
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'userWithId' }
+ expose :parameters, documentation: { type: 'string', example: '{"userIds": "user1"}' }
expose :scopes, using: FeatureFlag::Scope
end
end
diff --git a/lib/api/entities/release.rb b/lib/api/entities/release.rb
index 2403c907f7f..5feb1edbff6 100644
--- a/lib/api/entities/release.rb
+++ b/lib/api/entities/release.rb
@@ -16,11 +16,13 @@ module API
release.milestones.order_by_dates_and_title
end
- expose :commit_path, expose_nil: false
- expose :tag_path, expose_nil: false
+ expose :commit_path,
+ documentation: { type: 'string', example: '/root/app/commit/588440f66559714280628a4f9799f0c4eb880a4a' },
+ expose_nil: false
+ expose :tag_path, documentation: { type: 'string', example: '/root/app/-/tags/v1.0' }, expose_nil: false
expose :assets do
- expose :assets_count, as: :count
+ expose :assets_count, documentation: { type: 'integer', example: 2 }, as: :count
expose :sources, using: Entities::Releases::Source, if: ->(_, _) { can_download_code? }
expose :sorted_links, as: :links, using: Entities::Releases::Link
end
diff --git a/lib/api/entities/releases/evidence.rb b/lib/api/entities/releases/evidence.rb
index 01603a71dbf..9d324309213 100644
--- a/lib/api/entities/releases/evidence.rb
+++ b/lib/api/entities/releases/evidence.rb
@@ -6,9 +6,9 @@ module API
class Evidence < Grape::Entity
include ::API::Helpers::Presentable
- expose :sha
- expose :filepath
- expose :collected_at
+ expose :sha, documentation: { type: 'string', example: '760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d' }
+ expose :filepath, documentation: { type: 'string', example: 'https://gitlab.example.com/root/app/-/releases/v1.0/evidence.json' }
+ expose :collected_at, documentation: { type: 'dateTime', example: '2019-01-03T01:56:19.539Z' }
end
end
end
diff --git a/lib/api/entities/releases/link.rb b/lib/api/entities/releases/link.rb
index 5157645af69..abf380e11d5 100644
--- a/lib/api/entities/releases/link.rb
+++ b/lib/api/entities/releases/link.rb
@@ -4,14 +4,22 @@ module API
module Entities
module Releases
class Link < Grape::Entity
- expose :id
- expose :name
- expose :url
- expose :direct_asset_url do |link|
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'app-v1.0.dmg' }
+ expose :url, documentation:
+ {
+ type: 'string',
+ example: 'https://gitlab.example.com/root/app/-/jobs/688/artifacts/raw/bin/app-v1.0.dmg'
+ }
+ expose :direct_asset_url, documentation:
+ {
+ type: 'string',
+ example: 'https://gitlab.example.com/root/app/-/releases/v1.0/downloads/app-v1.0.dmg'
+ } do |link|
::Releases::LinkPresenter.new(link).direct_asset_url
end
- expose :external?, as: :external
- expose :link_type
+ expose :external?, documentation: { type: 'boolean' }, as: :external
+ expose :link_type, documentation: { type: 'string', example: 'other' }
end
end
end
diff --git a/lib/api/entities/releases/source.rb b/lib/api/entities/releases/source.rb
index 2b0c8038ddf..8c6750d6142 100644
--- a/lib/api/entities/releases/source.rb
+++ b/lib/api/entities/releases/source.rb
@@ -4,8 +4,8 @@ module API
module Entities
module Releases
class Source < Grape::Entity
- expose :format
- expose :url
+ expose :format, documentation: { type: 'string', example: 'zip' }
+ expose :url, documentation: { type: 'string', example: 'https://gitlab.example.com/root/app/-/archive/v1.0/app-v1.0.zip' }
end
end
end
diff --git a/lib/api/entities/ssh_key.rb b/lib/api/entities/ssh_key.rb
index e1554730cb6..3db10bb8ec2 100644
--- a/lib/api/entities/ssh_key.rb
+++ b/lib/api/entities/ssh_key.rb
@@ -3,8 +3,15 @@
module API
module Entities
class SSHKey < Grape::Entity
- expose :id, :title, :created_at, :expires_at
- expose :publishable_key, as: :key
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :title, documentation: { type: 'string', example: 'Sample key 25' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:44.627Z' }
+ expose :expires_at, documentation: { type: 'dateTime', example: '2020-09-03T07:24:44.627Z' }
+ expose :publishable_key, as: :key, documentation:
+ { type: 'string',
+ example: 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt1256k6Yjz\
+ GGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCdd\
+ NaP0L+hM7zhFNzjFvpaMgJw0=' }
end
end
end
diff --git a/lib/api/entities/user_basic.rb b/lib/api/entities/user_basic.rb
index b8ee4e5a6e0..9f20e0caa72 100644
--- a/lib/api/entities/user_basic.rb
+++ b/lib/api/entities/user_basic.rb
@@ -3,16 +3,16 @@
module API
module Entities
class UserBasic < UserSafe
- expose :state
+ expose :state, documentation: { type: 'string', example: 'active' }
- expose :avatar_url do |user, options|
+ expose :avatar_url, documentation: { type: 'string', example: 'https://gravatar.com/avatar/1' } do |user, options|
user.avatar_url(only_path: false)
end
expose :avatar_path, if: ->(user, options) { options.fetch(:only_path, false) && user.avatar_path }
expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes
- expose :web_url do |user, options|
+ expose :web_url, documentation: { type: 'string', example: 'https://gitlab.example.com/root' } do |user, options|
Gitlab::Routing.url_helpers.user_url(user)
end
end
diff --git a/lib/api/entities/user_public.rb b/lib/api/entities/user_public.rb
index 5d0e464abe1..9e21c5e12b6 100644
--- a/lib/api/entities/user_public.rb
+++ b/lib/api/entities/user_public.rb
@@ -3,17 +3,23 @@
module API
module Entities
class UserPublic < Entities::User
- expose :last_sign_in_at
- expose :confirmed_at
- expose :last_activity_on
- expose :email
- expose :theme_id, :color_scheme_id, :projects_limit, :current_sign_in_at
+ expose :last_sign_in_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
+ expose :confirmed_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
+ expose :last_activity_on, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
+ expose :email, documentation: { type: 'string', example: 'john@example.com' }
+ expose :theme_id, documentation: { type: 'integer', example: 2 }
+ expose :color_scheme_id, documentation: { type: 'integer', example: 1 }
+ expose :projects_limit, documentation: { type: 'integer', example: 10 }
+ expose :current_sign_in_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
expose :identities, using: Entities::Identity
- expose :can_create_group?, as: :can_create_group
- expose :can_create_project?, as: :can_create_project
- expose :two_factor_enabled?, as: :two_factor_enabled
- expose :external
- expose :private_profile
+ expose :can_create_group?, as: :can_create_group, documentation: { type: 'boolean', example: true }
+ expose :can_create_project?, as: :can_create_project, documentation: { type: 'boolean', example: true }
+
+ expose :two_factor_enabled?, as: :two_factor_enabled, documentation: { type: 'boolean', example: true }
+
+ expose :external, documentation: { type: 'boolean', example: false }
+
+ expose :private_profile, documentation: { type: 'boolean', example: :null }
expose :commit_email_or_default, as: :commit_email
end
end
diff --git a/lib/api/entities/user_safe.rb b/lib/api/entities/user_safe.rb
index 127a8ef2160..0fbb10307cf 100644
--- a/lib/api/entities/user_safe.rb
+++ b/lib/api/entities/user_safe.rb
@@ -5,8 +5,9 @@ module API
class UserSafe < Grape::Entity
include RequestAwareEntity
- expose :id, :username
- expose :name do |user|
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :username, documentation: { type: 'string', example: 'admin' }
+ expose :name, documentation: { type: 'string', example: 'Administrator' } do |user|
current_user = request.respond_to?(:current_user) ? request.current_user : options.fetch(:current_user, nil)
user.redacted_name(current_user)
diff --git a/lib/api/error_tracking/client_keys.rb b/lib/api/error_tracking/client_keys.rb
index c1c378111a7..b8104d4fc11 100644
--- a/lib/api/error_tracking/client_keys.rb
+++ b/lib/api/error_tracking/client_keys.rb
@@ -8,7 +8,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/error_tracking/collector.rb b/lib/api/error_tracking/collector.rb
index eea0fd2bce9..e10125e02c6 100644
--- a/lib/api/error_tracking/collector.rb
+++ b/lib/api/error_tracking/collector.rb
@@ -67,7 +67,7 @@ module API
detail 'This feature was introduced in GitLab 14.1.'
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
post 'error_tracking/collector/api/:id/envelope' do
# There is a reason why we have such uncommon path.
@@ -119,7 +119,7 @@ module API
detail 'This feature was introduced in GitLab 14.1.'
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
post 'error_tracking/collector/api/:id/store' do
# There is a reason why we have such uncommon path.
diff --git a/lib/api/error_tracking/project_settings.rb b/lib/api/error_tracking/project_settings.rb
index fefc2098137..01a55fbbd55 100644
--- a/lib/api/error_tracking/project_settings.rb
+++ b/lib/api/error_tracking/project_settings.rb
@@ -14,7 +14,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/feature_flags.rb b/lib/api/feature_flags.rb
index 67e96284449..b1599ab9b47 100644
--- a/lib/api/feature_flags.rb
+++ b/lib/api/feature_flags.rb
@@ -15,18 +15,20 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
resource :feature_flags do
- desc 'Get all feature flags of a project' do
- detail 'This feature was introduced in GitLab 12.5'
+ desc 'List feature flags for a project' do
+ detail 'Gets all feature flags of the requested project. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ is_array true
+ tags %w[feature_flags]
end
params do
optional :scope,
type: String,
- desc: 'The scope of feature flags',
+ desc: 'The scope of feature flags, one of: `enabled`, `disabled`',
values: %w[enabled disabled]
use :pagination
end
@@ -39,22 +41,18 @@ module API
end
desc 'Create a new feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
+ detail 'Creates a new feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ tags %w[feature_flags]
end
params do
- requires :name, type: String, desc: 'The name of feature flag'
+ requires :name, type: String, desc: 'The name of the feature flag'
optional :description, type: String, desc: 'The description of the feature flag'
- optional :active, type: Boolean, desc: 'Active/inactive value of the flag'
- optional :version, type: String, desc: 'The version of the feature flag'
- optional :scopes, type: Array do
- requires :environment_scope, type: String, desc: 'The environment scope of the scope'
- requires :active, type: Boolean, desc: 'Active/inactive of the scope'
- requires :strategies, type: JSON, desc: 'The strategies of the scope'
- end
+ optional :active, type: Boolean, desc: 'The active state of the flag. Defaults to `true`. Supported in GitLab 13.3 and later'
+ optional :version, type: String, desc: 'The version of the feature flag. Must be `new_version_flag`. Omit to create a Legacy feature flag.'
optional :strategies, type: Array do
- requires :name, type: String, desc: 'The strategy name'
- requires :parameters, type: JSON, desc: 'The strategy parameters'
+ requires :name, type: String, desc: 'The strategy name. Can be `default`, `gradualRolloutUserId`, `userWithId`, or `gitlabUserList`. In GitLab 13.5 and later, can be `flexibleRollout`'
+ requires :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
optional :scopes, type: Array do
requires :environment_scope, type: String, desc: 'The environment scope of the scope'
end
@@ -87,9 +85,10 @@ module API
requires :feature_flag_name, type: String, desc: 'The name of the feature flag'
end
resource 'feature_flags/:feature_flag_name', requirements: FEATURE_FLAG_ENDPOINT_REQUIREMENTS do
- desc 'Get a feature flag of a project' do
- detail 'This feature was introduced in GitLab 12.5'
+ desc 'Get a single feature flag' do
+ detail 'Gets a single feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ tags %w[feature_flags]
end
get do
authorize_read_feature_flag!
@@ -99,20 +98,21 @@ module API
end
desc 'Update a feature flag' do
- detail 'This feature was introduced in GitLab 13.2'
+ detail 'Updates a feature flag. This feature was introduced in GitLab 13.2.'
success ::API::Entities::FeatureFlag
+ tags %w[feature_flags]
end
params do
- optional :name, type: String, desc: 'The name of the feature flag'
+ optional :name, type: String, desc: 'The new name of the feature flag. Supported in GitLab 13.3 and later'
optional :description, type: String, desc: 'The description of the feature flag'
- optional :active, type: Boolean, desc: 'Active/inactive value of the flag'
+ optional :active, type: Boolean, desc: 'The active state of the flag. Supported in GitLab 13.3 and later'
optional :strategies, type: Array do
- optional :id, type: Integer, desc: 'The strategy id'
- optional :name, type: String, desc: 'The strategy type'
- optional :parameters, type: JSON, desc: 'The strategy parameters'
+ optional :id, type: Integer, desc: 'The feature flag strategy ID'
+ optional :name, type: String, desc: 'The strategy name'
+ optional :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
optional :_destroy, type: Boolean, desc: 'Delete the strategy when true'
optional :scopes, type: Array do
- optional :id, type: Integer, desc: 'The environment scope id'
+ optional :id, type: Integer, desc: 'The scope id'
optional :environment_scope, type: String, desc: 'The environment scope of the scope'
optional :_destroy, type: Boolean, desc: 'Delete the scope when true'
end
@@ -142,8 +142,9 @@ module API
end
desc 'Delete a feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
+ detail 'Deletes a feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ tags %w[feature_flags]
end
delete do
authorize_destroy_feature_flag!
diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb
index 0098b074f05..f7785cb8b52 100644
--- a/lib/api/generic_packages.rb
+++ b/lib/api/generic_packages.rb
@@ -18,7 +18,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/go_proxy.rb b/lib/api/go_proxy.rb
index 2d9c0cd6ce1..fbc1d12e755 100755
--- a/lib/api/go_proxy.rb
+++ b/lib/api/go_proxy.rb
@@ -17,6 +17,10 @@ module API
before { require_packages_enabled! }
helpers do
+ def project
+ user_project(action: :read_package)
+ end
+
def case_decode(str)
# Converts "github.com/!azure" to "github.com/Azure"
#
@@ -32,12 +36,12 @@ module API
end
def find_module
- not_found! unless Feature.enabled?(:go_proxy, user_project)
+ not_found! unless Feature.enabled?(:go_proxy, project)
module_name = case_decode params[:module_name]
bad_request_missing_attribute!('Module Name') if module_name.blank?
- mod = ::Packages::Go::ModuleFinder.new(user_project, module_name).execute
+ mod = ::Packages::Go::ModuleFinder.new(project, module_name).execute
not_found! unless mod
@@ -58,13 +62,13 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :module_name, type: String, desc: 'Module name', coerce_with: ->(val) { CGI.unescape(val) }
end
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, authenticate_non_public: true
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
- authorize_read_package!
+ authorize_read_package!(project)
end
namespace ':id/packages/go/*module_name/@v' do
diff --git a/lib/api/helpers/packages_helpers.rb b/lib/api/helpers/packages_helpers.rb
index 687c8330cc8..96a10d43401 100644
--- a/lib/api/helpers/packages_helpers.rb
+++ b/lib/api/helpers/packages_helpers.rb
@@ -3,6 +3,8 @@
module API
module Helpers
module PackagesHelpers
+ extend ::Gitlab::Utils::Override
+
MAX_PACKAGE_FILE_SIZE = 50.megabytes.freeze
def require_packages_enabled!
@@ -48,6 +50,34 @@ module API
require_gitlab_workhorse!
end
+ override :user_project
+ def user_project(action: :read_project)
+ case action
+ when :read_project
+ super()
+ when :read_package
+ user_project_with_read_package
+ else
+ raise ArgumentError, "unexpected action: #{action}"
+ end
+ end
+
+ # This function is similar to the `find_project!` function, but it considers the `read_package` ability.
+ def user_project_with_read_package
+ strong_memoize(:user_project_with_read_package) do
+ project = find_project(params[:id])
+
+ next forbidden! unless authorized_project_scope?(project)
+
+ next project if can?(current_user, :read_package, project&.packages_policy_subject)
+ # guest users can have :read_project but not :read_package
+ next forbidden! if can?(current_user, :read_project, project)
+ next unauthorized! if authenticate_non_public?
+
+ not_found!('Project')
+ end
+ end
+
def track_package_event(event_name, scope, **args)
::Packages::CreateEventService.new(nil, current_user, event_name: event_name, scope: scope).execute
category = args.delete(:category) || self.options[:for].name
diff --git a/lib/api/integrations.rb b/lib/api/integrations.rb
index 71c55704ddf..4eb5a966fc7 100644
--- a/lib/api/integrations.rb
+++ b/lib/api/integrations.rb
@@ -65,7 +65,7 @@ module API
# The support for `:id/services` can be dropped if we create an API V5.
[':id/services', ':id/integrations'].each do |path|
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authenticate! }
@@ -149,7 +149,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Trigger a slash command for #{integration_slug}" do
diff --git a/lib/api/issue_links.rb b/lib/api/issue_links.rb
index 563fb3358ed..0f92f7aeb91 100644
--- a/lib/api/issue_links.rb
+++ b/lib/api/issue_links.rb
@@ -10,7 +10,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
end
resource :projects, requirements: { id: %r{[^/]+} } do
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index b8b4019765d..b08819e34e3 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -198,7 +198,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
include TimeTrackingEndpoints
diff --git a/lib/api/keys.rb b/lib/api/keys.rb
index fb1bedd5e92..77952bac01a 100644
--- a/lib/api/keys.rb
+++ b/lib/api/keys.rb
@@ -9,8 +9,13 @@ module API
resource :keys do
desc 'Get single ssh key by id. Only available to admin users' do
+ detail 'Get SSH key with user by ID of an SSH key. Note only administrators can lookup SSH key with user by ID\
+ of an SSH key'
success Entities::SSHKeyWithUser
end
+ params do
+ requires :id, types: [String, Integer], desc: 'The ID of an SSH key', documentation: { example: '2' }
+ end
get ":id" do
authenticated_as_admin!
@@ -19,11 +24,14 @@ module API
present key, with: Entities::SSHKeyWithUser, current_user: current_user
end
- desc 'Get SSH Key information' do
+ desc 'Get user by fingerprint of SSH key' do
success Entities::UserWithAdmin
+ detail 'You can search for a user that owns a specific SSH key. Note only administrators can lookup SSH key\
+ with the fingerprint of an SSH key'
end
params do
- requires :fingerprint, type: String, desc: 'Search for a SSH fingerprint'
+ requires :fingerprint, type: String, desc: 'The fingerprint of an SSH key',
+ documentation: { example: 'ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1' }
end
get do
authenticated_with_can_read_all_resources!
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index 0a107a96d61..2e00affbbdf 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -15,7 +15,7 @@ module API
label_id: API::NO_SLASH_URL_PART_REGEX)
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: LABEL_ENDPOINT_REQUIREMENTS do
desc 'Get all labels of the project' do
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index 72313d6a588..e5799352fe9 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -220,7 +220,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Download the maven package file' do
diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb
index 26841bf6644..c7f0f88eacc 100644
--- a/lib/api/merge_request_diffs.rb
+++ b/lib/api/merge_request_diffs.rb
@@ -10,7 +10,7 @@ module API
feature_category :code_review
params do
- requires :id, type: String, desc: 'The ID of the project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of merge request diff versions' do
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index a0e7d0b10cd..bb2861aa221 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -170,7 +170,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
include TimeTrackingEndpoints
diff --git a/lib/api/ml/mlflow.rb b/lib/api/ml/mlflow.rb
index 356a4ef53d4..56bfac1530e 100644
--- a/lib/api/ml/mlflow.rb
+++ b/lib/api/ml/mlflow.rb
@@ -80,7 +80,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'API to interface with MLFlow Client, REST API version 1.28.0' do
diff --git a/lib/api/npm_project_packages.rb b/lib/api/npm_project_packages.rb
index 166c0b755fe..494b493f5e0 100644
--- a/lib/api/npm_project_packages.rb
+++ b/lib/api/npm_project_packages.rb
@@ -11,7 +11,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
namespace 'projects/:id/packages/npm' do
desc 'Download the NPM tarball' do
diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb
index 3e05ea13311..cc4e9777b07 100644
--- a/lib/api/nuget_project_packages.rb
+++ b/lib/api/nuget_project_packages.rb
@@ -91,7 +91,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project', regexp: ::API::Concerns::Packages::NugetEndpoints::POSITIVE_INTEGER_REGEX
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project', regexp: ::API::Concerns::Packages::NugetEndpoints::POSITIVE_INTEGER_REGEX
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/packages/nuget' do
diff --git a/lib/api/package_files.rb b/lib/api/package_files.rb
index 278dc4c2044..bf1cd88c18c 100644
--- a/lib/api/package_files.rb
+++ b/lib/api/package_files.rb
@@ -14,7 +14,7 @@ module API
helpers ::API::Helpers::PackagesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :package_id, type: Integer, desc: 'The ID of a package'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/pages.rb b/lib/api/pages.rb
index 5f695f3853d..7e230bd3c67 100644
--- a/lib/api/pages.rb
+++ b/lib/api/pages.rb
@@ -10,7 +10,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Unpublish pages' do
diff --git a/lib/api/pages_domains.rb b/lib/api/pages_domains.rb
index 9cf61967ba4..967847a8e62 100644
--- a/lib/api/pages_domains.rb
+++ b/lib/api/pages_domains.rb
@@ -54,7 +54,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
diff --git a/lib/api/project_clusters.rb b/lib/api/project_clusters.rb
index 4644d38ea80..6faa549d787 100644
--- a/lib/api/project_clusters.rb
+++ b/lib/api/project_clusters.rb
@@ -13,7 +13,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of the project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all clusters from the project' do
diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb
index 6a6275ed02a..2ee7b73c74c 100644
--- a/lib/api/project_container_repositories.rb
+++ b/lib/api/project_container_repositories.rb
@@ -16,7 +16,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
route_setting :authentication, job_token_allowed: true, job_token_scope: :project
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/project_debian_distributions.rb b/lib/api/project_debian_distributions.rb
index b8ca9428fa3..1e27f5c8856 100644
--- a/lib/api/project_debian_distributions.rb
+++ b/lib/api/project_debian_distributions.rb
@@ -3,7 +3,7 @@
module API
class ProjectDebianDistributions < ::API::Base
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
before do
diff --git a/lib/api/project_events.rb b/lib/api/project_events.rb
index e8829216336..6315a6c9b1a 100644
--- a/lib/api/project_events.rb
+++ b/lib/api/project_events.rb
@@ -12,7 +12,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "List a Project's visible events" do
diff --git a/lib/api/project_export.rb b/lib/api/project_export.rb
index 29fdfe45566..8f3f50adc86 100644
--- a/lib/api/project_export.rb
+++ b/lib/api/project_export.rb
@@ -11,7 +11,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get export status' do
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index 466e80d68c8..008fb5da0b2 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -37,7 +37,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/hooks' do
diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb
index 0da8c1ecedd..268a238421e 100644
--- a/lib/api/project_import.rb
+++ b/lib/api/project_import.rb
@@ -108,7 +108,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
desc 'Get a project import status' do
detail 'This feature was introduced in GitLab 10.6.'
diff --git a/lib/api/project_milestones.rb b/lib/api/project_milestones.rb
index 9f82dbf9813..a7a583aaa23 100644
--- a/lib/api/project_milestones.rb
+++ b/lib/api/project_milestones.rb
@@ -11,7 +11,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of project milestones' do
diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb
index 800966408fc..d09c481403f 100644
--- a/lib/api/project_packages.rb
+++ b/lib/api/project_packages.rb
@@ -14,7 +14,7 @@ module API
helpers ::API::Helpers::PackagesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all project packages' do
diff --git a/lib/api/project_repository_storage_moves.rb b/lib/api/project_repository_storage_moves.rb
index b9cb2e957bc..817dc49c431 100644
--- a/lib/api/project_repository_storage_moves.rb
+++ b/lib/api/project_repository_storage_moves.rb
@@ -55,7 +55,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of all project repository storage moves' do
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index 14792730eae..743cd4e4fbb 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -9,7 +9,7 @@ module API
feature_category :snippets
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
helpers Helpers::SnippetsHelpers
diff --git a/lib/api/project_statistics.rb b/lib/api/project_statistics.rb
index 3db8d20ebac..445feebc2b9 100644
--- a/lib/api/project_statistics.rb
+++ b/lib/api/project_statistics.rb
@@ -10,7 +10,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get the list of project fetch statistics for the last 30 days'
diff --git a/lib/api/project_templates.rb b/lib/api/project_templates.rb
index f6e1286d616..6c3e6368113 100644
--- a/lib/api/project_templates.rb
+++ b/lib/api/project_templates.rb
@@ -15,7 +15,7 @@ module API
feature_category :source_code_management
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|licenses|metrics_dashboard_ymls|issues|merge_requests) of the template'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index e579d18bb3f..81ccd6ba349 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -336,7 +336,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a single project' do
diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb
index 443b3e90dc3..786045684b8 100644
--- a/lib/api/protected_branches.rb
+++ b/lib/api/protected_branches.rb
@@ -13,7 +13,10 @@ module API
helpers Helpers::ProtectedBranchesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project', documentation: { example: 'gitlab-org/gitlab' }
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project',
+ documentation: { example: 'gitlab-org/gitlab' }
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Get a project's protected branches" do
diff --git a/lib/api/protected_tags.rb b/lib/api/protected_tags.rb
index 7d4d15ab4b3..7b55b1fd61d 100644
--- a/lib/api/protected_tags.rb
+++ b/lib/api/protected_tags.rb
@@ -13,7 +13,7 @@ module API
helpers Helpers::ProtectedTagsHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Get a project's protected tags" do
diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb
index a2386411524..ffc88d1c1cf 100644
--- a/lib/api/pypi_packages.rb
+++ b/lib/api/pypi_packages.rb
@@ -157,7 +157,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index cdfcce9dddb..ec9907b18f9 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -4,6 +4,8 @@ module API
class Releases < ::API::Base
include PaginationParams
+ releases_tags = %w[releases]
+
RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
RELEASE_CLI_USER_AGENT = 'GitLab-release-cli'
@@ -12,20 +14,37 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the group'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_read_group_releases! }
- desc 'Get a list of releases for projects in this group.' do
+ desc 'List group releases' do
+ detail 'Returns a list of group releases.'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags releases_tags
end
params do
- requires :id, type: Integer, desc: 'The ID of the group to get releases for'
- optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Return projects sorted in ascending and descending order by released_at'
- optional :simple, type: Boolean, default: false,
- desc: 'Return only the ID, URL, name, and path of each project'
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the group owned by the authenticated user'
+
+ optional :sort,
+ type: String,
+ values: %w[asc desc],
+ default: 'desc',
+ desc: 'The direction of the order. Either `desc` (default) for descending order or `asc` for ascending order'
+
+ optional :simple,
+ type: Boolean,
+ default: false,
+ desc: 'Return only limited fields for each release'
use :pagination
end
@@ -42,26 +61,38 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_read_releases! }
after { track_release_event }
- desc 'Get a project releases' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'List Releases' do
+ detail 'Returns a paginated list of releases. This feature was introduced in GitLab 11.7.'
named 'get_releases'
+ is_array true
success Entities::Release
+ tags releases_tags
end
params do
use :pagination
- optional :order_by, type: String, values: %w[released_at created_at], default: 'released_at',
- desc: 'Return releases ordered by `released_at` or `created_at`.'
- optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Return releases sorted in `asc` or `desc` order.'
- optional :include_html_description, type: Boolean,
- desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
+
+ optional :order_by,
+ type: String,
+ values: %w[released_at created_at],
+ default: 'released_at',
+ desc: 'The field to use as order. Either `released_at` (default) or `created_at`'
+
+ optional :sort,
+ type: String,
+ values: %w[asc desc],
+ default: 'desc',
+ desc: 'The direction of the order. Either `desc` (default) for descending order or `asc` for ascending order'
+
+ optional :include_html_description,
+ type: Boolean,
+ desc: 'If `true`, a response includes HTML rendered markdown of the release description'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases' do
@@ -81,15 +112,22 @@ module API
include_html_description: params[:include_html_description]
end
- desc 'Get a single project release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Get a release by a tag name' do
+ detail 'Gets a release for the given tag. This feature was introduced in GitLab 11.7.'
named 'get_release'
success Entities::Release
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
- optional :include_html_description, type: Boolean,
- desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
+
+ optional :include_html_description,
+ type: Boolean,
+ desc: 'If `true`, a response includes HTML rendered markdown of the release description'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
@@ -103,13 +141,19 @@ module API
desc 'Download a project release asset file' do
detail 'This feature was introduced in GitLab 15.4.'
named 'download_release_asset_file'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String,
- desc: 'The name of the tag.', as: :tag
- requires :file_path, type: String,
- file_path: true,
- desc: 'The path to the file to download, as specified when creating the release asset.'
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
+
+ requires :file_path,
+ type: String,
+ file_path: true,
+ desc: 'The path to the file to download, as specified when creating the release asset'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases/:tag_name/downloads/*file_path', format: false, requirements: RELEASE_ENDPOINT_REQUIREMENTS do
@@ -127,9 +171,17 @@ module API
desc 'Get the latest project release' do
detail 'This feature was introduced in GitLab 15.4.'
named 'get_latest_release'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :suffix_path, type: String, file_path: true, desc: 'The path to be suffixed to the latest release'
+ requires :suffix_path,
+ type: String,
+ file_path: true,
+ desc: 'The path to be suffixed to the latest release'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases/permalink/latest(/)(*suffix_path)', format: false, requirements: RELEASE_ENDPOINT_REQUIREMENTS do
@@ -156,27 +208,50 @@ module API
redirect redirect_url
end
- desc 'Create a new release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Create a release' do
+ detail 'Creates a release. Developer level access to the project is required to create a release. This feature was introduced in GitLab 11.7.'
named 'create_release'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ requires :tag_name, type: String, desc: 'The tag where the release is created from', as: :tag
optional :tag_message, type: String, desc: 'Message to use if creating a new annotated tag'
- optional :name, type: String, desc: 'The name of the release'
- optional :description, type: String, desc: 'The release notes'
- optional :ref, type: String, desc: 'Commit SHA or branch name to use if creating a new tag'
+ optional :name, type: String, desc: 'The release name'
+ optional :description, type: String, desc: 'The description of the release. You can use Markdown'
+
+ optional :ref,
+ type: String,
+ desc: "If a tag specified in `tag_name` doesn't exist, the release is created from `ref` and tagged " \
+ "with `tag_name`. It can be a commit SHA, another tag name, or a branch name."
+
optional :assets, type: Hash do
optional :links, type: Array do
- requires :name, type: String, desc: 'The name of the link'
- requires :url, type: String, desc: 'The URL of the link'
- optional :filepath, type: String, desc: 'The filepath of the link'
- optional :link_type, type: String, desc: 'The link type, one of: "runbook", "image", "package" or "other"'
+ requires :name, type: String, desc: 'The name of the link. Link names must be unique within the release'
+ requires :url, type: String, desc: 'The URL of the link. Link URLs must be unique within the release'
+ optional :filepath, type: String, desc: 'Optional path for a direct asset link'
+ optional :link_type, type: String, desc: 'The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`'
end
end
- optional :milestones, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The titles of the related milestones', default: []
- optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready. Defaults to the current time.'
+
+ optional :milestones,
+ type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'The title of each milestone the release is associated with. GitLab Premium customers can specify group milestones',
+ default: []
+
+ optional :released_at,
+ type: DateTime,
+ desc: 'Date and time for the release. Defaults to the current time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). ' \
+ 'Only provide this field if creating an upcoming or historical release.'
end
route_setting :authentication, job_token_allowed: true
post ':id/releases' do
@@ -196,16 +271,27 @@ module API
end
desc 'Update a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ detail 'Updates a release. Developer level access to the project is required to update a release. This feature was introduced in GitLab 11.7.'
named 'update_release'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
- optional :name, type: String, desc: 'The name of the release'
- optional :description, type: String, desc: 'Release notes with markdown support'
- optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready.'
- optional :milestones, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The titles of the related milestones'
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
+ optional :name, type: String, desc: 'The release name'
+ optional :description, type: String, desc: 'The description of the release. You can use Markdown'
+ optional :released_at, type: DateTime, desc: 'The date when the release is/was ready. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`)'
+
+ optional :milestones,
+ type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'The title of each milestone to associate with the release. GitLab Premium customers can specify group milestones. To remove all milestones from the release, specify `[]`'
end
route_setting :authentication, job_token_allowed: true
put ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
@@ -226,12 +312,19 @@ module API
end
desc 'Delete a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ detail "Delete a release. Deleting a release doesn't delete the associated tag. Maintainer level access to the project is required to delete a release. This feature was introduced in GitLab 11.7."
named 'delete_release'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
end
route_setting :authentication, job_token_allowed: true
delete ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
diff --git a/lib/api/remote_mirrors.rb b/lib/api/remote_mirrors.rb
index 8de155312fb..e041daca688 100644
--- a/lib/api/remote_mirrors.rb
+++ b/lib/api/remote_mirrors.rb
@@ -11,7 +11,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "List the project's remote mirrors" do
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index c2b77cd2fc4..640b23b402b 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -41,7 +41,7 @@ module API
feature_category :source_code_management
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
helpers do
diff --git a/lib/api/rpm_project_packages.rb b/lib/api/rpm_project_packages.rb
index 13bbdfc0e6c..40b8d022c6c 100644
--- a/lib/api/rpm_project_packages.rb
+++ b/lib/api/rpm_project_packages.rb
@@ -21,7 +21,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/packages/rpm' do
diff --git a/lib/api/search.rb b/lib/api/search.rb
index 8742d870425..cf6a1385783 100644
--- a/lib/api/search.rb
+++ b/lib/api/search.rb
@@ -171,7 +171,7 @@ module API
detail 'This feature was introduced in GitLab 10.5.'
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :search, type: String, desc: 'The expression it should be searched for'
requires :scope,
type: String,
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index 8d7b4045639..0022b51bd92 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -13,7 +13,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a project repository tags' do
diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb
index 61583ece82e..c54667964d5 100644
--- a/lib/api/terraform/state.rb
+++ b/lib/api/terraform/state.rb
@@ -41,7 +41,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/api/terraform/state_version.rb b/lib/api/terraform/state_version.rb
index ca37c786666..2d74ae4fd27 100644
--- a/lib/api/terraform/state_version.rb
+++ b/lib/api/terraform/state_version.rb
@@ -14,7 +14,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 996534f4194..870d93a951f 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -370,6 +370,8 @@ module Gitlab
end
def self.expected_server_version
+ return ENV[SERVER_VERSION_FILE] if ENV[SERVER_VERSION_FILE]
+
path = Rails.root.join(SERVER_VERSION_FILE)
path.read.chomp
end
diff --git a/rubocop/cop/graphql/enum_names.rb b/rubocop/cop/graphql/enum_names.rb
new file mode 100644
index 00000000000..74847cb8d17
--- /dev/null
+++ b/rubocop/cop/graphql/enum_names.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+# This cop enforces the enum naming conventions from the enum style guide:
+# https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#enums
+#
+# @example
+#
+# # bad
+# class FooBar < BaseEnum
+# value 'FOO'
+# end
+#
+# class SubparEnum < BaseEnum
+# end
+#
+# class UngoodEnum < BaseEnum
+# graphql_name 'UngoodEnum'
+# end
+#
+# # good
+#
+# class GreatEnum < BaseEnum
+# graphql_name 'Great'
+#
+# value 'BAR'
+# end
+#
+# class NiceEnum < BaseEnum
+# declarative_enum NiceDeclarativeEnum
+# end
+
+module RuboCop
+ module Cop
+ module Graphql
+ class EnumNames < RuboCop::Cop::Base
+ SEE_SG_MSG = "See https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#enums"
+ CLASS_NAME_SUFFIX_MSG = "Enum class names must end with `Enum`. #{SEE_SG_MSG}"
+ GRAPHQL_NAME_MISSING_MSG = "A `graphql_name` must be defined for a GraphQL enum. #{SEE_SG_MSG}"
+ GRAPHQL_NAME_WITH_ENUM_MSG = "The `graphql_name` must not contain the string \"Enum\". #{SEE_SG_MSG}"
+
+ def_node_matcher :enum_subclass, <<~PATTERN
+ (class $(const nil? _) (const {nil? cbase} /.*Enum$/) ...)
+ PATTERN
+
+ def_node_search :find_graphql_name, <<~PATTERN
+ (... `(send nil? :graphql_name $(...)) ...)
+ PATTERN
+
+ def_node_search :declarative_enum?, <<~PATTERN
+ (... (send nil? :declarative_enum ...) ...)
+ PATTERN
+
+ def on_class(node)
+ const_node = enum_subclass(node)
+ return unless const_node
+
+ check_class_name(const_node)
+ check_graphql_name(node)
+ end
+
+ private
+
+ def check_class_name(const_node)
+ return unless const_node&.const_name
+ return if const_node.const_name.end_with?('Enum')
+
+ add_offense(const_node, message: CLASS_NAME_SUFFIX_MSG)
+ end
+
+ def check_graphql_name(node)
+ graphql_name_node = find_graphql_name(node)&.first
+
+ if graphql_name_node
+ return unless graphql_name_node&.str_content
+ return unless graphql_name_node.str_content.downcase.include?('enum')
+
+ add_offense(graphql_name_node, message: GRAPHQL_NAME_WITH_ENUM_MSG)
+ else
+ return if declarative_enum?(node)
+
+ add_offense(node, message: GRAPHQL_NAME_MISSING_MSG)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/scripts/setup/as-if-jh.sh b/scripts/setup/as-if-jh.sh
new file mode 100755
index 00000000000..38c3ac9b913
--- /dev/null
+++ b/scripts/setup/as-if-jh.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+prepare_jh_branch() {
+ set -eu # https://explainshell.com/explain?cmd=set+-eu
+
+ JH_BRANCH="$(./scripts/setup/find-jh-branch.rb)"
+ export JH_BRANCH
+
+ echoinfo "JH_BRANCH: ${JH_BRANCH}"
+}
+
+download_jh_path() {
+ set -eu # https://explainshell.com/explain?cmd=set+-eu
+
+ for path in "$@"; do
+ # https://www.shellcheck.net/wiki/SC3043
+ # shellcheck disable=SC3043
+ local output="${path}.tar.gz"
+
+ echoinfo "Downloading ${path}"
+
+ curl --location -o "${output}" -H "Private-Token: ${ADD_JH_FILES_TOKEN}" "https://gitlab.com/api/v4/projects/${GITLAB_JH_MIRROR_PROJECT}/repository/archive?sha=${JH_BRANCH}&path=${path}"
+
+ tar -zxf "${output}"
+ rm "${output}"
+ mv gitlab-"${JH_BRANCH}"-*/"${path}" ./
+ done
+}
diff --git a/spec/frontend/boards/components/board_content_spec.js b/spec/frontend/boards/components/board_content_spec.js
index 97d9e08f5d4..bb1650cd2cc 100644
--- a/spec/frontend/boards/components/board_content_spec.js
+++ b/spec/frontend/boards/components/board_content_spec.js
@@ -1,6 +1,6 @@
import { GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
import Draggable from 'vuedraggable';
import Vuex from 'vuex';
import EpicsSwimlanes from 'ee_component/boards/components/epics_swimlanes.vue';
@@ -53,6 +53,29 @@ describe('BoardContent', () => {
});
};
+ beforeAll(() => {
+ global.ResizeObserver = class MockResizeObserver {
+ constructor(callback) {
+ this.callback = callback;
+
+ this.entries = [];
+ }
+
+ observe(entry) {
+ this.entries.push(entry);
+ }
+
+ disconnect() {
+ this.entries = [];
+ this.callback = null;
+ }
+
+ trigger() {
+ this.callback(this.entries);
+ }
+ };
+ });
+
afterEach(() => {
wrapper.destroy();
});
@@ -74,6 +97,17 @@ describe('BoardContent', () => {
expect(wrapper.findComponent(EpicsSwimlanes).exists()).toBe(false);
expect(wrapper.findComponent(GlAlert).exists()).toBe(false);
});
+
+ it('resizes the list on resize', async () => {
+ window.innerHeight = 1000;
+ jest.spyOn(Element.prototype, 'getBoundingClientRect').mockReturnValue({ top: 100 });
+
+ wrapper.vm.resizeObserver.trigger();
+
+ await nextTick();
+
+ expect(wrapper.findComponent({ ref: 'list' }).attributes('style')).toBe('height: 900px;');
+ });
});
describe('when issuableType is not issue', () => {
diff --git a/spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js b/spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js
deleted file mode 100644
index 962ff068b92..00000000000
--- a/spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js
+++ /dev/null
@@ -1,151 +0,0 @@
-import { mount } from '@vue/test-utils';
-import Vue from 'vue';
-import Vuex from 'vuex';
-import CodequalityIssueBody from '~/reports/codequality_report/components/codequality_issue_body.vue';
-import GroupedCodequalityReportsApp from '~/reports/codequality_report/grouped_codequality_reports_app.vue';
-import { getStoreConfig } from '~/reports/codequality_report/store';
-import { STATUS_NOT_FOUND } from '~/reports/constants';
-import { parsedReportIssues } from './mock_data';
-
-Vue.use(Vuex);
-
-describe('Grouped code quality reports app', () => {
- let wrapper;
- let mockStore;
-
- const PATHS = {
- codequalityHelpPath: 'codequality_help.html',
- baseBlobPath: 'base/blob/path/',
- headBlobPath: 'head/blob/path/',
- };
-
- const mountComponent = (props = {}) => {
- wrapper = mount(GroupedCodequalityReportsApp, {
- store: mockStore,
- propsData: {
- ...PATHS,
- ...props,
- },
- });
- };
-
- const findWidget = () => wrapper.find('.js-codequality-widget');
- const findIssueBody = () => wrapper.findComponent(CodequalityIssueBody);
-
- beforeEach(() => {
- const { state, ...storeConfig } = getStoreConfig();
- mockStore = new Vuex.Store({
- ...storeConfig,
- actions: {
- setPaths: () => {},
- fetchReports: () => {},
- },
- state: {
- ...state,
- ...PATHS,
- },
- });
-
- mountComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('when it is loading reports', () => {
- beforeEach(() => {
- mockStore.state.isLoading = true;
- });
-
- it('should render loading text', () => {
- expect(findWidget().text()).toEqual('Loading Code quality report');
- });
- });
-
- describe('when base and head reports are loaded and compared', () => {
- describe('with no issues', () => {
- beforeEach(() => {
- mockStore.state.newIssues = [];
- mockStore.state.resolvedIssues = [];
- });
-
- it('renders no changes text', () => {
- expect(findWidget().text()).toEqual('No changes to code quality');
- });
- });
-
- describe('with issues', () => {
- describe('with new issues', () => {
- beforeEach(() => {
- mockStore.state.newIssues = parsedReportIssues.newIssues;
- mockStore.state.resolvedIssues = [];
- });
-
- it('renders summary text', () => {
- expect(findWidget().text()).toContain('Code quality degraded');
- });
-
- it('renders custom codequality issue body', () => {
- expect(findIssueBody().props('issue')).toEqual(parsedReportIssues.newIssues[0]);
- });
- });
-
- describe('with resolved issues', () => {
- beforeEach(() => {
- mockStore.state.newIssues = [];
- mockStore.state.resolvedIssues = parsedReportIssues.resolvedIssues;
- });
-
- it('renders summary text', () => {
- expect(findWidget().text()).toContain('Code quality improved');
- });
-
- it('renders custom codequality issue body', () => {
- expect(findIssueBody().props('issue')).toEqual(parsedReportIssues.resolvedIssues[0]);
- });
- });
-
- describe('with new and resolved issues', () => {
- beforeEach(() => {
- mockStore.state.newIssues = parsedReportIssues.newIssues;
- mockStore.state.resolvedIssues = parsedReportIssues.resolvedIssues;
- });
-
- it('renders summary text', () => {
- expect(findWidget().text()).toContain(
- 'Code quality scanning detected 2 changes in merged results',
- );
- });
-
- it('renders custom codequality issue body', () => {
- expect(findIssueBody().props('issue')).toEqual(parsedReportIssues.newIssues[0]);
- });
- });
- });
- });
-
- describe('on error', () => {
- beforeEach(() => {
- mockStore.state.hasError = true;
- });
-
- it('renders error text', () => {
- expect(findWidget().text()).toContain('Failed to load Code quality report');
- });
-
- it('does not render a help icon', () => {
- expect(findWidget().find('[data-testid="question-o-icon"]').exists()).toBe(false);
- });
-
- describe('when base report was not found', () => {
- beforeEach(() => {
- mockStore.state.status = STATUS_NOT_FOUND;
- });
-
- it('renders a help icon with more information', () => {
- expect(findWidget().find('[data-testid="question-o-icon"]').exists()).toBe(true);
- });
- });
- });
-});
diff --git a/spec/frontend/reports/codequality_report/store/actions_spec.js b/spec/frontend/reports/codequality_report/store/actions_spec.js
index 71f1a0f4de0..1878b9f44b2 100644
--- a/spec/frontend/reports/codequality_report/store/actions_spec.js
+++ b/spec/frontend/reports/codequality_report/store/actions_spec.js
@@ -28,7 +28,6 @@ describe('Codequality Reports actions', () => {
baseBlobPath: 'baseBlobPath',
headBlobPath: 'headBlobPath',
reportsPath: 'reportsPath',
- helpPath: 'codequalityHelpPath',
};
return testAction(
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js
index 4826fecf98d..b17239384a7 100644
--- a/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js
@@ -7,6 +7,14 @@ import ActionButtons from '~/vue_merge_request_widget/components/action_buttons.
import Widget from '~/vue_merge_request_widget/components/widget/widget.vue';
import WidgetContentRow from '~/vue_merge_request_widget/components/widget/widget_content_row.vue';
+jest.mock('~/vue_merge_request_widget/components/extensions/telemetry', () => ({
+ createTelemetryHub: jest.fn().mockReturnValue({
+ viewed: jest.fn(),
+ expanded: jest.fn(),
+ fullReportClicked: jest.fn(),
+ }),
+}));
+
describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
let wrapper;
@@ -30,6 +38,7 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
slots,
stubs: {
StatusIcon,
+ ActionButtons,
ContentRow: WidgetContentRow,
},
});
@@ -323,4 +332,58 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
expect(wrapper.findByText('Failed to load').exists()).toBe(false);
});
});
+
+ describe('telemetry - enabled', () => {
+ beforeEach(() => {
+ createComponent({
+ propsData: {
+ isCollapsible: true,
+ fetchCollapsedData: jest.fn(),
+ fetchExpandedData: jest.fn(),
+ actionButtons: [
+ {
+ fullReport: true,
+ href: '#',
+ target: '_blank',
+ id: 'full-report-button',
+ text: 'Full Report',
+ },
+ ],
+ },
+ });
+ });
+
+ it('should call create a telemetry hub', () => {
+ expect(wrapper.vm.telemetryHub).not.toBe(null);
+ });
+
+ it('should call the viewed state', async () => {
+ await nextTick();
+ expect(wrapper.vm.telemetryHub.viewed).toHaveBeenCalledTimes(1);
+ });
+
+ it('when full report is clicked it should call the respective telemetry event', async () => {
+ expect(wrapper.vm.telemetryHub.fullReportClicked).not.toHaveBeenCalled();
+ wrapper.findByText('Full Report').vm.$emit('click');
+ await nextTick();
+ expect(wrapper.vm.telemetryHub.fullReportClicked).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('telemetry - disabled', () => {
+ beforeEach(() => {
+ createComponent({
+ propsData: {
+ isCollapsible: true,
+ telemetry: false,
+ fetchCollapsedData: jest.fn(),
+ fetchExpandedData: jest.fn(),
+ },
+ });
+ });
+
+ it('should not call create a telemetry hub', () => {
+ expect(wrapper.vm.telemetryHub).toBe(null);
+ });
+ });
});
diff --git a/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js b/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js
index 6622749da92..02454af7242 100644
--- a/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js
+++ b/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js
@@ -563,21 +563,6 @@ describe('MrWidgetOptions', () => {
});
});
- describe('code quality widget', () => {
- beforeEach(() => {
- jest.spyOn(document, 'dispatchEvent');
- });
- it('renders the component when refactorCodeQualityExtension is false', () => {
- createComponent(mockData, {}, { refactorCodeQualityExtension: false });
- expect(wrapper.find('.js-codequality-widget').exists()).toBe(true);
- });
-
- it('does not render the component when refactorCodeQualityExtension is true', () => {
- createComponent(mockData, {}, { refactorCodeQualityExtension: true });
- expect(wrapper.find('.js-codequality-widget').exists()).toBe(true);
- });
- });
-
describe('pipeline for target branch after merge', () => {
describe('with information for target branch pipeline', () => {
beforeEach(() => {
@@ -917,8 +902,7 @@ describe('MrWidgetOptions', () => {
});
it('extension polling is not called if enablePolling flag is not passed', () => {
- // called one time due to parent component polling (mount)
- expect(pollRequest).toHaveBeenCalledTimes(1);
+ expect(pollRequest).toHaveBeenCalledTimes(0);
});
});
@@ -1004,7 +988,7 @@ describe('MrWidgetOptions', () => {
await createComponent();
- expect(pollRequest).toHaveBeenCalledTimes(2);
+ expect(pollRequest).toHaveBeenCalledTimes(1);
});
});
@@ -1042,7 +1026,7 @@ describe('MrWidgetOptions', () => {
registerExtension(pollingErrorExtension);
await createComponent();
- expect(pollRequest).toHaveBeenCalledTimes(2);
+ expect(pollRequest).toHaveBeenCalledTimes(1);
});
it('captures sentry error and displays error when poll has failed', async () => {
diff --git a/spec/lib/api/helpers/packages_helpers_spec.rb b/spec/lib/api/helpers/packages_helpers_spec.rb
index d764ed4afff..b9c887b3e16 100644
--- a/spec/lib/api/helpers/packages_helpers_spec.rb
+++ b/spec/lib/api/helpers/packages_helpers_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe API::Helpers::PackagesHelpers do
- let_it_be(:helper) { Class.new.include(described_class).new }
+ let_it_be(:helper) { Class.new.include(API::Helpers).include(described_class).new }
let_it_be(:project) { create(:project) }
let_it_be(:group) { create(:group) }
let_it_be(:package) { create(:package) }
@@ -121,4 +121,121 @@ RSpec.describe API::Helpers::PackagesHelpers do
expect(subject).to eq nil
end
end
+
+ describe '#user_project' do
+ before do
+ allow(helper).to receive(:params).and_return(id: project.id)
+ end
+
+ it 'calls find_project! on default action' do
+ expect(helper).to receive(:find_project!)
+
+ helper.user_project
+ end
+
+ it 'calls find_project! on read_project action' do
+ expect(helper).to receive(:find_project!)
+
+ helper.user_project(action: :read_project)
+ end
+
+ it 'calls user_project_with_read_package on read_package action' do
+ expect(helper).to receive(:user_project_with_read_package)
+
+ helper.user_project(action: :read_package)
+ end
+
+ it 'throws ArgumentError on unexpected action' do
+ expect { helper.user_project(action: :other_action) }.to raise_error(ArgumentError, 'unexpected action: other_action')
+ end
+ end
+
+ describe '#user_project_with_read_package' do
+ before do
+ helper.clear_memoization(:user_project_with_read_package)
+
+ allow(helper).to receive(:params).and_return(id: params_id)
+ allow(helper).to receive(:route_authentication_setting).and_return({ authenticate_non_public: true })
+ allow(helper).to receive(:current_user).and_return(user)
+ allow(helper).to receive(:initial_current_user).and_return(user)
+ end
+
+ subject { helper.user_project_with_read_package }
+
+ context 'with non-existing project' do
+ let_it_be(:params_id) { non_existing_record_id }
+
+ context 'with current user' do
+ let_it_be(:user) { create(:user) }
+
+ it 'returns Not Found' do
+ expect(helper).to receive(:render_api_error!).with('404 Project Not Found', 404)
+
+ is_expected.to be_nil
+ end
+ end
+
+ context 'without current user' do
+ let_it_be(:user) { nil }
+
+ it 'returns Unauthorized' do
+ expect(helper).to receive(:render_api_error!).with('401 Unauthorized', 401)
+
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ context 'with existing project' do
+ let_it_be(:params_id) { project.id }
+
+ context 'with current user' do
+ let_it_be(:user) { create(:user) }
+
+ context 'as developer member' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns project' do
+ is_expected.to eq(project)
+ end
+ end
+
+ context 'as guest member' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'returns Forbidden' do
+ expect(helper).to receive(:render_api_error!).with('403 Forbidden', 403)
+
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ context 'without current user' do
+ let_it_be(:user) { nil }
+
+ it 'returns Unauthorized' do
+ expect(helper).to receive(:render_api_error!).with('401 Unauthorized', 401)
+
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ context 'if no authorized project scope' do
+ let_it_be(:params_id) { project.id }
+ let_it_be(:user) { nil }
+
+ it 'returns Forbidden' do
+ expect(helper).to receive(:authorized_project_scope?).and_return(false)
+ expect(helper).to receive(:render_api_error!).with('403 Forbidden', 403)
+
+ is_expected.to be_nil
+ end
+ end
+ end
end
diff --git a/spec/models/concerns/pg_full_text_searchable_spec.rb b/spec/models/concerns/pg_full_text_searchable_spec.rb
index 5a693f084e6..d9d5ec3f177 100644
--- a/spec/models/concerns/pg_full_text_searchable_spec.rb
+++ b/spec/models/concerns/pg_full_text_searchable_spec.rb
@@ -125,6 +125,17 @@ RSpec.describe PgFullTextSearchable do
end
end
+ context 'when search term is a path with underscores' do
+ let(:path) { 'browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb' }
+ let(:with_underscore) { model_class.create!(project: project, title: 'issue with path', description: "some #{path} other text") }
+
+ it 'allows searching by the path' do
+ with_underscore.update_search_data!
+
+ expect(model_class.pg_full_text_search(path)).to contain_exactly(with_underscore)
+ end
+ end
+
context 'when text has numbers preceded by a dash' do
let(:with_dash) { model_class.create!(project: project, title: 'issue with dash', description: 'ABC-123') }
diff --git a/spec/models/factories_spec.rb b/spec/models/factories_spec.rb
index 01331b0552f..072f5496bca 100644
--- a/spec/models/factories_spec.rb
+++ b/spec/models/factories_spec.rb
@@ -162,6 +162,13 @@ RSpec.describe 'factories', :saas do
board_assignee_lists
].index_with(true)
+ if Gitlab.jh?
+ licensed_features.merge! %i[
+ dingtalk_integration
+ feishu_bot_integration
+ ].index_with(true)
+ end
+
before do
stub_licensed_features(licensed_features)
end
diff --git a/spec/requests/api/go_proxy_spec.rb b/spec/requests/api/go_proxy_spec.rb
index fd74d06f383..5498ed6df13 100644
--- a/spec/requests/api/go_proxy_spec.rb
+++ b/spec/requests/api/go_proxy_spec.rb
@@ -406,6 +406,19 @@ RSpec.describe API::GoProxy do
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
+
+ context 'with access to package registry for everyone' do
+ let_it_be(:user) { nil }
+
+ before do
+ project.reload.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
+ end
+
+ it_behaves_like 'a module version list resource', 'v1.0.1', 'v1.0.2', 'v1.0.3'
+ it_behaves_like 'a module version information resource', 'v1.0.1'
+ it_behaves_like 'a module file resource', 'v1.0.1'
+ it_behaves_like 'a module archive resource', 'v1.0.1', ['README.md', 'go.mod', 'a.go']
+ end
end
context 'with a public project' do
diff --git a/spec/rubocop/cop/graphql/enum_names_spec.rb b/spec/rubocop/cop/graphql/enum_names_spec.rb
new file mode 100644
index 00000000000..f45df068381
--- /dev/null
+++ b/spec/rubocop/cop/graphql/enum_names_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+require_relative '../../../../rubocop/cop/graphql/enum_names'
+
+RSpec.describe RuboCop::Cop::Graphql::EnumNames do
+ describe 'class name' do
+ it 'adds an offense when class name does not end with `Enum`' do
+ expect_offense(<<~ENUM)
+ module Types
+ class Fake < BaseEnum
+ ^^^^ #{described_class::CLASS_NAME_SUFFIX_MSG}
+ graphql_name 'Fake'
+ end
+ end
+ ENUM
+ end
+ end
+
+ describe 'graphql_name' do
+ it 'adds an offense when `graphql_name` is not set' do
+ expect_offense(<<~ENUM)
+ module Types
+ class FakeEnum < BaseEnum
+ ^^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::GRAPHQL_NAME_MISSING_MSG}
+ end
+ end
+ ENUM
+ end
+
+ it 'adds no offense when `declarative_enum` is used' do
+ expect_no_offenses(<<~ENUM)
+ module Types
+ class FakeEnum < BaseEnum
+ declarative_enum ::FakeModule::FakeDeclarativeEnum
+ end
+ end
+ ENUM
+ end
+
+ it 'adds an offense when `graphql_name` includes `enum`' do
+ expect_offense(<<~ENUM)
+ module Types
+ class FakeEnum < BaseEnum
+ graphql_name 'FakeEnum'
+ ^^^^^^^^^^ #{described_class::GRAPHQL_NAME_WITH_ENUM_MSG}
+ end
+ end
+ ENUM
+ end
+ end
+end
diff --git a/spec/scripts/trigger-build_spec.rb b/spec/scripts/trigger-build_spec.rb
index ac8e3c7797c..9032ba85b9f 100644
--- a/spec/scripts/trigger-build_spec.rb
+++ b/spec/scripts/trigger-build_spec.rb
@@ -229,6 +229,7 @@ RSpec.describe Trigger do
context "when set in a file" do
before do
+ stub_env(version_file)
allow(File).to receive(:read).and_call_original
end
diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb
index 5c87b9ac8bb..c758d3d5477 100644
--- a/spec/services/groups/update_service_spec.rb
+++ b/spec/services/groups/update_service_spec.rb
@@ -101,6 +101,15 @@ RSpec.describe Groups::UpdateService do
expect(public_group.reload.name).to eq('new-name')
end
end
+
+ context 'when the path does not change' do
+ let(:params) { { name: 'new-name', path: public_group.path } }
+
+ it 'allows the update' do
+ expect(subject).to be true
+ expect(public_group.reload.name).to eq('new-name')
+ end
+ end
end
context 'within subgroup' do
diff --git a/spec/services/incident_management/timeline_events/create_service_spec.rb b/spec/services/incident_management/timeline_events/create_service_spec.rb
index 4e9cc4fa09c..3a924a40772 100644
--- a/spec/services/incident_management/timeline_events/create_service_spec.rb
+++ b/spec/services/incident_management/timeline_events/create_service_spec.rb
@@ -288,7 +288,7 @@ RSpec.describe IncidentManagement::TimelineEvents::CreateService do
let_it_be(:severity) { create(:issuable_severity, severity: :critical, issue: incident) }
- let(:expected_note) { "@#{current_user.username} changed the incident severity to **Critical**" }
+ let(:expected_note) { "@#{current_user.username} changed the incident severity to **Critical - S1**" }
let(:expected_action) { 'severity' }
it_behaves_like 'successfully created timeline event'
diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb
index d2f4fa0b8ef..37df90fff22 100644
--- a/spec/tasks/gitlab/gitaly_rake_spec.rb
+++ b/spec/tasks/gitlab/gitaly_rake_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'gitlab:gitaly namespace rake task', :silence_stdout do
let(:repo) { 'https://gitlab.com/gitlab-org/gitaly.git' }
let(:clone_path) { Rails.root.join('tmp/tests/gitaly').to_s }
let(:storage_path) { Rails.root.join('tmp/tests/repositories').to_s }
- let(:version) { File.read(Rails.root.join(Gitlab::GitalyClient::SERVER_VERSION_FILE)).chomp }
+ let(:version) { Gitlab::GitalyClient.expected_server_version }
describe 'clone' do
subject { run_rake_task('gitlab:gitaly:clone', clone_path, storage_path) }
diff --git a/workhorse/go.mod b/workhorse/go.mod
index 0ca3cce1d2f..d4bb000c05e 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -20,7 +20,7 @@ require (
github.com/johannesboyne/gofakes3 v0.0.0-20220627085814-c3ac35da23b2
github.com/jpillora/backoff v1.0.0
github.com/mitchellh/copystructure v1.2.0
- github.com/prometheus/client_golang v1.13.0
+ github.com/prometheus/client_golang v1.13.1
github.com/rafaeljusto/redigomock/v3 v3.1.1
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
github.com/sirupsen/logrus v1.9.0
diff --git a/workhorse/go.sum b/workhorse/go.sum
index caa3404527d..264d477e758 100644
--- a/workhorse/go.sum
+++ b/workhorse/go.sum
@@ -810,8 +810,9 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
-github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
+github.com/prometheus/client_golang v1.13.1 h1:3gMjIY2+/hzmqhtUC/aQNYldJA6DtH3CgQvwS+02K1c=
+github.com/prometheus/client_golang v1.13.1/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=