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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/editor/schema/ci.json86
-rw-r--r--app/assets/javascripts/issuable/issuable_form.js3
-rw-r--r--app/assets/javascripts/issues/list/components/issues_list_app.vue19
-rw-r--r--app/assets/javascripts/issues/list/constants.js2
-rw-r--r--app/assets/javascripts/issues/list/utils.js11
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue4
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue4
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js2
-rw-r--r--app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue8
-rw-r--r--app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue4
-rw-r--r--app/assets/stylesheets/framework/header.scss2
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/startup/startup-dark.scss21
-rw-r--r--app/assets/stylesheets/startup/startup-general.scss21
-rw-r--r--app/assets/stylesheets/startup/startup-signin.scss4
-rw-r--r--app/controllers/mailgun/webhooks_controller.rb55
-rw-r--r--app/controllers/members/mailgun/permanent_failures_controller.rb65
-rw-r--r--app/controllers/projects/ci/pipeline_editor_controller.rb1
-rw-r--r--app/graphql/resolvers/concerns/resolves_merge_requests.rb1
-rw-r--r--app/graphql/resolvers/merge_request_pipelines_resolver.rb7
-rw-r--r--app/models/merge_request.rb7
-rw-r--r--app/services/members/mailgun/process_webhook_service.rb4
-rw-r--r--app/services/projects/update_pages_service.rb5
-rw-r--r--app/views/layouts/header/_default.html.haml5
-rw-r--r--app/views/projects/releases/edit.html.haml2
-rw-r--r--app/workers/database/batched_background_migration/single_database_worker.rb20
-rw-r--r--app/workers/namespaces/process_sync_events_worker.rb2
-rw-r--r--app/workers/projects/process_sync_events_worker.rb2
29 files changed, 198 insertions, 178 deletions
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index 1352211b927..2f8719ee6af 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://gitlab.com/.gitlab-ci.yml",
"title": "Gitlab CI configuration",
- "description": "Gitlab has a built-in solution for doing CI called Gitlab CI. It is configured by supplying a file called `.gitlab-ci.yml`, which will list all the jobs that are going to run for the project. A full list of all options can be found at https://docs.gitlab.com/ee/ci/yaml/. You can read more about Gitlab CI at https://docs.gitlab.com/ee/ci/README.html.",
+ "markdownDescription": "Gitlab has a built-in solution for doing CI called Gitlab CI. It is configured by supplying a file called `.gitlab-ci.yml`, which will list all the jobs that are going to run for the project. A full list of all options can be found [here](https://docs.gitlab.com/ee/ci/yaml). [Learn More](https://docs.gitlab.com/ee/ci/index.html).",
"type": "object",
"properties": {
"$schema": {
@@ -33,7 +33,7 @@
},
"stages": {
"type": "array",
- "description": "Groups jobs into stages. All jobs in one stage must complete before next stage is executed. Defaults to ['build', 'test', 'deploy'].",
+ "markdownDescription": "Groups jobs into stages. All jobs in one stage must complete before next stage is executed. Defaults to ['build', 'test', 'deploy']. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#stages).",
"default": ["build", "test", "deploy"],
"items": {
"type": "string"
@@ -42,7 +42,7 @@
"minItems": 1
},
"include": {
- "description": "Can be `IncludeItem` or `IncludeItem[]`. Each `IncludeItem` will be a string, or an object with properties for the method if including external YAML file. The external content will be fetched, included and evaluated along the `.gitlab-ci.yml`.",
+ "markdownDescription": "Can be `IncludeItem` or `IncludeItem[]`. Each `IncludeItem` will be a string, or an object with properties for the method if including external YAML file. The external content will be fetched, included and evaluated along the `.gitlab-ci.yml`. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#include).",
"oneOf": [
{ "$ref": "#/definitions/include_item" },
{
@@ -53,7 +53,7 @@
},
"pages": {
"$ref": "#/definitions/job",
- "description": "A special job used to upload static sites to Gitlab pages. Requires a `public/` directory with `artifacts.path` pointing to it."
+ "markdownDescription": "A special job used to upload static sites to Gitlab pages. Requires a `public/` directory with `artifacts.path` pointing to it. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#pages)."
},
"workflow": {
"type": "object",
@@ -93,12 +93,12 @@
"definitions": {
"artifacts": {
"type": "object",
- "description": "Used to specify a list of files and directories that should be attached to the job if it succeeds. Artifacts are sent to Gitlab where they can be downloaded.",
+ "markdownDescription": "Used to specify a list of files and directories that should be attached to the job if it succeeds. Artifacts are sent to Gitlab where they can be downloaded. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#artifacts).",
"additionalProperties": false,
"properties": {
"paths": {
"type": "array",
- "description": "A list of paths to files/folders that should be included in the artifact.",
+ "markdownDescription": "A list of paths to files/folders that should be included in the artifact. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#artifactspaths).",
"items": {
"type": "string"
},
@@ -106,7 +106,7 @@
},
"exclude": {
"type": "array",
- "description": "A list of paths to files/folders that should be excluded in the artifact.",
+ "markdownDescription": "A list of paths to files/folders that should be excluded in the artifact. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#artifactsexclude).",
"items": {
"type": "string"
},
@@ -114,19 +114,19 @@
},
"expose_as": {
"type": "string",
- "description": "Can be used to expose job artifacts in the merge request UI. GitLab will add a link <expose_as> to the relevant merge request that points to the artifact."
+ "markdownDescription": "Can be used to expose job artifacts in the merge request UI. GitLab will add a link <expose_as> to the relevant merge request that points to the artifact. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#artifactsexpose_as)."
},
"name": {
"type": "string",
- "description": "Name for the archive created on job success. Can use variables in the name, e.g. '$CI_JOB_NAME'"
+ "markdownDescription": "Name for the archive created on job success. Can use variables in the name, e.g. '$CI_JOB_NAME' [Learn More](https://docs.gitlab.com/ee/ci/yaml/#artifactsname)."
},
"untracked": {
"type": "boolean",
- "description": "Whether to add all untracked files (along with 'artifacts.paths') to the artifact.",
+ "markdownDescription": "Whether to add all untracked files (along with 'artifacts.paths') to the artifact. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#artifactsuntracked).",
"default": false
},
"when": {
- "description": "Configure when artifacts are uploaded depended on job status.",
+ "markdownDescription": "Configure when artifacts are uploaded depended on job status. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#artifactswhen).",
"default": "on_success",
"oneOf": [
{
@@ -145,12 +145,12 @@
},
"expire_in": {
"type": "string",
- "description": "How long artifacts should be kept. They are saved 30 days by default. Artifacts that have expired are removed periodically via cron job. Supports a wide variety of formats, e.g. '1 week', '3 mins 4 sec', '2 hrs 20 min', '2h20min', '6 mos 1 day', '47 yrs 6 mos and 4d', '3 weeks and 2 days'.",
+ "markdownDescription": "How long artifacts should be kept. They are saved 30 days by default. Artifacts that have expired are removed periodically via cron job. Supports a wide variety of formats, e.g. '1 week', '3 mins 4 sec', '2 hrs 20 min', '2h20min', '6 mos 1 day', '47 yrs 6 mos and 4d', '3 weeks and 2 days'. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#artifactsexpire_in).",
"default": "30 days"
},
"reports": {
"type": "object",
- "description": "Reports will be uploaded as artifacts, and often displayed in the Gitlab UI, such as in Merge Requests.",
+ "markdownDescription": "Reports will be uploaded as artifacts, and often displayed in the Gitlab UI, such as in Merge Requests. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#artifactsreports).",
"additionalProperties": false,
"properties": {
"junit": {
@@ -367,11 +367,11 @@
"required": ["name"]
}
],
- "description": "Specifies the docker image to use for the job or globally for all jobs. Job configuration takes precedence over global setting. Requires a certain kind of Gitlab runner executor."
+ "markdownDescription": "Specifies the docker image to use for the job or globally for all jobs. Job configuration takes precedence over global setting. Requires a certain kind of Gitlab runner executor. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#image)."
},
"services": {
"type": "array",
- "description": "Similar to `image` property, but will link the specified services to the `image` container.",
+ "markdownDescription": "Similar to `image` property, but will link the specified services to the `image` container. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#services).",
"items": {
"oneOf": [
{
@@ -418,7 +418,7 @@
},
"secrets": {
"type": "object",
- "description": "Defines secrets to be injected as environment variables",
+ "markdownDescription": "Defines secrets to be injected as environment variables. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#secrets).",
"additionalProperties": {
"type": "object",
"description": "Environment variable name",
@@ -453,7 +453,7 @@
},
"before_script": {
"type": "array",
- "description": "Defines scripts that should run *before* the job. Can be set globally or per job.",
+ "markdownDescription": "Defines scripts that should run *before* the job. Can be set globally or per job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#before_script).",
"items": {
"anyOf": [
{
@@ -470,7 +470,7 @@
},
"after_script": {
"type": "array",
- "description": "Defines scripts that should run *after* the job. Can be set globally or per job.",
+ "markdownDescription": "Defines scripts that should run *after* the job. Can be set globally or per job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#after_script).",
"items": {
"anyOf": [
{
@@ -487,7 +487,7 @@
},
"rules": {
"type": "array",
- "description": "Rules allows for an array of individual rule objects to be evaluated in order, until one matches and dynamically provides attributes to the job.",
+ "markdownDescription": "Rules allows for an array of individual rule objects to be evaluated in order, until one matches and dynamically provides attributes to the job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#rules).",
"items": {
"type": "object",
"additionalProperties": false,
@@ -503,7 +503,7 @@
}
},
"globalVariables": {
- "description": "Defines environment variables globally. Job level property overrides global variables. If a job sets `variables: {}`, all global variables are turned off. You can use the value and description keywords to define variables that are prefilled when running a pipeline manually.",
+ "markdownDescription": "Defines environment variables globally. Job level property overrides global variables. If a job sets `variables: {}`, all global variables are turned off. You can use the value and description keywords to define variables that are prefilled when running a pipeline manually. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#variables).",
"type": "object",
"additionalProperties": {
"anyOf": [
@@ -523,41 +523,41 @@
},
"if": {
"type": "string",
- "description": "Expression to evaluate whether additional attributes should be provided to the job"
+ "markdownDescription": "Expression to evaluate whether additional attributes should be provided to the job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#rulesif)."
},
"changes": {
"type": "array",
- "description": "Additional attributes will be provided to job if any of the provided paths matches a modified file",
+ "markdownDescription": "Additional attributes will be provided to job if any of the provided paths matches a modified file. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#ruleschanges).",
"items": {
"type": "string"
}
},
"exists": {
"type": "array",
- "description": "Additional attributes will be provided to job if any of the provided paths matches an existing file in the repository",
+ "markdownDescription": "Additional attributes will be provided to job if any of the provided paths matches an existing file in the repository. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#rulesexists).",
"items": {
"type": "string"
}
},
"variables": {
"type": "object",
- "description": "Defines environment variables for specific jobs. Job level property overrides global variables. If a job sets `variables: {}`, all global variables are turned off.",
+ "markdownDescription": "Defines environment variables for specific jobs. Job level property overrides global variables. If a job sets `variables: {}`, all global variables are turned off. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#rulesvariables).",
"additionalProperties": {
"type": ["string", "integer"]
}
},
"timeout": {
"type": "string",
- "description": "Allows you to configure a timeout for a specific job (e.g. `1 minute`, `1h 30m 12s`). Read more: https://docs.gitlab.com/ee/ci/yaml/README.html#timeout",
+ "markdownDescription": "Allows you to configure a timeout for a specific job (e.g. `1 minute`, `1h 30m 12s`). [Learn More](https://docs.gitlab.com/ee/ci/yaml/index.html#timeout).",
"minLength": 1
},
"start_in": {
"type": "string",
- "description": "Used in conjunction with 'when: delayed' to set how long to delay before starting a job. e.g. '5', 5 seconds, 30 minutes, 1 week, etc. Read more: https://docs.gitlab.com/ee/ci/jobs/job_control.html#run-a-job-after-a-delay",
+ "markdownDescription": "Used in conjunction with 'when: delayed' to set how long to delay before starting a job. e.g. '5', 5 seconds, 30 minutes, 1 week, etc. [Learn More](https://docs.gitlab.com/ee/ci/jobs/job_control.html#run-a-job-after-a-delay).",
"minLength": 1
},
"allow_failure": {
- "description": "Allow job to fail. A failed job does not cause the pipeline to fail.",
+ "markdownDescription": "Allow job to fail. A failed job does not cause the pipeline to fail. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#allow_failure).",
"oneOf": [
{
"description": "Setting this option to true will allow the job to fail while still letting the pipeline pass.",
@@ -594,7 +594,7 @@
]
},
"when": {
- "description": "Describes the conditions for when to run the job. Defaults to 'on_success'.",
+ "markdownDescription": "Describes the conditions for when to run the job. Defaults to 'on_success'.",
"default": "on_success",
"oneOf": [
{
@@ -611,11 +611,11 @@
},
{
"enum": ["manual"],
- "description": "Execute the job manually from Gitlab UI or API. Read more: https://docs.gitlab.com/ee/ci/yaml/#when-manual"
+ "markdownDescription": "Execute the job manually from Gitlab UI or API. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#when)."
},
{
"enum": ["delayed"],
- "description": "Execute a job after the time limit in 'start_in' expires. Read more: https://docs.gitlab.com/ee/ci/yaml/#when-delayed"
+ "markdownDescription": "Execute a job after the time limit in 'start_in' expires. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#when)."
},
{
"enum": ["never"],
@@ -626,7 +626,7 @@
"cache": {
"properties": {
"when": {
- "description": "Defines when to save the cache, based on the status of the job.",
+ "markdownDescription": "Defines when to save the cache, based on the status of the job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cachewhen).",
"default": "on_success",
"oneOf": [
{
@@ -778,7 +778,7 @@
},
"variables": {
"type": "array",
- "description": "Filter job by checking comparing values of environment variables. Read more about variable expressions: https://docs.gitlab.com/ee/ci/variables/README.html#variables-expressions",
+ "markdownDescription": "Filter job by checking comparing values of CI/CD variables. [Learn More](https://docs.gitlab.com/ee/ci/jobs/job_control.html#cicd-variable-expressions).",
"items": {
"type": "string"
}
@@ -795,7 +795,7 @@
]
},
"retry": {
- "description": "Retry a job if it fails. Can be a simple integer or object definition.",
+ "markdownDescription": "Retry a job if it fails. Can be a simple integer or object definition. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#retry).",
"oneOf": [
{ "$ref": "#/definitions/retry_max" },
{
@@ -804,7 +804,7 @@
"properties": {
"max": { "$ref": "#/definitions/retry_max" },
"when": {
- "description": "Either a single or array of error types to trigger job retry.",
+ "markdownDescription": "Either a single or array of error types to trigger job retry. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#retrywhen).",
"oneOf": [
{ "$ref": "#/definitions/retry_errors" },
{
@@ -884,7 +884,7 @@
},
"interruptible": {
"type": "boolean",
- "description": "Interruptible is used to indicate that a job should be canceled if made redundant by a newer pipeline run.",
+ "markdownDescription": "Interruptible is used to indicate that a job should be canceled if made redundant by a newer pipeline run. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#interruptible).",
"default": false
},
"job": {
@@ -1241,11 +1241,11 @@
"description": "Limit job concurrency. Can be used to ensure that the Runner will not run certain jobs simultaneously."
},
"trigger": {
- "description": "Trigger allows you to define downstream pipeline trigger. When a job created from trigger definition is started by GitLab, a downstream pipeline gets created. Read more: https://docs.gitlab.com/ee/ci/yaml/README.html#trigger",
+ "markdownDescription": "Trigger allows you to define downstream pipeline trigger. When a job created from trigger definition is started by GitLab, a downstream pipeline gets created. [Learn More](https://docs.gitlab.com/ee/ci/yaml/index.html#trigger).",
"oneOf": [
{
"type": "object",
- "description": "Trigger a multi-project pipeline. Read more: https://docs.gitlab.com/ee/ci/pipelines/multi_project_pipelines.html#specify-a-downstream-pipeline-branch",
+ "markdownDescription": "Trigger a multi-project pipeline. [Learn More](https://docs.gitlab.com/ee/ci/pipelines/multi_project_pipelines.html#specify-a-downstream-pipeline-branch).",
"additionalProperties": false,
"properties": {
"project": {
@@ -1287,7 +1287,7 @@
},
{
"type": "object",
- "description": "Trigger a child pipeline. Read more: https://docs.gitlab.com/ee/ci/pipelines/parent_child_pipelines.html",
+ "description": "Trigger a child pipeline. [Learn More](https://docs.gitlab.com/ee/ci/pipelines/parent_child_pipelines.html).",
"additionalProperties": false,
"properties": {
"include": {
@@ -1398,7 +1398,7 @@
}
},
{
- "description": "Path to the project, e.g. `group/project`, or `group/sub-group/project`. Read more: https://docs.gitlab.com/ee/ci/pipelines/multi_project_pipelines.html#define-multi-project-pipelines-in-your-gitlab-ciyml-file",
+ "markdownDescription": "Path to the project, e.g. `group/project`, or `group/sub-group/project`. [Learn More](https://docs.gitlab.com/ee/ci/pipelines/multi_project_pipelines.html#define-multi-project-pipelines-in-your-gitlab-ciyml-file).",
"type": "string",
"pattern": "\\S/\\S"
}
@@ -1406,10 +1406,10 @@
},
"inherit": {
"type": "object",
- "description": "Controls inheritance of globally-defined defaults and variables. Boolean values control inheritance of all default: or variables: keywords. To inherit only a subset of default: or variables: keywords, specify what you wish to inherit. Anything not listed is not inherited.",
+ "markdownDescription": "Controls inheritance of globally-defined defaults and variables. Boolean values control inheritance of all default: or variables: keywords. To inherit only a subset of default: or variables: keywords, specify what you wish to inherit. Anything not listed is not inherited. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#inherit).",
"properties": {
"default": {
- "description": "Whether to inherit all globally-defined defaults or not. Or subset of inherited defaults",
+ "markdownDescription": "Whether to inherit all globally-defined defaults or not. Or subset of inherited defaults. [Learn more](https://docs.gitlab.com/ee/ci/yaml/#inheritdefault).",
"oneOf": [
{
"type": "boolean"
@@ -1435,7 +1435,7 @@
]
},
"variables": {
- "description": "Whether to inherit all globally-defined variables or not. Or subset of inherited variables",
+ "markdownDescription": "Whether to inherit all globally-defined variables or not. Or subset of inherited variables. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#inheritvariables).",
"oneOf": [
{ "type": "boolean" },
{
@@ -1470,7 +1470,7 @@
},
"tags": {
"type": "array",
- "description": "Used to select runners from the list of available runners. A runner must have all tags listed here to run the job.",
+ "markdownDescription": "Used to select runners from the list of available runners. A runner must have all tags listed here to run the job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#tags).",
"items": {
"type": "string"
}
diff --git a/app/assets/javascripts/issuable/issuable_form.js b/app/assets/javascripts/issuable/issuable_form.js
index 8e76a33c7dd..38453072af8 100644
--- a/app/assets/javascripts/issuable/issuable_form.js
+++ b/app/assets/javascripts/issuable/issuable_form.js
@@ -46,6 +46,9 @@ function getFallbackKey() {
export default class IssuableForm {
constructor(form) {
+ if (form.length === 0) {
+ return;
+ }
this.form = form;
this.toggleWip = this.toggleWip.bind(this);
this.renderWipExplanation = this.renderWipExplanation.bind(this);
diff --git a/app/assets/javascripts/issues/list/components/issues_list_app.vue b/app/assets/javascripts/issues/list/components/issues_list_app.vue
index b81ab103271..9d8b339e813 100644
--- a/app/assets/javascripts/issues/list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue
@@ -23,6 +23,7 @@ import CsvImportExportButtons from '~/issuable/components/csv_import_export_butt
import IssuableByEmail from '~/issuable/components/issuable_by_email.vue';
import { IssuableStatus } from '~/issues/constants';
import axios from '~/lib/utils/axios_utils';
+import { isPositiveInteger } from '~/lib/utils/number_utils';
import { scrollUp } from '~/lib/utils/scroll_utils';
import { getParameterByName, joinPaths } from '~/lib/utils/url_utility';
import {
@@ -45,6 +46,8 @@ import {
ISSUE_REFERENCE,
MAX_LIST_SIZE,
PAGE_SIZE,
+ PARAM_FIRST_PAGE_SIZE,
+ PARAM_LAST_PAGE_SIZE,
PARAM_PAGE_AFTER,
PARAM_PAGE_BEFORE,
PARAM_SORT,
@@ -390,12 +393,14 @@ export default {
},
urlParams() {
return {
- page_after: this.pageParams.afterCursor,
- page_before: this.pageParams.beforeCursor,
search: this.searchQuery,
sort: urlSortParams[this.sortKey],
state: this.state,
...this.urlFilterParams,
+ first_page_size: this.pageParams.firstPageSize,
+ last_page_size: this.pageParams.lastPageSize,
+ page_after: this.pageParams.afterCursor,
+ page_before: this.pageParams.beforeCursor,
};
},
hasCrmParameter() {
@@ -632,6 +637,8 @@ export default {
this.showBulkEditSidebar = showBulkEditSidebar;
},
updateData(sortValue) {
+ const firstPageSize = getParameterByName(PARAM_FIRST_PAGE_SIZE);
+ const lastPageSize = getParameterByName(PARAM_LAST_PAGE_SIZE);
const pageAfter = getParameterByName(PARAM_PAGE_AFTER);
const pageBefore = getParameterByName(PARAM_PAGE_BEFORE);
const state = getParameterByName(PARAM_STATE);
@@ -660,7 +667,13 @@ export default {
this.exportCsvPathWithQuery = this.getExportCsvPathWithQuery();
this.filterTokens = isSearchDisabled ? [] : getFilterTokens(window.location.search);
- this.pageParams = getInitialPageParams(sortKey, pageAfter, pageBefore);
+ this.pageParams = getInitialPageParams(
+ sortKey,
+ isPositiveInteger(firstPageSize) ? parseInt(firstPageSize, 10) : undefined,
+ isPositiveInteger(lastPageSize) ? parseInt(lastPageSize, 10) : undefined,
+ pageAfter,
+ pageBefore,
+ );
this.sortKey = sortKey;
this.state = state || IssuableStates.Opened;
},
diff --git a/app/assets/javascripts/issues/list/constants.js b/app/assets/javascripts/issues/list/constants.js
index 0795df10a7c..c7098d048ad 100644
--- a/app/assets/javascripts/issues/list/constants.js
+++ b/app/assets/javascripts/issues/list/constants.js
@@ -57,6 +57,8 @@ export const MAX_LIST_SIZE = 10;
export const PAGE_SIZE = 20;
export const PAGE_SIZE_MANUAL = 100;
export const PARAM_ASSIGNEE_ID = 'assignee_id';
+export const PARAM_FIRST_PAGE_SIZE = 'first_page_size';
+export const PARAM_LAST_PAGE_SIZE = 'last_page_size';
export const PARAM_PAGE_AFTER = 'page_after';
export const PARAM_PAGE_BEFORE = 'page_before';
export const PARAM_SORT = 'sort';
diff --git a/app/assets/javascripts/issues/list/utils.js b/app/assets/javascripts/issues/list/utils.js
index 3ca93069628..dfdc6e27f0d 100644
--- a/app/assets/javascripts/issues/list/utils.js
+++ b/app/assets/javascripts/issues/list/utils.js
@@ -46,8 +46,15 @@ import {
WEIGHT_DESC,
} from './constants';
-export const getInitialPageParams = (sortKey, afterCursor, beforeCursor) => ({
- firstPageSize: sortKey === RELATIVE_POSITION_ASC ? PAGE_SIZE_MANUAL : PAGE_SIZE,
+export const getInitialPageParams = (
+ sortKey,
+ firstPageSize = sortKey === RELATIVE_POSITION_ASC ? PAGE_SIZE_MANUAL : PAGE_SIZE,
+ lastPageSize,
+ afterCursor,
+ beforeCursor,
+) => ({
+ firstPageSize: lastPageSize ? undefined : firstPageSize,
+ lastPageSize,
afterCursor,
beforeCursor,
});
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue
index 15d92ab0ef7..9176210eb22 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue
@@ -25,6 +25,7 @@ import {
NOT_AVAILABLE_TEXT,
NOT_AVAILABLE_SIZE,
MORE_ACTIONS_TEXT,
+ COPY_IMAGE_PATH_TITLE,
} from '../../constants/index';
export default {
@@ -72,6 +73,7 @@ export default {
CONFIGURATION_DETAILS_ROW_TEST,
MISSING_MANIFEST_WARNING_TOOLTIP,
MORE_ACTIONS_TEXT,
+ COPY_IMAGE_PATH_TITLE,
},
computed: {
formattedSize() {
@@ -138,7 +140,7 @@ export default {
<clipboard-button
v-if="tag.location"
- :title="tag.location"
+ :title="$options.i18n.COPY_IMAGE_PATH_TITLE"
:text="tag.location"
category="tertiary"
:disabled="disabled"
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue
index d76a8245b63..e67d77210bb 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue
@@ -14,6 +14,7 @@ import {
IMAGE_FAILED_DELETED_STATUS,
IMAGE_MIGRATING_STATE,
ROOT_IMAGE_TEXT,
+ COPY_IMAGE_PATH_TITLE,
} from '../../constants/index';
import DeleteButton from '../delete_button.vue';
import CleanupStatus from './cleanup_status.vue';
@@ -52,6 +53,7 @@ export default {
i18n: {
REMOVE_REPOSITORY_LABEL,
ROW_SCHEDULED_FOR_DELETION,
+ COPY_IMAGE_PATH_TITLE,
},
computed: {
disabledDelete() {
@@ -115,7 +117,7 @@ export default {
v-if="item.location"
:disabled="deleting"
:text="item.location"
- :title="item.location"
+ :title="$options.i18n.COPY_IMAGE_PATH_TITLE"
category="tertiary"
/>
</template>
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js
index ceaf8a65a10..c6a7591e0d9 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/list.js
@@ -41,6 +41,8 @@ export const EMPTY_RESULT_MESSAGE = s__(
'ContainerRegistry|To widen your search, change or remove the filters above.',
);
+export const COPY_IMAGE_PATH_TITLE = s__('ContainerRegistry|Copy image path');
+
// Parameters
export const IMAGE_DELETE_SCHEDULED_STATUS = 'DELETE_SCHEDULED';
diff --git a/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue b/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
index 58df98d0fb7..8e95fad1e48 100644
--- a/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
+++ b/app/assets/javascripts/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
@@ -1,7 +1,6 @@
<script>
import { GlButton } from '@gitlab/ui';
import getAppStatus from '~/pipeline_editor/graphql/queries/client/app_status.query.graphql';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { EDITOR_APP_STATUS_EMPTY, EDITOR_APP_STATUS_LOADING } from '../../constants';
import FileTreePopover from '../popovers/file_tree_popover.vue';
import BranchSwitcher from './branch_switcher.vue';
@@ -12,7 +11,6 @@ export default {
FileTreePopover,
GlButton,
},
- mixins: [glFeatureFlagMixin()],
props: {
hasUnsavedChanges: {
type: Boolean,
@@ -43,11 +41,7 @@ export default {
return this.appStatus === EDITOR_APP_STATUS_LOADING;
},
showFileTreeToggle() {
- return (
- this.glFeatures.pipelineEditorFileTree &&
- !this.isNewCiConfigFile &&
- this.appStatus !== EDITOR_APP_STATUS_EMPTY
- );
+ return !this.isNewCiConfigFile && this.appStatus !== EDITOR_APP_STATUS_EMPTY;
},
},
methods: {
diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue
index 59022a91322..f26cdd8b017 100644
--- a/app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue
+++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_home.vue
@@ -1,7 +1,6 @@
<script>
import { GlModal } from '@gitlab/ui';
import { __ } from '~/locale';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import CommitSection from './components/commit/commit_section.vue';
import PipelineEditorDrawer from './components/drawer/pipeline_editor_drawer.vue';
import PipelineEditorFileNav from './components/file_nav/pipeline_editor_file_nav.vue';
@@ -34,7 +33,6 @@ export default {
PipelineEditorHeader,
PipelineEditorTabs,
},
- mixins: [glFeatureFlagMixin()],
props: {
ciConfigData: {
type: Object,
@@ -76,9 +74,6 @@ export default {
includesFiles() {
return this.ciConfigData?.includes || [];
},
- isFileTreeVisible() {
- return this.showFileTree && this.glFeatures.pipelineEditorFileTree;
- },
},
mounted() {
this.showFileTree = JSON.parse(localStorage.getItem(FILE_TREE_DISPLAY_KEY)) || false;
@@ -140,7 +135,7 @@ export default {
/>
<div class="gl-display-flex gl-w-full gl-sm-flex-direction-column">
<pipeline-editor-file-tree
- v-if="isFileTreeVisible"
+ v-if="showFileTree"
class="gl-flex-shrink-0"
:includes="includesFiles"
/>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue
index 0e31f97b9db..b1c4f7c5a7c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_summary.vue
@@ -98,10 +98,10 @@ export default {
<template>
<div data-qa-selector="approvals_summary_content">
- <strong>{{ approvalLeftMessage }}</strong>
+ <span class="gl-font-weight-bold">{{ approvalLeftMessage }}</span>
<template v-if="hasApprovers">
<span v-if="approvalLeftMessage">{{ message }}</span>
- <strong v-else>{{ message }}</strong>
+ <span v-else class="gl-font-weight-bold">{{ message }}</span>
<user-avatar-list
class="gl-display-inline-block gl-vertical-align-middle"
:img-size="24"
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index f76a0cbbae8..7c03a2bb049 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -234,6 +234,8 @@
.navbar-sub-nav {
display: flex;
+ align-items: center;
+ height: 100%;
margin: 0 0 0 6px;
.dropdown-chevron {
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index bc649b6407d..194ccb6b73e 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -439,7 +439,7 @@ $browser-scrollbar-size: 10px;
/*
* Misc
*/
-$header-height: var(--header-height, 40px);
+$header-height: var(--header-height, 48px);
$header-zindex: 1000;
$zindex-dropdown-menu: 300;
$suggestion-header-height: 46px;
diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss
index 001431e517b..b2a5906bb01 100644
--- a/app/assets/stylesheets/startup/startup-dark.scss
+++ b/app/assets/stylesheets/startup/startup-dark.scss
@@ -755,7 +755,7 @@ input {
padding: 0 16px;
z-index: 1000;
margin-bottom: 0;
- min-height: var(--header-height, 40px);
+ min-height: var(--header-height, 48px);
border: 0;
position: fixed;
top: 0;
@@ -771,7 +771,7 @@ input {
display: flex;
justify-content: space-between;
position: relative;
- min-height: var(--header-height, 40px);
+ min-height: var(--header-height, 48px);
padding-left: 0;
}
.navbar-gitlab .header-content .title {
@@ -787,9 +787,6 @@ input {
.navbar-gitlab .header-content .title img {
height: 24px;
}
-.navbar-gitlab .header-content .title img + .logo-text {
- margin-left: 8px;
-}
.navbar-gitlab .header-content .title a {
display: flex;
align-items: center;
@@ -915,6 +912,8 @@ input {
}
.navbar-sub-nav {
display: flex;
+ align-items: center;
+ height: 100%;
margin: 0 0 0 6px;
}
.caret-down,
@@ -1034,7 +1033,7 @@ input {
left: 0;
z-index: 600;
width: 220px;
- top: var(--header-height, 40px);
+ top: var(--header-height, 48px);
background-color: #303030;
transform: translate3d(0, 0, 0);
}
@@ -2044,19 +2043,9 @@ body.gl-dark {
.gl-display-none {
display: none;
}
-@media (min-width: 992px) {
- .gl-lg-display-none\! {
- display: none !important;
- }
-}
.gl-display-flex {
display: flex;
}
-@media (min-width: 992px) {
- .gl-lg-display-flex {
- display: flex;
- }
-}
@media (min-width: 576px) {
.gl-sm-display-block {
display: block;
diff --git a/app/assets/stylesheets/startup/startup-general.scss b/app/assets/stylesheets/startup/startup-general.scss
index c42b5554d8d..37d0c624eea 100644
--- a/app/assets/stylesheets/startup/startup-general.scss
+++ b/app/assets/stylesheets/startup/startup-general.scss
@@ -740,7 +740,7 @@ input {
padding: 0 16px;
z-index: 1000;
margin-bottom: 0;
- min-height: var(--header-height, 40px);
+ min-height: var(--header-height, 48px);
border: 0;
position: fixed;
top: 0;
@@ -756,7 +756,7 @@ input {
display: flex;
justify-content: space-between;
position: relative;
- min-height: var(--header-height, 40px);
+ min-height: var(--header-height, 48px);
padding-left: 0;
}
.navbar-gitlab .header-content .title {
@@ -772,9 +772,6 @@ input {
.navbar-gitlab .header-content .title img {
height: 24px;
}
-.navbar-gitlab .header-content .title img + .logo-text {
- margin-left: 8px;
-}
.navbar-gitlab .header-content .title a {
display: flex;
align-items: center;
@@ -900,6 +897,8 @@ input {
}
.navbar-sub-nav {
display: flex;
+ align-items: center;
+ height: 100%;
margin: 0 0 0 6px;
}
.caret-down,
@@ -1019,7 +1018,7 @@ input {
left: 0;
z-index: 600;
width: 220px;
- top: var(--header-height, 40px);
+ top: var(--header-height, 48px);
background-color: #f0f0f0;
transform: translate3d(0, 0, 0);
}
@@ -1704,19 +1703,9 @@ svg.s16 {
.gl-display-none {
display: none;
}
-@media (min-width: 992px) {
- .gl-lg-display-none\! {
- display: none !important;
- }
-}
.gl-display-flex {
display: flex;
}
-@media (min-width: 992px) {
- .gl-lg-display-flex {
- display: flex;
- }
-}
@media (min-width: 576px) {
.gl-sm-display-block {
display: block;
diff --git a/app/assets/stylesheets/startup/startup-signin.scss b/app/assets/stylesheets/startup/startup-signin.scss
index 020ed9c040b..7ac1a187bb8 100644
--- a/app/assets/stylesheets/startup/startup-signin.scss
+++ b/app/assets/stylesheets/startup/startup-signin.scss
@@ -419,7 +419,7 @@ body.navless {
}
}
.navless-container {
- margin-top: var(--header-height, 40px);
+ margin-top: var(--header-height, 48px);
padding-top: 32px;
}
.btn {
@@ -506,7 +506,7 @@ label.label-bold {
}
.navbar-empty {
justify-content: center;
- height: var(--header-height, 40px);
+ height: var(--header-height, 48px);
background: #fff;
border-bottom: 1px solid #dbdbdb;
}
diff --git a/app/controllers/mailgun/webhooks_controller.rb b/app/controllers/mailgun/webhooks_controller.rb
new file mode 100644
index 00000000000..faeda99769f
--- /dev/null
+++ b/app/controllers/mailgun/webhooks_controller.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+module Mailgun
+ class WebhooksController < ApplicationController
+ respond_to :json
+
+ skip_before_action :authenticate_user!
+ skip_before_action :verify_authenticity_token
+
+ before_action :ensure_feature_enabled!
+ before_action :authenticate_signature!
+
+ feature_category :team_planning
+
+ WEBHOOK_PROCESSORS = [
+ ::Members::Mailgun::ProcessWebhookService
+ ].freeze
+
+ def process_webhook
+ WEBHOOK_PROCESSORS.each do |processor_class|
+ processor = processor_class.new(params['event-data'] || {})
+ processor.execute if processor.should_process?
+ end
+
+ head :ok
+ end
+
+ private
+
+ def ensure_feature_enabled!
+ render_406 unless Gitlab::CurrentSettings.mailgun_events_enabled?
+ end
+
+ def authenticate_signature!
+ access_denied! unless valid_signature?
+ end
+
+ def valid_signature?
+ return false if Gitlab::CurrentSettings.mailgun_signing_key.blank?
+
+ # per this guide: https://documentation.mailgun.com/en/latest/user_manual.html#webhooks
+ digest = OpenSSL::Digest.new('SHA256')
+ data = [params.dig(:signature, :timestamp), params.dig(:signature, :token)].join
+
+ hmac_digest = OpenSSL::HMAC.hexdigest(digest, Gitlab::CurrentSettings.mailgun_signing_key, data)
+
+ ActiveSupport::SecurityUtils.secure_compare(params.dig(:signature, :signature), hmac_digest)
+ end
+
+ def render_406
+ # failure to stop retries per https://documentation.mailgun.com/en/latest/user_manual.html#webhooks
+ head :not_acceptable
+ end
+ end
+end
diff --git a/app/controllers/members/mailgun/permanent_failures_controller.rb b/app/controllers/members/mailgun/permanent_failures_controller.rb
deleted file mode 100644
index 685faa34694..00000000000
--- a/app/controllers/members/mailgun/permanent_failures_controller.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-
-module Members
- module Mailgun
- class PermanentFailuresController < ApplicationController
- respond_to :json
-
- skip_before_action :authenticate_user!
- skip_before_action :verify_authenticity_token
-
- before_action :ensure_feature_enabled!
- before_action :authenticate_signature!
- before_action :validate_invite_email!
-
- feature_category :authentication_and_authorization
-
- def create
- webhook_processor.execute
-
- head :ok
- end
-
- private
-
- def ensure_feature_enabled!
- render_406 unless Gitlab::CurrentSettings.mailgun_events_enabled?
- end
-
- def authenticate_signature!
- access_denied! unless valid_signature?
- end
-
- def valid_signature?
- return false if Gitlab::CurrentSettings.mailgun_signing_key.blank?
-
- # per this guide: https://documentation.mailgun.com/en/latest/user_manual.html#webhooks
- digest = OpenSSL::Digest.new('SHA256')
- data = [params.dig(:signature, :timestamp), params.dig(:signature, :token)].join
-
- hmac_digest = OpenSSL::HMAC.hexdigest(digest, Gitlab::CurrentSettings.mailgun_signing_key, data)
-
- ActiveSupport::SecurityUtils.secure_compare(params.dig(:signature, :signature), hmac_digest)
- end
-
- def validate_invite_email!
- # permanent_failures webhook does not provide a way to filter failures, so we'll get them all on this endpoint
- # and we only care about our invite_emails
- render_406 unless payload[:tags]&.include?(::Members::Mailgun::INVITE_EMAIL_TAG)
- end
-
- def webhook_processor
- ::Members::Mailgun::ProcessWebhookService.new(payload)
- end
-
- def payload
- @payload ||= params.permit!['event-data']
- end
-
- def render_406
- # failure to stop retries per https://documentation.mailgun.com/en/latest/user_manual.html#webhooks
- head :not_acceptable
- end
- end
- end
-end
diff --git a/app/controllers/projects/ci/pipeline_editor_controller.rb b/app/controllers/projects/ci/pipeline_editor_controller.rb
index dbf3b2051fb..84e5d59a2c3 100644
--- a/app/controllers/projects/ci/pipeline_editor_controller.rb
+++ b/app/controllers/projects/ci/pipeline_editor_controller.rb
@@ -4,7 +4,6 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController
before_action :check_can_collaborate!
before_action do
push_frontend_feature_flag(:schema_linting, @project)
- push_frontend_feature_flag(:pipeline_editor_file_tree, @project)
end
feature_category :pipeline_authoring
diff --git a/app/graphql/resolvers/concerns/resolves_merge_requests.rb b/app/graphql/resolvers/concerns/resolves_merge_requests.rb
index a72b9a09118..697cc6f5b03 100644
--- a/app/graphql/resolvers/concerns/resolves_merge_requests.rb
+++ b/app/graphql/resolvers/concerns/resolves_merge_requests.rb
@@ -52,6 +52,7 @@ module ResolvesMergeRequests
security_auto_fix: [:author],
head_pipeline: [:merge_request_diff, { head_pipeline: [:merge_request] }],
timelogs: [:timelogs],
+ pipelines: [:merge_request_diffs], # used by `recent_diff_head_shas` to load pipelines
committers: [merge_request_diff: [:merge_request_diff_commits]]
}
end
diff --git a/app/graphql/resolvers/merge_request_pipelines_resolver.rb b/app/graphql/resolvers/merge_request_pipelines_resolver.rb
index f84eedb4c3b..deb698c63e1 100644
--- a/app/graphql/resolvers/merge_request_pipelines_resolver.rb
+++ b/app/graphql/resolvers/merge_request_pipelines_resolver.rb
@@ -21,8 +21,9 @@ module Resolvers
super
end
- def query_for(args)
- resolve_pipelines(project, args).merge(merge_request.all_pipelines)
+ def query_for(input)
+ mr, args = input
+ resolve_pipelines(mr.source_project, args).merge(mr.all_pipelines)
end
def model_class
@@ -30,7 +31,7 @@ module Resolvers
end
def query_input(**args)
- args
+ [merge_request, args]
end
def project
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 39b5949ea7a..57eaf27069d 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1696,7 +1696,12 @@ class MergeRequest < ApplicationRecord
service_class.new(project, current_user, id: id, report_type: report_type).execute(comparison_base_pipeline(identifier), actual_head_pipeline)
end
- def recent_diff_head_shas(limit = 100)
+ MAX_RECENT_DIFF_HEAD_SHAS = 100
+
+ def recent_diff_head_shas(limit = MAX_RECENT_DIFF_HEAD_SHAS)
+ # see MergeRequestDiff.recent
+ return merge_request_diffs.to_a.sort_by(&:id).reverse.first(limit).pluck(:head_commit_sha) if merge_request_diffs.loaded?
+
merge_request_diffs.recent(limit).pluck(:head_commit_sha)
end
diff --git a/app/services/members/mailgun/process_webhook_service.rb b/app/services/members/mailgun/process_webhook_service.rb
index e359a83ad42..c0a9c2d5290 100644
--- a/app/services/members/mailgun/process_webhook_service.rb
+++ b/app/services/members/mailgun/process_webhook_service.rb
@@ -16,6 +16,10 @@ module Members
Gitlab::ErrorTracking.track_exception(e)
end
+ def should_process?
+ payload['event'] == 'failed' && payload['severity'] == 'permanent' && payload['tags']&.include?(::Members::Mailgun::INVITE_EMAIL_TAG)
+ end
+
private
attr_reader :payload, :member
diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb
index 2ec965fe2f4..c6ea364320f 100644
--- a/app/services/projects/update_pages_service.rb
+++ b/app/services/projects/update_pages_service.rb
@@ -30,6 +30,7 @@ module Projects
validate_state!
validate_max_size!
+ validate_public_folder!
validate_max_entries!
build.artifacts_file.use_file do |artifacts_path|
@@ -180,6 +181,10 @@ module Projects
end
end
+ def validate_public_folder!
+ raise InvalidStateError, 'Error: The `public/` folder is missing, or not declared in `.gitlab-ci.yml`.' unless total_size > 0
+ end
+
def entries_count
# we're using the full archive and pages daemon needs to read it
# so we want the total count from entries, not only "public/" directory
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 3cae8186750..4ba2a2d4fe4 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -9,10 +9,7 @@
%h1.title
%span.gl-sr-only GitLab
= link_to root_path, title: _('Dashboard'), id: 'logo', **tracking_attrs('main_navigation', 'click_gitlab_logo_link', 'navigation') do
- %span{ :class => "gl-display-none gl-lg-display-flex" }
- = brand_header_logo({add_gitlab_white_text: true})
- %span{ :class => "gl-lg-display-none! gl-display-flex" }
- = brand_header_logo
+ = brand_header_logo
- if Gitlab.com_and_canary?
= link_to Gitlab::Saas.canary_toggle_com_url, class: 'canary-badge bg-transparent', data: { qa_selector: 'canary_badge_link' }, target: :_blank, rel: 'noopener noreferrer' do
= gl_badge_tag({ variant: :success, size: :sm }) do
diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml
index 88ca64f2af0..1d53726e25c 100644
--- a/app/views/projects/releases/edit.html.haml
+++ b/app/views/projects/releases/edit.html.haml
@@ -1,3 +1,5 @@
- page_title _('Edit Release')
+- add_to_breadcrumbs _('Releases'), project_releases_path(@project)
+- add_to_breadcrumbs @release.name, project_release_path(@project, @release)
#js-edit-release-page{ data: data_for_edit_release_page }
diff --git a/app/workers/database/batched_background_migration/single_database_worker.rb b/app/workers/database/batched_background_migration/single_database_worker.rb
index aeadda4b8e1..8a0de268048 100644
--- a/app/workers/database/batched_background_migration/single_database_worker.rb
+++ b/app/workers/database/batched_background_migration/single_database_worker.rb
@@ -7,6 +7,7 @@ module Database
include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
+ include Gitlab::Utils::StrongMemoize
LEASE_TIMEOUT_MULTIPLIER = 3
MINIMUM_LEASE_TIMEOUT = 10.minutes.freeze
@@ -44,6 +45,15 @@ module Database
return
end
+ if shares_db_config?
+ Sidekiq.logger.info(
+ class: self.class.name,
+ database: self.class.tracking_database,
+ message: 'skipping migration execution for database that shares database configuration with another database')
+
+ return
+ end
+
Gitlab::Database::SharedModel.using_connection(base_model.connection) do
break unless self.class.enabled? && active_migration
@@ -63,7 +73,7 @@ module Database
private
def active_migration
- @active_migration ||= Gitlab::Database::BackgroundMigration::BatchedMigration.active_migration
+ @active_migration ||= Gitlab::Database::BackgroundMigration::BatchedMigration.active_migration(connection: base_model.connection)
end
def run_active_migration
@@ -71,7 +81,13 @@ module Database
end
def base_model
- @base_model ||= Gitlab::Database.database_base_models[self.class.tracking_database]
+ strong_memoize(:base_model) do
+ Gitlab::Database.database_base_models[self.class.tracking_database]
+ end
+ end
+
+ def shares_db_config?
+ base_model && Gitlab::Database.db_config_share_with(base_model.connection_db_config).present?
end
def with_exclusive_lease(interval)
diff --git a/app/workers/namespaces/process_sync_events_worker.rb b/app/workers/namespaces/process_sync_events_worker.rb
index 269710dd804..ea28fcd8720 100644
--- a/app/workers/namespaces/process_sync_events_worker.rb
+++ b/app/workers/namespaces/process_sync_events_worker.rb
@@ -13,7 +13,7 @@ module Namespaces
urgency :high
idempotent!
- deduplicate :until_executing
+ deduplicate :until_executed
def perform
results = ::Ci::ProcessSyncEventsService.new(
diff --git a/app/workers/projects/process_sync_events_worker.rb b/app/workers/projects/process_sync_events_worker.rb
index 1330ae47a68..6b6b4e3db7f 100644
--- a/app/workers/projects/process_sync_events_worker.rb
+++ b/app/workers/projects/process_sync_events_worker.rb
@@ -13,7 +13,7 @@ module Projects
urgency :high
idempotent!
- deduplicate :until_executing
+ deduplicate :until_executed
def perform
results = ::Ci::ProcessSyncEventsService.new(