Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
3a0f6ebaa9
commit
551b3bfd7e
|
@ -26,6 +26,9 @@
|
||||||
- export CI_ENVIRONMENT_URL="$(cat environment_url.txt)"
|
- export CI_ENVIRONMENT_URL="$(cat environment_url.txt)"
|
||||||
- echo "${CI_ENVIRONMENT_URL}"
|
- echo "${CI_ENVIRONMENT_URL}"
|
||||||
- cd qa
|
- cd qa
|
||||||
|
- if [ -n "$KNAPSACK_REPORT_PATH" ]; then
|
||||||
|
bundle exec rake knapsack:download;
|
||||||
|
fi
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- qa/tmp
|
- qa/tmp
|
||||||
|
@ -34,15 +37,22 @@
|
||||||
|
|
||||||
.parallel-qa-base:
|
.parallel-qa-base:
|
||||||
parallel: 5
|
parallel: 5
|
||||||
|
variables:
|
||||||
|
KNAPSACK_TEST_FILE_PATTERN: "qa/specs/features/**/*_spec.rb"
|
||||||
script:
|
script:
|
||||||
- export KNAPSACK_REPORT_PATH=knapsack/master_report.json
|
|
||||||
- export KNAPSACK_TEST_FILE_PATTERN=qa/specs/features/**/*_spec.rb
|
|
||||||
- |
|
- |
|
||||||
bin/test "${QA_SCENARIO}" "${CI_ENVIRONMENT_URL}" \
|
bin/test "${QA_SCENARIO}" "${CI_ENVIRONMENT_URL}" \
|
||||||
-- \
|
-- \
|
||||||
--color --format documentation \
|
--color --format documentation \
|
||||||
--format RspecJunitFormatter --out tmp/rspec.xml
|
--format RspecJunitFormatter --out tmp/rspec.xml
|
||||||
|
after_script:
|
||||||
|
- if [ -n "$KNAPSACK_GENERATE_REPORT" ]; then
|
||||||
|
mv qa/${KNAPSACK_REPORT_PATH} qa/knapsack/gcs/regenerated-${CI_NODE_INDEX}.json;
|
||||||
|
fi
|
||||||
artifacts:
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- qa/tmp # we can't merge list so need to include explicitly once more
|
||||||
|
- qa/knapsack/gcs/regenerated-*.json
|
||||||
reports:
|
reports:
|
||||||
junit: qa/tmp/rspec.xml
|
junit: qa/tmp/rspec.xml
|
||||||
|
|
||||||
|
@ -69,6 +79,16 @@
|
||||||
--ignore-missing-results \
|
--ignore-missing-results \
|
||||||
--color
|
--color
|
||||||
|
|
||||||
|
.knapsack-upload-base:
|
||||||
|
image:
|
||||||
|
name: ${QA_IMAGE}
|
||||||
|
entrypoint: [""]
|
||||||
|
stage: post-qa
|
||||||
|
before_script:
|
||||||
|
- cd qa
|
||||||
|
script:
|
||||||
|
- bundle exec rake 'knapsack:upload[knapsack/gcs/regenerated-*.json]'
|
||||||
|
|
||||||
review-qa-smoke:
|
review-qa-smoke:
|
||||||
extends:
|
extends:
|
||||||
- .review-qa-base
|
- .review-qa-base
|
||||||
|
@ -88,6 +108,7 @@ review-qa-reliable:
|
||||||
variables:
|
variables:
|
||||||
QA_RUN_TYPE: review-qa-reliable
|
QA_RUN_TYPE: review-qa-reliable
|
||||||
QA_SCENARIO: Test::Instance::Reliable
|
QA_SCENARIO: Test::Instance::Reliable
|
||||||
|
KNAPSACK_REPORT_PATH: knapsack/gcs/review-qa-reliable.json
|
||||||
|
|
||||||
review-qa-all:
|
review-qa-all:
|
||||||
extends:
|
extends:
|
||||||
|
@ -97,6 +118,7 @@ review-qa-all:
|
||||||
variables:
|
variables:
|
||||||
QA_RUN_TYPE: review-qa-all
|
QA_RUN_TYPE: review-qa-all
|
||||||
QA_SCENARIO: Test::Instance::All
|
QA_SCENARIO: Test::Instance::All
|
||||||
|
KNAPSACK_REPORT_PATH: knapsack/gcs/review-qa-all.json
|
||||||
|
|
||||||
review-performance:
|
review-performance:
|
||||||
extends:
|
extends:
|
||||||
|
@ -141,3 +163,19 @@ allure-report-qa-all:
|
||||||
variables:
|
variables:
|
||||||
ALLURE_REPORT_PATH_PREFIX: gitlab-review-all
|
ALLURE_REPORT_PATH_PREFIX: gitlab-review-all
|
||||||
ALLURE_JOB_NAME: review-qa-all
|
ALLURE_JOB_NAME: review-qa-all
|
||||||
|
|
||||||
|
knapsack-report-qa-all:
|
||||||
|
extends:
|
||||||
|
- .knapsack-upload-base
|
||||||
|
- .review:rules:knapsack-report-qa-all
|
||||||
|
needs: ["review-qa-all"]
|
||||||
|
variables:
|
||||||
|
KNAPSACK_REPORT_PATH: knapsack/gcs/review-qa-all.json
|
||||||
|
|
||||||
|
knapsack-report-qa-reliable:
|
||||||
|
extends:
|
||||||
|
- .knapsack-upload-base
|
||||||
|
- .review:rules:knapsack-report-qa-reliable
|
||||||
|
needs: ["review-qa-reliable"]
|
||||||
|
variables:
|
||||||
|
KNAPSACK_REPORT_PATH: knapsack/gcs/review-qa-reliable.json
|
||||||
|
|
|
@ -648,6 +648,8 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *code-backstage-patterns
|
changes: *code-backstage-patterns
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: *code-backstage-patterns
|
||||||
- <<: *if-default-refs
|
- <<: *if-default-refs
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
|
@ -661,6 +663,8 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-run-all-jest
|
- <<: *if-merge-request-labels-run-all-jest
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-default-refs
|
- <<: *if-default-refs
|
||||||
|
@ -815,6 +819,8 @@
|
||||||
changes: *db-patterns
|
changes: *db-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *db-patterns
|
changes: *db-patterns
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: *db-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
when: never
|
when: never
|
||||||
- changes: *db-patterns
|
- changes: *db-patterns
|
||||||
|
@ -825,6 +831,8 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-run-all-rspec
|
- <<: *if-merge-request-labels-run-all-rspec
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
|
@ -860,6 +868,8 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: *backend-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
when: never
|
when: never
|
||||||
- changes: *backend-patterns
|
- changes: *backend-patterns
|
||||||
|
@ -870,6 +880,8 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-run-all-rspec
|
- <<: *if-merge-request-labels-run-all-rspec
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
|
@ -890,6 +902,8 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: *backend-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
when: never
|
when: never
|
||||||
- changes: *backend-patterns
|
- changes: *backend-patterns
|
||||||
|
@ -900,6 +914,8 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-run-all-rspec
|
- <<: *if-merge-request-labels-run-all-rspec
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
|
@ -920,6 +936,8 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *code-backstage-patterns
|
changes: *code-backstage-patterns
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: *code-backstage-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
when: never
|
when: never
|
||||||
- changes: *code-backstage-patterns
|
- changes: *code-backstage-patterns
|
||||||
|
@ -930,6 +948,8 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-run-all-rspec
|
- <<: *if-merge-request-labels-run-all-rspec
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
|
@ -950,6 +970,8 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: ["config/**/*"]
|
changes: ["config/**/*"]
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: ["config/**/*"]
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
when: never
|
when: never
|
||||||
- changes: ["config/**/*"]
|
- changes: ["config/**/*"]
|
||||||
|
@ -960,6 +982,8 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-run-all-rspec
|
- <<: *if-merge-request-labels-run-all-rspec
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
|
@ -989,6 +1013,8 @@
|
||||||
changes: *db-patterns
|
changes: *db-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *db-patterns
|
changes: *db-patterns
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: *db-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
when: never
|
when: never
|
||||||
- changes: *db-patterns
|
- changes: *db-patterns
|
||||||
|
@ -1001,6 +1027,8 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-run-all-rspec
|
- <<: *if-merge-request-labels-run-all-rspec
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
|
@ -1024,6 +1052,8 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: *backend-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
when: never
|
when: never
|
||||||
- changes: *backend-patterns
|
- changes: *backend-patterns
|
||||||
|
@ -1036,6 +1066,8 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-run-all-rspec
|
- <<: *if-merge-request-labels-run-all-rspec
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
|
@ -1058,6 +1090,8 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: *backend-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
when: never
|
when: never
|
||||||
- changes: *backend-patterns
|
- changes: *backend-patterns
|
||||||
|
@ -1070,6 +1104,8 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-run-all-rspec
|
- <<: *if-merge-request-labels-run-all-rspec
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
|
@ -1092,6 +1128,8 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *code-backstage-patterns
|
changes: *code-backstage-patterns
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: *code-backstage-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
when: never
|
when: never
|
||||||
- changes: *code-backstage-patterns
|
- changes: *code-backstage-patterns
|
||||||
|
@ -1104,6 +1142,8 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-run-all-rspec
|
- <<: *if-merge-request-labels-run-all-rspec
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
|
@ -1130,6 +1170,8 @@
|
||||||
changes: *db-patterns
|
changes: *db-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *db-patterns
|
changes: *db-patterns
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
changes: *db-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
- <<: *if-merge-request-not-approved
|
||||||
when: never
|
when: never
|
||||||
|
|
||||||
|
@ -1141,15 +1183,14 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
changes: *core-backend-patterns
|
changes: *core-backend-patterns
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-security-merge-request
|
|
||||||
changes: *db-patterns
|
|
||||||
when: never
|
|
||||||
- <<: *if-merge-request-labels-as-if-foss
|
- <<: *if-merge-request-labels-as-if-foss
|
||||||
changes: *db-patterns
|
changes: *db-patterns
|
||||||
when: never
|
when: never
|
||||||
|
@ -1165,10 +1206,10 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
|
||||||
when: never
|
|
||||||
- <<: *if-security-merge-request
|
- <<: *if-security-merge-request
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
|
- <<: *if-merge-request-not-approved
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-as-if-foss
|
- <<: *if-merge-request-labels-as-if-foss
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
|
|
||||||
|
@ -1180,14 +1221,14 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
changes: *core-backend-patterns
|
changes: *core-backend-patterns
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-security-merge-request
|
|
||||||
changes: *backend-patterns
|
|
||||||
- <<: *if-merge-request-labels-as-if-foss
|
- <<: *if-merge-request-labels-as-if-foss
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
|
|
||||||
|
@ -1202,10 +1243,10 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
|
||||||
when: never
|
|
||||||
- <<: *if-security-merge-request
|
- <<: *if-security-merge-request
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
|
- <<: *if-merge-request-not-approved
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-as-if-foss
|
- <<: *if-merge-request-labels-as-if-foss
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
|
|
||||||
|
@ -1217,14 +1258,14 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
changes: *core-backend-patterns
|
changes: *core-backend-patterns
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-security-merge-request
|
|
||||||
changes: *backend-patterns
|
|
||||||
- <<: *if-merge-request-labels-as-if-foss
|
- <<: *if-merge-request-labels-as-if-foss
|
||||||
changes: *backend-patterns
|
changes: *backend-patterns
|
||||||
|
|
||||||
|
@ -1239,10 +1280,10 @@
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
changes: *code-backstage-patterns
|
changes: *code-backstage-patterns
|
||||||
- <<: *if-merge-request-not-approved
|
|
||||||
when: never
|
|
||||||
- <<: *if-security-merge-request
|
- <<: *if-security-merge-request
|
||||||
changes: *code-backstage-patterns
|
changes: *code-backstage-patterns
|
||||||
|
- <<: *if-merge-request-not-approved
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request-labels-as-if-foss
|
- <<: *if-merge-request-labels-as-if-foss
|
||||||
changes: *code-backstage-patterns
|
changes: *code-backstage-patterns
|
||||||
|
|
||||||
|
@ -1254,14 +1295,14 @@
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-automated-merge-request
|
- <<: *if-automated-merge-request
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-security-merge-request
|
||||||
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
changes: *core-backend-patterns
|
changes: *core-backend-patterns
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
changes: *ci-patterns
|
changes: *ci-patterns
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-security-merge-request
|
|
||||||
changes: *code-backstage-patterns
|
|
||||||
- <<: *if-merge-request-labels-as-if-foss
|
- <<: *if-merge-request-labels-as-if-foss
|
||||||
changes: *code-backstage-patterns
|
changes: *code-backstage-patterns
|
||||||
|
|
||||||
|
@ -1621,6 +1662,10 @@
|
||||||
|
|
||||||
.review:rules:review-qa-reliable:
|
.review:rules:review-qa-reliable:
|
||||||
rules:
|
rules:
|
||||||
|
- <<: *if-dot-com-ee-2-hourly-schedule
|
||||||
|
allow_failure: true
|
||||||
|
variables:
|
||||||
|
KNAPSACK_GENERATE_REPORT: "true"
|
||||||
- when: on_success
|
- when: on_success
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
|
|
||||||
|
@ -1631,6 +1676,10 @@
|
||||||
changes: *code-patterns
|
changes: *code-patterns
|
||||||
when: manual
|
when: manual
|
||||||
allow_failure: true # manual jobs needs to be allowd to fail, otherwise they block the pipeline
|
allow_failure: true # manual jobs needs to be allowd to fail, otherwise they block the pipeline
|
||||||
|
- <<: *if-dot-com-ee-2-hourly-schedule
|
||||||
|
allow_failure: true
|
||||||
|
variables:
|
||||||
|
KNAPSACK_GENERATE_REPORT: "true"
|
||||||
- when: on_success
|
- when: on_success
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
|
|
||||||
|
@ -1646,6 +1695,20 @@
|
||||||
- when: on_failure
|
- when: on_failure
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
|
|
||||||
|
# Generate knapsack report on successful runs only
|
||||||
|
# Reliable suite will pass most of the time so this should yield best distribution
|
||||||
|
.review:rules:knapsack-report-qa-reliable:
|
||||||
|
rules:
|
||||||
|
- <<: *if-dot-com-ee-2-hourly-schedule
|
||||||
|
when: on_success
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
.review:rules:knapsack-report-qa-all:
|
||||||
|
rules:
|
||||||
|
- <<: *if-dot-com-ee-2-hourly-schedule
|
||||||
|
when: always
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
.review:rules:review-cleanup:
|
.review:rules:review-cleanup:
|
||||||
rules:
|
rules:
|
||||||
- <<: *if-not-ee
|
- <<: *if-not-ee
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -185,7 +185,7 @@ gem 'rack', '~> 2.2.3'
|
||||||
gem 'rack-timeout', '~> 0.5.1', require: 'rack/timeout/base'
|
gem 'rack-timeout', '~> 0.5.1', require: 'rack/timeout/base'
|
||||||
|
|
||||||
group :puma do
|
group :puma do
|
||||||
gem 'puma', '~> 5.3.1', require: false
|
gem 'puma', '~> 5.5.2', require: false
|
||||||
gem 'puma_worker_killer', '~> 0.3.1', require: false
|
gem 'puma_worker_killer', '~> 0.3.1', require: false
|
||||||
gem 'sd_notify', '~> 0.1.0', require: false
|
gem 'sd_notify', '~> 0.1.0', require: false
|
||||||
end
|
end
|
||||||
|
|
|
@ -945,7 +945,7 @@ GEM
|
||||||
tty-markdown
|
tty-markdown
|
||||||
tty-prompt
|
tty-prompt
|
||||||
public_suffix (4.0.6)
|
public_suffix (4.0.6)
|
||||||
puma (5.3.2)
|
puma (5.5.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
puma_worker_killer (0.3.1)
|
puma_worker_killer (0.3.1)
|
||||||
get_process_mem (~> 0.2)
|
get_process_mem (~> 0.2)
|
||||||
|
@ -1581,7 +1581,7 @@ DEPENDENCIES
|
||||||
pry-byebug
|
pry-byebug
|
||||||
pry-rails (~> 0.3.9)
|
pry-rails (~> 0.3.9)
|
||||||
pry-shell (~> 0.5.0)
|
pry-shell (~> 0.5.0)
|
||||||
puma (~> 5.3.1)
|
puma (~> 5.5.2)
|
||||||
puma_worker_killer (~> 0.3.1)
|
puma_worker_killer (~> 0.3.1)
|
||||||
rack (~> 2.2.3)
|
rack (~> 2.2.3)
|
||||||
rack-attack (~> 6.3.0)
|
rack-attack (~> 6.3.0)
|
||||||
|
|
|
@ -11,3 +11,10 @@ export const FILTER_TYPE = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MAX_HISTORY_SIZE = 5;
|
export const MAX_HISTORY_SIZE = 5;
|
||||||
|
|
||||||
|
export const FILTERED_SEARCH = {
|
||||||
|
MERGE_REQUESTS: 'merge_requests',
|
||||||
|
ISSUES: 'issues',
|
||||||
|
ADMIN_RUNNERS: 'admin/runners',
|
||||||
|
GROUP_RUNNERS_ANCHOR: 'runners-settings',
|
||||||
|
};
|
||||||
|
|
|
@ -4,3 +4,8 @@ export const ISSUABLE_TYPE = {
|
||||||
issues: 'issues',
|
issues: 'issues',
|
||||||
mergeRequests: 'merge-requests',
|
mergeRequests: 'merge-requests',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ISSUABLE_INDEX = {
|
||||||
|
ISSUE: 'issue_',
|
||||||
|
MERGE_REQUEST: 'merge_request_',
|
||||||
|
};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlButton, GlKeysetPagination } from '@gitlab/ui';
|
|
||||||
import createFlash from '~/flash';
|
import createFlash from '~/flash';
|
||||||
|
import { n__ } from '~/locale';
|
||||||
import { joinPaths } from '~/lib/utils/url_utility';
|
import { joinPaths } from '~/lib/utils/url_utility';
|
||||||
|
import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue';
|
||||||
import {
|
import {
|
||||||
REMOVE_TAGS_BUTTON_TITLE,
|
REMOVE_TAGS_BUTTON_TITLE,
|
||||||
TAGS_LIST_TITLE,
|
TAGS_LIST_TITLE,
|
||||||
|
@ -16,11 +17,10 @@ import TagsLoader from './tags_loader.vue';
|
||||||
export default {
|
export default {
|
||||||
name: 'TagsList',
|
name: 'TagsList',
|
||||||
components: {
|
components: {
|
||||||
GlButton,
|
|
||||||
GlKeysetPagination,
|
|
||||||
TagsListRow,
|
TagsListRow,
|
||||||
EmptyState,
|
EmptyState,
|
||||||
TagsLoader,
|
TagsLoader,
|
||||||
|
RegistryList,
|
||||||
},
|
},
|
||||||
inject: ['config'],
|
inject: ['config'],
|
||||||
props: {
|
props: {
|
||||||
|
@ -61,11 +61,13 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedItems: {},
|
|
||||||
containerRepository: {},
|
containerRepository: {},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
listTitle() {
|
||||||
|
return n__('%d tag', '%d tags', this.tags.length);
|
||||||
|
},
|
||||||
tags() {
|
tags() {
|
||||||
return this.containerRepository?.tags?.nodes || [];
|
return this.containerRepository?.tags?.nodes || [];
|
||||||
},
|
},
|
||||||
|
@ -78,18 +80,9 @@ export default {
|
||||||
first: GRAPHQL_PAGE_SIZE,
|
first: GRAPHQL_PAGE_SIZE,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
hasSelectedItems() {
|
|
||||||
return this.tags.some((tag) => this.selectedItems[tag.name]);
|
|
||||||
},
|
|
||||||
showMultiDeleteButton() {
|
showMultiDeleteButton() {
|
||||||
return this.tags.some((tag) => tag.canDelete) && !this.isMobile;
|
return this.tags.some((tag) => tag.canDelete) && !this.isMobile;
|
||||||
},
|
},
|
||||||
multiDeleteButtonIsDisabled() {
|
|
||||||
return !this.hasSelectedItems || this.disabled;
|
|
||||||
},
|
|
||||||
showPagination() {
|
|
||||||
return this.tagsPageInfo.hasPreviousPage || this.tagsPageInfo.hasNextPage;
|
|
||||||
},
|
|
||||||
hasNoTags() {
|
hasNoTags() {
|
||||||
return this.tags.length === 0;
|
return this.tags.length === 0;
|
||||||
},
|
},
|
||||||
|
@ -98,19 +91,13 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateSelectedItems(name) {
|
|
||||||
this.$set(this.selectedItems, name, !this.selectedItems[name]);
|
|
||||||
},
|
|
||||||
mapTagsToBeDleeted(items) {
|
|
||||||
return this.tags.filter((tag) => items[tag.name]);
|
|
||||||
},
|
|
||||||
fetchNextPage() {
|
fetchNextPage() {
|
||||||
this.$apollo.queries.containerRepository.fetchMore({
|
this.$apollo.queries.containerRepository.fetchMore({
|
||||||
variables: {
|
variables: {
|
||||||
after: this.tagsPageInfo?.endCursor,
|
after: this.tagsPageInfo?.endCursor,
|
||||||
first: GRAPHQL_PAGE_SIZE,
|
first: GRAPHQL_PAGE_SIZE,
|
||||||
},
|
},
|
||||||
updateQuery(previousResult, { fetchMoreResult }) {
|
updateQuery(_, { fetchMoreResult }) {
|
||||||
return fetchMoreResult;
|
return fetchMoreResult;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -122,7 +109,7 @@ export default {
|
||||||
before: this.tagsPageInfo?.startCursor,
|
before: this.tagsPageInfo?.startCursor,
|
||||||
last: GRAPHQL_PAGE_SIZE,
|
last: GRAPHQL_PAGE_SIZE,
|
||||||
},
|
},
|
||||||
updateQuery(previousResult, { fetchMoreResult }) {
|
updateQuery(_, { fetchMoreResult }) {
|
||||||
return fetchMoreResult;
|
return fetchMoreResult;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -137,42 +124,27 @@ export default {
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<empty-state v-if="hasNoTags" :no-containers-image="config.noContainersImage" />
|
<empty-state v-if="hasNoTags" :no-containers-image="config.noContainersImage" />
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="gl-display-flex gl-justify-content-space-between gl-mb-3">
|
<registry-list
|
||||||
<h5 data-testid="list-title">
|
:title="listTitle"
|
||||||
{{ $options.i18n.TAGS_LIST_TITLE }}
|
:pagination="tagsPageInfo"
|
||||||
</h5>
|
:items="tags"
|
||||||
|
id-property="name"
|
||||||
<gl-button
|
@prev-page="fetchPreviousPage"
|
||||||
v-if="showMultiDeleteButton"
|
@next-page="fetchNextPage"
|
||||||
:disabled="multiDeleteButtonIsDisabled"
|
@delete="$emit('delete', $event)"
|
||||||
category="secondary"
|
>
|
||||||
variant="danger"
|
<template #default="{ selectItem, isSelected, item, first }">
|
||||||
@click="$emit('delete', mapTagsToBeDleeted(selectedItems))"
|
<tags-list-row
|
||||||
>
|
:tag="item"
|
||||||
{{ $options.i18n.REMOVE_TAGS_BUTTON_TITLE }}
|
:first="first"
|
||||||
</gl-button>
|
:selected="isSelected(item)"
|
||||||
</div>
|
:is-mobile="isMobile"
|
||||||
<tags-list-row
|
:disabled="disabled"
|
||||||
v-for="(tag, index) in tags"
|
@select="selectItem(item)"
|
||||||
:key="tag.path"
|
@delete="$emit('delete', [item])"
|
||||||
:tag="tag"
|
/>
|
||||||
:first="index === 0"
|
</template>
|
||||||
:selected="selectedItems[tag.name]"
|
</registry-list>
|
||||||
:is-mobile="isMobile"
|
|
||||||
:disabled="disabled"
|
|
||||||
@select="updateSelectedItems(tag.name)"
|
|
||||||
@delete="$emit('delete', mapTagsToBeDleeted({ [tag.name]: true }))"
|
|
||||||
/>
|
|
||||||
<div class="gl-display-flex gl-justify-content-center">
|
|
||||||
<gl-keyset-pagination
|
|
||||||
v-if="showPagination"
|
|
||||||
:has-next-page="tagsPageInfo.hasNextPage"
|
|
||||||
:has-previous-page="tagsPageInfo.hasPreviousPage"
|
|
||||||
class="gl-mt-3"
|
|
||||||
@prev="fetchPreviousPage"
|
|
||||||
@next="fetchNextPage"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
export const FILTERED_SEARCH = {
|
|
||||||
MERGE_REQUESTS: 'merge_requests',
|
|
||||||
ISSUES: 'issues',
|
|
||||||
ADMIN_RUNNERS: 'admin/runners',
|
|
||||||
GROUP_RUNNERS_ANCHOR: 'runners-settings',
|
|
||||||
};
|
|
|
@ -1,6 +1,6 @@
|
||||||
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
|
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
|
||||||
import initManualOrdering from '~/manual_ordering';
|
import initManualOrdering from '~/manual_ordering';
|
||||||
import { FILTERED_SEARCH } from '~/pages/constants';
|
import { FILTERED_SEARCH } from '~/filtered_search/constants';
|
||||||
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
||||||
import projectSelect from '~/project_select';
|
import projectSelect from '~/project_select';
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import addExtraTokensForMergeRequests from 'ee_else_ce/filtered_search/add_extra_tokens_for_merge_requests';
|
import addExtraTokensForMergeRequests from 'ee_else_ce/filtered_search/add_extra_tokens_for_merge_requests';
|
||||||
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
|
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
|
||||||
import { FILTERED_SEARCH } from '~/pages/constants';
|
import { FILTERED_SEARCH } from '~/filtered_search/constants';
|
||||||
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
||||||
import projectSelect from '~/project_select';
|
import projectSelect from '~/project_select';
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable
|
||||||
import issuableInitBulkUpdateSidebar from '~/issuable/bulk_update_sidebar/issuable_init_bulk_update_sidebar';
|
import issuableInitBulkUpdateSidebar from '~/issuable/bulk_update_sidebar/issuable_init_bulk_update_sidebar';
|
||||||
import { mountIssuablesListApp, mountIssuesListApp } from '~/issues_list';
|
import { mountIssuablesListApp, mountIssuesListApp } from '~/issues_list';
|
||||||
import initManualOrdering from '~/manual_ordering';
|
import initManualOrdering from '~/manual_ordering';
|
||||||
import { FILTERED_SEARCH } from '~/pages/constants';
|
import { FILTERED_SEARCH } from '~/filtered_search/constants';
|
||||||
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
||||||
import projectSelect from '~/project_select';
|
import projectSelect from '~/project_select';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import addExtraTokensForMergeRequests from 'ee_else_ce/filtered_search/add_extra_tokens_for_merge_requests';
|
import addExtraTokensForMergeRequests from 'ee_else_ce/filtered_search/add_extra_tokens_for_merge_requests';
|
||||||
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
|
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
|
||||||
import issuableInitBulkUpdateSidebar from '~/issuable/bulk_update_sidebar/issuable_init_bulk_update_sidebar';
|
import issuableInitBulkUpdateSidebar from '~/issuable/bulk_update_sidebar/issuable_init_bulk_update_sidebar';
|
||||||
import { FILTERED_SEARCH } from '~/pages/constants';
|
import { FILTERED_SEARCH } from '~/filtered_search/constants';
|
||||||
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
||||||
import projectSelect from '~/project_select';
|
import projectSelect from '~/project_select';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import initVariableList from '~/ci_variable_list';
|
import initVariableList from '~/ci_variable_list';
|
||||||
import GroupRunnersFilteredSearchTokenKeys from '~/filtered_search/group_runners_filtered_search_token_keys';
|
import GroupRunnersFilteredSearchTokenKeys from '~/filtered_search/group_runners_filtered_search_token_keys';
|
||||||
import initSharedRunnersForm from '~/group_settings/mount_shared_runners';
|
import initSharedRunnersForm from '~/group_settings/mount_shared_runners';
|
||||||
import { FILTERED_SEARCH } from '~/pages/constants';
|
import { FILTERED_SEARCH } from '~/filtered_search/constants';
|
||||||
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
||||||
import { initRunnerAwsDeployments } from '~/pages/shared/mount_runner_aws_deployments';
|
import { initRunnerAwsDeployments } from '~/pages/shared/mount_runner_aws_deployments';
|
||||||
import { initInstallRunner } from '~/pages/shared/mount_runner_instructions';
|
import { initInstallRunner } from '~/pages/shared/mount_runner_instructions';
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
export const ISSUABLE_INDEX = {
|
|
||||||
MERGE_REQUEST: 'merge_request_',
|
|
||||||
ISSUE: 'issue_',
|
|
||||||
};
|
|
|
@ -5,8 +5,8 @@ import initIssuableByEmail from '~/issuable/init_issuable_by_email';
|
||||||
import IssuableIndex from '~/issuable/issuable_index';
|
import IssuableIndex from '~/issuable/issuable_index';
|
||||||
import { mountIssuablesListApp, mountIssuesListApp, mountJiraIssuesListApp } from '~/issues_list';
|
import { mountIssuablesListApp, mountIssuesListApp, mountJiraIssuesListApp } from '~/issues_list';
|
||||||
import initManualOrdering from '~/manual_ordering';
|
import initManualOrdering from '~/manual_ordering';
|
||||||
import { FILTERED_SEARCH } from '~/pages/constants';
|
import { FILTERED_SEARCH } from '~/filtered_search/constants';
|
||||||
import { ISSUABLE_INDEX } from '~/pages/projects/constants';
|
import { ISSUABLE_INDEX } from '~/issuable/constants';
|
||||||
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
||||||
import UsersSelect from '~/users_select';
|
import UsersSelect from '~/users_select';
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered
|
||||||
import initCsvImportExportButtons from '~/issuable/init_csv_import_export_buttons';
|
import initCsvImportExportButtons from '~/issuable/init_csv_import_export_buttons';
|
||||||
import initIssuableByEmail from '~/issuable/init_issuable_by_email';
|
import initIssuableByEmail from '~/issuable/init_issuable_by_email';
|
||||||
import IssuableIndex from '~/issuable/issuable_index';
|
import IssuableIndex from '~/issuable/issuable_index';
|
||||||
import { FILTERED_SEARCH } from '~/pages/constants';
|
import { FILTERED_SEARCH } from '~/filtered_search/constants';
|
||||||
import { ISSUABLE_INDEX } from '~/pages/projects/constants';
|
import { ISSUABLE_INDEX } from '~/issuable/constants';
|
||||||
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
import initFilteredSearch from '~/pages/search/init_filtered_search';
|
||||||
import UsersSelect from '~/users_select';
|
import UsersSelect from '~/users_select';
|
||||||
|
|
||||||
|
|
|
@ -235,6 +235,12 @@ module Ci
|
||||||
pipeline.run_after_commit do
|
pipeline.run_after_commit do
|
||||||
PipelineHooksWorker.perform_async(pipeline.id)
|
PipelineHooksWorker.perform_async(pipeline.id)
|
||||||
|
|
||||||
|
if pipeline.project.jira_subscription_exists?
|
||||||
|
# Passing the seq-id ensures this is idempotent
|
||||||
|
seq_id = ::Atlassian::JiraConnect::Client.generate_update_sequence_id
|
||||||
|
::JiraConnect::SyncBuildsWorker.perform_async(pipeline.id, seq_id)
|
||||||
|
end
|
||||||
|
|
||||||
if Feature.enabled?(:expire_job_and_pipeline_cache_synchronously, pipeline.project, default_enabled: :yaml)
|
if Feature.enabled?(:expire_job_and_pipeline_cache_synchronously, pipeline.project, default_enabled: :yaml)
|
||||||
Ci::ExpirePipelineCacheService.new.execute(pipeline) # rubocop: disable CodeReuse/ServiceClass
|
Ci::ExpirePipelineCacheService.new.execute(pipeline) # rubocop: disable CodeReuse/ServiceClass
|
||||||
else
|
else
|
||||||
|
@ -274,14 +280,6 @@ module Ci
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
after_transition any => any do |pipeline|
|
|
||||||
pipeline.run_after_commit do
|
|
||||||
# Passing the seq-id ensures this is idempotent
|
|
||||||
seq_id = ::Atlassian::JiraConnect::Client.generate_update_sequence_id
|
|
||||||
::JiraConnect::SyncBuildsWorker.perform_async(pipeline.id, seq_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
after_transition any => ::Ci::Pipeline.completed_statuses do |pipeline|
|
after_transition any => ::Ci::Pipeline.completed_statuses do |pipeline|
|
||||||
pipeline.run_after_commit do
|
pipeline.run_after_commit do
|
||||||
::Ci::TestFailureHistoryService.new(pipeline).async.perform_if_needed # rubocop: disable CodeReuse/ServiceClass
|
::Ci::TestFailureHistoryService.new(pipeline).async.perform_if_needed # rubocop: disable CodeReuse/ServiceClass
|
||||||
|
|
|
@ -119,6 +119,8 @@ class Deployment < ApplicationRecord
|
||||||
next if transition.loopback?
|
next if transition.loopback?
|
||||||
|
|
||||||
deployment.run_after_commit do
|
deployment.run_after_commit do
|
||||||
|
next unless deployment.project.jira_subscription_exists?
|
||||||
|
|
||||||
::JiraConnect::SyncDeploymentsWorker.perform_async(id)
|
::JiraConnect::SyncDeploymentsWorker.perform_async(id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -126,6 +128,8 @@ class Deployment < ApplicationRecord
|
||||||
|
|
||||||
after_create unless: :importing? do |deployment|
|
after_create unless: :importing? do |deployment|
|
||||||
run_after_commit do
|
run_after_commit do
|
||||||
|
next unless deployment.project.jira_subscription_exists?
|
||||||
|
|
||||||
::JiraConnect::SyncDeploymentsWorker.perform_async(deployment.id)
|
::JiraConnect::SyncDeploymentsWorker.perform_async(deployment.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,6 +43,7 @@ module FeatureFlags
|
||||||
|
|
||||||
def sync_to_jira(feature_flag)
|
def sync_to_jira(feature_flag)
|
||||||
return unless feature_flag.present?
|
return unless feature_flag.present?
|
||||||
|
return unless project.jira_subscription_exists?
|
||||||
|
|
||||||
seq_id = ::Atlassian::JiraConnect::Client.generate_update_sequence_id
|
seq_id = ::Atlassian::JiraConnect::Client.generate_update_sequence_id
|
||||||
feature_flag.run_after_commit do
|
feature_flag.run_after_commit do
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddIndexSnippetsOnProjectIdAndTitle < Gitlab::Database::Migration[1.0]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
INDEX_NAME = 'index_snippets_on_project_id_and_title'
|
||||||
|
|
||||||
|
def up
|
||||||
|
add_concurrent_index :snippets, [:project_id, :title], name: INDEX_NAME
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_concurrent_index_by_name :snippets, name: INDEX_NAME
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CleanupFirstMentionedInCommitJobs < Gitlab::Database::Migration[1.0]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
MIGRATION = 'FixFirstMentionedInCommitAt'
|
||||||
|
INDEX_NAME = 'index_issue_metrics_first_mentioned_in_commit'
|
||||||
|
|
||||||
|
def up
|
||||||
|
finalize_background_migration(MIGRATION)
|
||||||
|
|
||||||
|
remove_concurrent_index_by_name :issue_metrics, name: INDEX_NAME
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
# Handles reported schema inconsistencies (column with or without timezone)
|
||||||
|
# We did the same in db/post_migrate/20211004110500_add_temporary_index_to_issue_metrics.rb
|
||||||
|
condition = Gitlab::BackgroundMigration::FixFirstMentionedInCommitAt::TmpIssueMetrics
|
||||||
|
.first_mentioned_in_commit_at_condition
|
||||||
|
add_concurrent_index :issue_metrics, :issue_id, where: condition, name: INDEX_NAME
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1 @@
|
||||||
|
6a3591e70ddd6573ad68360c1a8774ef61e7812ce831c75066baec5754e2bd76
|
|
@ -0,0 +1 @@
|
||||||
|
c30656c3f079e789f386b5b607710a7d4df6d2eb20bd457bab3a2e8d9eeb051b
|
|
@ -26346,8 +26346,6 @@ CREATE UNIQUE INDEX index_issue_links_on_source_id_and_target_id ON issue_links
|
||||||
|
|
||||||
CREATE INDEX index_issue_links_on_target_id ON issue_links USING btree (target_id);
|
CREATE INDEX index_issue_links_on_target_id ON issue_links USING btree (target_id);
|
||||||
|
|
||||||
CREATE INDEX index_issue_metrics_first_mentioned_in_commit ON issue_metrics USING btree (issue_id) WHERE (date_part('year'::text, first_mentioned_in_commit_at) > (2019)::double precision);
|
|
||||||
|
|
||||||
CREATE INDEX index_issue_metrics_on_issue_id_and_timestamps ON issue_metrics USING btree (issue_id, first_mentioned_in_commit_at, first_associated_with_milestone_at, first_added_to_board_at);
|
CREATE INDEX index_issue_metrics_on_issue_id_and_timestamps ON issue_metrics USING btree (issue_id, first_mentioned_in_commit_at, first_associated_with_milestone_at, first_added_to_board_at);
|
||||||
|
|
||||||
CREATE INDEX index_issue_on_project_id_state_id_and_blocking_issues_count ON issues USING btree (project_id, state_id, blocking_issues_count);
|
CREATE INDEX index_issue_on_project_id_state_id_and_blocking_issues_count ON issues USING btree (project_id, state_id, blocking_issues_count);
|
||||||
|
@ -27448,6 +27446,8 @@ CREATE INDEX index_snippets_on_id_and_created_at ON snippets USING btree (id, cr
|
||||||
|
|
||||||
CREATE INDEX index_snippets_on_id_and_type ON snippets USING btree (id, type);
|
CREATE INDEX index_snippets_on_id_and_type ON snippets USING btree (id, type);
|
||||||
|
|
||||||
|
CREATE INDEX index_snippets_on_project_id_and_title ON snippets USING btree (project_id, title);
|
||||||
|
|
||||||
CREATE INDEX index_snippets_on_project_id_and_visibility_level ON snippets USING btree (project_id, visibility_level);
|
CREATE INDEX index_snippets_on_project_id_and_visibility_level ON snippets USING btree (project_id, visibility_level);
|
||||||
|
|
||||||
CREATE INDEX index_snippets_on_title_trigram ON snippets USING gin (title gin_trgm_ops);
|
CREATE INDEX index_snippets_on_title_trigram ON snippets USING gin (title gin_trgm_ops);
|
||||||
|
|
|
@ -68,6 +68,7 @@ In addition, there are a few circumstances where we would always run the full RS
|
||||||
|
|
||||||
- when the `pipeline:run-all-rspec` label is set on the merge request
|
- when the `pipeline:run-all-rspec` label is set on the merge request
|
||||||
- when the merge request is created by an automation (e.g. Gitaly update or MR targeting a stable branch)
|
- when the merge request is created by an automation (e.g. Gitaly update or MR targeting a stable branch)
|
||||||
|
- when the merge request is created in a security mirror
|
||||||
- when any CI config file is changed (i.e. `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
|
- when any CI config file is changed (i.e. `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
|
||||||
|
|
||||||
### Jest minimal jobs
|
### Jest minimal jobs
|
||||||
|
@ -83,6 +84,7 @@ In addition, there are a few circumstances where we would always run the full Je
|
||||||
|
|
||||||
- when the `pipeline:run-all-jest` label is set on the merge request
|
- when the `pipeline:run-all-jest` label is set on the merge request
|
||||||
- when the merge request is created by an automation (e.g. Gitaly update or MR targeting a stable branch)
|
- when the merge request is created by an automation (e.g. Gitaly update or MR targeting a stable branch)
|
||||||
|
- when the merge request is created in a security mirror
|
||||||
- when any CI config file is changed (i.e. `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
|
- when any CI config file is changed (i.e. `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
|
||||||
- when any frontend "core" file is changed (i.e. `package.json`, `yarn.lock`, `babel.config.js`, `jest.config.*.js`, `config/helpers/**/*.js`)
|
- when any frontend "core" file is changed (i.e. `package.json`, `yarn.lock`, `babel.config.js`, `jest.config.*.js`, `config/helpers/**/*.js`)
|
||||||
- when any vendored JavaScript file is changed (i.e. `vendor/assets/javascripts/**/*`)
|
- when any vendored JavaScript file is changed (i.e. `vendor/assets/javascripts/**/*`)
|
||||||
|
|
|
@ -113,7 +113,7 @@ CREATE ROLE slony WITH SUPERUSER LOGIN REPLICATION ENCRYPTED PASSWORD 'password
|
||||||
ALTER ROLE slony SET statement_timeout TO 0;
|
ALTER ROLE slony SET statement_timeout TO 0;
|
||||||
```
|
```
|
||||||
|
|
||||||
Make sure you replace "password string here" with the actual password for the
|
Make sure you replace "password string here" with an actual password for the
|
||||||
user. A password is required. This user must be created on both the old and
|
user. A password is required. This user must be created on both the old and
|
||||||
new database server using the same password.
|
new database server using the same password.
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ Now run the following commands:
|
||||||
\i /tmp/migrations.sql
|
\i /tmp/migrations.sql
|
||||||
```
|
```
|
||||||
|
|
||||||
To verify if the structure is in place close the session, start it again, then
|
To verify if the structure is in place close the session (`\q`), start it again, then
|
||||||
run `\d`. If all went well you should see output along the lines of the
|
run `\d`. If all went well you should see output along the lines of the
|
||||||
following:
|
following:
|
||||||
|
|
||||||
|
@ -459,7 +459,7 @@ main
|
||||||
Upload this script to the _target_ server and execute it as follows:
|
Upload this script to the _target_ server and execute it as follows:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
bash path/to/the/script/above.sh
|
sudo bash path/to/the/script/above.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
This corrects the ownership of sequences and reset the next value for the
|
This corrects the ownership of sequences and reset the next value for the
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
# Vulnerability Report **(ULTIMATE)**
|
# Vulnerability Report **(ULTIMATE)**
|
||||||
|
|
||||||
The Vulnerability Report provides information about vulnerabilities from scans of the default branch. It is available for groups, projects, and the Security Center.
|
The Vulnerability Report provides information about vulnerabilities from scans of the default branch. It is available for projects, groups, and the Security Center.
|
||||||
|
|
||||||
At all levels, the Vulnerability Report contains:
|
At all levels, the Vulnerability Report contains:
|
||||||
|
|
||||||
|
@ -214,3 +214,12 @@ You can dismiss a vulnerability for the entire project:
|
||||||
1. Optional. Add a reason for the dismissal and select **Save comment**.
|
1. Optional. Add a reason for the dismissal and select **Save comment**.
|
||||||
|
|
||||||
To undo this action, select a different status from the same menu.
|
To undo this action, select a different status from the same menu.
|
||||||
|
|
||||||
|
## Operational vulnerabilities
|
||||||
|
|
||||||
|
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6345) in GitLab 14.6.
|
||||||
|
|
||||||
|
The **Operational vulnerabilities** tab lists vulnerabilities found by the `cluster_image_scanner`.
|
||||||
|
This tab appears on the project, group, and Security Center vulnerability reports.
|
||||||
|
|
||||||
|
![Operational Vulnerability Tab](img/operational_vulnerability_tab_v14_6.png)
|
||||||
|
|
|
@ -26,7 +26,7 @@ To manage linked issues through our API, visit the [issue links API documentatio
|
||||||
1. Link one issue to another by selecting the add linked issue button (**{plus}**) in the
|
1. Link one issue to another by selecting the add linked issue button (**{plus}**) in the
|
||||||
**Linked issues** section of an issue.
|
**Linked issues** section of an issue.
|
||||||
|
|
||||||
1. Select the relationship the between the two issues. Either:
|
1. Select the relationship between the two issues. Either:
|
||||||
- **relates to**
|
- **relates to**
|
||||||
- **blocks** **(PREMIUM)**
|
- **blocks** **(PREMIUM)**
|
||||||
- **is blocked by** **(PREMIUM)**
|
- **is blocked by** **(PREMIUM)**
|
||||||
|
|
|
@ -38,16 +38,19 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def host_stats
|
def host_stats
|
||||||
return [] unless ActiveRecord::Base.connected?
|
Gitlab::Database.database_base_models.each_value.with_object([]) do |base_model, stats|
|
||||||
|
next unless base_model.connected?
|
||||||
|
|
||||||
[{ labels: labels_for_class(ActiveRecord::Base), stats: ActiveRecord::Base.connection_pool.stat }]
|
stats << { labels: labels_for_class(base_model), stats: base_model.connection_pool.stat }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def labels_for_class(klass)
|
def labels_for_class(klass)
|
||||||
{
|
{
|
||||||
host: klass.connection_db_config.host,
|
host: klass.connection_db_config.host,
|
||||||
port: klass.connection_db_config.configuration_hash[:port],
|
port: klass.connection_db_config.configuration_hash[:port],
|
||||||
class: klass.to_s
|
class: klass.to_s,
|
||||||
|
db_config_name: klass.connection_db_config.name
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4446,7 +4446,7 @@ msgstr ""
|
||||||
msgid "ApprovalSettings|This setting is configured at the instance level and can only be changed by an administrator."
|
msgid "ApprovalSettings|This setting is configured at the instance level and can only be changed by an administrator."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "ApprovalSettings|This setting is configured in %{groupName} and can only be changed by an administrator or group owner."
|
msgid "ApprovalSettings|This setting is configured in %{groupName} and can only be changed in the group settings by an administrator or group owner."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "ApprovalStatusTooltip|Adheres to separation of duties"
|
msgid "ApprovalStatusTooltip|Adheres to separation of duties"
|
||||||
|
|
|
@ -15,7 +15,7 @@ gem 'rest-client', '~> 2.1.0'
|
||||||
gem 'rspec-retry', '~> 0.6.1', require: 'rspec/retry'
|
gem 'rspec-retry', '~> 0.6.1', require: 'rspec/retry'
|
||||||
gem 'rspec_junit_formatter', '~> 0.4.1'
|
gem 'rspec_junit_formatter', '~> 0.4.1'
|
||||||
gem 'faker', '~> 2.19', '>= 2.19.0'
|
gem 'faker', '~> 2.19', '>= 2.19.0'
|
||||||
gem 'knapsack', '~> 1.17'
|
gem 'knapsack', '~> 4.0'
|
||||||
gem 'parallel_tests', '~> 2.29'
|
gem 'parallel_tests', '~> 2.29'
|
||||||
gem 'rotp', '~> 3.1.0'
|
gem 'rotp', '~> 3.1.0'
|
||||||
gem 'timecop', '~> 0.9.1'
|
gem 'timecop', '~> 0.9.1'
|
||||||
|
@ -27,6 +27,7 @@ gem 'zeitwerk', '~> 2.4'
|
||||||
gem 'influxdb-client', '~> 1.17'
|
gem 'influxdb-client', '~> 1.17'
|
||||||
gem 'terminal-table', '~> 1.8', require: false
|
gem 'terminal-table', '~> 1.8', require: false
|
||||||
gem 'slack-notifier', '~> 2.4', require: false
|
gem 'slack-notifier', '~> 2.4', require: false
|
||||||
|
gem 'fog-google', '~> 1.17', require: false
|
||||||
|
|
||||||
gem 'chemlab', '~> 0.9'
|
gem 'chemlab', '~> 0.9'
|
||||||
gem 'chemlab-library-www-gitlab-com', '~> 0.1'
|
gem 'chemlab-library-www-gitlab-com', '~> 0.1'
|
||||||
|
|
|
@ -29,6 +29,7 @@ GEM
|
||||||
uuid (>= 2.3, < 3)
|
uuid (>= 2.3, < 3)
|
||||||
ast (2.4.2)
|
ast (2.4.2)
|
||||||
binding_ninja (0.2.3)
|
binding_ninja (0.2.3)
|
||||||
|
builder (3.2.4)
|
||||||
byebug (9.1.0)
|
byebug (9.1.0)
|
||||||
capybara (3.35.3)
|
capybara (3.35.3)
|
||||||
addressable
|
addressable
|
||||||
|
@ -56,12 +57,14 @@ GEM
|
||||||
adamantium (~> 0.2.0)
|
adamantium (~> 0.2.0)
|
||||||
equalizer (~> 0.0.9)
|
equalizer (~> 0.0.9)
|
||||||
concurrent-ruby (1.1.9)
|
concurrent-ruby (1.1.9)
|
||||||
|
declarative (0.0.20)
|
||||||
deprecation_toolkit (1.5.1)
|
deprecation_toolkit (1.5.1)
|
||||||
activesupport (>= 4.2)
|
activesupport (>= 4.2)
|
||||||
diff-lcs (1.3)
|
diff-lcs (1.3)
|
||||||
domain_name (0.5.20190701)
|
domain_name (0.5.20190701)
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
equalizer (0.0.11)
|
equalizer (0.0.11)
|
||||||
|
excon (0.88.0)
|
||||||
faker (2.19.0)
|
faker (2.19.0)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
faraday (1.5.1)
|
faraday (1.5.1)
|
||||||
|
@ -85,6 +88,30 @@ GEM
|
||||||
ffi-compiler (1.0.1)
|
ffi-compiler (1.0.1)
|
||||||
ffi (>= 1.0.0)
|
ffi (>= 1.0.0)
|
||||||
rake
|
rake
|
||||||
|
fog-core (2.1.0)
|
||||||
|
builder
|
||||||
|
excon (~> 0.58)
|
||||||
|
formatador (~> 0.2)
|
||||||
|
mime-types
|
||||||
|
fog-google (1.17.0)
|
||||||
|
fog-core (<= 2.1.0)
|
||||||
|
fog-json (~> 1.2)
|
||||||
|
fog-xml (~> 0.1.0)
|
||||||
|
google-apis-compute_v1 (~> 0.14)
|
||||||
|
google-apis-dns_v1 (~> 0.12)
|
||||||
|
google-apis-iamcredentials_v1 (~> 0.6)
|
||||||
|
google-apis-monitoring_v3 (~> 0.12)
|
||||||
|
google-apis-pubsub_v1 (~> 0.7)
|
||||||
|
google-apis-sqladmin_v1beta4 (~> 0.13)
|
||||||
|
google-apis-storage_v1 (~> 0.6)
|
||||||
|
google-cloud-env (~> 1.2)
|
||||||
|
fog-json (1.2.0)
|
||||||
|
fog-core
|
||||||
|
multi_json (~> 1.10)
|
||||||
|
fog-xml (0.1.4)
|
||||||
|
fog-core
|
||||||
|
nokogiri (>= 1.5.11, < 2.0.0)
|
||||||
|
formatador (0.3.0)
|
||||||
gitlab (4.16.1)
|
gitlab (4.16.1)
|
||||||
httparty (~> 0.14, >= 0.14.0)
|
httparty (~> 0.14, >= 0.14.0)
|
||||||
terminal-table (~> 1.5, >= 1.5.1)
|
terminal-table (~> 1.5, >= 1.5.1)
|
||||||
|
@ -94,6 +121,38 @@ GEM
|
||||||
http (~> 5.0)
|
http (~> 5.0)
|
||||||
nokogiri (~> 1.10)
|
nokogiri (~> 1.10)
|
||||||
table_print (= 1.5.7)
|
table_print (= 1.5.7)
|
||||||
|
google-apis-compute_v1 (0.21.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-apis-core (0.4.1)
|
||||||
|
addressable (~> 2.5, >= 2.5.1)
|
||||||
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
|
httpclient (>= 2.8.1, < 3.a)
|
||||||
|
mini_mime (~> 1.0)
|
||||||
|
representable (~> 3.0)
|
||||||
|
retriable (>= 2.0, < 4.a)
|
||||||
|
rexml
|
||||||
|
webrick
|
||||||
|
google-apis-dns_v1 (0.16.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-apis-iamcredentials_v1 (0.8.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-apis-monitoring_v3 (0.18.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-apis-pubsub_v1 (0.10.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-apis-sqladmin_v1beta4 (0.21.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-apis-storage_v1 (0.9.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-cloud-env (1.5.0)
|
||||||
|
faraday (>= 0.17.3, < 2.0)
|
||||||
|
googleauth (1.1.0)
|
||||||
|
faraday (>= 0.17.3, < 2.0)
|
||||||
|
jwt (>= 1.4, < 3.0)
|
||||||
|
memoist (~> 0.16)
|
||||||
|
multi_json (~> 1.11)
|
||||||
|
os (>= 0.9, < 2.0)
|
||||||
|
signet (>= 0.16, < 2.a)
|
||||||
http (5.0.4)
|
http (5.0.4)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
http-cookie (~> 1.0)
|
http-cookie (~> 1.0)
|
||||||
|
@ -106,11 +165,13 @@ GEM
|
||||||
httparty (0.20.0)
|
httparty (0.20.0)
|
||||||
mime-types (~> 3.0)
|
mime-types (~> 3.0)
|
||||||
multi_xml (>= 0.5.2)
|
multi_xml (>= 0.5.2)
|
||||||
|
httpclient (2.8.3)
|
||||||
i18n (1.8.11)
|
i18n (1.8.11)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
ice_nine (0.11.2)
|
ice_nine (0.11.2)
|
||||||
influxdb-client (1.17.0)
|
influxdb-client (1.17.0)
|
||||||
knapsack (1.17.1)
|
jwt (2.3.0)
|
||||||
|
knapsack (4.0.0)
|
||||||
rake
|
rake
|
||||||
launchy (2.4.3)
|
launchy (2.4.3)
|
||||||
addressable (~> 2.3)
|
addressable (~> 2.3)
|
||||||
|
@ -119,6 +180,7 @@ GEM
|
||||||
rake (~> 13.0)
|
rake (~> 13.0)
|
||||||
macaddr (1.7.2)
|
macaddr (1.7.2)
|
||||||
systemu (~> 2.6.5)
|
systemu (~> 2.6.5)
|
||||||
|
memoist (0.16.2)
|
||||||
memoizable (0.4.2)
|
memoizable (0.4.2)
|
||||||
thread_safe (~> 0.3, >= 0.3.1)
|
thread_safe (~> 0.3, >= 0.3.1)
|
||||||
method_source (0.9.0)
|
method_source (0.9.0)
|
||||||
|
@ -128,6 +190,7 @@ GEM
|
||||||
mini_mime (1.1.0)
|
mini_mime (1.1.0)
|
||||||
mini_portile2 (2.6.1)
|
mini_portile2 (2.6.1)
|
||||||
minitest (5.14.4)
|
minitest (5.14.4)
|
||||||
|
multi_json (1.15.0)
|
||||||
multi_xml (0.6.0)
|
multi_xml (0.6.0)
|
||||||
multipart-post (2.1.1)
|
multipart-post (2.1.1)
|
||||||
netrc (0.11.0)
|
netrc (0.11.0)
|
||||||
|
@ -138,6 +201,7 @@ GEM
|
||||||
faraday (>= 0.9)
|
faraday (>= 0.9)
|
||||||
sawyer (~> 0.8.0, >= 0.5.3)
|
sawyer (~> 0.8.0, >= 0.5.3)
|
||||||
oj (3.13.8)
|
oj (3.13.8)
|
||||||
|
os (1.1.4)
|
||||||
parallel (1.19.2)
|
parallel (1.19.2)
|
||||||
parallel_tests (2.29.0)
|
parallel_tests (2.29.0)
|
||||||
parallel
|
parallel
|
||||||
|
@ -161,12 +225,17 @@ GEM
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rake (13.0.6)
|
rake (13.0.6)
|
||||||
regexp_parser (2.1.1)
|
regexp_parser (2.1.1)
|
||||||
|
representable (3.1.1)
|
||||||
|
declarative (< 0.1.0)
|
||||||
|
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||||
|
uber (< 0.2.0)
|
||||||
require_all (3.0.0)
|
require_all (3.0.0)
|
||||||
rest-client (2.1.0)
|
rest-client (2.1.0)
|
||||||
http-accept (>= 1.7.0, < 2.0)
|
http-accept (>= 1.7.0, < 2.0)
|
||||||
http-cookie (>= 1.0.2, < 2.0)
|
http-cookie (>= 1.0.2, < 2.0)
|
||||||
mime-types (>= 1.16, < 4.0)
|
mime-types (>= 1.16, < 4.0)
|
||||||
netrc (~> 0.8)
|
netrc (~> 0.8)
|
||||||
|
retriable (3.1.2)
|
||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
rotp (3.1.0)
|
rotp (3.1.0)
|
||||||
rspec (3.10.0)
|
rspec (3.10.0)
|
||||||
|
@ -203,6 +272,11 @@ GEM
|
||||||
childprocess (>= 0.5, < 5.0)
|
childprocess (>= 0.5, < 5.0)
|
||||||
rexml (~> 3.2, >= 3.2.5)
|
rexml (~> 3.2, >= 3.2.5)
|
||||||
rubyzip (>= 1.2.2)
|
rubyzip (>= 1.2.2)
|
||||||
|
signet (0.16.0)
|
||||||
|
addressable (~> 2.8)
|
||||||
|
faraday (>= 0.17.3, < 2.0)
|
||||||
|
jwt (>= 1.5, < 3.0)
|
||||||
|
multi_json (~> 1.10)
|
||||||
slack-notifier (2.4.0)
|
slack-notifier (2.4.0)
|
||||||
systemu (2.6.5)
|
systemu (2.6.5)
|
||||||
table_print (1.5.7)
|
table_print (1.5.7)
|
||||||
|
@ -210,8 +284,10 @@ GEM
|
||||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
timecop (0.9.1)
|
timecop (0.9.1)
|
||||||
|
trailblazer-option (0.1.2)
|
||||||
tzinfo (2.0.4)
|
tzinfo (2.0.4)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
|
uber (0.1.0)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.8)
|
unf_ext (0.0.8)
|
||||||
|
@ -233,6 +309,7 @@ GEM
|
||||||
nokogiri (~> 1.6)
|
nokogiri (~> 1.6)
|
||||||
rubyzip (>= 1.3.0)
|
rubyzip (>= 1.3.0)
|
||||||
selenium-webdriver (~> 4.0)
|
selenium-webdriver (~> 4.0)
|
||||||
|
webrick (1.7.0)
|
||||||
xpath (3.2.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
zeitwerk (2.5.1)
|
zeitwerk (2.5.1)
|
||||||
|
@ -250,9 +327,10 @@ DEPENDENCIES
|
||||||
chemlab-library-www-gitlab-com (~> 0.1)
|
chemlab-library-www-gitlab-com (~> 0.1)
|
||||||
deprecation_toolkit (~> 1.5.1)
|
deprecation_toolkit (~> 1.5.1)
|
||||||
faker (~> 2.19, >= 2.19.0)
|
faker (~> 2.19, >= 2.19.0)
|
||||||
|
fog-google (~> 1.17)
|
||||||
gitlab-qa
|
gitlab-qa
|
||||||
influxdb-client (~> 1.17)
|
influxdb-client (~> 1.17)
|
||||||
knapsack (~> 1.17)
|
knapsack (~> 4.0)
|
||||||
octokit (~> 4.21)
|
octokit (~> 4.21)
|
||||||
parallel (~> 1.19)
|
parallel (~> 1.19)
|
||||||
parallel_tests (~> 2.29)
|
parallel_tests (~> 2.29)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
# rubocop:disable Rails/RakeEnvironment
|
# rubocop:disable Rails/RakeEnvironment
|
||||||
|
|
||||||
load 'tasks/webdrivers.rake'
|
Dir['tasks/*.rake'].each { |file| load file }
|
||||||
load 'tasks/reliable_report.rake'
|
|
||||||
|
|
||||||
require_relative 'qa/tools/revoke_all_personal_access_tokens'
|
require_relative 'qa/tools/revoke_all_personal_access_tokens'
|
||||||
require_relative 'qa/tools/delete_subgroups'
|
require_relative 'qa/tools/delete_subgroups'
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
**
|
||||||
|
|
||||||
|
!.gitignore
|
|
@ -0,0 +1,88 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "fog/google"
|
||||||
|
|
||||||
|
module QA
|
||||||
|
module Tools
|
||||||
|
class KnapsackReport
|
||||||
|
PROJECT = "gitlab-qa-resources"
|
||||||
|
BUCKET = "knapsack-reports"
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def download
|
||||||
|
new.download_report
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload(glob)
|
||||||
|
new.upload_report(glob)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
ENV["KNAPSACK_REPORT_PATH"] || raise("KNAPSACK_REPORT_PATH env var is required!")
|
||||||
|
ENV["QA_KNAPSACK_REPORT_GCS_CREDENTIALS"] || raise("QA_KNAPSACK_REPORT_GCS_CREDENTIALS env var is required!")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Download knapsack report from gcs bucket
|
||||||
|
#
|
||||||
|
# @return [void]
|
||||||
|
def download_report
|
||||||
|
logger.info("Downloading latest knapsack report '#{report_file}'")
|
||||||
|
file = client.get_object(BUCKET, report_file)
|
||||||
|
|
||||||
|
logger.info("Saving latest knapsack report to '#{report_path}'")
|
||||||
|
File.write(report_path, file[:body])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Merge and upload knapsack report to gcs bucket
|
||||||
|
#
|
||||||
|
# @param [String] glob
|
||||||
|
# @return [void]
|
||||||
|
def upload_report(glob)
|
||||||
|
reports = Dir[glob]
|
||||||
|
return logger.error("Pattern '#{glob}' did not match any files!") if reports.empty?
|
||||||
|
|
||||||
|
report = reports
|
||||||
|
.map { |path| JSON.parse(File.read(path)) }
|
||||||
|
.reduce({}, :merge)
|
||||||
|
return logger.error("Knapsack generated empty report, skipping upload!") if report.empty?
|
||||||
|
|
||||||
|
logger.info("Uploading latest knapsack report '#{report_file}'")
|
||||||
|
client.put_object(BUCKET, report_file, JSON.pretty_generate(report))
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Logger instance
|
||||||
|
#
|
||||||
|
# @return [Logger]
|
||||||
|
def logger
|
||||||
|
@logger ||= Logger.new($stdout)
|
||||||
|
end
|
||||||
|
|
||||||
|
# GCS client
|
||||||
|
#
|
||||||
|
# @return [Fog::Storage::GoogleJSON]
|
||||||
|
def client
|
||||||
|
@client ||= Fog::Storage::Google.new(
|
||||||
|
google_project: PROJECT,
|
||||||
|
google_json_key_location: ENV["QA_KNAPSACK_REPORT_GCS_CREDENTIALS"]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Knapsack report path
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def report_path
|
||||||
|
@report_path ||= ENV["KNAPSACK_REPORT_PATH"]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Knapsack report name
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def report_file
|
||||||
|
@report_name ||= report_path.split("/").last
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,17 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
# rubocop:disable Rails/RakeEnvironment
|
||||||
|
|
||||||
|
require_relative "../qa/tools/knapsack_report"
|
||||||
|
|
||||||
|
namespace :knapsack do
|
||||||
|
desc "Download latest knapsack report"
|
||||||
|
task :download do
|
||||||
|
QA::Tools::KnapsackReport.download
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Merge and upload knapsack report"
|
||||||
|
task :upload, [:glob_pattern] do |_task, args|
|
||||||
|
QA::Tools::KnapsackReport.upload(args[:glob_pattern])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# rubocop:enable Rails/RakeEnvironment
|
|
@ -82,7 +82,7 @@ RSpec.describe 'Container Registry', :js do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows the image tags' do
|
it 'shows the image tags' do
|
||||||
expect(page).to have_content 'Image tags'
|
expect(page).to have_content '1 tag'
|
||||||
first_tag = first('[data-testid="name"]')
|
first_tag = first('[data-testid="name"]')
|
||||||
expect(first_tag).to have_content 'latest'
|
expect(first_tag).to have_content 'latest'
|
||||||
end
|
end
|
||||||
|
|
|
@ -87,7 +87,7 @@ RSpec.describe 'Container Registry', :js do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows the image tags' do
|
it 'shows the image tags' do
|
||||||
expect(page).to have_content 'Image tags'
|
expect(page).to have_content '20 tags'
|
||||||
first_tag = first('[data-testid="name"]')
|
first_tag = first('[data-testid="name"]')
|
||||||
expect(first_tag).to have_content '1'
|
expect(first_tag).to have_content '1'
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
import { GlButton, GlKeysetPagination } from '@gitlab/ui';
|
|
||||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||||
import { nextTick } from 'vue';
|
import { nextTick } from 'vue';
|
||||||
import VueApollo from 'vue-apollo';
|
import VueApollo from 'vue-apollo';
|
||||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||||
import waitForPromises from 'helpers/wait_for_promises';
|
import waitForPromises from 'helpers/wait_for_promises';
|
||||||
|
import { stripTypenames } from 'helpers/graphql_helpers';
|
||||||
import EmptyTagsState from '~/packages_and_registries/container_registry/explorer/components/details_page/empty_state.vue';
|
import EmptyTagsState from '~/packages_and_registries/container_registry/explorer/components/details_page/empty_state.vue';
|
||||||
import component from '~/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue';
|
import component from '~/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue';
|
||||||
import TagsListRow from '~/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue';
|
import TagsListRow from '~/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue';
|
||||||
import TagsLoader from '~/packages_and_registries/container_registry/explorer/components/details_page/tags_loader.vue';
|
import TagsLoader from '~/packages_and_registries/container_registry/explorer/components/details_page/tags_loader.vue';
|
||||||
import {
|
import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue';
|
||||||
TAGS_LIST_TITLE,
|
|
||||||
REMOVE_TAGS_BUTTON_TITLE,
|
|
||||||
} from '~/packages_and_registries/container_registry/explorer/constants/index';
|
|
||||||
import getContainerRepositoryTagsQuery from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql';
|
import getContainerRepositoryTagsQuery from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql';
|
||||||
|
import { GRAPHQL_PAGE_SIZE } from '~/packages_and_registries/container_registry/explorer/constants/index';
|
||||||
import { tagsMock, imageTagsMock, tagsPageInfo } from '../../mock_data';
|
import { tagsMock, imageTagsMock, tagsPageInfo } from '../../mock_data';
|
||||||
|
|
||||||
const localVue = createLocalVue();
|
const localVue = createLocalVue();
|
||||||
|
@ -20,25 +18,20 @@ const localVue = createLocalVue();
|
||||||
describe('Tags List', () => {
|
describe('Tags List', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
let apolloProvider;
|
let apolloProvider;
|
||||||
|
let resolver;
|
||||||
const tags = [...tagsMock];
|
const tags = [...tagsMock];
|
||||||
const readOnlyTags = tags.map((t) => ({ ...t, canDelete: false }));
|
|
||||||
|
|
||||||
const findTagsListRow = () => wrapper.findAll(TagsListRow);
|
const findTagsListRow = () => wrapper.findAllComponents(TagsListRow);
|
||||||
const findDeleteButton = () => wrapper.find(GlButton);
|
const findRegistryList = () => wrapper.findComponent(RegistryList);
|
||||||
const findListTitle = () => wrapper.find('[data-testid="list-title"]');
|
const findEmptyState = () => wrapper.findComponent(EmptyTagsState);
|
||||||
const findPagination = () => wrapper.find(GlKeysetPagination);
|
const findTagsLoader = () => wrapper.findComponent(TagsLoader);
|
||||||
const findEmptyState = () => wrapper.find(EmptyTagsState);
|
|
||||||
const findTagsLoader = () => wrapper.find(TagsLoader);
|
|
||||||
|
|
||||||
const waitForApolloRequestRender = async () => {
|
const waitForApolloRequestRender = async () => {
|
||||||
await waitForPromises();
|
await waitForPromises();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
};
|
};
|
||||||
|
|
||||||
const mountComponent = ({
|
const mountComponent = ({ propsData = { isMobile: false, id: 1 } } = {}) => {
|
||||||
propsData = { isMobile: false, id: 1 },
|
|
||||||
resolver = jest.fn().mockResolvedValue(imageTagsMock()),
|
|
||||||
} = {}) => {
|
|
||||||
localVue.use(VueApollo);
|
localVue.use(VueApollo);
|
||||||
|
|
||||||
const requestHandlers = [[getContainerRepositoryTagsQuery, resolver]];
|
const requestHandlers = [[getContainerRepositoryTagsQuery, resolver]];
|
||||||
|
@ -48,6 +41,7 @@ describe('Tags List', () => {
|
||||||
localVue,
|
localVue,
|
||||||
apolloProvider,
|
apolloProvider,
|
||||||
propsData,
|
propsData,
|
||||||
|
stubs: { RegistryList },
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
config: {},
|
config: {},
|
||||||
|
@ -56,99 +50,58 @@ describe('Tags List', () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
resolver = jest.fn().mockResolvedValue(imageTagsMock());
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.destroy();
|
wrapper.destroy();
|
||||||
wrapper = null;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('List title', () => {
|
describe('registry list', () => {
|
||||||
it('exists', async () => {
|
beforeEach(() => {
|
||||||
mountComponent();
|
mountComponent();
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
return waitForApolloRequestRender();
|
||||||
|
|
||||||
expect(findListTitle().exists()).toBe(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has the correct text', async () => {
|
it('binds the correct props', () => {
|
||||||
mountComponent();
|
expect(findRegistryList().props()).toMatchObject({
|
||||||
|
title: '2 tags',
|
||||||
await waitForApolloRequestRender();
|
pagination: stripTypenames(tagsPageInfo),
|
||||||
|
items: stripTypenames(tags),
|
||||||
expect(findListTitle().text()).toBe(TAGS_LIST_TITLE);
|
idProperty: 'name',
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('delete button', () => {
|
|
||||||
it.each`
|
|
||||||
inputTags | isMobile | isVisible
|
|
||||||
${tags} | ${false} | ${true}
|
|
||||||
${tags} | ${true} | ${false}
|
|
||||||
${readOnlyTags} | ${false} | ${false}
|
|
||||||
${readOnlyTags} | ${true} | ${false}
|
|
||||||
`(
|
|
||||||
'is $isVisible that delete button exists when tags is $inputTags and isMobile is $isMobile',
|
|
||||||
async ({ inputTags, isMobile, isVisible }) => {
|
|
||||||
mountComponent({
|
|
||||||
propsData: { tags: inputTags, isMobile, id: 1 },
|
|
||||||
resolver: jest.fn().mockResolvedValue(imageTagsMock(inputTags)),
|
|
||||||
});
|
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
|
||||||
|
|
||||||
expect(findDeleteButton().exists()).toBe(isVisible);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
it('has the correct text', async () => {
|
|
||||||
mountComponent();
|
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
|
||||||
|
|
||||||
expect(findDeleteButton().text()).toBe(REMOVE_TAGS_BUTTON_TITLE);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('has the correct props', async () => {
|
|
||||||
mountComponent();
|
|
||||||
await waitForApolloRequestRender();
|
|
||||||
|
|
||||||
expect(findDeleteButton().attributes()).toMatchObject({
|
|
||||||
category: 'secondary',
|
|
||||||
variant: 'danger',
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each`
|
describe('events', () => {
|
||||||
disabled | doSelect | buttonDisabled
|
it('prev-page fetch the previous page', () => {
|
||||||
${true} | ${false} | ${'true'}
|
findRegistryList().vm.$emit('prev-page');
|
||||||
${true} | ${true} | ${'true'}
|
|
||||||
${false} | ${false} | ${'true'}
|
|
||||||
${false} | ${true} | ${undefined}
|
|
||||||
`(
|
|
||||||
'is $buttonDisabled that the button is disabled when the component disabled state is $disabled and is $doSelect that the user selected a tag',
|
|
||||||
async ({ disabled, buttonDisabled, doSelect }) => {
|
|
||||||
mountComponent({ propsData: { tags, disabled, isMobile: false, id: 1 } });
|
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
expect(resolver).toHaveBeenCalledWith({
|
||||||
|
first: null,
|
||||||
|
before: tagsPageInfo.startCursor,
|
||||||
|
last: GRAPHQL_PAGE_SIZE,
|
||||||
|
id: '1',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (doSelect) {
|
it('next-page fetch the previous page', () => {
|
||||||
findTagsListRow().at(0).vm.$emit('select');
|
findRegistryList().vm.$emit('next-page');
|
||||||
await nextTick();
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(findDeleteButton().attributes('disabled')).toBe(buttonDisabled);
|
expect(resolver).toHaveBeenCalledWith({
|
||||||
},
|
after: tagsPageInfo.endCursor,
|
||||||
);
|
first: GRAPHQL_PAGE_SIZE,
|
||||||
|
id: '1',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('click event emits a deleted event with selected items', async () => {
|
it('emits a delete event when list emits delete', () => {
|
||||||
mountComponent();
|
const eventPayload = 'foo';
|
||||||
|
findRegistryList().vm.$emit('delete', eventPayload);
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
expect(wrapper.emitted('delete')).toEqual([[eventPayload]]);
|
||||||
|
});
|
||||||
findTagsListRow().at(0).vm.$emit('select');
|
|
||||||
findDeleteButton().vm.$emit('click');
|
|
||||||
|
|
||||||
expect(wrapper.emitted('delete')[0][0][0].name).toBe(tags[0].name);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -199,10 +152,12 @@ describe('Tags List', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when the list of tags is empty', () => {
|
describe('when the list of tags is empty', () => {
|
||||||
const resolver = jest.fn().mockResolvedValue(imageTagsMock([]));
|
beforeEach(() => {
|
||||||
|
resolver = jest.fn().mockResolvedValue(imageTagsMock([]));
|
||||||
|
});
|
||||||
|
|
||||||
it('has the empty state', async () => {
|
it('has the empty state', async () => {
|
||||||
mountComponent({ resolver });
|
mountComponent();
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
await waitForApolloRequestRender();
|
||||||
|
|
||||||
|
@ -210,7 +165,7 @@ describe('Tags List', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not show the loader', async () => {
|
it('does not show the loader', async () => {
|
||||||
mountComponent({ resolver });
|
mountComponent();
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
await waitForApolloRequestRender();
|
||||||
|
|
||||||
|
@ -218,76 +173,13 @@ describe('Tags List', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not show the list', async () => {
|
it('does not show the list', async () => {
|
||||||
mountComponent({ resolver });
|
mountComponent();
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
await waitForApolloRequestRender();
|
||||||
|
|
||||||
expect(findTagsListRow().exists()).toBe(false);
|
expect(findRegistryList().exists()).toBe(false);
|
||||||
expect(findListTitle().exists()).toBe(false);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('pagination', () => {
|
|
||||||
it('exists', async () => {
|
|
||||||
mountComponent();
|
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
|
||||||
|
|
||||||
expect(findPagination().exists()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is hidden when loading', () => {
|
|
||||||
mountComponent();
|
|
||||||
|
|
||||||
expect(findPagination().exists()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is hidden when there are no more pages', async () => {
|
|
||||||
mountComponent({ resolver: jest.fn().mockResolvedValue(imageTagsMock([])) });
|
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
|
||||||
|
|
||||||
expect(findPagination().exists()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is wired to the correct pagination props', async () => {
|
|
||||||
mountComponent();
|
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
|
||||||
|
|
||||||
expect(findPagination().props()).toMatchObject({
|
|
||||||
hasNextPage: tagsPageInfo.hasNextPage,
|
|
||||||
hasPreviousPage: tagsPageInfo.hasPreviousPage,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fetch next page when user clicks next', async () => {
|
|
||||||
const resolver = jest.fn().mockResolvedValue(imageTagsMock());
|
|
||||||
mountComponent({ resolver });
|
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
|
||||||
|
|
||||||
findPagination().vm.$emit('next');
|
|
||||||
|
|
||||||
expect(resolver).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({ after: tagsPageInfo.endCursor }),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fetch previous page when user clicks prev', async () => {
|
|
||||||
const resolver = jest.fn().mockResolvedValue(imageTagsMock());
|
|
||||||
mountComponent({ resolver });
|
|
||||||
|
|
||||||
await waitForApolloRequestRender();
|
|
||||||
|
|
||||||
findPagination().vm.$emit('prev');
|
|
||||||
|
|
||||||
expect(resolver).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({ first: null, before: tagsPageInfo.startCursor }),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('loading state', () => {
|
describe('loading state', () => {
|
||||||
it.each`
|
it.each`
|
||||||
isImageLoading | queryExecuting | loadingVisible
|
isImageLoading | queryExecuting | loadingVisible
|
||||||
|
@ -306,8 +198,6 @@ describe('Tags List', () => {
|
||||||
|
|
||||||
expect(findTagsLoader().exists()).toBe(loadingVisible);
|
expect(findTagsLoader().exists()).toBe(loadingVisible);
|
||||||
expect(findTagsListRow().exists()).toBe(!loadingVisible);
|
expect(findTagsListRow().exists()).toBe(!loadingVisible);
|
||||||
expect(findListTitle().exists()).toBe(!loadingVisible);
|
|
||||||
expect(findPagination().exists()).toBe(!loadingVisible);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,43 +8,61 @@ RSpec.describe Gitlab::Metrics::Samplers::DatabaseSampler do
|
||||||
it_behaves_like 'metrics sampler', 'DATABASE_SAMPLER'
|
it_behaves_like 'metrics sampler', 'DATABASE_SAMPLER'
|
||||||
|
|
||||||
describe '#sample' do
|
describe '#sample' do
|
||||||
|
let(:active_record_labels) do
|
||||||
|
{
|
||||||
|
class: 'ActiveRecord::Base',
|
||||||
|
host: ApplicationRecord.database.config['host'],
|
||||||
|
port: ApplicationRecord.database.config['port'],
|
||||||
|
db_config_name: 'main'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:ci_application_record_labels) do
|
||||||
|
{
|
||||||
|
class: 'Ci::ApplicationRecord',
|
||||||
|
host: Ci::ApplicationRecord.database.config['host'],
|
||||||
|
port: Ci::ApplicationRecord.database.config['port'],
|
||||||
|
db_config_name: 'ci'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
described_class::METRIC_DESCRIPTIONS.each_key do |metric|
|
described_class::METRIC_DESCRIPTIONS.each_key do |metric|
|
||||||
allow(subject.metrics[metric]).to receive(:set)
|
allow(subject.metrics[metric]).to receive(:set)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
allow(Gitlab::Database).to receive(:database_base_models)
|
||||||
|
.and_return({ main: ActiveRecord::Base, ci: Ci::ApplicationRecord })
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'for ActiveRecord::Base' do
|
context 'when the database is connected', :add_ci_connection do
|
||||||
let(:labels) do
|
it 'samples connection pool statistics' do
|
||||||
{
|
expect(subject.metrics[:size]).to receive(:set).with(active_record_labels, a_value >= 1)
|
||||||
class: 'ActiveRecord::Base',
|
expect(subject.metrics[:connections]).to receive(:set).with(active_record_labels, a_value >= 1)
|
||||||
host: ApplicationRecord.database.config['host'],
|
expect(subject.metrics[:busy]).to receive(:set).with(active_record_labels, a_value >= 1)
|
||||||
port: ApplicationRecord.database.config['port']
|
expect(subject.metrics[:dead]).to receive(:set).with(active_record_labels, a_value >= 0)
|
||||||
}
|
expect(subject.metrics[:waiting]).to receive(:set).with(active_record_labels, a_value >= 0)
|
||||||
|
|
||||||
|
expect(subject.metrics[:size]).to receive(:set).with(ci_application_record_labels, a_value >= 1)
|
||||||
|
expect(subject.metrics[:connections]).to receive(:set).with(ci_application_record_labels, a_value >= 1)
|
||||||
|
expect(subject.metrics[:busy]).to receive(:set).with(ci_application_record_labels, a_value >= 1)
|
||||||
|
expect(subject.metrics[:dead]).to receive(:set).with(ci_application_record_labels, a_value >= 0)
|
||||||
|
expect(subject.metrics[:waiting]).to receive(:set).with(ci_application_record_labels, a_value >= 0)
|
||||||
|
|
||||||
|
subject.sample
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a database is not connected', :add_ci_connection do
|
||||||
|
before do
|
||||||
|
allow(Ci::ApplicationRecord).to receive(:connected?).and_return(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the database is connected' do
|
it 'records no samples for that database' do
|
||||||
it 'samples connection pool statistics' do
|
expect(subject.metrics[:size]).to receive(:set).with(active_record_labels, anything)
|
||||||
expect(subject.metrics[:size]).to receive(:set).with(labels, a_value >= 1)
|
expect(subject.metrics[:size]).not_to receive(:set).with(ci_application_record_labels, anything)
|
||||||
expect(subject.metrics[:connections]).to receive(:set).with(labels, a_value >= 1)
|
|
||||||
expect(subject.metrics[:busy]).to receive(:set).with(labels, a_value >= 1)
|
|
||||||
expect(subject.metrics[:dead]).to receive(:set).with(labels, a_value >= 0)
|
|
||||||
expect(subject.metrics[:waiting]).to receive(:set).with(labels, a_value >= 0)
|
|
||||||
|
|
||||||
subject.sample
|
subject.sample
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the database is not connected' do
|
|
||||||
before do
|
|
||||||
allow(ActiveRecord::Base).to receive(:connected?).and_return(false)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'records no samples' do
|
|
||||||
expect(subject.metrics[:size]).not_to receive(:set).with(labels, anything)
|
|
||||||
|
|
||||||
subject.sample
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1356,12 +1356,26 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
|
||||||
describe 'synching status to Jira' do
|
describe 'synching status to Jira' do
|
||||||
let(:worker) { ::JiraConnect::SyncBuildsWorker }
|
let(:worker) { ::JiraConnect::SyncBuildsWorker }
|
||||||
|
|
||||||
%i[prepare! run! skip! drop! succeed! cancel! block! delay!].each do |event|
|
context 'when Jira Connect subscription does not exist' do
|
||||||
context "when we call pipeline.#{event}" do
|
it 'does not trigger a Jira synch worker' do
|
||||||
it 'triggers a Jira synch worker' do
|
expect(worker).not_to receive(:perform_async)
|
||||||
expect(worker).to receive(:perform_async).with(pipeline.id, Integer)
|
|
||||||
|
|
||||||
pipeline.send(event)
|
pipeline.prepare!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when Jira Connect subscription exists' do
|
||||||
|
before_all do
|
||||||
|
create(:jira_connect_subscription, namespace: project.namespace)
|
||||||
|
end
|
||||||
|
|
||||||
|
%i[prepare! run! skip! drop! succeed! cancel! block! delay!].each do |event|
|
||||||
|
context "when we call pipeline.#{event}" do
|
||||||
|
it 'triggers a Jira synch worker' do
|
||||||
|
expect(worker).to receive(:perform_async).with(pipeline.id, Integer)
|
||||||
|
|
||||||
|
pipeline.send(event)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -269,30 +269,45 @@ RSpec.describe Deployment do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'synching status to Jira' do
|
describe 'synching status to Jira' do
|
||||||
let(:deployment) { create(:deployment) }
|
let_it_be(:project) { create(:project, :repository) }
|
||||||
|
|
||||||
|
let(:deployment) { create(:deployment, project: project) }
|
||||||
let(:worker) { ::JiraConnect::SyncDeploymentsWorker }
|
let(:worker) { ::JiraConnect::SyncDeploymentsWorker }
|
||||||
|
|
||||||
it 'calls the worker on creation' do
|
context 'when Jira Connect subscription does not exist' do
|
||||||
expect(worker).to receive(:perform_async).with(Integer)
|
it 'does not call the worker' do
|
||||||
|
expect(worker).not_to receive(:perform_async)
|
||||||
|
|
||||||
deployment
|
deployment
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not call the worker for skipped deployments' do
|
context 'when Jira Connect subscription exists' do
|
||||||
expect(deployment).to be_present # warm-up, ignore the creation trigger
|
before_all do
|
||||||
|
create(:jira_connect_subscription, namespace: project.namespace)
|
||||||
|
end
|
||||||
|
|
||||||
expect(worker).not_to receive(:perform_async)
|
it 'calls the worker on creation' do
|
||||||
|
expect(worker).to receive(:perform_async).with(Integer)
|
||||||
|
|
||||||
deployment.skip!
|
deployment
|
||||||
end
|
end
|
||||||
|
|
||||||
%i[run! succeed! drop! cancel!].each do |event|
|
it 'does not call the worker for skipped deployments' do
|
||||||
context "when we call pipeline.#{event}" do
|
expect(deployment).to be_present # warm-up, ignore the creation trigger
|
||||||
it 'triggers a Jira synch worker' do
|
|
||||||
expect(worker).to receive(:perform_async).with(deployment.id)
|
|
||||||
|
|
||||||
deployment.send(event)
|
expect(worker).not_to receive(:perform_async)
|
||||||
|
|
||||||
|
deployment.skip!
|
||||||
|
end
|
||||||
|
|
||||||
|
%i[run! succeed! drop! cancel!].each do |event|
|
||||||
|
context "when we call pipeline.#{event}" do
|
||||||
|
it 'triggers a Jira synch worker' do
|
||||||
|
expect(worker).to receive(:perform_async).with(deployment.id)
|
||||||
|
|
||||||
|
deployment.send(event)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -62,10 +62,24 @@ RSpec.describe FeatureFlags::CreateService do
|
||||||
expect { subject }.to change { Operations::FeatureFlag.count }.by(1)
|
expect { subject }.to change { Operations::FeatureFlag.count }.by(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'syncs the feature flag to Jira' do
|
context 'when Jira Connect subscription does not exist' do
|
||||||
expect(::JiraConnect::SyncFeatureFlagsWorker).to receive(:perform_async).with(Integer, Integer)
|
it 'does not sync the feature flag to Jira' do
|
||||||
|
expect(::JiraConnect::SyncFeatureFlagsWorker).not_to receive(:perform_async)
|
||||||
|
|
||||||
subject
|
subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when Jira Connect subscription exists' do
|
||||||
|
before do
|
||||||
|
create(:jira_connect_subscription, namespace: project.namespace)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'syncs the feature flag to Jira' do
|
||||||
|
expect(::JiraConnect::SyncFeatureFlagsWorker).to receive(:perform_async).with(Integer, Integer)
|
||||||
|
|
||||||
|
subject
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates audit event' do
|
it 'creates audit event' do
|
||||||
|
|
|
@ -27,10 +27,24 @@ RSpec.describe FeatureFlags::UpdateService do
|
||||||
expect(subject[:status]).to eq(:success)
|
expect(subject[:status]).to eq(:success)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'syncs the feature flag to Jira' do
|
context 'when Jira Connect subscription does not exist' do
|
||||||
expect(::JiraConnect::SyncFeatureFlagsWorker).to receive(:perform_async).with(Integer, Integer)
|
it 'does not sync the feature flag to Jira' do
|
||||||
|
expect(::JiraConnect::SyncFeatureFlagsWorker).not_to receive(:perform_async)
|
||||||
|
|
||||||
subject
|
subject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when Jira Connect subscription exists' do
|
||||||
|
before do
|
||||||
|
create(:jira_connect_subscription, namespace: project.namespace)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'syncs the feature flag to Jira' do
|
||||||
|
expect(::JiraConnect::SyncFeatureFlagsWorker).to receive(:perform_async).with(Integer, Integer)
|
||||||
|
|
||||||
|
subject
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates audit event with correct message' do
|
it 'creates audit event with correct message' do
|
||||||
|
|
Loading…
Reference in New Issue