diff options
Diffstat (limited to 'app')
31 files changed, 563 insertions, 186 deletions
diff --git a/app/assets/javascripts/alert_management/components/alert_management_table.vue b/app/assets/javascripts/alert_management/components/alert_management_table.vue index 37a6ea16018..c0cac958a42 100644 --- a/app/assets/javascripts/alert_management/components/alert_management_table.vue +++ b/app/assets/javascripts/alert_management/components/alert_management_table.vue @@ -216,8 +216,11 @@ export default { this.pagination = initialPaginationState; this.sort = sortObjectToString({ sortBy, sortDesc }); }, + showAlertLink({ iid }) { + return joinPaths(window.location.pathname, iid, 'details'); + }, navigateToAlertDetails({ iid }, index, { metaKey }) { - return visitUrl(joinPaths(window.location.pathname, iid, 'details'), metaKey); + return visitUrl(this.showAlertLink({ iid }), metaKey); }, hasAssignees(assignees) { return Boolean(assignees.nodes?.length); @@ -357,7 +360,7 @@ export default { :title="`${item.iid} - ${item.title}`" data-testid="idField" > - #{{ item.iid }} {{ item.title }} + <gl-link :href="showAlertLink(item)"> #{{ item.iid }} {{ item.title }} </gl-link> </div> </template> diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json index afdf6b9eee5..52bf9d25e6b 100644 --- a/app/assets/javascripts/editor/schema/ci.json +++ b/app/assets/javascripts/editor/schema/ci.json @@ -8,34 +8,74 @@ "type": "string", "format": "uri" }, - "image": { "$ref": "#/definitions/image" }, - "services": { "$ref": "#/definitions/services" }, - "before_script": { "$ref": "#/definitions/before_script" }, - "after_script": { "$ref": "#/definitions/after_script" }, - "variables": { "$ref": "#/definitions/globalVariables" }, - "cache": { "$ref": "#/definitions/cache" }, - "!reference": {"$ref" : "#/definitions/!reference"}, + "image": { + "$ref": "#/definitions/image" + }, + "services": { + "$ref": "#/definitions/services" + }, + "before_script": { + "$ref": "#/definitions/before_script" + }, + "after_script": { + "$ref": "#/definitions/after_script" + }, + "variables": { + "$ref": "#/definitions/globalVariables" + }, + "cache": { + "$ref": "#/definitions/cache" + }, + "!reference": { + "$ref": "#/definitions/!reference" + }, "default": { "type": "object", "properties": { - "after_script": { "$ref": "#/definitions/after_script" }, - "artifacts": { "$ref": "#/definitions/artifacts" }, - "before_script": { "$ref": "#/definitions/before_script" }, - "cache": { "$ref": "#/definitions/cache" }, - "image": { "$ref": "#/definitions/image" }, - "interruptible": { "$ref": "#/definitions/interruptible" }, - "retry": { "$ref": "#/definitions/retry" }, - "services": { "$ref": "#/definitions/services" }, - "tags": { "$ref": "#/definitions/tags" }, - "timeout": { "$ref": "#/definitions/timeout" }, - "!reference": {"$ref" : "#/definitions/!reference"} + "after_script": { + "$ref": "#/definitions/after_script" + }, + "artifacts": { + "$ref": "#/definitions/artifacts" + }, + "before_script": { + "$ref": "#/definitions/before_script" + }, + "cache": { + "$ref": "#/definitions/cache" + }, + "image": { + "$ref": "#/definitions/image" + }, + "interruptible": { + "$ref": "#/definitions/interruptible" + }, + "retry": { + "$ref": "#/definitions/retry" + }, + "services": { + "$ref": "#/definitions/services" + }, + "tags": { + "$ref": "#/definitions/tags" + }, + "timeout": { + "$ref": "#/definitions/timeout" + }, + "!reference": { + "$ref": "#/definitions/!reference" + } }, "additionalProperties": false }, "stages": { "type": "array", "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"], + "default": [ + "build", + "test", + "deploy" + ], "items": { "type": "string" }, @@ -45,10 +85,14 @@ "include": { "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" }, + { + "$ref": "#/definitions/include_item" + }, { "type": "array", - "items": { "$ref": "#/definitions/include_item" } + "items": { + "$ref": "#/definitions/include_item" + } } ] }, @@ -63,17 +107,36 @@ "type": "array", "items": { "anyOf": [ - {"type": "object"}, - {"type": "array", "minLength": 1, "items": { "type": "string" }} + { + "type": "object" + }, + { + "type": "array", + "minLength": 1, + "items": { + "type": "string" + } + } ], "properties": { - "if": { "$ref": "#/definitions/if" }, - "changes": { "$ref": "#/definitions/changes" }, - "exists": { "$ref": "#/definitions/exists" }, - "variables": { "$ref": "#/definitions/variables" }, + "if": { + "$ref": "#/definitions/if" + }, + "changes": { + "$ref": "#/definitions/changes" + }, + "exists": { + "$ref": "#/definitions/exists" + }, + "variables": { + "$ref": "#/definitions/variables" + }, "when": { "type": "string", - "enum": ["always", "never"] + "enum": [ + "always", + "never" + ] } }, "additionalProperties": false @@ -86,8 +149,12 @@ "^[.]": { "description": "Hidden keys.", "anyOf": [ - { "$ref": "#/definitions/job_template" }, - { "description": "Arbitrary YAML anchor." } + { + "$ref": "#/definitions/job_template" + }, + { + "description": "Arbitrary YAML anchor." + } ] } }, @@ -134,15 +201,21 @@ "default": "on_success", "oneOf": [ { - "enum": ["on_success"], + "enum": [ + "on_success" + ], "description": "Upload artifacts only when the job succeeds (this is the default)." }, { - "enum": ["on_failure"], + "enum": [ + "on_failure" + ], "description": "Upload artifacts only when the job fails." }, { - "enum": ["always"], + "enum": [ + "always" + ], "description": "Upload artifacts regardless of job status." } ] @@ -180,7 +253,9 @@ "properties": { "coverage_format": { "description": "Code coverage format used by the test framework.", - "enum": ["cobertura"] + "enum": [ + "cobertura" + ] }, "path": { "description": "Path to the coverage report file that should be parsed.", @@ -284,9 +359,13 @@ "format": "uri-reference", "pattern": "\\.ya?ml$" }, - "rules": { "$ref": "#/definitions/rules" } + "rules": { + "$ref": "#/definitions/rules" + } }, - "required": ["local"] + "required": [ + "local" + ] }, { "type": "object", @@ -319,7 +398,10 @@ ] } }, - "required": ["project", "file"] + "required": [ + "project", + "file" + ] }, { "type": "object", @@ -332,7 +414,9 @@ "pattern": "\\.ya?ml$" } }, - "required": ["template"] + "required": [ + "template" + ] }, { "type": "object", @@ -345,7 +429,9 @@ "pattern": "^https?://.+\\.ya?ml$" } }, - "required": ["remote"] + "required": [ + "remote" + ] } ] }, @@ -406,7 +492,9 @@ ] } }, - "required": ["name"] + "required": [ + "name" + ] }, { "type": "array", @@ -487,7 +575,9 @@ "minLength": 1 } }, - "required": ["name"] + "required": [ + "name" + ] } ] } @@ -511,20 +601,37 @@ "engine": { "type": "object", "properties": { - "name": { "type": "string" }, - "path": { "type": "string" } + "name": { + "type": "string" + }, + "path": { + "type": "string" + } }, - "required": ["name", "path"] + "required": [ + "name", + "path" + ] }, - "path": { "type": "string" }, - "field": { "type": "string" } + "path": { + "type": "string" + }, + "field": { + "type": "string" + } }, - "required": ["engine", "path", "field"] + "required": [ + "engine", + "path", + "field" + ] } ] } }, - "required": ["vault"] + "required": [ + "vault" + ] } }, "before_script": { @@ -570,17 +677,40 @@ "type": "object", "additionalProperties": false, "properties": { - "if": { "$ref": "#/definitions/if" }, - "changes": { "$ref": "#/definitions/changes" }, - "exists": { "$ref": "#/definitions/exists" }, - "variables": { "$ref": "#/definitions/variables" }, - "when": { "$ref": "#/definitions/when" }, - "start_in": { "$ref": "#/definitions/start_in" }, - "allow_failure": { "$ref": "#/definitions/allow_failure" } + "if": { + "$ref": "#/definitions/if" + }, + "changes": { + "$ref": "#/definitions/changes" + }, + "exists": { + "$ref": "#/definitions/exists" + }, + "variables": { + "$ref": "#/definitions/variables" + }, + "when": { + "$ref": "#/definitions/when" + }, + "start_in": { + "$ref": "#/definitions/start_in" + }, + "allow_failure": { + "$ref": "#/definitions/allow_failure" + } } }, - {"type": "string", "minLength": 1}, - {"type": "array", "minLength": 1, "items": { "type": "string" }} + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "minLength": 1, + "items": { + "type": "string" + } + } ] } }, @@ -591,7 +721,10 @@ ".*": { "oneOf": [ { - "type": ["string", "number"] + "type": [ + "string", + "number" + ] }, { "type": "object", @@ -621,7 +754,9 @@ { "type": "object", "additionalProperties": false, - "required": ["paths"], + "required": [ + "paths" + ], "properties": { "paths": { "type": "array", @@ -656,7 +791,10 @@ "type": "object", "patternProperties": { ".*": { - "type": ["string", "number"] + "type": [ + "string", + "number" + ] }, "additionalProperties": false } @@ -683,7 +821,9 @@ "description": "Exit code that are not considered failure. The job fails for any other exit code.", "type": "object", "additionalProperties": false, - "required": ["exit_codes"], + "required": [ + "exit_codes" + ], "properties": { "exit_codes": { "type": "integer" @@ -694,7 +834,9 @@ "description": "You can list which exit codes are not considered failures. The job fails for any other exit code.", "type": "object", "additionalProperties": false, - "required": ["exit_codes"], + "required": [ + "exit_codes" + ], "properties": { "exit_codes": { "type": "array", @@ -713,27 +855,39 @@ "default": "on_success", "oneOf": [ { - "enum": ["on_success"], + "enum": [ + "on_success" + ], "description": "Execute job only when all jobs from prior stages succeed." }, { - "enum": ["on_failure"], + "enum": [ + "on_failure" + ], "description": "Execute job when at least one job from prior stages fails." }, { - "enum": ["always"], + "enum": [ + "always" + ], "description": "Execute job regardless of the status from prior stages." }, { - "enum": ["manual"], + "enum": [ + "manual" + ], "markdownDescription": "Execute the job manually from Gitlab UI or API. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#when)." }, { - "enum": ["delayed"], + "enum": [ + "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"], + "enum": [ + "never" + ], "description": "Never execute the job." } ] @@ -745,15 +899,21 @@ "default": "on_success", "oneOf": [ { - "enum": ["on_success"], + "enum": [ + "on_success" + ], "description": "Save the cache only when the job succeeds." }, { - "enum": ["on_failure"], + "enum": [ + "on_failure" + ], "description": "Save the cache only when the job fails. " }, { - "enum": ["always"], + "enum": [ + "always" + ], "description": "Always save the cache. " } ] @@ -805,15 +965,21 @@ "default": "pull-push", "oneOf": [ { - "enum": ["pull"], + "enum": [ + "pull" + ], "description": "Pull will download cache but skip uploading after job completes." }, { - "enum": ["push"], + "enum": [ + "push" + ], "description": "Push will skip downloading cache and always recreate cache after job completes." }, { - "enum": ["pull-push"], + "enum": [ + "pull-push" + ], "description": "Pull-push will both download cache at job start and upload cache on job success." } ] @@ -828,39 +994,57 @@ { "oneOf": [ { - "enum": ["branches"], + "enum": [ + "branches" + ], "description": "When a branch is pushed." }, { - "enum": ["tags"], + "enum": [ + "tags" + ], "description": "When a tag is pushed." }, { - "enum": ["api"], + "enum": [ + "api" + ], "description": "When a pipeline has been triggered by a second pipelines API (not triggers API)." }, { - "enum": ["external"], + "enum": [ + "external" + ], "description": "When using CI services other than Gitlab" }, { - "enum": ["pipelines"], + "enum": [ + "pipelines" + ], "description": "For multi-project triggers, created using the API with 'CI_JOB_TOKEN'." }, { - "enum": ["pushes"], + "enum": [ + "pushes" + ], "description": "Pipeline is triggered by a `git push` by the user" }, { - "enum": ["schedules"], + "enum": [ + "schedules" + ], "description": "For scheduled pipelines." }, { - "enum": ["triggers"], + "enum": [ + "triggers" + ], "description": "For pipelines created using a trigger token." }, { - "enum": ["web"], + "enum": [ + "web" + ], "description": "For pipelines created using *Run pipeline* button in Gitlab UI (under your project's *Pipelines*)." } ] @@ -888,7 +1072,9 @@ "$ref": "#/definitions/filter_refs" }, "kubernetes": { - "enum": ["active"], + "enum": [ + "active" + ], "description": "Filter job based on if Kubernetes integration is active." }, "variables": { @@ -912,16 +1098,22 @@ "retry": { "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" }, + { + "$ref": "#/definitions/retry_max" + }, { "type": "object", "additionalProperties": false, "properties": { - "max": { "$ref": "#/definitions/retry_max" }, + "max": { + "$ref": "#/definitions/retry_max" + }, "when": { "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" }, + { + "$ref": "#/definitions/retry_errors" + }, { "type": "array", "items": { @@ -1004,21 +1196,39 @@ }, "job": { "allOf": [ - { "$ref": "#/definitions/job_template" } + { + "$ref": "#/definitions/job_template" + } ] }, "job_template": { "type": "object", "additionalProperties": false, "properties": { - "image": { "$ref": "#/definitions/image" }, - "services": { "$ref": "#/definitions/services" }, - "before_script": { "$ref": "#/definitions/before_script" }, - "after_script": { "$ref": "#/definitions/after_script" }, - "rules": { "$ref": "#/definitions/rules" }, - "variables": { "$ref": "#/definitions/variables" }, - "cache": { "$ref": "#/definitions/cache" }, - "secrets": { "$ref": "#/definitions/secrets" }, + "image": { + "$ref": "#/definitions/image" + }, + "services": { + "$ref": "#/definitions/services" + }, + "before_script": { + "$ref": "#/definitions/before_script" + }, + "after_script": { + "$ref": "#/definitions/after_script" + }, + "rules": { + "$ref": "#/definitions/rules" + }, + "variables": { + "$ref": "#/definitions/variables" + }, + "cache": { + "$ref": "#/definitions/cache" + }, + "secrets": { + "$ref": "#/definitions/secrets" + }, "script": { "markdownDescription": "Shell scripts executed by the Runner. The only required property of jobs. Be careful with special characters (e.g. `:`, `{`, `}`, `&`) and use single or double quotes to avoid issues. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#script)", "oneOf": [ @@ -1060,7 +1270,7 @@ } } ] - }, + }, "only": { "$ref": "#/definitions/filter", "description": "Job will run *only* when these filtering options match." @@ -1102,7 +1312,9 @@ "type": "boolean" } }, - "required": ["job"] + "required": [ + "job" + ] }, { "type": "object", @@ -1118,7 +1330,10 @@ "type": "boolean" } }, - "required": ["job", "pipeline"] + "required": [ + "job", + "pipeline" + ] }, { "type": "object", @@ -1137,7 +1352,11 @@ "type": "boolean" } }, - "required": ["job", "project", "ref"] + "required": [ + "job", + "project", + "ref" + ] } ] } @@ -1174,7 +1393,9 @@ "environment": { "description": "Used to associate environment metadata with a deploy. Environment can have a name and URL attached to it, and will be displayed under /environments under the project.", "oneOf": [ - { "type": "string" }, + { + "type": "string" + }, { "type": "object", "additionalProperties": false, @@ -1195,7 +1416,13 @@ "description": "The name of a job to execute when the environment is about to be stopped." }, "action": { - "enum": ["start", "prepare", "stop", "verify", "access"], + "enum": [ + "start", + "prepare", + "stop", + "verify", + "access" + ], "description": "Specifies what this job will do. 'start' (default) indicates the job will start the deployment. 'prepare'/'verify'/'access' indicates this will not affect the deployment. 'stop' indicates this will stop the deployment.", "default": "start" }, @@ -1226,7 +1453,9 @@ ] } }, - "required": ["name"] + "required": [ + "name" + ] } ] }, @@ -1306,15 +1535,23 @@ ] } }, - "required": ["name", "url"] + "required": [ + "name", + "url" + ] }, "minItems": 1 } }, - "required": ["links"] + "required": [ + "links" + ] } }, - "required": ["tag_name", "description"] + "required": [ + "tag_name", + "description" + ] }, "coverage": { "type": "string", @@ -1345,14 +1582,20 @@ "type": "object", "description": "Defines environment variables for specific job.", "additionalProperties": { - "type": ["string", "number", "array"] + "type": [ + "string", + "number", + "array" + ] } }, "maxItems": 50 } }, "additionalProperties": false, - "required": ["matrix"] + "required": [ + "matrix" + ] } ] }, @@ -1383,7 +1626,9 @@ "strategy": { "description": "You can mirror the pipeline status from the triggered pipeline to the source bridge job by using strategy: depend", "type": "string", - "enum": ["depend"] + "enum": [ + "depend" + ] }, "forward": { "description": "Specify what to forward to the downstream pipeline.", @@ -1403,9 +1648,13 @@ } } }, - "required": ["project"], + "required": [ + "project" + ], "dependencies": { - "branch": ["project"] + "branch": [ + "project" + ] } }, { @@ -1466,7 +1715,10 @@ "type": "string" } }, - "required": ["artifact", "job"] + "required": [ + "artifact", + "job" + ] }, { "type": "object", @@ -1489,7 +1741,10 @@ "pattern": "\\.ya?ml$" } }, - "required": ["project", "file"] + "required": [ + "project", + "file" + ] } ] } @@ -1499,7 +1754,9 @@ "strategy": { "description": "You can mirror the pipeline status from the triggered pipeline to the source bridge job by using strategy: depend", "type": "string", - "enum": ["depend"] + "enum": [ + "depend" + ] }, "forward": { "description": "Specify what to forward to the downstream pipeline.", @@ -1560,7 +1817,9 @@ "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" }, + { + "type": "boolean" + }, { "type": "array", "items": { @@ -1576,15 +1835,24 @@ "oneOf": [ { "properties": { - "when": { "enum": ["delayed"] } + "when": { + "enum": [ + "delayed" + ] + } }, - "required": ["when", "start_in"] + "required": [ + "when", + "start_in" + ] }, { "properties": { "when": { "not": { - "enum": ["delayed"] + "enum": [ + "delayed" + ] } } } @@ -1612,4 +1880,4 @@ } } } -} +}
\ No newline at end of file diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue index 3c07dee025f..4b7d606b52c 100644 --- a/app/assets/javascripts/integrations/edit/components/integration_form.vue +++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue @@ -230,10 +230,8 @@ export default { @change="setOverride" /> - <div v-if="!hasSections" class="row"> - <div class="col-lg-4"></div> - - <div class="col-lg-8"> + <section v-if="!hasSections" class="gl-lg-display-flex gl-justify-content-end"> + <div class="gl-flex-basis-two-thirds"> <!-- helpHtml is trusted input --> <div v-if="helpHtml" v-safe-html:[$options.helpHtmlConfig]="helpHtml"></div> @@ -249,7 +247,7 @@ export default { :type="propsSource.type" /> </div> - </div> + </section> <template v-if="hasSections"> <div @@ -258,8 +256,8 @@ export default { :class="{ 'gl-border-b gl-pb-3 gl-mb-6': index !== customState.sections.length - 1 }" data-testid="integration-section" > - <div class="row"> - <div class="col-lg-4"> + <section class="gl-lg-display-flex"> + <div class="gl-flex-basis-third"> <h4 class="gl-mt-0"> {{ section.title }}<gl-badge @@ -277,7 +275,7 @@ export default { <p v-safe-html="section.description"></p> </div> - <div class="col-lg-8"> + <div class="gl-flex-basis-two-thirds"> <component :is="$options.integrationFormSectionComponents[section.type]" :fields="fieldsForSection(section)" @@ -286,14 +284,12 @@ export default { @request-jira-issue-types="onRequestJiraIssueTypes" /> </div> - </div> + </section> </div> </template> - <div v-if="hasFieldsWithoutSection" class="row"> - <div class="col-lg-4"></div> - - <div class="col-lg-8"> + <section v-if="hasFieldsWithoutSection" class="gl-lg-display-flex gl-justify-content-end"> + <div class="gl-flex-basis-two-thirds"> <dynamic-field v-for="field in fieldsWithoutSection" :key="`${currentKey}-${field.name}`" @@ -302,12 +298,12 @@ export default { :data-qa-selector="`${field.name}_div`" /> </div> - </div> + </section> - <div v-if="isEditable" class="row"> - <div :class="hasSections ? 'col' : 'col-lg-8 offset-lg-4'"> + <section v-if="isEditable" :class="!hasSections && 'gl-lg-display-flex gl-justify-content-end'"> + <div :class="!hasSections && 'gl-flex-basis-two-thirds'"> <div - class="footer-block row-content-block gl-display-flex gl-justify-content-space-between" + class="footer-block row-content-block gl-lg-display-flex gl-justify-content-space-between" > <div> <template v-if="isInstanceOrGroupLevel"> @@ -369,6 +365,6 @@ export default { </template> </div> </div> - </div> + </section> </gl-form> </template> diff --git a/app/assets/javascripts/notes/components/discussion_filter_note.vue b/app/assets/javascripts/notes/components/discussion_filter_note.vue index 61af0b06535..39b3df899a5 100644 --- a/app/assets/javascripts/notes/components/discussion_filter_note.vue +++ b/app/assets/javascripts/notes/components/discussion_filter_note.vue @@ -31,7 +31,7 @@ export default { <div class="timeline-icon d-none d-lg-flex"> <gl-icon name="comment" /> </div> - <div class="timeline-content"> + <div class="timeline-content gl-pl-8"> <div data-testid="discussion-filter-timeline-content"> <gl-sprintf :message="$options.i18n.information"> <template #bold="{ content }"> diff --git a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js index b7768cfa5b9..df1188d365b 100644 --- a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js +++ b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js @@ -4,7 +4,7 @@ export const tdClass = 'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap'; export const thClass = 'gl-hover-bg-blue-50'; export const bodyTrClass = - 'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-cursor-pointer gl-hover-bg-blue-50 gl-hover-border-b-solid gl-hover-border-blue-200'; + 'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-cursor-pointer gl-hover-bg-gray-50 gl-hover-border-b-solid'; export const defaultPageSize = 20; diff --git a/app/assets/stylesheets/components/milestone_combobox.scss b/app/assets/stylesheets/components/milestone_combobox.scss deleted file mode 100644 index 94d295c324b..00000000000 --- a/app/assets/stylesheets/components/milestone_combobox.scss +++ /dev/null @@ -1,5 +0,0 @@ -.milestone-combobox { - .dropdown-menu.show { - overflow: hidden; - } -} diff --git a/app/assets/stylesheets/components/release_block.scss b/app/assets/stylesheets/components/release_block.scss deleted file mode 100644 index 7e82d0960d7..00000000000 --- a/app/assets/stylesheets/components/release_block.scss +++ /dev/null @@ -1,3 +0,0 @@ -.release-block { - transition: background-color 1s linear; -} diff --git a/app/assets/stylesheets/components/dashboard_skeleton.scss b/app/assets/stylesheets/page_bundles/operations.scss index 1dcaa47470b..497cb63033c 100644 --- a/app/assets/stylesheets/components/dashboard_skeleton.scss +++ b/app/assets/stylesheets/page_bundles/operations.scss @@ -1,3 +1,5 @@ +@import 'mixins_and_variables_and_functions'; + .dashboard-cards { margin-right: -$gl-padding-8; margin-left: -$gl-padding-8; @@ -8,7 +10,7 @@ &-header { &-warning { - background-color: $orange-100; + background-color: var(--orange-100, $orange-100); } } @@ -16,16 +18,16 @@ min-height: 120px; &-warning { - background-color: $orange-50; + background-color: var(--orange-50, $orange-50); } &-failed { - background-color: $red-50; + background-color: var(--red-50, $red-50); } } &-icon { - color: $gray-300; + color: var(--gray-300, $gray-300); } &-footer { @@ -33,7 +35,7 @@ height: $gl-padding-32; &-arrow { - color: $gray-200; + color: var(--gray-200, $gray-200); } &-downstream { @@ -41,7 +43,7 @@ } &-extra { - background-color: $gray-200; + background-color: var(--gray-200, $gray-200); font-size: 10px; line-height: $gl-line-height; width: $gl-padding; @@ -50,7 +52,7 @@ &-header { &-failed { - background-color: $red-100; + background-color: var(--red-100, $red-100); } } @@ -66,10 +68,10 @@ background-repeat: no-repeat; background-size: cover; background-image: linear-gradient(to right, - $gray-50 0%, - $gray-10 20%, - $gray-50 40%, - $gray-50 100%); + var(--gray-50, $gray-50) 0%, + var(--gray-10, $gray-10) 20%, + var(--gray-50, $gray-50) 40%, + var(--gray-50, $gray-50) 100%); border-radius: $gl-padding; height: $gl-padding; margin-top: -$gl-padding-8; diff --git a/app/assets/stylesheets/components/release_block_milestone_info.scss b/app/assets/stylesheets/page_bundles/releases.scss index b6a85ae965a..24ffbf9b90c 100644 --- a/app/assets/stylesheets/components/release_block_milestone_info.scss +++ b/app/assets/stylesheets/page_bundles/releases.scss @@ -1,3 +1,9 @@ +@import 'mixins_and_variables_and_functions'; + +.release-block { + transition: background-color 1s linear; +} + .release-block-milestone-info { .milestone-progress-bar-container { width: 300px; diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index bd61e8df699..cfad34760ad 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -435,8 +435,8 @@ $system-note-svg-size: 1rem; .discussion-filter-note { .timeline-icon { - width: $system-note-icon-size + 6; - height: $system-note-icon-size + 6; + width: $system-note-icon-size; + height: $system-note-icon-size; margin-top: -8px; } } diff --git a/app/finders/labels_finder.rb b/app/finders/labels_finder.rb index ecd6270ed47..9f9d0da6efd 100644 --- a/app/finders/labels_finder.rb +++ b/app/finders/labels_finder.rb @@ -19,7 +19,7 @@ class LabelsFinder < UnionFinder items = with_title(items) items = by_subscription(items) items = by_search(items) - sort(items) + sort(items.with_preloaded_container) end private diff --git a/app/graphql/resolvers/base_issues_resolver.rb b/app/graphql/resolvers/base_issues_resolver.rb index 479b1df6876..6357132705e 100644 --- a/app/graphql/resolvers/base_issues_resolver.rb +++ b/app/graphql/resolvers/base_issues_resolver.rb @@ -47,7 +47,6 @@ module Resolvers def preloads { alert_management_alert: [:alert_management_alert], - labels: [:labels], assignees: [:assignees], participants: Issue.participant_includes, timelogs: [:timelogs], diff --git a/app/graphql/resolvers/bulk_labels_resolver.rb b/app/graphql/resolvers/bulk_labels_resolver.rb new file mode 100644 index 00000000000..a758ef70f93 --- /dev/null +++ b/app/graphql/resolvers/bulk_labels_resolver.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Resolvers + class BulkLabelsResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + + type Types::LabelType.connection_type, null: true + + def resolve + authorize!(object) + + BatchLoader::GraphQL.for(object.id).batch(cache: false) do |ids, loader, args| + labels = Label.for_targets(ids, object.class.name).group_by(&:target_id) + + ids.each do |id| + loader.call(id, labels[id] || []) + end + end + end + + private + + def authorized_resource?(object) + Ability.allowed?(current_user, :read_label, object.issuing_parent) + end + end +end diff --git a/app/graphql/resolvers/concerns/resolves_merge_requests.rb b/app/graphql/resolvers/concerns/resolves_merge_requests.rb index 697cc6f5b03..b6510e7c5fa 100644 --- a/app/graphql/resolvers/concerns/resolves_merge_requests.rb +++ b/app/graphql/resolvers/concerns/resolves_merge_requests.rb @@ -42,7 +42,6 @@ module ResolvesMergeRequests assignees: [:assignees], reviewers: [:reviewers], participants: MergeRequest.participant_includes, - labels: [:labels], author: [:author], merged_at: [:metrics], commit_count: [:metrics], diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index ca4eb044bab..76fac831199 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -43,8 +43,10 @@ module Types field :updated_by, Types::UserType, null: true, description: 'User that last updated the issue.' - field :labels, Types::LabelType.connection_type, null: true, - description: 'Labels of the issue.' + field :labels, Types::LabelType.connection_type, + null: true, + description: 'Labels of the issue.', + resolver: Resolvers::BulkLabelsResolver field :milestone, Types::MilestoneType, null: true, description: 'Milestone of the issue.' diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 3a39236bafa..8cc600fc68e 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -158,8 +158,11 @@ module Types description: 'Human-readable time estimate of the merge request.' field :human_total_time_spent, GraphQL::Types::String, null: true, description: 'Human-readable total time reported as spent on the merge request.' - field :labels, Types::LabelType.connection_type, null: true, complexity: 5, - description: 'Labels of the merge request.' + field :labels, Types::LabelType.connection_type, + null: true, complexity: 5, + description: 'Labels of the merge request.', + resolver: Resolvers::BulkLabelsResolver + field :milestone, Types::MilestoneType, null: true, description: 'Milestone of the merge request.' field :participants, Types::MergeRequests::ParticipantType.connection_type, null: true, complexity: 15, diff --git a/app/models/ci/secure_file.rb b/app/models/ci/secure_file.rb index 0644c9f3235..3cc57e8f907 100644 --- a/app/models/ci/secure_file.rb +++ b/app/models/ci/secure_file.rb @@ -7,6 +7,7 @@ module Ci FILE_SIZE_LIMIT = 5.megabytes.freeze CHECKSUM_ALGORITHM = 'sha256' + PARSABLE_EXTENSIONS = ['cer'].freeze self.limit_scope = :project self.limit_name = 'project_ci_secure_files' @@ -34,6 +35,37 @@ module Ci CHECKSUM_ALGORITHM end + def file_extension + File.extname(name).delete_prefix('.') + end + + def metadata_parsable? + PARSABLE_EXTENSIONS.include?(file_extension) + end + + def metadata_parser + return unless metadata_parsable? + + case file_extension + when 'cer' + Gitlab::Ci::SecureFiles::Cer.new(file.read) + end + end + + def update_metadata! + return unless metadata_parser + + begin + parser = metadata_parser + self.metadata = parser.metadata + self.expires_at = parser.expires_at if parser.respond_to?(:expires_at) + save! + rescue StandardError => err + Gitlab::AppLogger.error("Secure File Parser Failure (#{id}): #{err.message} - #{parser.error}.") + nil + end + end + private def assign_checksum diff --git a/app/models/group_label.rb b/app/models/group_label.rb index ff14529c6e6..0d2eb524929 100644 --- a/app/models/group_label.rb +++ b/app/models/group_label.rb @@ -2,6 +2,7 @@ class GroupLabel < Label belongs_to :group + belongs_to :parent_container, foreign_key: :group_id, class_name: 'Group' validates :group, presence: true diff --git a/app/models/label.rb b/app/models/label.rb index 6608a0573cb..35daca92089 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -42,6 +42,7 @@ class Label < ApplicationRecord scope :order_name_asc, -> { reorder(title: :asc) } scope :order_name_desc, -> { reorder(title: :desc) } scope :subscribed_by, ->(user_id) { joins(:subscriptions).where(subscriptions: { user_id: user_id, subscribed: true }) } + scope :with_preloaded_container, -> { preload(parent_container: :route) } scope :top_labels_by_target, -> (target_relation) { label_id_column = arel_table[:id] @@ -59,6 +60,14 @@ class Label < ApplicationRecord .distinct } + scope :for_targets, ->(target_ids, targets_type) do + joins(:label_links) + .where(label_links: { target_id: target_ids }) + .where(label_links: { target_type: targets_type }) + .select("labels.*, target_id") + .with_preloaded_container + end + def self.prioritized(project) joins(:priorities) .where(label_priorities: { project_id: project }) diff --git a/app/models/preloaders/labels_preloader.rb b/app/models/preloaders/labels_preloader.rb index 722d588d8bc..b6e73c1cd02 100644 --- a/app/models/preloaders/labels_preloader.rb +++ b/app/models/preloaders/labels_preloader.rb @@ -21,8 +21,10 @@ module Preloaders def preload_all preloader = ActiveRecord::Associations::Preloader.new + preloader.preload(labels, parent_container: :route) preloader.preload(labels.select { |l| l.is_a? ProjectLabel }, { project: [:project_feature, namespace: :route] }) preloader.preload(labels.select { |l| l.is_a? GroupLabel }, { group: :route }) + labels.each do |label| label.lazy_subscription(user) label.lazy_subscription(user, project) if project.present? diff --git a/app/models/project_label.rb b/app/models/project_label.rb index d0b16cc98b4..dc647901b46 100644 --- a/app/models/project_label.rb +++ b/app/models/project_label.rb @@ -4,6 +4,7 @@ class ProjectLabel < Label MAX_NUMBER_OF_PRIORITIES = 1 belongs_to :project + belongs_to :parent_container, foreign_key: :project_id, class_name: 'Project' validates :project, presence: true diff --git a/app/models/user.rb b/app/models/user.rb index d64a52ff7b9..be3bec0d142 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -935,6 +935,7 @@ class User < ApplicationRecord # that the password is the user's password def valid_password?(password) return false unless password_allowed?(password) + return false if password_automatically_set? return super if Feature.enabled?(:pbkdf2_password_encryption) Devise::Encryptor.compare(self.class, encrypted_password, password) diff --git a/app/policies/group_label_policy.rb b/app/policies/group_label_policy.rb index 9f3acd44b23..4a848e44fec 100644 --- a/app/policies/group_label_policy.rb +++ b/app/policies/group_label_policy.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class GroupLabelPolicy < BasePolicy - delegate { @subject.group } + delegate { @subject.parent_container } end diff --git a/app/policies/project_label_policy.rb b/app/policies/project_label_policy.rb index 5ce896ecaf2..6656d5990a5 100644 --- a/app/policies/project_label_policy.rb +++ b/app/policies/project_label_policy.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class ProjectLabelPolicy < BasePolicy - delegate { @subject.project } + delegate { @subject.parent_container } end diff --git a/app/services/labels/promote_service.rb b/app/services/labels/promote_service.rb index e3b110f8f26..2786a2e357e 100644 --- a/app/services/labels/promote_service.rb +++ b/app/services/labels/promote_service.rb @@ -9,7 +9,7 @@ module Labels return unless project.group && label.is_a?(ProjectLabel) - Label.transaction do + ProjectLabel.transaction do # use the existing group label if it exists group_label = find_or_create_group_label(label) @@ -50,7 +50,7 @@ module Labels .new(current_user, title: group_label.title, group_id: project.group.id) .execute(skip_authorization: true) .where.not(id: group_label) - .select(:id) # Can't use pluck() to avoid object-creation because of the batching + .select(:id, :project_id, :group_id, :type) # Can't use pluck() to avoid object-creation because of the batching end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 6d31a29f5a7..6b4f9dbe509 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -26,6 +26,7 @@ module MergeRequests @merge_request = merge_request @options = options + jid = merge_jid validate! @@ -37,7 +38,7 @@ module MergeRequests end end - log_info("Merge process finished on JID #{merge_jid} with state #{state}") + log_info("Merge process finished on JID #{jid} with state #{state}") rescue MergeError => e handle_merge_error(log_message: e.message, save_message_on_model: true) ensure @@ -159,17 +160,32 @@ module MergeRequests end def handle_merge_error(log_message:, save_message_on_model: false) - Gitlab::AppLogger.error("MergeService ERROR: #{merge_request_info} - #{log_message}") + log_error("MergeService ERROR: #{merge_request_info} - #{log_message}") @merge_request.update(merge_error: log_message) if save_message_on_model end def log_info(message) + payload = log_payload("#{merge_request_info} - #{message}") + logger.info(**payload) + end + + def log_error(message) + payload = log_payload(message) + logger.error(**payload) + end + + def logger @logger ||= Gitlab::AppLogger - @logger.info("#{merge_request_info} - #{message}") + end + + def log_payload(message) + Gitlab::ApplicationContext.current + .merge(merge_request_info: merge_request_info, + message: message) end def merge_request_info - merge_request.to_reference(full: true) + @merge_request_info ||= merge_request.to_reference(full: true) end def source_matches? diff --git a/app/services/pages_domains/create_acme_order_service.rb b/app/services/pages_domains/create_acme_order_service.rb index e289a78091b..c600f497fa5 100644 --- a/app/services/pages_domains/create_acme_order_service.rb +++ b/app/services/pages_domains/create_acme_order_service.rb @@ -2,9 +2,6 @@ module PagesDomains class CreateAcmeOrderService - # elliptic curve algorithm to generate the private key - ECDSA_CURVE = "prime256v1" - attr_reader :pages_domain def initialize(pages_domain) @@ -17,12 +14,7 @@ module PagesDomains challenge = order.new_challenge - private_key = if Feature.enabled?(:pages_lets_encrypt_ecdsa, pages_domain.project) - OpenSSL::PKey::EC.generate(ECDSA_CURVE) - else - OpenSSL::PKey::RSA.new(4096) - end - + private_key = OpenSSL::PKey::RSA.new(4096) saved_order = pages_domain.acme_orders.create!( url: order.url, expires_at: order.expires, diff --git a/app/views/projects/releases/index.html.haml b/app/views/projects/releases/index.html.haml index 9ddf2201fad..975abaefc6c 100644 --- a/app/views/projects/releases/index.html.haml +++ b/app/views/projects/releases/index.html.haml @@ -1,4 +1,5 @@ - page_title _('Releases') +- add_page_specific_style 'page_bundles/releases' - if use_startup_query_for_index_page? - add_page_startup_graphql_call('releases/all_releases', index_page_startup_query_variables) diff --git a/app/views/projects/releases/show.html.haml b/app/views/projects/releases/show.html.haml index 91ee9ad70a3..66b187c8c72 100644 --- a/app/views/projects/releases/show.html.haml +++ b/app/views/projects/releases/show.html.haml @@ -1,5 +1,6 @@ - add_to_breadcrumbs _("Releases"), project_releases_path(@project) - page_title @release.name - page_description @release.description_html +- add_page_specific_style 'page_bundles/releases' #js-show-release-page{ data: data_for_show_page } diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 26f9f45e4bd..e02285e7f34 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -2181,6 +2181,15 @@ :weight: 1 :idempotent: true :tags: [] +- :name: ci_parse_secure_file_metadata + :worker_name: Ci::ParseSecureFileMetadataWorker + :feature_category: :mobile_signing_deployment + :has_external_dependencies: false + :urgency: :low + :resource_boundary: :unknown + :weight: 1 + :idempotent: true + :tags: [] - :name: ci_runners_process_runner_version_update :worker_name: Ci::Runners::ProcessRunnerVersionUpdateWorker :feature_category: :runner_fleet diff --git a/app/workers/ci/parse_secure_file_metadata_worker.rb b/app/workers/ci/parse_secure_file_metadata_worker.rb new file mode 100644 index 00000000000..0d2495d3155 --- /dev/null +++ b/app/workers/ci/parse_secure_file_metadata_worker.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Ci + class ParseSecureFileMetadataWorker + include ::ApplicationWorker + + feature_category :mobile_signing_deployment + urgency :low + idempotent! + + def perform(secure_file_id) + ::Ci::SecureFile.find_by_id(secure_file_id).try(&:update_metadata!) + end + end +end |