Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									763dd8a47a
								
							
						
					
					
						commit
						b794758ce4
					
				|  | @ -4,8 +4,9 @@ | |||
| .if-not-canonical-namespace: &if-not-canonical-namespace | ||||
|   if: '$CI_PROJECT_NAMESPACE !~ /^gitlab(-org)?($|\/)/' | ||||
| 
 | ||||
| .if-not-ee: &if-not-ee | ||||
|   if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/' | ||||
| .exists-ee: &exists-ee | ||||
|   exists: | ||||
|     - ee/**/* | ||||
| 
 | ||||
| .if-not-foss: &if-not-foss | ||||
|   if: '$CI_PROJECT_NAME != "gitlab-foss" && $CI_PROJECT_NAME != "gitlab-ce" && $CI_PROJECT_NAME != "gitlabhq"' | ||||
|  | @ -311,13 +312,14 @@ | |||
| ###################### | ||||
| .build-images:rules:build-qa-image: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-dot-com-gitlab-org-and-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-build-images-patterns | ||||
|     - <<: *if-dot-com-gitlab-org-and-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-qa-patterns | ||||
|     - <<: *if-dot-com-gitlab-org-schedule | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .build-images:rules:build-assets-image: | ||||
|   rules: | ||||
|  | @ -363,9 +365,8 @@ | |||
| 
 | ||||
| .dev-fixtures:rules:ee-only: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-default-refs | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|       when: on_success | ||||
| 
 | ||||
|  | @ -391,9 +392,8 @@ | |||
| 
 | ||||
| .graphql:rules:graphql-verify: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-default-refs | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-qa-patterns | ||||
|       when: on_success | ||||
| 
 | ||||
|  | @ -414,9 +414,8 @@ | |||
| 
 | ||||
| .frontend:rules:compile-test-assets-as-if-foss: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request  # Always run for MRs since `compile-test-assets as-if-foss` is either needed by `rspec foss-impact` or the `rspec * as-if-foss` jobs. | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-qa-patterns | ||||
| 
 | ||||
| .frontend:rules:default-frontend-jobs: | ||||
|  | @ -426,39 +425,37 @@ | |||
| 
 | ||||
| .frontend:rules:default-frontend-jobs-ee: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-default-refs | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
| 
 | ||||
| .frontend:rules:default-frontend-jobs-as-if-foss: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-patterns | ||||
| 
 | ||||
| .frontend:rules:eslint-as-if-foss: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *frontend-patterns | ||||
| 
 | ||||
| .frontend:rules:ee-mr-and-default-branch-only: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|       when: always | ||||
|     - <<: *if-default-branch-refs | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
| 
 | ||||
| .frontend:rules:qa-frontend-node: | ||||
|  | @ -499,9 +496,8 @@ | |||
| ############### | ||||
| .pages:rules: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-default-branch-schedule-2-hourly | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| ############ | ||||
| # QA rules # | ||||
|  | @ -514,30 +510,34 @@ | |||
| 
 | ||||
| .qa:rules:as-if-foss: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-qa-patterns | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-patterns | ||||
| 
 | ||||
| .qa:rules:package-and-qa: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-dot-com-gitlab-org-and-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-qa-patterns | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-and-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *qa-patterns | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-and-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-patterns | ||||
|       when: manual | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-schedule | ||||
|       <<: *exists-ee | ||||
|       allow_failure: true | ||||
| 
 | ||||
| ############### | ||||
|  | @ -649,15 +649,13 @@ | |||
| 
 | ||||
| .rails:rules:ee-only-migration: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - changes: *db-patterns | ||||
|     - <<: *exists-ee | ||||
|       changes: *db-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .rails:rules:ee-only-migration:minimal: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-rspec-minimal-disabled | ||||
|       when: never | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|  | @ -666,19 +664,18 @@ | |||
|       changes: *ci-patterns | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *db-patterns | ||||
| 
 | ||||
| .rails:rules:ee-only-unit: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - changes: *backend-patterns | ||||
|     - <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .rails:rules:ee-only-unit:minimal: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-rspec-minimal-disabled | ||||
|       when: never | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|  | @ -687,19 +684,18 @@ | |||
|       changes: *ci-patterns | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
| 
 | ||||
| .rails:rules:ee-only-integration: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - changes: *backend-patterns | ||||
|     - <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .rails:rules:ee-only-integration:minimal: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-rspec-minimal-disabled | ||||
|       when: never | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|  | @ -708,19 +704,18 @@ | |||
|       changes: *ci-patterns | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
| 
 | ||||
| .rails:rules:ee-only-system: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - changes: *code-backstage-patterns | ||||
|     - <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .rails:rules:ee-only-system:minimal: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-rspec-minimal-disabled | ||||
|       when: never | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|  | @ -729,129 +724,143 @@ | |||
|       changes: *ci-patterns | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
| 
 | ||||
| .rails:rules:as-if-foss-migration: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *db-patterns | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|       changes: *db-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-patterns | ||||
| 
 | ||||
| .rails:rules:as-if-foss-migration:minimal: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-rspec-minimal-disabled | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       changes: *ci-patterns | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *db-patterns | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|       changes: *db-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .rails:rules:as-if-foss-unit: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-patterns | ||||
| 
 | ||||
| .rails:rules:as-if-foss-unit:minimal: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-rspec-minimal-disabled | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       changes: *ci-patterns | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
| 
 | ||||
| .rails:rules:as-if-foss-integration: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-patterns | ||||
| 
 | ||||
| .rails:rules:as-if-foss-integration:minimal: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-rspec-minimal-disabled | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       changes: *ci-patterns | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|       changes: *backend-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .rails:rules:as-if-foss-system: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-patterns | ||||
| 
 | ||||
| .rails:rules:as-if-foss-system:minimal: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-rspec-minimal-disabled | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       changes: *ci-patterns | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .rails:rules:ee-and-foss-db-library-code: | ||||
|   rules: | ||||
|     - changes: *db-library-patterns | ||||
|     - <<: *exists-ee | ||||
|       changes: *db-library-patterns | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .rails:rules:ee-mr-and-default-branch-only: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|     - <<: *if-default-branch-refs | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
| 
 | ||||
| .rails:rules:detect-tests: | ||||
|  | @ -861,13 +870,13 @@ | |||
| 
 | ||||
| .rails:rules:rspec-foss-impact: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
| 
 | ||||
| .rails:rules:rspec fail-fast: | ||||
|  | @ -876,11 +885,11 @@ | |||
|       when: never | ||||
|     - <<: *if-rspec-fail-fast-skipped | ||||
|       when: never | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
| 
 | ||||
| .rails:rules:fail-pipeline-early: | ||||
|  | @ -889,40 +898,41 @@ | |||
|       when: never | ||||
|     - <<: *if-rspec-fail-fast-skipped | ||||
|       when: never | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|       when: on_failure | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|       when: on_failure | ||||
| 
 | ||||
| .rails:rules:deprecations: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-default-branch-schedule-nightly | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .rails:rules:rspec-coverage: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|       when: always | ||||
|     - <<: *if-default-branch-schedule-2-hourly | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
|       when: always | ||||
| 
 | ||||
| .rails:rules:rspec-feature-flags: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-default-branch-schedule-2-hourly | ||||
|       <<: *exists-ee | ||||
|       allow_failure: true | ||||
|     - <<: *if-merge-request-title-run-all-rspec | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .rails:rules:default-branch-schedule-nightly--code-backstage: | ||||
|   rules: | ||||
|  | @ -932,10 +942,10 @@ | |||
| 
 | ||||
| .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-default-branch-schedule-nightly | ||||
|       <<: *exists-ee | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: [".gitlab/ci/rails.gitlab-ci.yml"] | ||||
| 
 | ||||
| ######################### | ||||
|  | @ -948,13 +958,14 @@ | |||
| 
 | ||||
| .static-analysis:rules:as-if-foss: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-merge-request-title-as-if-foss | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-qa-patterns | ||||
|     - <<: *if-security-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-qa-patterns | ||||
|     - <<: *if-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-patterns | ||||
| 
 | ||||
| ####################### | ||||
|  | @ -1060,108 +1071,116 @@ | |||
| ################ | ||||
| .review:rules:review-build-cng: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-review-patterns | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *frontend-patterns | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-patterns | ||||
|       when: manual | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *qa-patterns | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-schedule | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| .review:rules:review-deploy: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-review-patterns | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *frontend-patterns | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-patterns | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *qa-patterns | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-schedule | ||||
|       <<: *exists-ee | ||||
|       allow_failure: true | ||||
| 
 | ||||
| .review:rules:review-performance: | ||||
|   rules: | ||||
|     - if: '$DAST_RUN == "true"'  # Skip this job when DAST is run | ||||
|       when: never | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-review-patterns | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *frontend-patterns | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-qa-patterns | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-schedule | ||||
|       <<: *exists-ee | ||||
|       allow_failure: true | ||||
| 
 | ||||
| .review:rules:review-stop-failed-deployment: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-qa-patterns | ||||
| 
 | ||||
| .review:rules:review-qa-smoke: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *ci-review-patterns | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *frontend-patterns | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-qa-patterns | ||||
|       allow_failure: true | ||||
| 
 | ||||
| .review:rules:review-qa-all: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-patterns | ||||
|       when: manual | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *qa-patterns | ||||
|       allow_failure: true | ||||
| 
 | ||||
| .review:rules:review-cleanup: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-qa-patterns | ||||
|       when: manual | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-schedule | ||||
|       <<: *exists-ee | ||||
|       allow_failure: true | ||||
| 
 | ||||
| .review:rules:review-stop: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-dot-com-gitlab-org-merge-request | ||||
|       <<: *exists-ee | ||||
|       changes: *code-qa-patterns | ||||
|       when: manual | ||||
|       allow_failure: true | ||||
|     - <<: *if-dot-com-gitlab-org-schedule | ||||
|       <<: *exists-ee | ||||
|       allow_failure: true | ||||
| 
 | ||||
| .review:rules:danger: | ||||
|  | @ -1204,9 +1223,8 @@ | |||
| 
 | ||||
| .setup:rules:verify-tests-yml: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - <<: *if-default-refs | ||||
|       <<: *exists-ee | ||||
|       changes: *code-backstage-patterns | ||||
|       when: on_success | ||||
| 
 | ||||
|  | @ -1221,12 +1239,12 @@ | |||
| 
 | ||||
| .test-metadata:rules:update-tests-metadata: | ||||
|   rules: | ||||
|     - <<: *if-not-ee | ||||
|       when: never | ||||
|     - changes: | ||||
|     - <<: *exists-ee | ||||
|       changes: | ||||
|         - ".gitlab/ci/test-metadata.gitlab-ci.yml" | ||||
|         - "scripts/rspec_helpers.sh" | ||||
|     - <<: *if-dot-com-ee-schedule | ||||
|       <<: *exists-ee | ||||
| 
 | ||||
| ################### | ||||
| # workhorse rules # | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| # WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/322903 | ||||
| Graphql/Descriptions: | ||||
|   Exclude: | ||||
|     - 'app/graphql/types/snippets/blob_action_enum.rb' | ||||
|     - 'ee/app/graphql/ee/types/list_limit_metric_enum.rb' | ||||
|     - 'ee/app/graphql/types/epic_state_enum.rb' | ||||
|     - 'ee/app/graphql/types/health_status_enum.rb' | ||||
|  | @ -1655,21 +1654,17 @@ Gitlab/NamespacedClass: | |||
|     - 'app/models/project_repository_storage_move.rb' | ||||
|     - 'app/models/project_services/alerts_service.rb' | ||||
|     - 'app/models/project_services/alerts_service_data.rb' | ||||
|     - 'app/models/project_services/bugzilla_service.rb' | ||||
|     - 'app/models/project_services/buildkite_service.rb' | ||||
|     - 'app/models/project_services/chat_notification_service.rb' | ||||
|     - 'app/models/project_services/ci_service.rb' | ||||
|     - 'app/models/project_services/custom_issue_tracker_service.rb' | ||||
|     - 'app/models/project_services/discord_service.rb' | ||||
|     - 'app/models/project_services/drone_ci_service.rb' | ||||
|     - 'app/models/project_services/ewm_service.rb' | ||||
|     - 'app/models/project_services/external_wiki_service.rb' | ||||
|     - 'app/models/project_services/flowdock_service.rb' | ||||
|     - 'app/models/project_services/hangouts_chat_service.rb' | ||||
|     - 'app/models/project_services/hipchat_service.rb' | ||||
|     - 'app/models/project_services/irker_service.rb' | ||||
|     - 'app/models/project_services/issue_tracker_data.rb' | ||||
|     - 'app/models/project_services/issue_tracker_service.rb' | ||||
|     - 'app/models/project_services/jenkins_service.rb' | ||||
|     - 'app/models/project_services/jira_service.rb' | ||||
|     - 'app/models/project_services/jira_tracker_data.rb' | ||||
|  | @ -1679,21 +1674,18 @@ Gitlab/NamespacedClass: | |||
|     - 'app/models/project_services/mock_ci_service.rb' | ||||
|     - 'app/models/project_services/mock_monitoring_service.rb' | ||||
|     - 'app/models/project_services/monitoring_service.rb' | ||||
|     - 'app/models/project_services/open_project_service.rb' | ||||
|     - 'app/models/project_services/open_project_tracker_data.rb' | ||||
|     - 'app/models/project_services/packagist_service.rb' | ||||
|     - 'app/models/project_services/pipelines_email_service.rb' | ||||
|     - 'app/models/project_services/pivotaltracker_service.rb' | ||||
|     - 'app/models/project_services/prometheus_service.rb' | ||||
|     - 'app/models/project_services/pushover_service.rb' | ||||
|     - 'app/models/project_services/redmine_service.rb' | ||||
|     - 'app/models/project_services/slack_service.rb' | ||||
|     - 'app/models/project_services/slack_slash_commands_service.rb' | ||||
|     - 'app/models/project_services/slash_commands_service.rb' | ||||
|     - 'app/models/project_services/teamcity_service.rb' | ||||
|     - 'app/models/project_services/unify_circuit_service.rb' | ||||
|     - 'app/models/project_services/webex_teams_service.rb' | ||||
|     - 'app/models/project_services/youtrack_service.rb' | ||||
|     - 'app/models/project_setting.rb' | ||||
|     - 'app/models/project_snippet.rb' | ||||
|     - 'app/models/project_statistics.rb' | ||||
|  |  | |||
|  | @ -152,7 +152,7 @@ Lint/MissingCopEnableDirective: | |||
| Lint/MixedRegexpCaptureTypes: | ||||
|   Exclude: | ||||
|     - 'app/models/alert_management/alert.rb' | ||||
|     - 'app/models/project_services/ewm_service.rb' | ||||
|     - 'app/models/integrations/ewm.rb' | ||||
|     - 'app/uploaders/file_uploader.rb' | ||||
|     - 'ee/lib/gitlab/code_owners/reference_extractor.rb' | ||||
|     - 'lib/gitlab/ci/pipeline/expression/lexeme/string.rb' | ||||
|  |  | |||
|  | @ -112,7 +112,7 @@ export default { | |||
|       :empty-text="s__('AdminUsers|No users found')" | ||||
|       show-empty | ||||
|       stacked="md" | ||||
|       data-qa-selector="user_row_content" | ||||
|       :tbody-tr-attr="{ 'data-qa-selector': 'user_row_content' }" | ||||
|     > | ||||
|       <template #cell(name)="{ item: user }"> | ||||
|         <user-avatar :user="user" :admin-user-path="paths.adminUser" /> | ||||
|  |  | |||
|  | @ -6,10 +6,10 @@ module Types | |||
|       graphql_name 'SnippetBlobActionEnum' | ||||
|       description 'Type of a snippet blob input action' | ||||
| 
 | ||||
|       value 'create', value: :create | ||||
|       value 'update', value: :update | ||||
|       value 'delete', value: :delete | ||||
|       value 'move', value: :move | ||||
|       value 'create', description: 'Create a snippet blob.', value: :create | ||||
|       value 'update', description: 'Update a snippet blob.', value: :update | ||||
|       value 'delete', description: 'Delete a snippet blob.', value: :delete | ||||
|       value 'move', description: 'Move a snippet blob.', value: :move | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ module Mentionable | |||
| 
 | ||||
|     def self.external_pattern | ||||
|       strong_memoize(:external_pattern) do | ||||
|         issue_pattern = IssueTrackerService.reference_pattern | ||||
|         issue_pattern = Integrations::IssueTracker.reference_pattern | ||||
|         link_patterns = URI::DEFAULT_PARSER.make_regexp(%w(http https)) | ||||
|         reference_pattern(link_patterns, issue_pattern) | ||||
|       end | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Integrations | ||||
|   class Bugzilla < IssueTracker | ||||
|     include ActionView::Helpers::UrlHelper | ||||
| 
 | ||||
|     validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? | ||||
| 
 | ||||
|     def title | ||||
|       'Bugzilla' | ||||
|     end | ||||
| 
 | ||||
|     def description | ||||
|       s_("IssueTracker|Use Bugzilla as this project's issue tracker.") | ||||
|     end | ||||
| 
 | ||||
|     def help | ||||
|       docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/bugzilla'), target: '_blank', rel: 'noopener noreferrer' | ||||
|       s_("IssueTracker|Use Bugzilla as this project's issue tracker. %{docs_link}").html_safe % { docs_link: docs_link.html_safe } | ||||
|     end | ||||
| 
 | ||||
|     def self.to_param | ||||
|       'bugzilla' | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,25 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Integrations | ||||
|   class CustomIssueTracker < IssueTracker | ||||
|     include ActionView::Helpers::UrlHelper | ||||
|     validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? | ||||
| 
 | ||||
|     def title | ||||
|       s_('IssueTracker|Custom issue tracker') | ||||
|     end | ||||
| 
 | ||||
|     def description | ||||
|       s_("IssueTracker|Use a custom issue tracker as this project's issue tracker.") | ||||
|     end | ||||
| 
 | ||||
|     def help | ||||
|       docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/custom_issue_tracker'), target: '_blank', rel: 'noopener noreferrer' | ||||
|       s_('IssueTracker|Use a custom issue tracker that is not in the integration list. %{docs_link}').html_safe % { docs_link: docs_link.html_safe } | ||||
|     end | ||||
| 
 | ||||
|     def self.to_param | ||||
|       'custom_issue_tracker' | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,38 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Integrations | ||||
|   class Ewm < IssueTracker | ||||
|     include ActionView::Helpers::UrlHelper | ||||
| 
 | ||||
|     validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? | ||||
| 
 | ||||
|     def self.reference_pattern(only_long: true) | ||||
|       @reference_pattern ||= %r{(?<issue>\b(bug|task|work item|workitem|rtcwi|defect)\b\s+\d+)}i | ||||
|     end | ||||
| 
 | ||||
|     def title | ||||
|       'EWM' | ||||
|     end | ||||
| 
 | ||||
|     def description | ||||
|       s_("IssueTracker|Use IBM Engineering Workflow Management as this project's issue tracker.") | ||||
|     end | ||||
| 
 | ||||
|     def help | ||||
|       docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/ewm'), target: '_blank', rel: 'noopener noreferrer' | ||||
|       s_("IssueTracker|Use IBM Engineering Workflow Management as this project's issue tracker. %{docs_link}").html_safe % { docs_link: docs_link.html_safe } | ||||
|     end | ||||
| 
 | ||||
|     def self.to_param | ||||
|       'ewm' | ||||
|     end | ||||
| 
 | ||||
|     def can_test? | ||||
|       false | ||||
|     end | ||||
| 
 | ||||
|     def issue_url(iid) | ||||
|       issues_url.gsub(':id', iid.to_s.split(' ')[-1]) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,154 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Integrations | ||||
|   class IssueTracker < Integration | ||||
|     validate :one_issue_tracker, if: :activated?, on: :manual_change | ||||
| 
 | ||||
|     # TODO: we can probably just delegate as part of | ||||
|     # https://gitlab.com/gitlab-org/gitlab/issues/29404 | ||||
|     data_field :project_url, :issues_url, :new_issue_url | ||||
| 
 | ||||
|     default_value_for :category, 'issue_tracker' | ||||
| 
 | ||||
|     before_validation :handle_properties | ||||
|     before_validation :set_default_data, on: :create | ||||
| 
 | ||||
|     # Pattern used to extract links from comments | ||||
|     # Override this method on services that uses different patterns | ||||
|     # This pattern does not support cross-project references | ||||
|     # The other code assumes that this pattern is a superset of all | ||||
|     # overridden patterns. See ReferenceRegexes.external_pattern | ||||
|     def self.reference_pattern(only_long: false) | ||||
|       if only_long | ||||
|         /(\b[A-Z][A-Z0-9_]*-)#{Gitlab::Regex.issue}/ | ||||
|       else | ||||
|         /(\b[A-Z][A-Z0-9_]*-|#{Issue.reference_prefix})#{Gitlab::Regex.issue}/ | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     def handle_properties | ||||
|       # this has been moved from initialize_properties and should be improved | ||||
|       # as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 | ||||
|       return unless properties | ||||
| 
 | ||||
|       @legacy_properties_data = properties.dup | ||||
|       data_values = properties.slice!('title', 'description') | ||||
|       data_values.reject! { |key| data_fields.changed.include?(key) } | ||||
|       data_values.slice!(*data_fields.attributes.keys) | ||||
|       data_fields.assign_attributes(data_values) if data_values.present? | ||||
| 
 | ||||
|       self.properties = {} | ||||
|     end | ||||
| 
 | ||||
|     def legacy_properties_data | ||||
|       @legacy_properties_data ||= {} | ||||
|     end | ||||
| 
 | ||||
|     def supports_data_fields? | ||||
|       true | ||||
|     end | ||||
| 
 | ||||
|     def data_fields | ||||
|       issue_tracker_data || self.build_issue_tracker_data | ||||
|     end | ||||
| 
 | ||||
|     def default? | ||||
|       default | ||||
|     end | ||||
| 
 | ||||
|     def issue_url(iid) | ||||
|       issues_url.gsub(':id', iid.to_s) | ||||
|     end | ||||
| 
 | ||||
|     def issue_tracker_path | ||||
|       project_url | ||||
|     end | ||||
| 
 | ||||
|     def new_issue_path | ||||
|       new_issue_url | ||||
|     end | ||||
| 
 | ||||
|     def issue_path(iid) | ||||
|       issue_url(iid) | ||||
|     end | ||||
| 
 | ||||
|     def fields | ||||
|       [ | ||||
|         { type: 'text', name: 'project_url', title: _('Project URL'), help: s_('IssueTracker|The URL to the project in the external issue tracker.'), required: true }, | ||||
|         { type: 'text', name: 'issues_url', title: s_('IssueTracker|Issue URL'), help: s_('IssueTracker|The URL to view an issue in the external issue tracker. Must contain %{colon_id}.') % { colon_id: '<code>:id</code>'.html_safe }, required: true }, | ||||
|         { type: 'text', name: 'new_issue_url', title: s_('IssueTracker|New issue URL'), help: s_('IssueTracker|The URL to create an issue in the external issue tracker.'), required: true } | ||||
|       ] | ||||
|     end | ||||
| 
 | ||||
|     def initialize_properties | ||||
|       {} | ||||
|     end | ||||
| 
 | ||||
|     # Initialize with default properties values | ||||
|     def set_default_data | ||||
|       return unless issues_tracker.present? | ||||
| 
 | ||||
|       # we don't want to override if we have set something | ||||
|       return if project_url || issues_url || new_issue_url | ||||
| 
 | ||||
|       data_fields.project_url = issues_tracker['project_url'] | ||||
|       data_fields.issues_url = issues_tracker['issues_url'] | ||||
|       data_fields.new_issue_url = issues_tracker['new_issue_url'] | ||||
|     end | ||||
| 
 | ||||
|     def self.supported_events | ||||
|       %w(push) | ||||
|     end | ||||
| 
 | ||||
|     def execute(data) | ||||
|       return unless supported_events.include?(data[:object_kind]) | ||||
| 
 | ||||
|       message = "#{self.type} was unable to reach #{self.project_url}. Check the url and try again." | ||||
|       result = false | ||||
| 
 | ||||
|       begin | ||||
|         response = Gitlab::HTTP.head(self.project_url, verify: true) | ||||
| 
 | ||||
|         if response | ||||
|           message = "#{self.type} received response #{response.code} when attempting to connect to #{self.project_url}" | ||||
|           result = true | ||||
|         end | ||||
|       rescue Gitlab::HTTP::Error, Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError => error | ||||
|         message = "#{self.type} had an error when trying to connect to #{self.project_url}: #{error.message}" | ||||
|       end | ||||
|       log_info(message) | ||||
|       result | ||||
|     end | ||||
| 
 | ||||
|     def support_close_issue? | ||||
|       false | ||||
|     end | ||||
| 
 | ||||
|     def support_cross_reference? | ||||
|       false | ||||
|     end | ||||
| 
 | ||||
|     private | ||||
| 
 | ||||
|     def enabled_in_gitlab_config | ||||
|       Gitlab.config.issues_tracker && | ||||
|         Gitlab.config.issues_tracker.values.any? && | ||||
|         issues_tracker | ||||
|     end | ||||
| 
 | ||||
|     def issues_tracker | ||||
|       Gitlab.config.issues_tracker[to_param] | ||||
|     end | ||||
| 
 | ||||
|     def one_issue_tracker | ||||
|       return if template? || instance? | ||||
|       return if project.blank? | ||||
| 
 | ||||
|       if project.integrations.external_issue_trackers.where.not(id: id).any? | ||||
|         errors.add(:base, _('Another issue tracker is already in use. Only one issue tracker service can be active at a time')) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| Integrations::IssueTracker.prepend_mod_with('Integrations::IssueTracker') | ||||
|  | @ -0,0 +1,20 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Integrations | ||||
|   class OpenProject < IssueTracker | ||||
|     validates :url, public_url: true, presence: true, if: :activated? | ||||
|     validates :api_url, public_url: true, allow_blank: true, if: :activated? | ||||
|     validates :token, presence: true, if: :activated? | ||||
|     validates :project_identifier_code, presence: true, if: :activated? | ||||
| 
 | ||||
|     data_field :url, :api_url, :token, :closed_status_id, :project_identifier_code | ||||
| 
 | ||||
|     def data_fields | ||||
|       open_project_tracker_data || self.build_open_project_tracker_data | ||||
|     end | ||||
| 
 | ||||
|     def self.to_param | ||||
|       'open_project' | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,25 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Integrations | ||||
|   class Redmine < IssueTracker | ||||
|     include ActionView::Helpers::UrlHelper | ||||
|     validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? | ||||
| 
 | ||||
|     def title | ||||
|       'Redmine' | ||||
|     end | ||||
| 
 | ||||
|     def description | ||||
|       s_("IssueTracker|Use Redmine as this project's issue tracker.") | ||||
|     end | ||||
| 
 | ||||
|     def help | ||||
|       docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/redmine'), target: '_blank', rel: 'noopener noreferrer' | ||||
|       s_('IssueTracker|Use Redmine as the issue tracker. %{docs_link}').html_safe % { docs_link: docs_link.html_safe } | ||||
|     end | ||||
| 
 | ||||
|     def self.to_param | ||||
|       'redmine' | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,42 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Integrations | ||||
|   class Youtrack < IssueTracker | ||||
|     include ActionView::Helpers::UrlHelper | ||||
| 
 | ||||
|     validates :project_url, :issues_url, presence: true, public_url: true, if: :activated? | ||||
| 
 | ||||
|     # {PROJECT-KEY}-{NUMBER} Examples: YT-1, PRJ-1, gl-030 | ||||
|     def self.reference_pattern(only_long: false) | ||||
|       if only_long | ||||
|         /(?<issue>\b[A-Za-z][A-Za-z0-9_]*-\d+\b)/ | ||||
|       else | ||||
|         /(?<issue>\b[A-Za-z][A-Za-z0-9_]*-\d+\b)|(#{Issue.reference_prefix}#{Gitlab::Regex.issue})/ | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     def title | ||||
|       'YouTrack' | ||||
|     end | ||||
| 
 | ||||
|     def description | ||||
|       s_("IssueTracker|Use YouTrack as this project's issue tracker.") | ||||
|     end | ||||
| 
 | ||||
|     def help | ||||
|       docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/youtrack'), target: '_blank', rel: 'noopener noreferrer' | ||||
|       s_("IssueTracker|Use YouTrack as this project's issue tracker. %{docs_link}").html_safe % { docs_link: docs_link.html_safe } | ||||
|     end | ||||
| 
 | ||||
|     def self.to_param | ||||
|       'youtrack' | ||||
|     end | ||||
| 
 | ||||
|     def fields | ||||
|       [ | ||||
|         { type: 'text', name: 'project_url', title: _('Project URL'), help: s_('IssueTracker|The URL to the project in YouTrack.'), required: true }, | ||||
|         { type: 'text', name: 'issues_url', title: s_('ProjectService|Issue URL'), help: s_('IssueTracker|The URL to view an issue in the YouTrack project. Must contain %{colon_id}.') % { colon_id: '<code>:id</code>'.html_safe }, required: true } | ||||
|       ] | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -9,6 +9,9 @@ class Label < ApplicationRecord | |||
|   include Sortable | ||||
|   include FromUnion | ||||
|   include Presentable | ||||
|   include IgnorableColumns | ||||
| 
 | ||||
|   ignore_column :remove_on_close, remove_with: '14.1', remove_after: '2021-06-22' | ||||
| 
 | ||||
|   cache_markdown_field :description, pipeline: :single_line | ||||
| 
 | ||||
|  |  | |||
|  | @ -186,13 +186,17 @@ class Project < ApplicationRecord | |||
|   has_one :asana_service, class_name: 'Integrations::Asana' | ||||
|   has_one :assembla_service, class_name: 'Integrations::Assembla' | ||||
|   has_one :bamboo_service, class_name: 'Integrations::Bamboo' | ||||
|   has_one :bugzilla_service, class_name: 'Integrations::Bugzilla' | ||||
|   has_one :campfire_service, class_name: 'Integrations::Campfire' | ||||
|   has_one :confluence_service, class_name: 'Integrations::Confluence' | ||||
|   has_one :custom_issue_tracker_service, class_name: 'Integrations::CustomIssueTracker' | ||||
|   has_one :datadog_service, class_name: 'Integrations::Datadog' | ||||
|   has_one :emails_on_push_service, class_name: 'Integrations::EmailsOnPush' | ||||
|   has_one :ewm_service, class_name: 'Integrations::Ewm' | ||||
|   has_one :redmine_service, class_name: 'Integrations::Redmine' | ||||
|   has_one :youtrack_service, class_name: 'Integrations::Youtrack' | ||||
|   has_one :discord_service | ||||
|   has_one :drone_ci_service | ||||
|   has_one :ewm_service | ||||
|   has_one :pipelines_email_service | ||||
|   has_one :irker_service | ||||
|   has_one :pivotaltracker_service | ||||
|  | @ -206,10 +210,6 @@ class Project < ApplicationRecord | |||
|   has_one :pushover_service | ||||
|   has_one :jenkins_service | ||||
|   has_one :jira_service | ||||
|   has_one :redmine_service | ||||
|   has_one :youtrack_service | ||||
|   has_one :custom_issue_tracker_service | ||||
|   has_one :bugzilla_service | ||||
|   has_one :external_wiki_service | ||||
|   has_one :prometheus_service, inverse_of: :project | ||||
|   has_one :mock_ci_service | ||||
|  |  | |||
|  | @ -1,24 +0,0 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class BugzillaService < IssueTrackerService | ||||
|   include ActionView::Helpers::UrlHelper | ||||
| 
 | ||||
|   validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? | ||||
| 
 | ||||
|   def title | ||||
|     'Bugzilla' | ||||
|   end | ||||
| 
 | ||||
|   def description | ||||
|     s_("IssueTracker|Use Bugzilla as this project's issue tracker.") | ||||
|   end | ||||
| 
 | ||||
|   def help | ||||
|     docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/bugzilla'), target: '_blank', rel: 'noopener noreferrer' | ||||
|     s_("IssueTracker|Use Bugzilla as this project's issue tracker. %{docs_link}").html_safe % { docs_link: docs_link.html_safe } | ||||
|   end | ||||
| 
 | ||||
|   def self.to_param | ||||
|     'bugzilla' | ||||
|   end | ||||
| end | ||||
|  | @ -1,23 +0,0 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class CustomIssueTrackerService < IssueTrackerService | ||||
|   include ActionView::Helpers::UrlHelper | ||||
|   validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? | ||||
| 
 | ||||
|   def title | ||||
|     s_('IssueTracker|Custom issue tracker') | ||||
|   end | ||||
| 
 | ||||
|   def description | ||||
|     s_("IssueTracker|Use a custom issue tracker as this project's issue tracker.") | ||||
|   end | ||||
| 
 | ||||
|   def help | ||||
|     docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/custom_issue_tracker'), target: '_blank', rel: 'noopener noreferrer' | ||||
|     s_('IssueTracker|Use a custom issue tracker that is not in the integration list. %{docs_link}').html_safe % { docs_link: docs_link.html_safe } | ||||
|   end | ||||
| 
 | ||||
|   def self.to_param | ||||
|     'custom_issue_tracker' | ||||
|   end | ||||
| end | ||||
|  | @ -1,36 +0,0 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class EwmService < IssueTrackerService | ||||
|   include ActionView::Helpers::UrlHelper | ||||
| 
 | ||||
|   validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? | ||||
| 
 | ||||
|   def self.reference_pattern(only_long: true) | ||||
|     @reference_pattern ||= %r{(?<issue>\b(bug|task|work item|workitem|rtcwi|defect)\b\s+\d+)}i | ||||
|   end | ||||
| 
 | ||||
|   def title | ||||
|     'EWM' | ||||
|   end | ||||
| 
 | ||||
|   def description | ||||
|     s_("IssueTracker|Use IBM Engineering Workflow Management as this project's issue tracker.") | ||||
|   end | ||||
| 
 | ||||
|   def help | ||||
|     docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/ewm'), target: '_blank', rel: 'noopener noreferrer' | ||||
|     s_("IssueTracker|Use IBM Engineering Workflow Management as this project's issue tracker. %{docs_link}").html_safe % { docs_link: docs_link.html_safe } | ||||
|   end | ||||
| 
 | ||||
|   def self.to_param | ||||
|     'ewm' | ||||
|   end | ||||
| 
 | ||||
|   def can_test? | ||||
|     false | ||||
|   end | ||||
| 
 | ||||
|   def issue_url(iid) | ||||
|     issues_url.gsub(':id', iid.to_s.split(' ')[-1]) | ||||
|   end | ||||
| end | ||||
|  | @ -1,152 +0,0 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class IssueTrackerService < Integration | ||||
|   validate :one_issue_tracker, if: :activated?, on: :manual_change | ||||
| 
 | ||||
|   # TODO: we can probably just delegate as part of | ||||
|   # https://gitlab.com/gitlab-org/gitlab/issues/29404 | ||||
|   data_field :project_url, :issues_url, :new_issue_url | ||||
| 
 | ||||
|   default_value_for :category, 'issue_tracker' | ||||
| 
 | ||||
|   before_validation :handle_properties | ||||
|   before_validation :set_default_data, on: :create | ||||
| 
 | ||||
|   # Pattern used to extract links from comments | ||||
|   # Override this method on services that uses different patterns | ||||
|   # This pattern does not support cross-project references | ||||
|   # The other code assumes that this pattern is a superset of all | ||||
|   # overridden patterns. See ReferenceRegexes.external_pattern | ||||
|   def self.reference_pattern(only_long: false) | ||||
|     if only_long | ||||
|       /(\b[A-Z][A-Z0-9_]*-)#{Gitlab::Regex.issue}/ | ||||
|     else | ||||
|       /(\b[A-Z][A-Z0-9_]*-|#{Issue.reference_prefix})#{Gitlab::Regex.issue}/ | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def handle_properties | ||||
|     # this has been moved from initialize_properties and should be improved | ||||
|     # as part of https://gitlab.com/gitlab-org/gitlab/issues/29404 | ||||
|     return unless properties | ||||
| 
 | ||||
|     @legacy_properties_data = properties.dup | ||||
|     data_values = properties.slice!('title', 'description') | ||||
|     data_values.reject! { |key| data_fields.changed.include?(key) } | ||||
|     data_values.slice!(*data_fields.attributes.keys) | ||||
|     data_fields.assign_attributes(data_values) if data_values.present? | ||||
| 
 | ||||
|     self.properties = {} | ||||
|   end | ||||
| 
 | ||||
|   def legacy_properties_data | ||||
|     @legacy_properties_data ||= {} | ||||
|   end | ||||
| 
 | ||||
|   def supports_data_fields? | ||||
|     true | ||||
|   end | ||||
| 
 | ||||
|   def data_fields | ||||
|     issue_tracker_data || self.build_issue_tracker_data | ||||
|   end | ||||
| 
 | ||||
|   def default? | ||||
|     default | ||||
|   end | ||||
| 
 | ||||
|   def issue_url(iid) | ||||
|     issues_url.gsub(':id', iid.to_s) | ||||
|   end | ||||
| 
 | ||||
|   def issue_tracker_path | ||||
|     project_url | ||||
|   end | ||||
| 
 | ||||
|   def new_issue_path | ||||
|     new_issue_url | ||||
|   end | ||||
| 
 | ||||
|   def issue_path(iid) | ||||
|     issue_url(iid) | ||||
|   end | ||||
| 
 | ||||
|   def fields | ||||
|     [ | ||||
|       { type: 'text', name: 'project_url', title: _('Project URL'), help: s_('IssueTracker|The URL to the project in the external issue tracker.'), required: true }, | ||||
|       { type: 'text', name: 'issues_url', title: s_('IssueTracker|Issue URL'), help: s_('IssueTracker|The URL to view an issue in the external issue tracker. Must contain %{colon_id}.') % { colon_id: '<code>:id</code>'.html_safe }, required: true }, | ||||
|       { type: 'text', name: 'new_issue_url', title: s_('IssueTracker|New issue URL'), help: s_('IssueTracker|The URL to create an issue in the external issue tracker.'), required: true } | ||||
|     ] | ||||
|   end | ||||
| 
 | ||||
|   def initialize_properties | ||||
|     {} | ||||
|   end | ||||
| 
 | ||||
|   # Initialize with default properties values | ||||
|   def set_default_data | ||||
|     return unless issues_tracker.present? | ||||
| 
 | ||||
|     # we don't want to override if we have set something | ||||
|     return if project_url || issues_url || new_issue_url | ||||
| 
 | ||||
|     data_fields.project_url = issues_tracker['project_url'] | ||||
|     data_fields.issues_url = issues_tracker['issues_url'] | ||||
|     data_fields.new_issue_url = issues_tracker['new_issue_url'] | ||||
|   end | ||||
| 
 | ||||
|   def self.supported_events | ||||
|     %w(push) | ||||
|   end | ||||
| 
 | ||||
|   def execute(data) | ||||
|     return unless supported_events.include?(data[:object_kind]) | ||||
| 
 | ||||
|     message = "#{self.type} was unable to reach #{self.project_url}. Check the url and try again." | ||||
|     result = false | ||||
| 
 | ||||
|     begin | ||||
|       response = Gitlab::HTTP.head(self.project_url, verify: true) | ||||
| 
 | ||||
|       if response | ||||
|         message = "#{self.type} received response #{response.code} when attempting to connect to #{self.project_url}" | ||||
|         result = true | ||||
|       end | ||||
|     rescue Gitlab::HTTP::Error, Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError => error | ||||
|       message = "#{self.type} had an error when trying to connect to #{self.project_url}: #{error.message}" | ||||
|     end | ||||
|     log_info(message) | ||||
|     result | ||||
|   end | ||||
| 
 | ||||
|   def support_close_issue? | ||||
|     false | ||||
|   end | ||||
| 
 | ||||
|   def support_cross_reference? | ||||
|     false | ||||
|   end | ||||
| 
 | ||||
|   private | ||||
| 
 | ||||
|   def enabled_in_gitlab_config | ||||
|     Gitlab.config.issues_tracker && | ||||
|       Gitlab.config.issues_tracker.values.any? && | ||||
|       issues_tracker | ||||
|   end | ||||
| 
 | ||||
|   def issues_tracker | ||||
|     Gitlab.config.issues_tracker[to_param] | ||||
|   end | ||||
| 
 | ||||
|   def one_issue_tracker | ||||
|     return if template? || instance? | ||||
|     return if project.blank? | ||||
| 
 | ||||
|     if project.integrations.external_issue_trackers.where.not(id: id).any? | ||||
|       errors.add(:base, _('Another issue tracker is already in use. Only one issue tracker service can be active at a time')) | ||||
|     end | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| IssueTrackerService.prepend_mod_with('IssueTrackerService') | ||||
|  | @ -1,7 +1,7 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| # Accessible as Project#external_issue_tracker | ||||
| class JiraService < IssueTrackerService | ||||
| class JiraService < Integrations::IssueTracker | ||||
|   extend ::Gitlab::Utils::Override | ||||
|   include Gitlab::Routing | ||||
|   include ApplicationHelper | ||||
|  |  | |||
|  | @ -1,18 +0,0 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class OpenProjectService < IssueTrackerService | ||||
|   validates :url, public_url: true, presence: true, if: :activated? | ||||
|   validates :api_url, public_url: true, allow_blank: true, if: :activated? | ||||
|   validates :token, presence: true, if: :activated? | ||||
|   validates :project_identifier_code, presence: true, if: :activated? | ||||
| 
 | ||||
|   data_field :url, :api_url, :token, :closed_status_id, :project_identifier_code | ||||
| 
 | ||||
|   def data_fields | ||||
|     open_project_tracker_data || self.build_open_project_tracker_data | ||||
|   end | ||||
| 
 | ||||
|   def self.to_param | ||||
|     'open_project' | ||||
|   end | ||||
| end | ||||
|  | @ -1,23 +0,0 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class RedmineService < IssueTrackerService | ||||
|   include ActionView::Helpers::UrlHelper | ||||
|   validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated? | ||||
| 
 | ||||
|   def title | ||||
|     'Redmine' | ||||
|   end | ||||
| 
 | ||||
|   def description | ||||
|     s_("IssueTracker|Use Redmine as this project's issue tracker.") | ||||
|   end | ||||
| 
 | ||||
|   def help | ||||
|     docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/redmine'), target: '_blank', rel: 'noopener noreferrer' | ||||
|     s_('IssueTracker|Use Redmine as the issue tracker. %{docs_link}').html_safe % { docs_link: docs_link.html_safe } | ||||
|   end | ||||
| 
 | ||||
|   def self.to_param | ||||
|     'redmine' | ||||
|   end | ||||
| end | ||||
|  | @ -1,40 +0,0 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class YoutrackService < IssueTrackerService | ||||
|   include ActionView::Helpers::UrlHelper | ||||
| 
 | ||||
|   validates :project_url, :issues_url, presence: true, public_url: true, if: :activated? | ||||
| 
 | ||||
|   # {PROJECT-KEY}-{NUMBER} Examples: YT-1, PRJ-1, gl-030 | ||||
|   def self.reference_pattern(only_long: false) | ||||
|     if only_long | ||||
|       /(?<issue>\b[A-Za-z][A-Za-z0-9_]*-\d+\b)/ | ||||
|     else | ||||
|       /(?<issue>\b[A-Za-z][A-Za-z0-9_]*-\d+\b)|(#{Issue.reference_prefix}#{Gitlab::Regex.issue})/ | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def title | ||||
|     'YouTrack' | ||||
|   end | ||||
| 
 | ||||
|   def description | ||||
|     s_("IssueTracker|Use YouTrack as this project's issue tracker.") | ||||
|   end | ||||
| 
 | ||||
|   def help | ||||
|     docs_link = link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/youtrack'), target: '_blank', rel: 'noopener noreferrer' | ||||
|     s_("IssueTracker|Use YouTrack as this project's issue tracker. %{docs_link}").html_safe % { docs_link: docs_link.html_safe } | ||||
|   end | ||||
| 
 | ||||
|   def self.to_param | ||||
|     'youtrack' | ||||
|   end | ||||
| 
 | ||||
|   def fields | ||||
|     [ | ||||
|       { type: 'text', name: 'project_url', title: _('Project URL'), help: s_('IssueTracker|The URL to the project in YouTrack.'), required: true }, | ||||
|       { type: 'text', name: 'issues_url', title: s_('ProjectService|Issue URL'), help: s_('IssueTracker|The URL to view an issue in the YouTrack project. Must contain %{colon_id}.') % { colon_id: '<code>:id</code>'.html_safe }, required: true } | ||||
|     ] | ||||
|   end | ||||
| end | ||||
|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| title: Add options events to Redis HLL metrics for filtering data | ||||
| merge_request: 61685 | ||||
| author: | ||||
| type: other | ||||
|  | @ -1,16 +1,18 @@ | |||
| --- | ||||
| key_path: usage_activity_by_stage_monthly.create.action_monthly_active_users_design_management | ||||
| description: | ||||
| description: Monthly active users for design management | ||||
| product_section: dev | ||||
| product_stage: create | ||||
| product_group: group::knowledge | ||||
| product_stage: plan | ||||
| product_group: group::product planning | ||||
| product_category: design_management | ||||
| value_type: number | ||||
| status: data_available | ||||
| time_frame: 28d | ||||
| data_source: | ||||
| data_source: redis_hll | ||||
| distribution: | ||||
| - ce | ||||
| - ee | ||||
| tier: | ||||
| - free | ||||
| skip_validation: true | ||||
| - premium | ||||
| - ultimate | ||||
|  |  | |||
|  | @ -9,7 +9,10 @@ value_type: number | |||
| status: data_available | ||||
| time_frame: 28d | ||||
| data_source: redis_hll | ||||
| instrumentation_class: CountUsersUsingApproveQuickActionMetric | ||||
| instrumentation_class: RedisHLLMetric | ||||
| options: | ||||
|   events: | ||||
|     - i_quickactions_approve | ||||
| distribution: | ||||
| - ce | ||||
| - ee | ||||
|  |  | |||
|  | @ -9,7 +9,10 @@ value_type: number | |||
| status: data_available | ||||
| time_frame: 7d | ||||
| data_source: redis_hll | ||||
| instrumentation_class: CountUsersUsingApproveQuickActionMetric | ||||
| instrumentation_class: RedisHLLMetric | ||||
| options: | ||||
|   events: | ||||
|     - i_quickactions_approve | ||||
| distribution: | ||||
| - ce | ||||
| - ee | ||||
|  |  | |||
|  | @ -1,16 +1,18 @@ | |||
| --- | ||||
| key_path: counts.design_management_designs_create | ||||
| description: | ||||
| description: Number of designs that were created | ||||
| product_section: dev | ||||
| product_stage: create | ||||
| product_group: group::knowledge | ||||
| product_stage: plan | ||||
| product_group: group::product planning | ||||
| product_category: design_management | ||||
| value_type: number | ||||
| status: data_available | ||||
| time_frame: all | ||||
| data_source: database | ||||
| data_source: redis | ||||
| distribution: | ||||
| - ce | ||||
| - ee | ||||
| tier: | ||||
| - free | ||||
| skip_validation: true | ||||
| - premium | ||||
| - ultimate | ||||
|  |  | |||
|  | @ -1,16 +1,18 @@ | |||
| --- | ||||
| key_path: counts.design_management_designs_update | ||||
| description: | ||||
| description: Number of updates to designs | ||||
| product_section: dev | ||||
| product_stage: create | ||||
| product_group: group::knowledge | ||||
| product_stage: plan | ||||
| product_group: group::product planning | ||||
| product_category: design_management | ||||
| value_type: number | ||||
| status: data_available | ||||
| time_frame: all | ||||
| data_source: database | ||||
| data_source: redis | ||||
| distribution: | ||||
| - ce | ||||
| - ee | ||||
| tier: | ||||
| - free | ||||
| skip_validation: true | ||||
| - premium | ||||
| - ultimate | ||||
|  |  | |||
|  | @ -1,16 +1,18 @@ | |||
| --- | ||||
| key_path: counts.design_management_designs_delete | ||||
| description: | ||||
| description: Number of designs that were deleted | ||||
| product_section: dev | ||||
| product_stage: create | ||||
| product_group: group::knowledge | ||||
| product_stage: plan | ||||
| product_group: group::product planning | ||||
| product_category: design_management | ||||
| value_type: number | ||||
| status: data_available | ||||
| time_frame: all | ||||
| data_source: database | ||||
| data_source: redis | ||||
| distribution: | ||||
| - ce | ||||
| - ee | ||||
| tier: | ||||
| - free | ||||
| skip_validation: true | ||||
| - premium | ||||
| - ultimate | ||||
|  |  | |||
|  | @ -43,7 +43,7 @@ | |||
|     "introduced_by_url": { | ||||
|       "type": ["string", "null"] | ||||
|     }, | ||||
|     "extra": { | ||||
|     "options": { | ||||
|       "type": "object" | ||||
|     }, | ||||
|     "time_frame": { | ||||
|  | @ -56,7 +56,7 @@ | |||
|     }, | ||||
|     "instrumentation_class": { | ||||
|       "type": "string", | ||||
|       "pattern": "^(([A-Z][a-z]+)+::)*(([A-Z][a-z]+)+)$" | ||||
|       "pattern": "^(([A-Z][a-z]+)+::)*(([A-Z]+[a-z]+)+)$" | ||||
|     }, | ||||
|     "distribution": { | ||||
|       "type": "array", | ||||
|  |  | |||
|  | @ -14602,10 +14602,10 @@ Type of a snippet blob input action. | |||
| 
 | ||||
| | Value | Description | | ||||
| | ----- | ----------- | | ||||
| | <a id="snippetblobactionenumcreate"></a>`create` |  | | ||||
| | <a id="snippetblobactionenumdelete"></a>`delete` |  | | ||||
| | <a id="snippetblobactionenummove"></a>`move` |  | | ||||
| | <a id="snippetblobactionenumupdate"></a>`update` |  | | ||||
| | <a id="snippetblobactionenumcreate"></a>`create` | Create a snippet blob. | | ||||
| | <a id="snippetblobactionenumdelete"></a>`delete` | Delete a snippet blob. | | ||||
| | <a id="snippetblobactionenummove"></a>`move` | Move a snippet blob. | | ||||
| | <a id="snippetblobactionenumupdate"></a>`update` | Update a snippet blob. | | ||||
| 
 | ||||
| ### `Sort` | ||||
| 
 | ||||
|  |  | |||
|  | @ -758,7 +758,6 @@ and included in `rules` definitions via [YAML anchors](../ci/yaml/README.md#anch | |||
| | `if:` conditions | Description | Notes | | ||||
| |------------------|-------------|-------| | ||||
| | `if-not-canonical-namespace`                                 | Matches if the project isn't in the canonical (`gitlab-org/`) or security (`gitlab-org/security`) namespace. | Use to create a job for forks (by using `when: on_success|manual`), or **not** create a job for forks (by using `when: never`). | | ||||
| | `if-not-ee`                                                  | Matches if the project isn't EE (i.e. project name isn't `gitlab` or `gitlab-ee`). | Use to create a job only in the FOSS project (by using `when: on_success|manual`), or **not** create a job if the project is EE (by using `when: never`). | | ||||
| | `if-not-foss`                                                | Matches if the project isn't FOSS (i.e. project name isn't `gitlab-foss`, `gitlab-ce`, or `gitlabhq`). | Use to create a job only in the EE project (by using `when: on_success|manual`), or **not** create a job if the project is FOSS (by using `when: never`). | | ||||
| | `if-default-refs`                                            | Matches if the pipeline is for `master`, `main`, `/^[\d-]+-stable(-ee)?$/` (stable branches), `/^\d+-\d+-auto-deploy-\d+$/` (auto-deploy branches), `/^security\//` (security branches), merge requests, and tags. | Note that jobs aren't created for branches with this default configuration. | | ||||
| | `if-master-refs`                                             | Matches if the current branch is `master` or `main`. | | | ||||
|  | @ -788,6 +787,16 @@ and included in `rules` definitions via [YAML anchors](../ci/yaml/README.md#anch | |||
| 
 | ||||
| <!-- vale gitlab.Substitutions = YES --> | ||||
| 
 | ||||
| #### `exists:` conditions | ||||
| 
 | ||||
| <!-- vale gitlab.Substitutions = NO --> | ||||
| 
 | ||||
| | `exists:` conditions | Description | Notes | | ||||
| |----------------------|-------------|-------| | ||||
| | `exists-ee`          | Matches if the project is EE (i.e. project contains `ee/` directory). | Use to create a job only in the EE project. | | ||||
| 
 | ||||
| <!-- vale gitlab.Substitutions = YES --> | ||||
| 
 | ||||
| #### `changes:` patterns | ||||
| 
 | ||||
| | `changes:` patterns          | Description                                                              | | ||||
|  |  | |||
|  | @ -1020,39 +1020,39 @@ Tiers: `free`, `premium`, `ultimate` | |||
| 
 | ||||
| ### `counts.design_management_designs_create` | ||||
| 
 | ||||
| Missing description | ||||
| Number of designs that were created | ||||
| 
 | ||||
| [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210216180740_design_management_designs_create.yml) | ||||
| 
 | ||||
| Group: `group::knowledge` | ||||
| Group: `group::product planning` | ||||
| 
 | ||||
| Status: `data_available` | ||||
| 
 | ||||
| Tiers: `free` | ||||
| Tiers: `free`, `premium`, `ultimate` | ||||
| 
 | ||||
| ### `counts.design_management_designs_delete` | ||||
| 
 | ||||
| Missing description | ||||
| Number of designs that were deleted | ||||
| 
 | ||||
| [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210216180743_design_management_designs_delete.yml) | ||||
| 
 | ||||
| Group: `group::knowledge` | ||||
| Group: `group::product planning` | ||||
| 
 | ||||
| Status: `data_available` | ||||
| 
 | ||||
| Tiers: `free` | ||||
| Tiers: `free`, `premium`, `ultimate` | ||||
| 
 | ||||
| ### `counts.design_management_designs_update` | ||||
| 
 | ||||
| Missing description | ||||
| Number of updates to designs | ||||
| 
 | ||||
| [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210216180741_design_management_designs_update.yml) | ||||
| 
 | ||||
| Group: `group::knowledge` | ||||
| Group: `group::product planning` | ||||
| 
 | ||||
| Status: `data_available` | ||||
| 
 | ||||
| Tiers: `free` | ||||
| Tiers: `free`, `premium`, `ultimate` | ||||
| 
 | ||||
| ### `counts.environments` | ||||
| 
 | ||||
|  | @ -2182,6 +2182,18 @@ Status: `implemented` | |||
| 
 | ||||
| Tiers: `free`, `premium`, `ultimate` | ||||
| 
 | ||||
| ### `counts.in_product_marketing_email_experience_0_sent` | ||||
| 
 | ||||
| Total sent emails of the experience track's first email | ||||
| 
 | ||||
| [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210518081225_in_product_marketing_email_experience_0_sent.yml) | ||||
| 
 | ||||
| Group: `group::activation` | ||||
| 
 | ||||
| Status: `implemented` | ||||
| 
 | ||||
| Tiers: `free`, `premium`, `ultimate` | ||||
| 
 | ||||
| ### `counts.in_product_marketing_email_team_0_cta_clicked` | ||||
| 
 | ||||
| Total clicks on the team track's first email | ||||
|  | @ -2398,18 +2410,6 @@ Status: `implemented` | |||
| 
 | ||||
| Tiers: `free`, `premium`, `ultimate` | ||||
| 
 | ||||
| ### `counts.in_product_marketing_email_experience_0_sent` | ||||
| 
 | ||||
| Total sent emails of the experience track's first email | ||||
| 
 | ||||
| [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210518081225_in_product_marketing_email_experience_0_sent.yml) | ||||
| 
 | ||||
| Group: `group::activation` | ||||
| 
 | ||||
| Status: `implemented` | ||||
| 
 | ||||
| Tiers: `free`, `premium`, `ultimate` | ||||
| 
 | ||||
| ### `counts.in_review_folder` | ||||
| 
 | ||||
| Missing description | ||||
|  | @ -11994,7 +11994,7 @@ Count of unique users to receive a notification while on-call | |||
| 
 | ||||
| Group: `group::monitor` | ||||
| 
 | ||||
| Status: `implemented` | ||||
| Status: `data_available` | ||||
| 
 | ||||
| Tiers: `premium`, `ultimate` | ||||
| 
 | ||||
|  | @ -12006,7 +12006,7 @@ Count of unique users to receive a notification while on-call | |||
| 
 | ||||
| Group: `group::monitor` | ||||
| 
 | ||||
| Status: `implemented` | ||||
| Status: `data_available` | ||||
| 
 | ||||
| Tiers: `premium`, `ultimate` | ||||
| 
 | ||||
|  | @ -17680,15 +17680,15 @@ Tiers: `free`, `premium`, `ultimate` | |||
| 
 | ||||
| ### `usage_activity_by_stage_monthly.create.action_monthly_active_users_design_management` | ||||
| 
 | ||||
| Missing description | ||||
| Monthly active users for design management | ||||
| 
 | ||||
| [YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216180745_action_monthly_active_users_design_management.yml) | ||||
| 
 | ||||
| Group: `group::knowledge` | ||||
| Group: `group::product planning` | ||||
| 
 | ||||
| Status: `data_available` | ||||
| 
 | ||||
| Tiers: `free` | ||||
| Tiers: `free`, `premium`, `ultimate` | ||||
| 
 | ||||
| ### `usage_activity_by_stage_monthly.create.action_monthly_active_users_git_write` | ||||
| 
 | ||||
|  |  | |||
|  | @ -43,7 +43,7 @@ Each metric is defined in a separate YAML file consisting of a number of fields: | |||
| | `milestone`         | no       | The milestone when the metric is introduced. | | ||||
| | `milestone_removed` | no       | The milestone when the metric is removed. | | ||||
| | `introduced_by_url` | no       | The URL to the Merge Request that introduced the metric. | | ||||
| | `extra`             | no       | `object`: extra information needed to calculate the metric value. | | ||||
| | `options`           | no       | `object`: options information needed to calculate the metric value. | | ||||
| | `skip_validation`   | no       | This should **not** be set. [Used for imported metrics until we review, update and make them valid](https://gitlab.com/groups/gitlab-org/-/epics/5425). | | ||||
| 
 | ||||
| ### Metric statuses | ||||
|  |  | |||
|  | @ -53,20 +53,17 @@ end | |||
| 
 | ||||
| ## Redis HyperLogLog metrics | ||||
| 
 | ||||
| [Example of a merge request that adds a `RedisHLL` metric](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60089/diffs). | ||||
| [Example of a merge request that adds a `RedisHLL` metric](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61685). | ||||
| 
 | ||||
| ```ruby | ||||
| module Gitlab | ||||
|   module Usage | ||||
|     module Metrics | ||||
|       module Instrumentations | ||||
|         class CountUsersUsingApproveQuickActionMetric < RedisHLLMetric | ||||
|           event_names :i_quickactions_approve | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
| Count unique values for `i_quickactions_approve` event. | ||||
| 
 | ||||
| ```yaml | ||||
| time_frame: 28d | ||||
| data_source: redis_hll | ||||
| instrumentation_class: 'Gitlab::Usage::Metrics::Instrumentations::RedisHLLMetric' | ||||
| options: | ||||
|   events: | ||||
|     - i_quickactions_approve | ||||
| ``` | ||||
| 
 | ||||
| ## Generic metrics | ||||
|  |  | |||
|  | @ -777,16 +777,18 @@ module API | |||
|           ::Integrations::Asana, | ||||
|           ::Integrations::Assembla, | ||||
|           ::Integrations::Bamboo, | ||||
|           ::Integrations::Bugzilla, | ||||
|           ::Integrations::Campfire, | ||||
|           ::Integrations::Confluence, | ||||
|           ::Integrations::CustomIssueTracker, | ||||
|           ::Integrations::Datadog, | ||||
|           ::Integrations::EmailsOnPush, | ||||
|           ::BugzillaService, | ||||
|           ::Integrations::Ewm, | ||||
|           ::Integrations::Redmine, | ||||
|           ::Integrations::Youtrack, | ||||
|           ::BuildkiteService, | ||||
|           ::CustomIssueTrackerService, | ||||
|           ::DiscordService, | ||||
|           ::DroneCiService, | ||||
|           ::EwmService, | ||||
|           ::ExternalWikiService, | ||||
|           ::FlowdockService, | ||||
|           ::HangoutsChatService, | ||||
|  | @ -800,8 +802,6 @@ module API | |||
|           ::PivotaltrackerService, | ||||
|           ::PrometheusService, | ||||
|           ::PushoverService, | ||||
|           ::RedmineService, | ||||
|           ::YoutrackService, | ||||
|           ::SlackService, | ||||
|           ::MattermostService, | ||||
|           ::MicrosoftTeamsService, | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ module Gitlab | |||
|     #                                a proc that computes the sleep time given the number of preceding attempts | ||||
|     #                               (from 1 to retries - 1) | ||||
|     # | ||||
|     # Note: It's basically discouraged to use this method in a unicorn thread, | ||||
|     # Note: It's basically discouraged to use this method in a webserver thread, | ||||
|     #       because this ties up all thread related resources until all `retries` are consumed. | ||||
|     #       This could potentially eat up all connection pools. | ||||
|     def in_lock(key, ttl: 1.minute, retries: 10, sleep_sec: 0.01.seconds) | ||||
|  |  | |||
|  | @ -4,7 +4,8 @@ module Gitlab | |||
|   module Integrations | ||||
|     class StiType < ActiveRecord::Type::String | ||||
|       NAMESPACED_INTEGRATIONS = Set.new(%w( | ||||
|         Asana Assembla Bamboo Campfire Confluence Datadog EmailsOnPush | ||||
|         Asana Assembla Bamboo Bugzilla Campfire Confluence CustomIssueTracker Datadog | ||||
|         EmailsOnPush Ewm IssueTracker Redmine Youtrack | ||||
|       )).freeze | ||||
| 
 | ||||
|       def cast(value) | ||||
|  |  | |||
|  | @ -8,9 +8,11 @@ module Gitlab | |||
|           include Gitlab::Utils::UsageData | ||||
| 
 | ||||
|           attr_reader :time_frame | ||||
|           attr_reader :options | ||||
| 
 | ||||
|           def initialize(time_frame:) | ||||
|           def initialize(time_frame:, options: {}) | ||||
|             @time_frame = time_frame | ||||
|             @options = options | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  |  | |||
|  | @ -1,13 +0,0 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Gitlab | ||||
|   module Usage | ||||
|     module Metrics | ||||
|       module Instrumentations | ||||
|         class CountUsersUsingApproveQuickActionMetric < RedisHLLMetric | ||||
|           event_names :i_quickactions_approve | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -7,20 +7,24 @@ module Gitlab | |||
|         class RedisHLLMetric < BaseMetric | ||||
|           # Usage example | ||||
|           # | ||||
|           # class CountUsersVisitingAnalyticsValuestreamMetric < RedisHLLMetric | ||||
|           #   event_names :g_analytics_valuestream | ||||
|           # In metric YAML defintion | ||||
|           # instrumentation_class: RedisHLLMetric | ||||
|           #   events: | ||||
|           #     - g_analytics_valuestream | ||||
|           # end | ||||
|           class << self | ||||
|             def event_names(events = nil) | ||||
|               @metric_events = events | ||||
|           def initialize(time_frame:, options: {}) | ||||
|             super | ||||
| 
 | ||||
|             raise ArgumentError, "options events are required" unless metric_events.present? | ||||
|           end | ||||
| 
 | ||||
|             attr_reader :metric_events | ||||
|           def metric_events | ||||
|             options[:events] | ||||
|           end | ||||
| 
 | ||||
|           def value | ||||
|             redis_usage_data do | ||||
|               event_params = time_constraints.merge(event_names: self.class.metric_events) | ||||
|               event_params = time_constraints.merge(event_names: metric_events) | ||||
| 
 | ||||
|               Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(**event_params) | ||||
|             end | ||||
|  | @ -35,7 +39,7 @@ module Gitlab | |||
|             when '7d' | ||||
|               { start_date: 7.days.ago.to_date, end_date: Date.current } | ||||
|             else | ||||
|               raise "Unknown time frame: #{time_frame} for TimeConstraint" | ||||
|               raise "Unknown time frame: #{time_frame} for RedisHLLMetric" | ||||
|             end | ||||
|           end | ||||
|         end | ||||
|  |  | |||
|  | @ -7,9 +7,12 @@ module Gitlab | |||
|       def uncached_data | ||||
|         ::Gitlab::Usage::MetricDefinition.all.map do |definition| | ||||
|           instrumentation_class = definition.attributes[:instrumentation_class] | ||||
|           options = definition.attributes[:options] | ||||
| 
 | ||||
|           if instrumentation_class.present? | ||||
|             metric_value = "Gitlab::Usage::Metrics::Instrumentations::#{instrumentation_class}".constantize.new(time_frame: definition.attributes[:time_frame]).value | ||||
|             metric_value = "Gitlab::Usage::Metrics::Instrumentations::#{instrumentation_class}".constantize.new( | ||||
|               time_frame: definition.attributes[:time_frame], | ||||
|               options: options).value | ||||
| 
 | ||||
|             metric_payload(definition.key_path, metric_value) | ||||
|           else | ||||
|  |  | |||
|  | @ -9,13 +9,13 @@ module QA | |||
|         Capybara.current_session | ||||
|       end | ||||
| 
 | ||||
|       def confirm_user(username) | ||||
|       def confirm_user(user) | ||||
|         Flow::Login.while_signed_in_as_admin do | ||||
|           Page::Main::Menu.perform(&:go_to_admin_area) | ||||
|           Page::Admin::Menu.perform(&:go_to_users_overview) | ||||
|           Page::Admin::Overview::Users::Index.perform do |index| | ||||
|             index.search_user(username) | ||||
|             index.click_user(username) | ||||
|             index.search_user(user.email) | ||||
|             index.click_user(user.name) | ||||
|           end | ||||
| 
 | ||||
|           Page::Admin::Overview::Users::Show.perform(&:confirm_user) | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ module QA | |||
|               element :pending_approval_tab | ||||
|             end | ||||
| 
 | ||||
|             view 'app/views/admin/users/_user.html.haml' do | ||||
|             view 'app/assets/javascripts/admin/users/components/users_table.vue' do | ||||
|               element :user_row_content | ||||
|             end | ||||
| 
 | ||||
|  |  | |||
|  | @ -44,7 +44,7 @@ RSpec.describe Admin::ServicesController do | |||
|   describe "#update" do | ||||
|     let(:project) { create(:project) } | ||||
|     let!(:service_template) do | ||||
|       RedmineService.create!( | ||||
|       Integrations::Redmine.create!( | ||||
|         project: nil, | ||||
|         active: false, | ||||
|         template: true, | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ FactoryBot.define do | |||
|     type { 'Integration' } | ||||
|   end | ||||
| 
 | ||||
|   factory :custom_issue_tracker_service, class: 'CustomIssueTrackerService' do | ||||
|   factory :custom_issue_tracker_service, class: 'Integrations::CustomIssueTracker' do | ||||
|     project | ||||
|     active { true } | ||||
|     issue_tracker | ||||
|  | @ -85,25 +85,25 @@ FactoryBot.define do | |||
|     confluence_url { 'https://example.atlassian.net/wiki' } | ||||
|   end | ||||
| 
 | ||||
|   factory :bugzilla_service do | ||||
|   factory :bugzilla_service, class: 'Integrations::Bugzilla' do | ||||
|     project | ||||
|     active { true } | ||||
|     issue_tracker | ||||
|   end | ||||
| 
 | ||||
|   factory :redmine_service do | ||||
|   factory :redmine_service, class: 'Integrations::Redmine' do | ||||
|     project | ||||
|     active { true } | ||||
|     issue_tracker | ||||
|   end | ||||
| 
 | ||||
|   factory :youtrack_service do | ||||
|   factory :youtrack_service, class: 'Integrations::Youtrack' do | ||||
|     project | ||||
|     active { true } | ||||
|     issue_tracker | ||||
|   end | ||||
| 
 | ||||
|   factory :ewm_service do | ||||
|   factory :ewm_service, class: 'Integrations::Ewm' do | ||||
|     project | ||||
|     active { true } | ||||
|     issue_tracker | ||||
|  | @ -134,7 +134,7 @@ FactoryBot.define do | |||
|     external_wiki_url { 'http://external-wiki-url.com' } | ||||
|   end | ||||
| 
 | ||||
|   factory :open_project_service do | ||||
|   factory :open_project_service, class: 'Integrations::OpenProject' do | ||||
|     project | ||||
|     active { true } | ||||
| 
 | ||||
|  | @ -182,13 +182,13 @@ FactoryBot.define do | |||
|     create_data { false } | ||||
| 
 | ||||
|     after(:build) do | ||||
|       IssueTrackerService.skip_callback(:validation, :before, :handle_properties) | ||||
|       Integrations::IssueTracker.skip_callback(:validation, :before, :handle_properties) | ||||
|     end | ||||
| 
 | ||||
|     to_create { |instance| instance.save!(validate: false) } | ||||
| 
 | ||||
|     after(:create) do | ||||
|       IssueTrackerService.set_callback(:validation, :before, :handle_properties) | ||||
|       Integrations::IssueTracker.set_callback(:validation, :before, :handle_properties) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,14 +33,6 @@ RSpec.describe Gitlab::GitalyClient do | |||
|       it { expect(subject.long_timeout).to eq(6.hours) } | ||||
|     end | ||||
| 
 | ||||
|     context 'running in Unicorn' do | ||||
|       before do | ||||
|         allow(Gitlab::Runtime).to receive(:unicorn?).and_return(true) | ||||
|       end | ||||
| 
 | ||||
|       it { expect(subject.long_timeout).to eq(55) } | ||||
|     end | ||||
| 
 | ||||
|     context 'running in Puma' do | ||||
|       before do | ||||
|         allow(Gitlab::Runtime).to receive(:puma?).and_return(true) | ||||
|  |  | |||
|  | @ -99,25 +99,6 @@ RSpec.describe Gitlab::Runtime do | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context "unicorn" do | ||||
|     before do | ||||
|       stub_const('::Unicorn', Module.new) | ||||
|       stub_const('::Unicorn::HttpServer', Class.new) | ||||
|       stub_env('ACTION_CABLE_IN_APP', 'false') | ||||
|     end | ||||
| 
 | ||||
|     it_behaves_like "valid runtime", :unicorn, 1 | ||||
| 
 | ||||
|     context "when ActionCable in-app mode is enabled" do | ||||
|       before do | ||||
|         stub_env('ACTION_CABLE_IN_APP', 'true') | ||||
|         stub_env('ACTION_CABLE_WORKER_POOL_SIZE', '3') | ||||
|       end | ||||
| 
 | ||||
|       it_behaves_like "valid runtime", :unicorn, 4 | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context "sidekiq" do | ||||
|     let(:sidekiq_type) { double('::Sidekiq') } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountUsersUsingApproveQuickActionMetric, :clean_gitlab_redis_shared_state do | ||||
| RSpec.describe Gitlab::Usage::Metrics::Instrumentations::RedisHLLMetric, :clean_gitlab_redis_shared_state do | ||||
|   before do | ||||
|     Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 1, time: 1.week.ago) | ||||
|     Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 1, time: 2.weeks.ago) | ||||
|  | @ -10,6 +10,10 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountUsersUsingApproveQ | |||
|     Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 2, time: 2.months.ago) | ||||
|   end | ||||
| 
 | ||||
|   it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', data_source: 'redis_hll' }, 2 | ||||
|   it_behaves_like 'a correct instrumented metric value', { time_frame: '7d', data_source: 'redis_hll' }, 1 | ||||
|   it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', options: { events: ['i_quickactions_approve'] } }, 2 | ||||
|   it_behaves_like 'a correct instrumented metric value', { time_frame: '7d', options: { events: ['i_quickactions_approve'] } }, 1 | ||||
| 
 | ||||
|   it 'raise exception if vents options is not present' do | ||||
|     expect { described_class.new(time_frame: '28d') }.to raise_error(ArgumentError) | ||||
|   end | ||||
| end | ||||
|  | @ -95,7 +95,7 @@ RSpec.describe Gitlab::UsageData::Topology do | |||
|                   }, | ||||
|                   { | ||||
|                     name: 'web', | ||||
|                     server: 'unicorn' | ||||
|                     server: 'puma' | ||||
|                   } | ||||
|                 ] | ||||
|               } | ||||
|  | @ -724,7 +724,7 @@ RSpec.describe Gitlab::UsageData::Topology do | |||
|         }, | ||||
|         # instance 2 | ||||
|         { | ||||
|           'metric' => { 'instance' => 'instance2:8080', 'job' => 'gitlab-rails', 'server' => 'unicorn' }, | ||||
|           'metric' => { 'instance' => 'instance2:8080', 'job' => 'gitlab-rails', 'server' => 'puma' }, | ||||
|           'value' => [1000, '1'] | ||||
|         } | ||||
|       ]) | ||||
|  |  | |||
|  | @ -159,7 +159,7 @@ RSpec.describe Integration do | |||
|       context 'when instance-level service' do | ||||
|         Integration.available_services_types.each do |service_type| | ||||
|           let(:service) do | ||||
|             service_type.constantize.new(instance: true) | ||||
|             described_class.send(:service_type_to_model, service_type).new(instance: true) | ||||
|           end | ||||
| 
 | ||||
|           it { is_expected.to be_falsey } | ||||
|  | @ -169,7 +169,7 @@ RSpec.describe Integration do | |||
|       context 'when group-level service' do | ||||
|         Integration.available_services_types.each do |service_type| | ||||
|           let(:service) do | ||||
|             service_type.constantize.new(group_id: group.id) | ||||
|             described_class.send(:service_type_to_model, service_type).new(group_id: group.id) | ||||
|           end | ||||
| 
 | ||||
|           it { is_expected.to be_falsey } | ||||
|  | @ -672,7 +672,7 @@ RSpec.describe Integration do | |||
|       expect(described_class.service_name_to_model('asana')).to eq(Integrations::Asana) | ||||
|       # TODO We can remove this test when all models have been namespaced: | ||||
|       # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60968#note_570994955 | ||||
|       expect(described_class.service_name_to_model('youtrack')).to eq(YoutrackService) | ||||
|       expect(described_class.service_name_to_model('webex_teams')).to eq(WebexTeamsService) | ||||
|     end | ||||
| 
 | ||||
|     it 'raises an error if service name is invalid' do | ||||
|  | @ -802,7 +802,7 @@ RSpec.describe Integration do | |||
| 
 | ||||
|   describe 'initialize service with no properties' do | ||||
|     let(:service) do | ||||
|       BugzillaService.create!( | ||||
|       Integrations::Bugzilla.create!( | ||||
|         project: project, | ||||
|         project_url: 'http://gitlab.example.com' | ||||
|       ) | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe BugzillaService do | ||||
| RSpec.describe Integrations::Bugzilla do | ||||
|   describe 'Associations' do | ||||
|     it { is_expected.to belong_to :project } | ||||
|     it { is_expected.to have_one :service_hook } | ||||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe CustomIssueTrackerService do | ||||
| RSpec.describe Integrations::CustomIssueTracker do | ||||
|   describe 'Associations' do | ||||
|     it { is_expected.to belong_to :project } | ||||
|     it { is_expected.to have_one :service_hook } | ||||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe EwmService do | ||||
| RSpec.describe Integrations::Ewm do | ||||
|   describe 'Associations' do | ||||
|     it { is_expected.to belong_to :project } | ||||
|     it { is_expected.to have_one :service_hook } | ||||
|  | @ -2,12 +2,12 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe IssueTrackerService do | ||||
| RSpec.describe Integrations::IssueTracker do | ||||
|   describe 'Validations' do | ||||
|     let(:project) { create :project } | ||||
| 
 | ||||
|     describe 'only one issue tracker per project' do | ||||
|       let(:service) { RedmineService.new(project: project, active: true, issue_tracker_data: build(:issue_tracker_data)) } | ||||
|       let(:service) { Integrations::Redmine.new(project: project, active: true, issue_tracker_data: build(:issue_tracker_data)) } | ||||
| 
 | ||||
|       before do | ||||
|         create(:custom_issue_tracker_service, project: project) | ||||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe OpenProjectService do | ||||
| RSpec.describe Integrations::OpenProject do | ||||
|   describe 'Validations' do | ||||
|     context 'when service is active' do | ||||
|       before do | ||||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe RedmineService do | ||||
| RSpec.describe Integrations::Redmine do | ||||
|   describe 'Associations' do | ||||
|     it { is_expected.to belong_to :project } | ||||
|     it { is_expected.to have_one :service_hook } | ||||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe YoutrackService do | ||||
| RSpec.describe Integrations::Youtrack do | ||||
|   describe 'Associations' do | ||||
|     it { is_expected.to belong_to :project } | ||||
|     it { is_expected.to have_one :service_hook } | ||||
|  | @ -1086,7 +1086,7 @@ RSpec.describe Project, factory_default: :keep do | |||
|       project = create(:redmine_project) | ||||
| 
 | ||||
|       expect(project).to receive(:integrations).once.and_call_original | ||||
|       2.times { expect(project.external_issue_tracker).to be_a_kind_of(RedmineService) } | ||||
|       2.times { expect(project.external_issue_tracker).to be_a_kind_of(Integrations::Redmine) } | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -156,15 +156,6 @@ RSpec.describe API::Terraform::State do | |||
|           expect(response).to have_gitlab_http_status(:ok) | ||||
|           expect(Gitlab::Json.parse(response.body)).to be_empty | ||||
|         end | ||||
| 
 | ||||
|         context 'on Unicorn', :unicorn do | ||||
|           it 'updates the state' do | ||||
|             expect { request }.to change { Terraform::State.count }.by(0) | ||||
| 
 | ||||
|             expect(response).to have_gitlab_http_status(:ok) | ||||
|             expect(Gitlab::Json.parse(response.body)).to be_empty | ||||
|           end | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context 'without body' do | ||||
|  | @ -200,15 +191,6 @@ RSpec.describe API::Terraform::State do | |||
|           expect(response).to have_gitlab_http_status(:ok) | ||||
|           expect(Gitlab::Json.parse(response.body)).to be_empty | ||||
|         end | ||||
| 
 | ||||
|         context 'on Unicorn', :unicorn do | ||||
|           it 'creates a new state' do | ||||
|             expect { request }.to change { Terraform::State.count }.by(1) | ||||
| 
 | ||||
|             expect(response).to have_gitlab_http_status(:ok) | ||||
|             expect(Gitlab::Json.parse(response.body)).to be_empty | ||||
|           end | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       context 'without body' do | ||||
|  |  | |||
|  | @ -1,13 +1,14 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| RSpec.shared_examples 'a correct instrumented metric value' do |options, expected_value| | ||||
|   let(:time_frame) { options[:time_frame] } | ||||
| RSpec.shared_examples 'a correct instrumented metric value' do |params, expected_value| | ||||
|   let(:time_frame) { params[:time_frame] } | ||||
|   let(:options) { params[:options] } | ||||
| 
 | ||||
|   before do | ||||
|     allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false) | ||||
|   end | ||||
| 
 | ||||
|   it 'has correct value' do | ||||
|     expect(described_class.new(time_frame: time_frame).value).to eq(expected_value) | ||||
|     expect(described_class.new(time_frame: time_frame, options: options).value).to eq(expected_value) | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -294,16 +294,6 @@ RSpec.shared_examples 'rejects invalid upload_url params' do | |||
|   end | ||||
| end | ||||
| 
 | ||||
| RSpec.shared_examples 'successful response when using Unicorn' do | ||||
|   context 'on Unicorn', :unicorn do | ||||
|     it 'returns successfully' do | ||||
|       subject | ||||
| 
 | ||||
|       expect(response).to have_gitlab_http_status(:ok) | ||||
|     end | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| RSpec.shared_examples 'recipe snapshot endpoint' do | ||||
|   subject { get api(url), headers: headers } | ||||
| 
 | ||||
|  | @ -372,7 +362,6 @@ RSpec.shared_examples 'recipe upload_urls endpoint' do | |||
| 
 | ||||
|   it_behaves_like 'rejects invalid recipe' | ||||
|   it_behaves_like 'rejects invalid upload_url params' | ||||
|   it_behaves_like 'successful response when using Unicorn' | ||||
| 
 | ||||
|   it 'returns a set of upload urls for the files requested' do | ||||
|     subject | ||||
|  | @ -434,7 +423,6 @@ RSpec.shared_examples 'package upload_urls endpoint' do | |||
| 
 | ||||
|   it_behaves_like 'rejects invalid recipe' | ||||
|   it_behaves_like 'rejects invalid upload_url params' | ||||
|   it_behaves_like 'successful response when using Unicorn' | ||||
| 
 | ||||
|   it 'returns a set of upload urls for the files requested' do | ||||
|     expected_response = { | ||||
|  |  | |||
|  | @ -1,27 +0,0 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| REQUEST_CLASSES = [ | ||||
|   ::Grape::Request, | ||||
|   ::Rack::Request | ||||
| ].freeze | ||||
| 
 | ||||
| def request_body_class | ||||
|   return ::Unicorn::TeeInput if defined?(::Unicorn) | ||||
| 
 | ||||
|   Class.new(StringIO) do | ||||
|     def string | ||||
|       raise NotImplementedError, '#string is only valid under Puma which uses StringIO, use #read instead' | ||||
|     end | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| RSpec.configure do |config| | ||||
|   config.before(:each, :unicorn) do | ||||
|     REQUEST_CLASSES.each do |request_class| | ||||
|       allow_any_instance_of(request_class) | ||||
|         .to receive(:body).and_wrap_original do |m, *args| | ||||
|           request_body_class.new(m.call(*args).read) | ||||
|         end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -23,7 +23,7 @@ RSpec.describe 'projects/services/_form' do | |||
|     end | ||||
| 
 | ||||
|     it 'display merge_request_events and commit_events descriptions' do | ||||
|       allow(RedmineService).to receive(:supported_events).and_return(%w(commit merge_request)) | ||||
|       allow(Integrations::Redmine).to receive(:supported_events).and_return(%w(commit merge_request)) | ||||
| 
 | ||||
|       render | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ All new configuration options that get added to Workhorse should go into the con | |||
| 
 | ||||
| Options: | ||||
|   -apiCiLongPollingDuration duration | ||||
|       Long polling duration for job requesting for runners (default 50s - enabled) (default 50ns) | ||||
|       Long polling duration for job requesting for runners (default 50ns) | ||||
|   -apiLimit uint | ||||
|       Number of API requests allowed at single time | ||||
|   -apiQueueDuration duration | ||||
|  |  | |||
|  | @ -102,7 +102,7 @@ func buildConfig(arg0 string, args []string) (*bootConfig, *config.Config, error | |||
| 	fset.UintVar(&cfg.APILimit, "apiLimit", 0, "Number of API requests allowed at single time") | ||||
| 	fset.UintVar(&cfg.APIQueueLimit, "apiQueueLimit", 0, "Number of API requests allowed to be queued") | ||||
| 	fset.DurationVar(&cfg.APIQueueTimeout, "apiQueueDuration", queueing.DefaultTimeout, "Maximum queueing duration of requests") | ||||
| 	fset.DurationVar(&cfg.APICILongPollingDuration, "apiCiLongPollingDuration", 50, "Long polling duration for job requesting for runners (default 50s - enabled)") | ||||
| 	fset.DurationVar(&cfg.APICILongPollingDuration, "apiCiLongPollingDuration", 50, "Long polling duration for job requesting for runners") | ||||
| 	fset.BoolVar(&cfg.PropagateCorrelationID, "propagateCorrelationID", false, "Reuse existing Correlation-ID from the incoming request header `X-Request-ID` if present") | ||||
| 
 | ||||
| 	if err := fset.Parse(args); err != nil { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue