Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
71c6e099a8
commit
07d811cd3c
|
|
@ -115,12 +115,6 @@ Dangerfile @gl-quality/eng-prod
|
|||
/ee/spec/frontend/license_compliance/components/detected_licenses_table_spec.js @gitlab-org/govern/threat-insights-frontend-team
|
||||
|
||||
^[Secure]
|
||||
/ee/lib/gitlab/ci/parsers/license_compliance/ @gitlab-org/secure/composition-analysis-be
|
||||
/ee/lib/gitlab/ci/parsers/security/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/dynamic-analysis-be @gitlab-org/secure/static-analysis-be @gitlab-org/secure/fuzzing-be
|
||||
/ee/lib/gitlab/ci/reports/coverage_fuzzing/ @gitlab-org/secure/fuzzing-be
|
||||
/ee/lib/gitlab/ci/reports/dependency_list/ @gitlab-org/secure/composition-analysis-be
|
||||
/ee/lib/gitlab/ci/reports/license_scanning/ @gitlab-org/secure/composition-analysis-be
|
||||
/ee/lib/gitlab/ci/reports/security/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/dynamic-analysis-be @gitlab-org/secure/static-analysis-be @gitlab-org/secure/fuzzing-be
|
||||
/ee/app/services/app_sec/dast/ @gitlab-org/secure/dynamic-analysis-be
|
||||
|
||||
^[Security Policies]
|
||||
|
|
@ -1372,6 +1366,16 @@ lib/gitlab/checks/** @proglottis @toon
|
|||
/lib/gitlab/ci/templates/Jobs/SAST.*.yml @gitlab-org/secure/static-analysis
|
||||
/lib/gitlab/ci/templates/Jobs/Secret-Detection.*.yml @gitlab-org/secure/static-analysis
|
||||
|
||||
# Overrides for Verify. These files below require approval from teams outside Verify.
|
||||
/**/ci/reports/**/ @gitlab-org/maintainers/rails-backend
|
||||
/**/ci/parsers/**/ @gitlab-org/maintainers/rails-backend
|
||||
/ee/lib/gitlab/ci/parsers/license_compliance/ @gitlab-org/secure/composition-analysis-be
|
||||
/ee/lib/gitlab/ci/parsers/security/ @gitlab-org/govern/threat-insights-backend-team
|
||||
/ee/lib/gitlab/ci/reports/coverage_fuzzing/ @gitlab-org/secure/fuzzing-be
|
||||
/ee/lib/gitlab/ci/reports/dependency_list/ @gitlab-org/secure/composition-analysis-be
|
||||
/ee/lib/gitlab/ci/reports/license_scanning/ @gitlab-org/secure/composition-analysis-be
|
||||
/ee/lib/gitlab/ci/reports/security/ @gitlab-org/govern/threat-insights-backend-team
|
||||
|
||||
[Manage::Workspace]
|
||||
lib/api/entities/basic_project_details.rb @gitlab-org/manage/manage-workspace/backend-approvers
|
||||
lib/api/entities/project_with_access.rb @gitlab-org/manage/manage-workspace/backend-approvers
|
||||
|
|
|
|||
|
|
@ -619,6 +619,8 @@
|
|||
|
||||
.rails:rules:ee-and-foss-default-rules:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
- <<: *if-merge-request
|
||||
changes: *core-backend-patterns
|
||||
|
|
@ -631,6 +633,8 @@
|
|||
|
||||
.rails:rules:system-default-rules:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
- <<: *if-merge-request
|
||||
changes: *core-backend-patterns
|
||||
|
|
@ -645,6 +649,8 @@
|
|||
|
||||
.rails:rules:previous-failed-tests-default-rules:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-security-merge-request
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
|
|
@ -811,6 +817,8 @@
|
|||
rules:
|
||||
- <<: *if-not-canonical-namespace
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-targeting-stable-branch
|
||||
- <<: *if-merge-request-labels-run-review-app
|
||||
- <<: *if-dot-com-gitlab-org-and-security-merge-request
|
||||
|
|
@ -859,6 +867,8 @@
|
|||
rules:
|
||||
- <<: *if-not-canonical-namespace
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-targeting-stable-branch
|
||||
- <<: *if-ruby2-branch
|
||||
- <<: *if-merge-request-labels-run-review-app
|
||||
|
|
@ -954,6 +964,8 @@
|
|||
######################
|
||||
.dev-fixtures:rules:ee-and-foss:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-patterns
|
||||
|
||||
|
|
@ -961,6 +973,8 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-patterns
|
||||
|
||||
|
|
@ -1006,6 +1020,8 @@
|
|||
rules:
|
||||
# The `glfm-verify` job has dependencies on EE, so only run it for EE
|
||||
- !reference [".strict-ee-only-rules", rules]
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
# If any of the files that are DIRECTLY related to generating or managing the GLFM specification change,
|
||||
# run `glfm-verify` to get quick feedback on any needed updates, even if the MR is not yet approved
|
||||
- changes: *glfm-patterns
|
||||
|
|
@ -1032,7 +1048,6 @@
|
|||
##################
|
||||
# Frontend rules #
|
||||
##################
|
||||
|
||||
.frontend:rules:predictive-default-rules:
|
||||
rules:
|
||||
- <<: *if-merge-request-approved
|
||||
|
|
@ -1041,11 +1056,15 @@
|
|||
when: never
|
||||
- <<: *if-security-merge-request
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
|
||||
.frontend:rules:compile-production-assets:
|
||||
rules:
|
||||
- <<: *if-not-canonical-namespace
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-targeting-stable-branch
|
||||
- <<: *if-merge-request-labels-run-review-app
|
||||
- <<: *if-merge-request-labels-run-all-e2e
|
||||
|
|
@ -1064,8 +1083,6 @@
|
|||
when: never
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- !reference [.frontend:rules:compile-production-assets, rules]
|
||||
|
||||
.frontend:rules:compile-test-assets:
|
||||
|
|
@ -1092,6 +1109,8 @@
|
|||
|
||||
.frontend:rules:default-frontend-jobs:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
- <<: *if-merge-request-labels-frontend-and-feature-flag
|
||||
- <<: *if-default-refs
|
||||
|
|
@ -1100,6 +1119,8 @@
|
|||
.frontend:rules:default-frontend-jobs-as-if-foss:
|
||||
rules:
|
||||
- !reference [".strict-ee-only-rules", rules]
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-security-merge-request
|
||||
changes: *code-backstage-patterns
|
||||
- <<: *if-merge-request-labels-as-if-foss
|
||||
|
|
@ -1136,6 +1157,8 @@
|
|||
|
||||
.frontend:rules:jest:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-fork-merge-request
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-jest
|
||||
|
|
@ -1175,6 +1198,8 @@
|
|||
rules:
|
||||
- !reference [".strict-ee-only-rules", rules]
|
||||
- <<: *if-merge-request-labels-as-if-foss
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-jest
|
||||
- <<: *if-merge-request
|
||||
changes: *frontend-dependency-patterns
|
||||
|
|
@ -1205,6 +1230,8 @@
|
|||
rules:
|
||||
- !reference [".strict-ee-only-rules", rules]
|
||||
- <<: *if-merge-request-labels-as-if-foss
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *frontend-patterns-for-as-if-foss
|
||||
|
||||
|
|
@ -1223,6 +1250,8 @@
|
|||
rules:
|
||||
- <<: *if-not-canonical-namespace
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-default-branch-refs
|
||||
changes: *frontend-build-patterns
|
||||
allow_failure: true
|
||||
|
|
@ -1235,6 +1264,8 @@
|
|||
################
|
||||
.memory:rules:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-default-refs
|
||||
changes: *code-patterns
|
||||
|
||||
|
|
@ -1295,6 +1326,8 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-targeting-stable-branch
|
||||
allow_failure: true
|
||||
- <<: *if-dot-com-gitlab-org-and-security-merge-request
|
||||
|
|
@ -1431,6 +1464,8 @@
|
|||
.rails:rules:single-db:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-run-single-db
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *db-patterns
|
||||
- <<: *if-merge-request
|
||||
|
|
@ -1440,6 +1475,8 @@
|
|||
.rails:rules:db:check-migrations-single-db:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-run-single-db
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *db-patterns
|
||||
- <<: *if-merge-request
|
||||
|
|
@ -1448,6 +1485,8 @@
|
|||
.rails:rules:single-db-ci-connection:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-run-single-db
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *db-patterns
|
||||
- <<: *if-merge-request
|
||||
|
|
@ -1457,6 +1496,8 @@
|
|||
.rails:rules:db:check-migrations-single-db-ci-connection:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-run-single-db
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *db-patterns
|
||||
- <<: *if-merge-request
|
||||
|
|
@ -1464,6 +1505,8 @@
|
|||
|
||||
.rails:rules:db-backup:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
- <<: *if-default-refs
|
||||
changes: *db-backup-patterns
|
||||
|
|
@ -1490,6 +1533,8 @@
|
|||
rules:
|
||||
- <<: *if-fork-merge-request
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
- <<: *if-merge-request
|
||||
changes: *core-backend-patterns
|
||||
|
|
@ -1504,6 +1549,8 @@
|
|||
|
||||
.rails:rules:rspec-predictive:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-approved
|
||||
when: never
|
||||
- <<: *if-automated-merge-request
|
||||
|
|
@ -1523,6 +1570,8 @@
|
|||
|
||||
.rails:rules:ee-and-foss-mr-with-migration:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *db-patterns
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
|
|
@ -1579,6 +1628,8 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
- <<: *if-merge-request
|
||||
changes: *core-backend-patterns
|
||||
|
|
@ -1635,6 +1686,8 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
- <<: *if-merge-request
|
||||
changes: *core-backend-patterns
|
||||
|
|
@ -1661,6 +1714,8 @@
|
|||
when: never
|
||||
- <<: *if-fork-merge-request
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- !reference [".rails:rules:ee-and-foss-default-rules", rules]
|
||||
- <<: *if-merge-request-labels-as-if-foss
|
||||
changes: *backend-patterns
|
||||
|
|
@ -1671,6 +1726,8 @@
|
|||
when: never
|
||||
- <<: *if-fork-merge-request
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- !reference [".rails:rules:ee-and-foss-default-rules", rules]
|
||||
- <<: *if-merge-request-labels-as-if-foss
|
||||
changes: *backend-patterns
|
||||
|
|
@ -1681,12 +1738,16 @@
|
|||
when: never
|
||||
- <<: *if-fork-merge-request
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- !reference [".rails:rules:system-default-rules", rules]
|
||||
- <<: *if-merge-request-labels-as-if-foss
|
||||
changes: *code-backstage-patterns
|
||||
|
||||
.rails:rules:ee-and-foss-db-library-code:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-default-refs
|
||||
changes: *db-library-patterns
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
|
|
@ -1696,6 +1757,8 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
- <<: *if-merge-request
|
||||
changes: *code-backstage-patterns
|
||||
|
|
@ -1724,6 +1787,8 @@
|
|||
when: never
|
||||
- <<: *if-merge-request-labels-as-if-foss
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-security-merge-request
|
||||
changes: *code-backstage-patterns
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
|
|
@ -1753,6 +1818,8 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-default-branch-schedule-nightly
|
||||
- <<: *if-ruby2-branch-schedule-nightly
|
||||
- <<: *if-merge-request-labels-run-all-rspec
|
||||
|
|
@ -1791,6 +1858,8 @@
|
|||
|
||||
.rails:rules:default-branch-schedule-nightly--code-backstage-default-rules:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-default-branch-schedule-nightly
|
||||
- <<: *if-merge-request
|
||||
changes: [".gitlab/ci/rails.gitlab-ci.yml"]
|
||||
|
|
@ -1809,6 +1878,8 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-patterns
|
||||
|
||||
|
|
@ -2025,6 +2096,8 @@
|
|||
#################
|
||||
.reports:rules:code_quality:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- if: '$CODE_QUALITY_DISABLED'
|
||||
when: never
|
||||
# Run code_quality on master until https://gitlab.com/gitlab-org/gitlab/-/issues/363747 is resolved
|
||||
|
|
@ -2036,6 +2109,8 @@
|
|||
|
||||
.reports:rules:brakeman-sast:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- if: $SAST_DISABLED
|
||||
when: never
|
||||
- if: $SAST_EXCLUDED_ANALYZERS =~ /brakeman/
|
||||
|
|
@ -2047,6 +2122,8 @@
|
|||
|
||||
.reports:rules:semgrep-sast:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- if: $SAST_DISABLED
|
||||
when: never
|
||||
- if: $SAST_EXCLUDED_ANALYZERS =~ /semgrep/
|
||||
|
|
@ -2064,6 +2141,8 @@
|
|||
|
||||
.reports:rules:secret_detection:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- if: '$SECRET_DETECTION_DISABLED'
|
||||
when: never
|
||||
# Scan each commit on master to feed the Vulnerability Reports with detected secrets
|
||||
|
|
@ -2073,6 +2152,8 @@
|
|||
|
||||
.reports:rules:gemnasium-dependency_scanning:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- if: '$DEPENDENCY_SCANNING_DISABLED || $GITLAB_FEATURES !~ /\bdependency_scanning\b/ || $DS_EXCLUDED_ANALYZERS =~ /gemnasium([^-]|$)/'
|
||||
when: never
|
||||
# Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/361657 is resolved
|
||||
|
|
@ -2082,6 +2163,8 @@
|
|||
|
||||
.reports:rules:gemnasium-python-dependency_scanning:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- if: '$DEPENDENCY_SCANNING_DISABLED || $GITLAB_FEATURES !~ /\bdependency_scanning\b/ || $DS_EXCLUDED_ANALYZERS =~ /gemnasium-python/'
|
||||
when: never
|
||||
# Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/361657 is resolved
|
||||
|
|
@ -2091,6 +2174,8 @@
|
|||
|
||||
.reports:rules:yarn-audit-dependency_scanning:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- if: '$DEPENDENCY_SCANNING_DISABLED || $GITLAB_FEATURES !~ /\bdependency_scanning\b/'
|
||||
when: never
|
||||
# Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/361657 is resolved
|
||||
|
|
@ -2100,6 +2185,8 @@
|
|||
|
||||
.reports:rules:test-dast:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- if: '$DAST_DISABLED || $GITLAB_FEATURES !~ /\bdast\b/'
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
|
|
@ -2281,6 +2368,8 @@
|
|||
|
||||
.setup:rules:gitlab_git_test:
|
||||
rules:
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-patterns
|
||||
|
||||
|
|
@ -2311,6 +2400,8 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-labels-pipeline-expedite
|
||||
when: never
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-patterns
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,18 @@
|
|||
<!-- AI Project Proposal title format: 🤖 [AI Proposal] {`Need/outcome` } + {`Beneficiary`} + {`Job/Small Job`}
|
||||
<!--
|
||||
HOW TO USE THIS TEMPLATE
|
||||
To propose an AI experiment, focus on completing the “Experiment” section first. As you refine the idea and gather feedback on your experiment, use the “Feature release” section to define how it will evolve as a Beta or GA capability. It's important that we link experiment to feature release. Feel free to add sections, but keep the existing ones.
|
||||
|
||||
The title should be something that is easily understood that quickly communicates the intent of the project allowing team members to easily understand and recognize the expected work that will be done.
|
||||
You can choose how to get started with this template. For example, the proposal can start as an issue, and then be promoted to an epic to house all the work related to the experiment/prototype and feature release. If you prefer to start with an epic, you have to manually apply the proposal template. Regardless, if the experiment is eventually prioritized for development, the template content will need to appear in a top-level epic so it can be tracked alongside other prioritized AI experiments.
|
||||
|
||||
A proposal title should combine the beneficiary of the feature/UI, the job it will allow them to accomplish, and their expected outcome when the work is delivered. Well-defined statements are concise without sacrificing the substance of the proposal so that anyone can understand it at a glance. (e.g.🤖 {Reduce the effort} + {for security teams} + {when prioritizing business-critical risks in their assets}) -->
|
||||
TITLE FORMAT
|
||||
🤖 [AI Proposal] {Need/outcome} {Beneficiary} {Job/Small Job}
|
||||
|
||||
The title should be something that is easily understood that quickly communicates the intent of the project allowing team members to easily understand and recognize the expected work that will be done. A proposal title should combine the beneficiary of the feature/UI, the job it will allow them to accomplish (see https://about.gitlab.com/handbook/product/ux/jobs-to-be-done/#how-to-write-a-jtbd), and their expected outcome when the work is delivered. Well-defined statements are concise without sacrificing the substance of the proposal so that anyone can understand it at a glance. (e.g. {Reduce the effort} {for security teams} {when prioritizing business-critical risks in their assets}).
|
||||
-->
|
||||
|
||||
# Experiment
|
||||
|
||||
This section should be completed prior to work on the Experiment beginning.
|
||||
|
||||
# [Experiment](https://docs.gitlab.com/ee/policy/alpha-beta-support.html#experiment)
|
||||
|
||||
|
|
@ -21,19 +31,22 @@ _What assumptions are you making about this problem and the solution?_
|
|||
_What [personas](https://about.gitlab.com/handbook/product/personas/#list-of-user-personas) have this problem, who is the intended user?_
|
||||
|
||||
## Proposal
|
||||
<!-- Use this section to explain the proposed changes, including details around usage and business drivers. -->
|
||||
<!-- Explain the proposed changes, including details around usage and business drivers. -->
|
||||
|
||||
### Success
|
||||
_How will you measure whether this experiment is a success?_
|
||||
|
||||
# [General Availability](https://docs.gitlab.com/ee/policy/alpha-beta-support.html#generally-available-ga)
|
||||
|
||||
## Main Job story
|
||||
# Feature release
|
||||
<!-- DO NOT REMOVE THIS SECTION
|
||||
Although the initial focus is on the “Experiment” section, do not remove this “Feature release” section. It's important that we link experiment to feature release. Fill this section as you progress.
|
||||
-->
|
||||
### Main Job story
|
||||
_What job to be done will this solve?_
|
||||
<!-- What is the [Main Job story](https://about.gitlab.com/handbook/product/ux/jobs-to-be-done/#how-to-write-a-jtbd) that this proposal was derived from? (e.g. When I am on triage rotation, I want to address all the business-critical risks in my assets, So I can minimize the likelihood of my organization being compromised by a security breach.) -->
|
||||
|
||||
### Proposal updates/additions
|
||||
<!-- Use this section to explain any changes or updates to the original proposal, including details around usage, business drivers, and reasonings that drove the updates/additions. -->
|
||||
## Proposal updates/additions
|
||||
<!-- Explain any changes or updates to the original proposal from the experiment, including details around usage, business drivers, and reasonings that drove the updates/additions. -->
|
||||
|
||||
### Problem validation
|
||||
_What validation exists that customers have this problem?_
|
||||
|
|
@ -59,34 +72,33 @@ _What tasks or actions should the user be capable of performing with this featur
|
|||
#### The user needs to be able to:
|
||||
- ...
|
||||
- ...
|
||||
- ...
|
||||
|
||||
## Checklist
|
||||
|
||||
### Experiment
|
||||
|
||||
<details>
|
||||
<summary> Issue information </summary>
|
||||
<details> <summary> Issue information </summary>
|
||||
|
||||
- [ ] Add information to the issue body about:
|
||||
- [ ] The user problem being solved
|
||||
- [ ] Your assumptions
|
||||
- [ ] Who it's for, list of personas impacted
|
||||
- [ ] Your proposal
|
||||
- [ ] The user problem being solved
|
||||
- [ ] Your assumptions
|
||||
- [ ] Who it's for, list of personas impacted
|
||||
- [ ] Your proposal
|
||||
- [ ] Add relevant designs to the Design Management area of the issue if available
|
||||
- [ ] Confirm that an unexpected outage of this feature will not negatively impact the application or other features
|
||||
- [ ] Add a feature flag so that this feature can be quickly disabled if/when needed
|
||||
- [ ] If this experiment introduces a new service or data store, ensure it is not processing or storing [red data](https://about.gitlab.com/handbook/security/data-classification-standard.html#data-classification-levels) without a security and if needed legal review
|
||||
- *NOTE*: We recommend using one of the already adopted models or data stores. If you need to use something else, be aware that using other models or data stores will require additional review during the feature stage for operational fitness and compliance.
|
||||
- [ ] Ensure this issue has the ~wg-ai-integration label to ensure visibility to various teams working on this
|
||||
|
||||
</details>
|
||||
|
||||
### General Availability
|
||||
|
||||
<details>
|
||||
<summary>Issue information</summary>
|
||||
### Feature release
|
||||
<details> <summary> Issue information </summary>
|
||||
|
||||
- [ ] Add information to the issue body about:
|
||||
- [ ] Your proposal
|
||||
- [ ] The Job Statement it's expected to satisfy
|
||||
- [ ] Details about the user problem and provide any research or problem validation
|
||||
- [ ] Your proposal
|
||||
- [ ] The Job Statement it's expected to satisfy
|
||||
- [ ] Details about the user problem and provide any research or problem validation
|
||||
- [ ] List the personas impacted by the proposal.
|
||||
- [ ] Add all relevant solution validation issues to the Linked items section that shows this proposal will solve the customer problem, or details explaining why it's not possible to provide that validation.
|
||||
- [ ] Add relevant designs to the Design Management area of the issue.
|
||||
|
|
@ -95,30 +107,27 @@ _What tasks or actions should the user be capable of performing with this featur
|
|||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Technical needs</summary>
|
||||
<details> <summary> Technical needs </summary>
|
||||
|
||||
- [ ] [Operational Requirements Review - Checklist - #note_1337519985](https://gitlab.com/gitlab-org/gitlab/-/issues/403859#note_1337519985)
|
||||
- [ ] Please consider the operational aspects of the feature you are creating. A list of things to think about is in: https://gitlab.com/gitlab-org/gitlab/-/issues/403859. We will be improving this process in the future: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117637#note_1353253349.
|
||||
|
||||
1. **Work estimate and skills needs to build an ML viable feature:** To build any ML feature depending on the work, there are many personas that contribute including, Data Scientist, NLP engineer, ML Engineer, MLOps Engineer, ML Infra engineers, and Fullstack engineer to integrate the ML Services with Gitlab. Post-prototype we would assess the skills needed to build a production-grade ML feature for the prototype
|
||||
2. **Data Limitation:** We would like to upfront validate if we have viable data for the feature including whether we can use the DataOps pipeline of ModelOps or create a custom one. We would want to understand the training data, test data, and feedback data to dial up the accuracy and the limitations of the data.
|
||||
3. **Model Limitation:** We would want to understand if we can use an open-source pre-trained model, tune and customize it or start a model from scratch as well. Further, we would asses based on the ModelOps model evaluation framework which would be the right model to use based on the use case.
|
||||
4. **Cost, Scalability, Reliability:** We would want to estimate the cost of hosting, serving, inference of the model, and the full end-to-end infrastructure including monitoring and observability.
|
||||
5. **Legal and Ethical Framework:** We would want to align with legal and ethical framework like any other ModelOps features to cover across the nine principles of responsible ML and any legal support needed.
|
||||
1. Work estimate and skills needs to build an ML viable feature: To build any ML feature depending on the work, there are many personas that contribute including, Data Scientist, NLP engineer, ML Engineer, MLOps Engineer, ML Infra engineers, and Fullstack engineer to integrate the ML Services with Gitlab. Post-prototype we would assess the skills needed to build a production-grade ML feature for the prototype.
|
||||
2. Data Limitation: We would like to upfront validate if we have viable data for the feature including whether we can use the DataOps pipeline of ModelOps or create a custom one. We would want to understand the training data, test data, and feedback data to dial up the accuracy and the limitations of the data.
|
||||
3. Model Limitation: We would want to understand if we can use an open-source pre-trained model, tune and customize it or start a model from scratch as well. Further, we would assess based on the ModelOps model evaluation framework which would be the right model to use based on the use case.
|
||||
4. Cost, Scalability, Reliability: We would want to estimate the cost of hosting, serving, inference of the model, and the full end-to-end infrastructure including monitoring and observability.
|
||||
5. Legal and Ethical Framework: We would want to align with legal and ethical framework like any other ModelOps features to cover across the nine principles of responsible ML and any legal support needed.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Dependency needs</summary>
|
||||
<details> <summary> Dependency needs </summary>
|
||||
|
||||
- [ ] [Operational Requirements Review - Checklist - #note_1337519985](https://gitlab.com/gitlab-org/gitlab/-/issues/403859#note_1337519985)
|
||||
- [ ] Please consider the operational aspects of the service you are creating. A list of things to think about is in: https://gitlab.com/gitlab-org/gitlab/-/issues/403859. We will be improving this process in the future: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117637#note_1353253349.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Legal needs</summary>
|
||||
<details> <summary> Legal needs </summary>
|
||||
|
||||
- [ ] TBD
|
||||
- [ ] TBD
|
||||
|
||||
</details>
|
||||
|
||||
|
|
@ -134,5 +143,3 @@ _What tasks or actions should the user be capable of performing with this featur
|
|||
/label ~wg-ai-integration
|
||||
/cc @tmccaslin @hbenson @wayne @pedroms @jmandell
|
||||
/confidential
|
||||
|
||||
[Make change to this template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/AI%20Project%20Proposal.md)
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ InternalAffairs/DeprecateCopHelper:
|
|||
|
||||
Layout/LineLength:
|
||||
AllowedPatterns: ['^RSpec\.describe\s.*\sdo']
|
||||
Exclude:
|
||||
- 'ee/spec/controllers/concerns/routable_actions_spec.rb'
|
||||
|
||||
Lint/LastKeywordArgument:
|
||||
Safe: false
|
||||
|
|
|
|||
|
|
@ -77,8 +77,13 @@ export default {
|
|||
class="issuable-milestone gl-mr-3 gl-text-truncate gl-max-w-26 gl-display-inline-block gl-vertical-align-bottom"
|
||||
data-testid="issuable-milestone"
|
||||
>
|
||||
<gl-link v-gl-tooltip :href="milestoneLink" :title="milestoneDate" class="gl-font-sm">
|
||||
<gl-icon name="clock" />
|
||||
<gl-link
|
||||
v-gl-tooltip
|
||||
:href="milestoneLink"
|
||||
:title="milestoneDate"
|
||||
class="gl-font-sm gl-text-gray-500!"
|
||||
>
|
||||
<gl-icon name="clock" :size="12" />
|
||||
{{ issue.milestone.title }}
|
||||
</gl-link>
|
||||
</span>
|
||||
|
|
@ -90,7 +95,7 @@ export default {
|
|||
:title="__('Due date')"
|
||||
data-testid="issuable-due-date"
|
||||
>
|
||||
<gl-icon name="calendar" />
|
||||
<gl-icon name="calendar" :size="12" />
|
||||
{{ dueDate }}
|
||||
</span>
|
||||
<span
|
||||
|
|
@ -100,7 +105,7 @@ export default {
|
|||
:title="__('Estimate')"
|
||||
data-testid="time-estimate"
|
||||
>
|
||||
<gl-icon name="timer" />
|
||||
<gl-icon name="timer" :size="12" />
|
||||
{{ timeEstimate }}
|
||||
</span>
|
||||
<slot></slot>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<script>
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { scrollToElement } from '~/lib/utils/common_utils';
|
||||
import { getLocationHash } from '~/lib/utils/url_utility';
|
||||
import CollapsibleLogSection from './collapsible_section.vue';
|
||||
import LogLine from './line.vue';
|
||||
|
||||
|
|
@ -25,13 +27,25 @@ export default {
|
|||
},
|
||||
updated() {
|
||||
this.$nextTick(() => {
|
||||
this.handleScrollDown();
|
||||
if (!window.location.hash) {
|
||||
this.handleScrollDown();
|
||||
}
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.handleScrollDown();
|
||||
});
|
||||
if (window.location.hash) {
|
||||
const lineNumber = getLocationHash();
|
||||
|
||||
this.unwatchJobLog = this.$watch('jobLog', async () => {
|
||||
if (this.jobLog.length) {
|
||||
await this.$nextTick();
|
||||
|
||||
const el = document.getElementById(lineNumber);
|
||||
scrollToElement(el);
|
||||
this.unwatchJobLog();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['toggleCollapsibleLine', 'scrollBottom']),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
<script>
|
||||
import { GlAlert, GlSkeletonLoader, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { GlAlert, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import { createAlert } from '~/alert';
|
||||
import { setUrlParams, updateHistory, queryToObject } from '~/lib/utils/url_utility';
|
||||
import JobsSkeletonLoader from '~/pages/admin/jobs/components/jobs_skeleton_loader.vue';
|
||||
import JobsFilteredSearch from '../filtered_search/jobs_filtered_search.vue';
|
||||
import { validateQueryString } from '../filtered_search/utils';
|
||||
import GetJobs from './graphql/queries/get_jobs.query.graphql';
|
||||
|
|
@ -22,13 +23,13 @@ export default {
|
|||
'gl-my-0 gl-p-5 gl-bg-gray-10 gl-text-gray-900 gl-border-b gl-border-gray-100',
|
||||
components: {
|
||||
GlAlert,
|
||||
GlSkeletonLoader,
|
||||
JobsFilteredSearch,
|
||||
JobsTable,
|
||||
JobsTableEmptyState,
|
||||
JobsTableTabs,
|
||||
GlIntersectionObserver,
|
||||
GlLoadingIcon,
|
||||
JobsSkeletonLoader,
|
||||
},
|
||||
inject: {
|
||||
fullPath: {
|
||||
|
|
@ -217,22 +218,7 @@ export default {
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="showSkeletonLoader" class="gl-mt-5">
|
||||
<gl-skeleton-loader :width="1248" :height="73">
|
||||
<circle cx="748.031" cy="37.7193" r="15.0307" />
|
||||
<circle cx="787.241" cy="37.7193" r="15.0307" />
|
||||
<circle cx="827.759" cy="37.7193" r="15.0307" />
|
||||
<circle cx="866.969" cy="37.7193" r="15.0307" />
|
||||
<circle cx="380" cy="37" r="18" />
|
||||
<rect x="432" y="19" width="126.587" height="15" />
|
||||
<rect x="432" y="41" width="247" height="15" />
|
||||
<rect x="158" y="19" width="86.1" height="15" />
|
||||
<rect x="158" y="41" width="168" height="15" />
|
||||
<rect x="22" y="19" width="96" height="36" />
|
||||
<rect x="924" y="30" width="96" height="15" />
|
||||
<rect x="1057" y="20" width="166" height="35" />
|
||||
</gl-skeleton-loader>
|
||||
</div>
|
||||
<jobs-skeleton-loader v-if="showSkeletonLoader" class="gl-mt-5" />
|
||||
|
||||
<jobs-table-empty-state v-else-if="showEmptyState" />
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ export default {
|
|||
// the job log response will not have a defined
|
||||
// html or size. We keep the old value otherwise these
|
||||
// will be set to `null`
|
||||
|
||||
state.jobLog = log.lines ? logLinesParser(log.lines) : state.jobLog;
|
||||
state.jobLog = log.lines ? logLinesParser(log.lines, [], window.location.hash) : state.jobLog;
|
||||
|
||||
state.jobLogSize = log.size || state.jobLogSize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,26 @@ export const parseLine = (line = {}, lineNumber) => ({
|
|||
* @param Object line
|
||||
* @param Number lineNumber
|
||||
*/
|
||||
export const parseHeaderLine = (line = {}, lineNumber) => ({
|
||||
isClosed: parseBoolean(line.section_options?.collapsed),
|
||||
isHeader: true,
|
||||
line: parseLine(line, lineNumber),
|
||||
lines: [],
|
||||
});
|
||||
export const parseHeaderLine = (line = {}, lineNumber, hash) => {
|
||||
// if a hash is present in the URL then we ensure
|
||||
// all sections are visible so we can scroll to the hash
|
||||
// in the DOM
|
||||
if (hash) {
|
||||
return {
|
||||
isClosed: false,
|
||||
isHeader: true,
|
||||
line: parseLine(line, lineNumber),
|
||||
lines: [],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isClosed: parseBoolean(line.section_options?.collapsed),
|
||||
isHeader: true,
|
||||
line: parseLine(line, lineNumber),
|
||||
lines: [],
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds the matching header section
|
||||
|
|
@ -104,7 +118,7 @@ export const getIncrementalLineNumber = (acc) => {
|
|||
* @param Array accumulator
|
||||
* @returns Array parsed log lines
|
||||
*/
|
||||
export const logLinesParser = (lines = [], accumulator = []) =>
|
||||
export const logLinesParser = (lines = [], accumulator = [], hash = '') =>
|
||||
lines.reduce(
|
||||
(acc, line, index) => {
|
||||
const lineNumber = accumulator.length > 0 ? getIncrementalLineNumber(acc) : index;
|
||||
|
|
@ -113,7 +127,7 @@ export const logLinesParser = (lines = [], accumulator = []) =>
|
|||
|
||||
// If the object is an header, we parse it into another structure
|
||||
if (line.section_header) {
|
||||
acc.push(parseHeaderLine(line, lineNumber));
|
||||
acc.push(parseHeaderLine(line, lineNumber, hash));
|
||||
} else if (isCollapsibleSection(acc, last, line)) {
|
||||
// if the object belongs to a nested section, we append it to the new `lines` array of the
|
||||
// previously formatted header
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
<script>
|
||||
import { GlSkeletonLoader } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlSkeletonLoader,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-skeleton-loader :width="1248" :height="73">
|
||||
<circle cx="748.031" cy="37.7193" r="15.0307" />
|
||||
<circle cx="787.241" cy="37.7193" r="15.0307" />
|
||||
<circle cx="827.759" cy="37.7193" r="15.0307" />
|
||||
<circle cx="866.969" cy="37.7193" r="15.0307" />
|
||||
<circle cx="380" cy="37" r="18" />
|
||||
<rect x="432" y="19" width="126.587" height="15" />
|
||||
<rect x="432" y="41" width="247" height="15" />
|
||||
<rect x="158" y="19" width="86.1" height="15" />
|
||||
<rect x="158" y="41" width="168" height="15" />
|
||||
<rect x="22" y="19" width="96" height="36" />
|
||||
<rect x="924" y="30" width="96" height="15" />
|
||||
<rect x="1057" y="20" width="166" height="35" />
|
||||
</gl-skeleton-loader>
|
||||
</template>
|
||||
|
|
@ -7,6 +7,7 @@ import JobsTable from '~/jobs/components/table/jobs_table.vue';
|
|||
import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
|
||||
import JobsTableEmptyState from '~/jobs/components/table/jobs_table_empty_state.vue';
|
||||
import { DEFAULT_FIELDS_ADMIN } from '../constants';
|
||||
import JobsSkeletonLoader from '../jobs_skeleton_loader.vue';
|
||||
import GetAllJobs from './graphql/queries/get_all_jobs.query.graphql';
|
||||
|
||||
export default {
|
||||
|
|
@ -14,6 +15,7 @@ export default {
|
|||
jobsFetchErrorMsg: __('There was an error fetching the jobs.'),
|
||||
},
|
||||
components: {
|
||||
JobsSkeletonLoader,
|
||||
JobsTableEmptyState,
|
||||
GlAlert,
|
||||
JobsTable,
|
||||
|
|
@ -85,6 +87,12 @@ export default {
|
|||
jobsCount() {
|
||||
return this.jobs.count;
|
||||
},
|
||||
showLoadingSpinner() {
|
||||
return this.loading && this.infiniteScrollingTriggered;
|
||||
},
|
||||
showSkeletonLoader() {
|
||||
return this.loading && !this.showLoadingSpinner;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// this watcher ensures that the count on the all tab
|
||||
|
|
@ -106,7 +114,9 @@ export default {
|
|||
|
||||
<jobs-table-tabs :all-jobs-count="count" :loading="loading" />
|
||||
|
||||
<jobs-table-empty-state v-if="showEmptyState" />
|
||||
<jobs-skeleton-loader v-if="showSkeletonLoader" class="gl-mt-5" />
|
||||
|
||||
<jobs-table-empty-state v-else-if="showEmptyState" />
|
||||
|
||||
<jobs-table
|
||||
v-else
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
<script>
|
||||
import { GlIcon, GlButton, GlTooltipDirective } from '@gitlab/ui';
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import { s__ } from '~/locale';
|
||||
import AccessorUtilities from '~/lib/utils/accessor';
|
||||
import { getTopFrequentItems, formatContextSwitcherItems } from '../utils';
|
||||
import ItemsList from './items_list.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlIcon,
|
||||
GlButton,
|
||||
ItemsList,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
|
|
@ -36,16 +29,12 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
cachedFrequentItems: [],
|
||||
isItemsListEditable: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isEmpty() {
|
||||
return !this.cachedFrequentItems.length;
|
||||
},
|
||||
allowItemsEditing() {
|
||||
return !this.isEmpty && AccessorUtilities.canUseLocalStorage();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getItemsFromLocalStorage();
|
||||
|
|
@ -63,9 +52,6 @@ export default {
|
|||
Sentry.captureException(e);
|
||||
}
|
||||
},
|
||||
toggleItemsListEditablity() {
|
||||
this.isItemsListEditable = !this.isItemsListEditable;
|
||||
},
|
||||
handleItemRemove(item) {
|
||||
try {
|
||||
// Remove item from local storage
|
||||
|
|
@ -82,9 +68,6 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
frequentItemsEditToggle: s__('Navigation|Toggle edit mode'),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -96,29 +79,11 @@ export default {
|
|||
class="gl-display-flex gl-align-items-center gl-text-transform-uppercase gl-text-secondary gl-font-weight-bold gl-font-xs gl-line-height-12 gl-letter-spacing-06em gl-my-3"
|
||||
>
|
||||
<span class="gl-flex-grow-1">{{ title }}</span>
|
||||
<gl-button
|
||||
v-if="allowItemsEditing"
|
||||
v-gl-tooltip.left
|
||||
size="small"
|
||||
category="tertiary"
|
||||
:aria-label="$options.i18n.frequentItemsEditToggle"
|
||||
:title="$options.i18n.frequentItemsEditToggle"
|
||||
:class="{ 'gl-bg-gray-100!': isItemsListEditable }"
|
||||
class="gl-p-2!"
|
||||
@click="toggleItemsListEditablity"
|
||||
>
|
||||
<gl-icon name="pencil" :class="{ 'gl-text-gray-900!': isItemsListEditable }" />
|
||||
</gl-button>
|
||||
</div>
|
||||
<div v-if="isEmpty" data-testid="empty-text" class="gl-text-gray-500 gl-font-sm gl-my-3">
|
||||
{{ pristineText }}
|
||||
</div>
|
||||
<items-list
|
||||
:aria-label="title"
|
||||
:items="cachedFrequentItems"
|
||||
:editable="isItemsListEditable"
|
||||
@remove-item="handleItemRemove"
|
||||
>
|
||||
<items-list :aria-label="title" :items="cachedFrequentItems" @remove-item="handleItemRemove">
|
||||
<template #view-all-items>
|
||||
<slot name="view-all-items"></slot>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
<script>
|
||||
import { GlBadge, GlButton, GlDisclosureDropdown, GlDisclosureDropdownGroup } from '@gitlab/ui';
|
||||
import {
|
||||
GlBadge,
|
||||
GlButton,
|
||||
GlIcon,
|
||||
GlDisclosureDropdown,
|
||||
GlDisclosureDropdownGroup,
|
||||
} from '@gitlab/ui';
|
||||
import GitlabVersionCheckBadge from '~/gitlab_version_check/components/gitlab_version_check_badge.vue';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
|
||||
|
|
@ -15,6 +21,7 @@ export default {
|
|||
components: {
|
||||
GlBadge,
|
||||
GlButton,
|
||||
GlIcon,
|
||||
GlDisclosureDropdown,
|
||||
GlDisclosureDropdownGroup,
|
||||
GitlabVersionCheckBadge,
|
||||
|
|
@ -31,6 +38,7 @@ export default {
|
|||
shortcuts: __('Keyboard shortcuts'),
|
||||
version: __('Your GitLab version'),
|
||||
whatsnew: __("What's new"),
|
||||
tanuki: __('Ask the Tanuki Bot'),
|
||||
},
|
||||
props: {
|
||||
sidebarData: {
|
||||
|
|
@ -60,6 +68,14 @@ export default {
|
|||
},
|
||||
helpLinks: {
|
||||
items: [
|
||||
this.sidebarData.show_tanuki_bot && {
|
||||
icon: 'tanuki',
|
||||
text: this.$options.i18n.tanuki,
|
||||
action: this.showTanukiBotChat,
|
||||
extraAttrs: {
|
||||
...this.trackingAttrs('tanuki_bot_help_dropdown'),
|
||||
},
|
||||
},
|
||||
{
|
||||
text: this.$options.i18n.help,
|
||||
href: helpPagePath(),
|
||||
|
|
@ -109,7 +125,7 @@ export default {
|
|||
...this.trackingAttrs('submit_feedback'),
|
||||
},
|
||||
},
|
||||
],
|
||||
].filter(Boolean),
|
||||
},
|
||||
helpActions: {
|
||||
items: [
|
||||
|
|
@ -159,6 +175,11 @@ export default {
|
|||
this.$refs.dropdown.close();
|
||||
},
|
||||
|
||||
async showTanukiBotChat() {
|
||||
// This will be implemented in the following MR: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117930
|
||||
return true;
|
||||
},
|
||||
|
||||
async showWhatsNew() {
|
||||
this.$refs.dropdown.close();
|
||||
this.showWhatsNewNotification = false;
|
||||
|
|
@ -236,7 +257,14 @@ export default {
|
|||
<gl-disclosure-dropdown-group
|
||||
:group="itemGroups.helpLinks"
|
||||
:bordered="sidebarData.show_version_check"
|
||||
/>
|
||||
>
|
||||
<template #list-item="{ item }">
|
||||
<span class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
|
||||
{{ item.text }}
|
||||
<gl-icon v-if="item.icon" :name="item.icon" class="gl-text-orange-500" />
|
||||
</span>
|
||||
</template>
|
||||
</gl-disclosure-dropdown-group>
|
||||
|
||||
<gl-disclosure-dropdown-group :group="itemGroups.helpActions" bordered>
|
||||
<template #list-item="{ item }">
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
<script>
|
||||
import { GlIcon, GlButton, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
|
||||
import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
|
||||
import NavItem from './nav_item.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlIcon,
|
||||
GlButton,
|
||||
ProjectAvatar,
|
||||
NavItem,
|
||||
|
|
@ -19,11 +18,6 @@ export default {
|
|||
required: false,
|
||||
default: () => [],
|
||||
},
|
||||
editable: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -47,18 +41,16 @@ export default {
|
|||
</template>
|
||||
<template #actions>
|
||||
<gl-button
|
||||
v-if="editable"
|
||||
v-gl-tooltip.left
|
||||
v-gl-tooltip.right.viewport
|
||||
size="small"
|
||||
category="tertiary"
|
||||
icon="dash"
|
||||
:aria-label="__('Remove')"
|
||||
:title="__('Remove')"
|
||||
class="gl-align-self-center gl-p-1! gl-absolute gl-right-4"
|
||||
data-testid="item-remove"
|
||||
@click.stop.prevent="$emit('remove-item', item)"
|
||||
>
|
||||
<gl-icon name="close" />
|
||||
</gl-button>
|
||||
/>
|
||||
</template>
|
||||
</nav-item>
|
||||
<slot name="view-all-items"></slot>
|
||||
|
|
|
|||
|
|
@ -203,6 +203,11 @@ export default {
|
|||
</gl-form-checkbox>
|
||||
<div class="issuable-main-info">
|
||||
<div data-testid="issuable-title" class="issue-title title">
|
||||
<work-item-type-icon
|
||||
v-if="showWorkItemTypeIcon"
|
||||
:work-item-type="issuable.type"
|
||||
show-tooltip-on-hover
|
||||
/>
|
||||
<gl-icon
|
||||
v-if="issuable.confidential"
|
||||
v-gl-tooltip
|
||||
|
|
@ -236,11 +241,6 @@ export default {
|
|||
</span>
|
||||
</div>
|
||||
<div class="issuable-info">
|
||||
<work-item-type-icon
|
||||
v-if="showWorkItemTypeIcon"
|
||||
:work-item-type="issuable.type"
|
||||
show-tooltip-on-hover
|
||||
/>
|
||||
<slot v-if="hasSlotContents('reference')" name="reference"></slot>
|
||||
<span v-else data-testid="issuable-reference" class="issuable-reference">
|
||||
{{ reference }}
|
||||
|
|
@ -268,7 +268,7 @@ export default {
|
|||
:data-avatar-url="author.avatarUrl"
|
||||
:href="author.webUrl"
|
||||
data-testid="issuable-author"
|
||||
class="author-link js-user-link gl-font-sm"
|
||||
class="author-link js-user-link gl-font-sm gl-text-gray-500!"
|
||||
>
|
||||
<span class="author">{{ author.name }}</span>
|
||||
</gl-link>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
- if display_whats_new?
|
||||
#whats-new-app{ data: { version_digest: whats_new_version_digest } }
|
||||
|
||||
= render_if_exists "layouts/tanuki_bot_chat"
|
||||
|
||||
- elsif defined?(nav) && nav
|
||||
= render "layouts/nav/sidebar/#{nav}"
|
||||
.content-wrapper{ class: "#{@content_wrapper_class}" }
|
||||
|
|
|
|||
|
|
@ -15,27 +15,27 @@
|
|||
= hidden_merge_request_icon(merge_request)
|
||||
= link_to merge_request.title, merge_request_path(merge_request), class: 'js-prefetch-document'
|
||||
- if merge_request.tasks?
|
||||
%span.task-status.d-none.d-sm-inline-block
|
||||
%span.task-status.d-none.d-sm-inline-block.gl-font-sm
|
||||
|
||||
= merge_request.task_status
|
||||
|
||||
.issuable-info
|
||||
%span.issuable-reference
|
||||
#{issuable_reference(merge_request)}
|
||||
%span.issuable-authored.d-none.d-sm-inline-block
|
||||
%span.issuable-authored.d-none.d-sm-inline-block.gl-text-gray-500!
|
||||
·
|
||||
#{s_('IssueList|created %{timeAgoString} by %{user}').html_safe % { timeAgoString: time_ago_with_tooltip(merge_request.created_at, placement: 'bottom'), user: link_to_member(@project, merge_request.author, avatar: false) }}
|
||||
#{s_('IssueList|created %{timeAgoString} by %{user}').html_safe % { timeAgoString: time_ago_with_tooltip(merge_request.created_at, placement: 'bottom'), user: link_to_member(@project, merge_request.author, avatar: false, extra_class: 'gl-text-gray-500!') }}
|
||||
= render_if_exists 'shared/issuable/gitlab_team_member_badge', author: merge_request.author
|
||||
- if merge_request.milestone
|
||||
%span.issuable-milestone.d-none.d-sm-inline-block.gl-text-truncate.gl-max-w-26.gl-vertical-align-bottom
|
||||
|
||||
= link_to project_merge_requests_path(merge_request.project, milestone_title: merge_request.milestone.title), data: { html: 'true', toggle: 'tooltip', title: milestone_tooltip_due_date(merge_request.milestone) } do
|
||||
= sprite_icon('clock', css_class: 'gl-vertical-align-text-bottom')
|
||||
= link_to project_merge_requests_path(merge_request.project, milestone_title: merge_request.milestone.title), class: 'gl-text-gray-500!', data: { html: 'true', toggle: 'tooltip', title: milestone_tooltip_due_date(merge_request.milestone) } do
|
||||
= sprite_icon('clock', size: 12, css_class: 'gl-vertical-align-text-bottom')
|
||||
= merge_request.milestone.title
|
||||
- if merge_request.target_project.default_branch != merge_request.target_branch
|
||||
%span.project-ref-path.has-tooltip.d-inline-block.gl-text-truncate.gl-max-w-26.gl-vertical-align-bottom{ title: _('Target branch: %{target_branch}') % {target_branch: merge_request.target_branch} }
|
||||
|
||||
= link_to project_ref_path(merge_request.project, merge_request.target_branch), class: 'ref-name' do
|
||||
= link_to project_ref_path(merge_request.project, merge_request.target_branch), class: 'ref-name gl-text-gray-500!' do
|
||||
= sprite_icon('branch', size: 12, css_class: 'fork-sprite')
|
||||
= merge_request.target_branch
|
||||
- if merge_request.labels.any?
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
- page_title s_('WorkItem|Work Items')
|
||||
- page_title "##{request.params['work_items_path']}"
|
||||
- add_to_breadcrumbs _("Issues"), project_issues_path(@project)
|
||||
- add_page_specific_style 'page_bundles/work_items'
|
||||
- @gfm_form = true
|
||||
- @noteable_type = 'WorkItem'
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ glab mr merge
|
|||
- [`glab completion`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/completion)
|
||||
- [`glab config`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/config)
|
||||
- [`glab incident`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/incident)
|
||||
- [`glab issue`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/ci)
|
||||
- [`glab issue`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/issue)
|
||||
- [`glab label`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/label)
|
||||
- [`glab mr`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/mr)
|
||||
- [`glab release`](https://gitlab.com/gitlab-org/cli/-/tree/main/docs/source/release)
|
||||
|
|
|
|||
|
|
@ -6,16 +6,15 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# GitLab for Jira Cloud app **(FREE)**
|
||||
|
||||
With the [GitLab for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud) app,
|
||||
you can integrate GitLab and Jira Cloud.
|
||||
With the [GitLab for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud) app, you can connect GitLab and Jira Cloud and use the Jira development panel.
|
||||
|
||||
If you use GitLab.com and Jira Cloud, you can install the GitLab for Jira Cloud app.
|
||||
If you do not use both of these environments, use the [Jira DVCS connector](dvcs/index.md) instead
|
||||
or [install the GitLab for Jira Cloud app manually](#install-the-gitlab-for-jira-cloud-app-manually).
|
||||
You should use the GitLab for Jira Cloud app because data is synchronized
|
||||
in real time. The Jira DVCS connector updates data only once per hour.
|
||||
- **For GitLab.com**:
|
||||
- [Install the GitLab for Jira Cloud app](#install-the-gitlab-for-jira-cloud-app).
|
||||
- **For self-managed GitLab**, do one of the following:
|
||||
- [Connect the GitLab for Jira Cloud app for self-managed instances](#connect-the-gitlab-for-jira-cloud-app-for-self-managed-instances) (GitLab 15.7 and later).
|
||||
- [Install the GitLab for Jira Cloud app manually](#install-the-gitlab-for-jira-cloud-app-manually).
|
||||
|
||||
This integration method supports [Smart Commits](dvcs/index.md#smart-commits).
|
||||
If you use Jira Server or Jira Data Center, use the [Jira DVCS connector](dvcs/index.md) instead.
|
||||
|
||||
## Install the GitLab for Jira Cloud app **(FREE SAAS)**
|
||||
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
WARNING:
|
||||
The Jira DVCS connector for Jira Cloud was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/362168) in GitLab 15.1
|
||||
and is planned for removal in 16.0. Use the [GitLab for Jira Cloud app](../connect-app.md) instead.
|
||||
The Jira DVCS connector was also deprecated for Jira 8.13 and earlier. You can only use the Jira DVCS connector with Jira Server or Jira Data Center in Jira 8.14 and later. Upgrade your Jira instance to Jira 8.14 or later, and reconfigure the Jira integration in your GitLab instance.
|
||||
|
||||
Use the Jira DVCS (distributed version control system) connector if you self-host
|
||||
your Jira instance and want to sync information between GitLab and Jira.
|
||||
If you're using the Jira DVCS connector with Jira Cloud, [migrate to the GitLab for Jira Cloud app](#migrate-to-the-gitlab-for-jira-cloud-app).
|
||||
your Jira instance with Jira Server or Jira Data Center and want to sync information between GitLab and Jira.
|
||||
If you're on Jira Cloud, [migrate to the GitLab for Jira Cloud app](#migrate-to-the-gitlab-for-jira-cloud-app).
|
||||
|
||||
When you configure the Jira DVCS connector, make sure your GitLab and Jira instances
|
||||
are accessible.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ module Gitlab
|
|||
class DatabaseEventsSnowplow < Snowplow
|
||||
extend ::Gitlab::Utils::Override
|
||||
|
||||
HOSTNAME = 'localhost:9091'
|
||||
HOSTNAME = 'db-snowplow.trx.gitlab.net'
|
||||
|
||||
override :enabled?
|
||||
# database events are only collected for SaaS instance
|
||||
|
|
@ -16,7 +16,9 @@ module Gitlab
|
|||
|
||||
override :hostname
|
||||
def hostname
|
||||
HOSTNAME
|
||||
return HOSTNAME if ::Gitlab.com?
|
||||
|
||||
'localhost:9091'
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -5874,6 +5874,9 @@ msgstr ""
|
|||
msgid "Ask someone with write access to resolve it."
|
||||
msgstr ""
|
||||
|
||||
msgid "Ask the Tanuki Bot"
|
||||
msgstr ""
|
||||
|
||||
msgid "Ask your group owner to set up a group runner."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -28888,9 +28891,6 @@ msgstr ""
|
|||
msgid "Navigation|There was an error fetching search results."
|
||||
msgstr ""
|
||||
|
||||
msgid "Navigation|Toggle edit mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Navigation|Unpin item"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -50341,9 +50341,6 @@ msgstr ""
|
|||
msgid "WorkItem|View current version"
|
||||
msgstr ""
|
||||
|
||||
msgid "WorkItem|Work Items"
|
||||
msgstr ""
|
||||
|
||||
msgid "WorkItem|Work item"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ RSpec.describe MetricsDashboard do
|
|||
|
||||
it 'includes project_blob_path only for project dashboards' do
|
||||
expect(system_dashboard['project_blob_path']).to be_nil
|
||||
expect(project_dashboard['project_blob_path']).to eq("/#{project.namespace.path}/#{project.name}/-/blob/master/.gitlab/dashboards/test.yml")
|
||||
expect(project_dashboard['project_blob_path']).to eq("/#{project.namespace.path}/#{project.path}/-/blob/master/.gitlab/dashboards/test.yml")
|
||||
end
|
||||
|
||||
it 'allows editing only for project dashboards' do
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ RSpec.describe Projects::ClustersController, feature_category: :deployment_manag
|
|||
{
|
||||
id: cluster.id,
|
||||
namespace_id: project.namespace.full_path,
|
||||
project_id: project.name
|
||||
project_id: project.path
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ RSpec.describe Projects::Environments::SampleMetricsController do
|
|||
{
|
||||
id: environment.id.to_s,
|
||||
namespace_id: project.namespace.full_path,
|
||||
project_id: project.name,
|
||||
project_id: project.path,
|
||||
identifier: 'sample_metric_query_result',
|
||||
start: '2019-12-02T23:31:45.000Z',
|
||||
end: '2019-12-03T00:01:45.000Z'
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do
|
|||
let(:params) do
|
||||
{
|
||||
namespace_id: project.namespace.full_path,
|
||||
project_id: project.name,
|
||||
project_id: project.path,
|
||||
proxy_path: 'api/v1/query_range',
|
||||
datasource_id: '1',
|
||||
query: 'rate(relevant_metric)',
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do
|
|||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:namespace) { create(:namespace) }
|
||||
|
||||
let!(:project) { create(:project, :repository, name: 'dashboard-project', namespace: namespace) }
|
||||
let_it_be(:project) { create(:project, :repository, namespace: namespace) }
|
||||
let(:repository) { project.repository }
|
||||
let(:branch) { double(name: branch_name) }
|
||||
let(:commit_message) { 'test' }
|
||||
|
|
@ -120,7 +120,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do
|
|||
end
|
||||
|
||||
context 'project without repository feature' do
|
||||
let!(:project) { create(:project, name: 'dashboard-project', namespace: namespace) }
|
||||
let_it_be(:project) { create(:project, namespace: namespace) }
|
||||
|
||||
it 'responds with :not_found status code' do
|
||||
post :create, params: params
|
||||
|
|
@ -246,7 +246,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do
|
|||
end
|
||||
|
||||
context 'project without repository feature' do
|
||||
let!(:project) { create(:project, name: 'dashboard-project', namespace: namespace) }
|
||||
let_it_be(:project) { create(:project, namespace: namespace) }
|
||||
|
||||
it 'responds with :not_found status code' do
|
||||
put :update, params: params
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
|
|||
expect(user_internal_regex['placeholder']).to eq 'Regex pattern'
|
||||
end
|
||||
|
||||
context 'Dormant users' do
|
||||
context 'Dormant users', feature_category: :user_management do
|
||||
context 'when Gitlab.com' do
|
||||
let(:dot_com?) { true }
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ RSpec.describe 'Group Packages', feature_category: :package_registry do
|
|||
end
|
||||
|
||||
context 'when there are packages' do
|
||||
let_it_be(:second_project) { create(:project, name: 'second-project', group: group) }
|
||||
let_it_be(:second_project) { create(:project, group: group) }
|
||||
let_it_be(:npm_package) { create(:npm_package, project: project, name: 'zzz', created_at: 1.day.ago, version: '1.0.0') }
|
||||
let_it_be(:maven_package) { create(:maven_package, project: second_project, name: 'aaa', created_at: 2.days.ago, version: '2.0.0') }
|
||||
let_it_be(:packages) { [npm_package, maven_package] }
|
||||
|
|
@ -50,10 +50,10 @@ RSpec.describe 'Group Packages', feature_category: :package_registry do
|
|||
it_behaves_like 'package details link'
|
||||
|
||||
it 'allows you to navigate to the project page' do
|
||||
find('[data-testid="root-link"]', text: project.name).click
|
||||
find('[data-testid="root-link"]', text: project.path).click
|
||||
|
||||
expect(page).to have_current_path(project_path(project))
|
||||
expect(page).to have_content(project.name)
|
||||
expect(page).to have_content(project.path)
|
||||
end
|
||||
|
||||
context 'sorting' do
|
||||
|
|
|
|||
|
|
@ -195,10 +195,11 @@ RSpec.describe 'File blob', :js, feature_category: :projects do
|
|||
end
|
||||
end
|
||||
|
||||
it 'successfully changes ref when the ref name matches the project name' do
|
||||
project.repository.create_branch(project.name)
|
||||
# Regression test for https://gitlab.com/gitlab-org/gitlab/-/issues/330947
|
||||
it 'successfully changes ref when the ref name matches the project path' do
|
||||
project.repository.create_branch(project.path)
|
||||
|
||||
visit_blob('files/js/application.js', ref: project.name)
|
||||
visit_blob('files/js/application.js', ref: project.path)
|
||||
switch_ref_to('master')
|
||||
|
||||
aggregate_failures do
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ RSpec.describe 'Projects > Settings > User renames a project', feature_category:
|
|||
end
|
||||
|
||||
context 'when changing project path' do
|
||||
let(:project) { create(:project, :repository, namespace: user.namespace, name: 'gitlabhq') }
|
||||
let(:project) { create(:project, :repository, namespace: user.namespace, path: 'gitlabhq') }
|
||||
|
||||
before(:context) do
|
||||
TestEnv.clean_test_path
|
||||
|
|
|
|||
|
|
@ -20,9 +20,15 @@ RSpec.describe 'Work item', :js, feature_category: :team_planning do
|
|||
visit work_items_path
|
||||
end
|
||||
|
||||
it 'shows project issues link in breadcrumbs' do
|
||||
within('[data-testid="breadcrumb-links"]') do
|
||||
expect(page).to have_link('Issues', href: project_issues_path(project))
|
||||
end
|
||||
end
|
||||
|
||||
it 'uses IID path in breadcrumbs' do
|
||||
within('[data-testid="breadcrumb-current-link"]') do
|
||||
expect(page).to have_link('Work Items', href: work_items_path)
|
||||
expect(page).to have_link("##{work_item.iid}", href: work_items_path)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { scrollToElement } from '~/lib/utils/common_utils';
|
||||
import Log from '~/jobs/components/log/log.vue';
|
||||
import LogLineHeader from '~/jobs/components/log/line_header.vue';
|
||||
import { logLinesParser } from '~/jobs/store/utils';
|
||||
import { jobLog } from './mock_data';
|
||||
|
||||
jest.mock('~/lib/utils/common_utils', () => ({
|
||||
...jest.requireActual('~/lib/utils/common_utils'),
|
||||
scrollToElement: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('Job Log', () => {
|
||||
let wrapper;
|
||||
let actions;
|
||||
|
|
@ -36,13 +43,15 @@ describe('Job Log', () => {
|
|||
actions,
|
||||
state,
|
||||
});
|
||||
|
||||
createComponent();
|
||||
});
|
||||
|
||||
const findCollapsibleLine = () => wrapper.findComponent(LogLineHeader);
|
||||
|
||||
describe('line numbers', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('renders a line number for each open line', () => {
|
||||
expect(wrapper.find('#L1').text()).toBe('1');
|
||||
expect(wrapper.find('#L2').text()).toBe('2');
|
||||
|
|
@ -55,6 +64,10 @@ describe('Job Log', () => {
|
|||
});
|
||||
|
||||
describe('collapsible sections', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('renders a clickable header section', () => {
|
||||
expect(findCollapsibleLine().attributes('role')).toBe('button');
|
||||
});
|
||||
|
|
@ -73,4 +86,49 @@ describe('Job Log', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('anchor scrolling', () => {
|
||||
afterEach(() => {
|
||||
window.location.hash = '';
|
||||
});
|
||||
|
||||
describe('when hash is not present', () => {
|
||||
it('does not scroll to line number', async () => {
|
||||
createComponent();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(wrapper.find('#L6').exists()).toBe(false);
|
||||
expect(scrollToElement).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when hash is present', () => {
|
||||
beforeEach(() => {
|
||||
window.location.hash = '#L6';
|
||||
});
|
||||
|
||||
it('scrolls to line number', async () => {
|
||||
createComponent();
|
||||
|
||||
state.jobLog = logLinesParser(jobLog, [], '#L6');
|
||||
await waitForPromises();
|
||||
|
||||
expect(scrollToElement).toHaveBeenCalledTimes(1);
|
||||
|
||||
state.jobLog = logLinesParser(jobLog, [], '#L7');
|
||||
await waitForPromises();
|
||||
|
||||
expect(scrollToElement).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('line number within collapsed section is visible', () => {
|
||||
state.jobLog = logLinesParser(jobLog, [], '#L6');
|
||||
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.find('#L6').exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,6 +22,30 @@ export const jobLog = [
|
|||
content: [{ text: 'Starting service postgres:9.6.14 ...', style: 'text-green' }],
|
||||
section: 'prepare-executor',
|
||||
},
|
||||
{
|
||||
offset: 1004,
|
||||
content: [
|
||||
{
|
||||
text: 'Restore cache',
|
||||
style: 'term-fg-l-cyan term-bold',
|
||||
},
|
||||
],
|
||||
section: 'restore-cache',
|
||||
section_header: true,
|
||||
section_options: {
|
||||
collapsed: 'true',
|
||||
},
|
||||
},
|
||||
{
|
||||
offset: 1005,
|
||||
content: [
|
||||
{
|
||||
text: 'Checking cache for ruby-gems-debian-bullseye-ruby-3.0-16...',
|
||||
style: 'term-fg-l-green term-bold',
|
||||
},
|
||||
],
|
||||
section: 'restore-cache',
|
||||
},
|
||||
];
|
||||
|
||||
export const utilsMockData = [
|
||||
|
|
|
|||
|
|
@ -1,10 +1,4 @@
|
|||
import {
|
||||
GlSkeletonLoader,
|
||||
GlAlert,
|
||||
GlEmptyState,
|
||||
GlIntersectionObserver,
|
||||
GlLoadingIcon,
|
||||
} from '@gitlab/ui';
|
||||
import { GlAlert, GlEmptyState, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { mount, shallowMount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
|
|
@ -19,6 +13,7 @@ import JobsTable from '~/jobs/components/table/jobs_table.vue';
|
|||
import JobsTableApp from '~/jobs/components/table/jobs_table_app.vue';
|
||||
import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
|
||||
import JobsFilteredSearch from '~/jobs/components/filtered_search/jobs_filtered_search.vue';
|
||||
import JobsSkeletonLoader from '~/pages/admin/jobs/components/jobs_skeleton_loader.vue';
|
||||
import * as urlUtils from '~/lib/utils/url_utility';
|
||||
import {
|
||||
mockJobsResponsePaginated,
|
||||
|
|
@ -41,7 +36,7 @@ describe('Job table app', () => {
|
|||
|
||||
const countSuccessHandler = jest.fn().mockResolvedValue(mockJobsCountResponse);
|
||||
|
||||
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
|
||||
const findSkeletonLoader = () => wrapper.findComponent(JobsSkeletonLoader);
|
||||
const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const findTable = () => wrapper.findComponent(JobsTable);
|
||||
const findTabs = () => wrapper.findComponent(JobsTableTabs);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,14 @@ describe('Jobs Store Utils', () => {
|
|||
|
||||
expect(parsedHeaderLine.isClosed).toBe(true);
|
||||
});
|
||||
|
||||
it('expands all pre-closed sections if hash is present', () => {
|
||||
const headerLine = { content: [{ text: 'foo' }], section_options: { collapsed: 'true' } };
|
||||
|
||||
const parsedHeaderLine = parseHeaderLine(headerLine, 2, '#L33');
|
||||
|
||||
expect(parsedHeaderLine.isClosed).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseLine', () => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
import { GlSkeletonLoader } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import JobsSkeletonLoader from '~/pages/admin/jobs/components/jobs_skeleton_loader.vue';
|
||||
|
||||
describe('jobs_skeleton_loader.vue', () => {
|
||||
let wrapper;
|
||||
|
||||
const findGlSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
|
||||
|
||||
const WIDTH = '1248';
|
||||
const HEIGHT = '73';
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallowMount(JobsSkeletonLoader);
|
||||
});
|
||||
|
||||
it('renders a GlSkeletonLoader', () => {
|
||||
expect(findGlSkeletonLoader().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has correct width', () => {
|
||||
expect(findGlSkeletonLoader().attributes('width')).toBe(WIDTH);
|
||||
});
|
||||
|
||||
it('has correct height', () => {
|
||||
expect(findGlSkeletonLoader().attributes('height')).toBe(HEIGHT);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlSkeletonLoader, GlLoadingIcon, GlEmptyState, GlAlert } from '@gitlab/ui';
|
||||
import { GlLoadingIcon, GlEmptyState, GlAlert } from '@gitlab/ui';
|
||||
import { mount, shallowMount } from '@vue/test-utils';
|
||||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
|
|
@ -7,6 +7,8 @@ import waitForPromises from 'helpers/wait_for_promises';
|
|||
import JobsTable from '~/jobs/components/table/jobs_table.vue';
|
||||
import getJobsQuery from '~/pages/admin/jobs/components/table/graphql/queries/get_all_jobs.query.graphql';
|
||||
import AdminJobsTableApp from '~/pages/admin/jobs/components/table/admin_jobs_table_app.vue';
|
||||
import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
|
||||
import JobsSkeletonLoader from '~/pages/admin/jobs/components/jobs_skeleton_loader.vue';
|
||||
|
||||
import {
|
||||
mockAllJobsResponsePaginated,
|
||||
|
|
@ -23,11 +25,12 @@ describe('Job table app', () => {
|
|||
const emptyHandler = jest.fn().mockResolvedValue(mockJobsResponseEmpty);
|
||||
const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
|
||||
|
||||
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
|
||||
const findSkeletonLoader = () => wrapper.findComponent(JobsSkeletonLoader);
|
||||
const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const findTable = () => wrapper.findComponent(JobsTable);
|
||||
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findTabs = () => wrapper.findComponent(JobsTableTabs);
|
||||
|
||||
const createMockApolloProvider = (handler) => {
|
||||
const requestHandlers = [[getJobsQuery, handler]];
|
||||
|
|
@ -53,6 +56,25 @@ describe('Job table app', () => {
|
|||
});
|
||||
};
|
||||
|
||||
describe('loading state', () => {
|
||||
it('should display skeleton loader when loading', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findSkeletonLoader().exists()).toBe(true);
|
||||
expect(findTable().exists()).toBe(false);
|
||||
expect(findLoadingSpinner().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('when switching tabs only the skeleton loader should show', () => {
|
||||
createComponent();
|
||||
|
||||
findTabs().vm.$emit('fetchJobsByStatus', null);
|
||||
|
||||
expect(findSkeletonLoader().exists()).toBe(true);
|
||||
expect(findLoadingSpinner().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('loaded state', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { GlModal, GlFormCheckbox } from '@gitlab/ui';
|
||||
import { nextTick } from 'vue';
|
||||
import { createWrapper } from '@vue/test-utils';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { useFakeDate } from 'helpers/fake_date';
|
||||
import { initEmojiMock, clearEmojiMock } from 'helpers/emoji';
|
||||
|
|
@ -10,13 +11,17 @@ import stubChildren from 'helpers/stub_children';
|
|||
import SetStatusModalWrapper from '~/set_status_modal/set_status_modal_wrapper.vue';
|
||||
import { AVAILABILITY_STATUS } from '~/set_status_modal/constants';
|
||||
import SetStatusForm from '~/set_status_modal/set_status_form.vue';
|
||||
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
|
||||
import { BV_HIDE_MODAL } from '~/lib/utils/constants';
|
||||
|
||||
jest.mock('~/alert');
|
||||
|
||||
describe('SetStatusModalWrapper', () => {
|
||||
let wrapper;
|
||||
const mockToastShow = jest.fn();
|
||||
|
||||
const $toast = {
|
||||
show: jest.fn(),
|
||||
show: mockToastShow,
|
||||
};
|
||||
|
||||
const defaultEmoji = 'speech_balloon';
|
||||
|
|
@ -58,18 +63,7 @@ describe('SetStatusModalWrapper', () => {
|
|||
const findClearStatusButton = () => wrapper.find('.js-clear-user-status-button');
|
||||
const findAvailabilityCheckbox = () => wrapper.findComponent(GlFormCheckbox);
|
||||
const getEmojiPicker = () => wrapper.findComponent(EmojiPickerStub);
|
||||
|
||||
const initModal = async ({ mockOnUpdateSuccess = true, mockOnUpdateFailure = true } = {}) => {
|
||||
const modal = findModal();
|
||||
// mock internal emoji methods
|
||||
wrapper.vm.showEmojiMenu = jest.fn();
|
||||
wrapper.vm.hideEmojiMenu = jest.fn();
|
||||
if (mockOnUpdateSuccess) wrapper.vm.onUpdateSuccess = jest.fn();
|
||||
if (mockOnUpdateFailure) wrapper.vm.onUpdateFail = jest.fn();
|
||||
|
||||
modal.vm.$emit('shown');
|
||||
await nextTick();
|
||||
};
|
||||
const initModal = () => findModal().vm.$emit('shown');
|
||||
|
||||
afterEach(() => {
|
||||
clearEmojiMock();
|
||||
|
|
@ -148,6 +142,8 @@ describe('SetStatusModalWrapper', () => {
|
|||
|
||||
describe('update status', () => {
|
||||
describe('succeeds', () => {
|
||||
useMockLocationHelper();
|
||||
|
||||
beforeEach(async () => {
|
||||
await initEmojiMock();
|
||||
wrapper = createComponent();
|
||||
|
|
@ -194,11 +190,21 @@ describe('SetStatusModalWrapper', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('calls the "onUpdateSuccess" handler', async () => {
|
||||
it('displays a toast message and reloads window', async () => {
|
||||
findModal().vm.$emit('primary');
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.vm.onUpdateSuccess).toHaveBeenCalled();
|
||||
expect(mockToastShow).toHaveBeenCalledWith('Status updated');
|
||||
expect(window.location.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('closes modal', async () => {
|
||||
const rootWrapper = createWrapper(wrapper.vm.$root);
|
||||
|
||||
findModal().vm.$emit('primary');
|
||||
await nextTick();
|
||||
|
||||
expect(rootWrapper.emitted(BV_HIDE_MODAL)).toEqual([['set-user-status-modal']]);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -227,11 +233,22 @@ describe('SetStatusModalWrapper', () => {
|
|||
jest.spyOn(UserApi, 'updateUserStatus').mockRejectedValue();
|
||||
});
|
||||
|
||||
it('calls the "onUpdateFail" handler', async () => {
|
||||
it('displays an error alert', async () => {
|
||||
findModal().vm.$emit('primary');
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.vm.onUpdateFail).toHaveBeenCalled();
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: "Sorry, we weren't able to set your status. Please try again later.",
|
||||
});
|
||||
});
|
||||
|
||||
it('closes modal', async () => {
|
||||
const rootWrapper = createWrapper(wrapper.vm.$root);
|
||||
|
||||
findModal().vm.$emit('primary');
|
||||
await nextTick();
|
||||
|
||||
expect(rootWrapper.emitted(BV_HIDE_MODAL)).toEqual([['set-user-status-modal']]);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { GlIcon, GlButton } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { s__ } from '~/locale';
|
||||
import FrequentItemsList from '~/super_sidebar/components//frequent_items_list.vue';
|
||||
|
|
@ -17,7 +16,6 @@ describe('FrequentItemsList component', () => {
|
|||
let wrapper;
|
||||
|
||||
const findListTitle = () => wrapper.findByTestId('list-title');
|
||||
const findListEditButton = () => findListTitle().findComponent(GlButton);
|
||||
const findItemsList = () => wrapper.findComponent(ItemsList);
|
||||
const findEmptyText = () => wrapper.findByTestId('empty-text');
|
||||
|
||||
|
|
@ -68,30 +66,8 @@ describe('FrequentItemsList component', () => {
|
|||
});
|
||||
|
||||
describe('items editing', () => {
|
||||
it('renders edit button within header', () => {
|
||||
const itemsEditButton = findListEditButton();
|
||||
|
||||
expect(itemsEditButton.exists()).toBe(true);
|
||||
expect(itemsEditButton.attributes('title')).toBe('Toggle edit mode');
|
||||
expect(itemsEditButton.findComponent(GlIcon).props('name')).toBe('pencil');
|
||||
});
|
||||
|
||||
it('clicking edit button makes items list editable', async () => {
|
||||
// Off by default
|
||||
expect(findItemsList().props('editable')).toBe(false);
|
||||
|
||||
// On when clicked
|
||||
await findListEditButton().vm.$emit('click');
|
||||
expect(findItemsList().props('editable')).toBe(true);
|
||||
|
||||
// Off when clicked again
|
||||
await findListEditButton().vm.$emit('click');
|
||||
expect(findItemsList().props('editable')).toBe(false);
|
||||
});
|
||||
|
||||
it('remove-item event emission from items-list causes list item to be removed', async () => {
|
||||
const localStorageProjects = findItemsList().props('items');
|
||||
await findListEditButton().vm.$emit('click');
|
||||
|
||||
await findItemsList().vm.$emit('remove-item', localStorageProjects[0]);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,45 +42,47 @@ describe('HelpCenter component', () => {
|
|||
};
|
||||
};
|
||||
|
||||
const DEFAULT_HELP_ITEMS = [
|
||||
{ text: HelpCenter.i18n.help, href: helpPagePath(), extraAttrs: trackingAttrs('help') },
|
||||
{
|
||||
text: HelpCenter.i18n.support,
|
||||
href: sidebarData.support_path,
|
||||
extraAttrs: trackingAttrs('support'),
|
||||
},
|
||||
{
|
||||
text: HelpCenter.i18n.docs,
|
||||
href: 'https://docs.gitlab.com',
|
||||
extraAttrs: trackingAttrs('gitlab_documentation'),
|
||||
},
|
||||
{
|
||||
text: HelpCenter.i18n.plans,
|
||||
href: `${PROMO_URL}/pricing`,
|
||||
extraAttrs: trackingAttrs('compare_gitlab_plans'),
|
||||
},
|
||||
{
|
||||
text: HelpCenter.i18n.forum,
|
||||
href: 'https://forum.gitlab.com/',
|
||||
extraAttrs: trackingAttrs('community_forum'),
|
||||
},
|
||||
{
|
||||
text: HelpCenter.i18n.contribute,
|
||||
href: helpPagePath('', { anchor: 'contributing-to-gitlab' }),
|
||||
extraAttrs: trackingAttrs('contribute_to_gitlab'),
|
||||
},
|
||||
{
|
||||
text: HelpCenter.i18n.feedback,
|
||||
href: 'https://about.gitlab.com/submit-feedback',
|
||||
extraAttrs: trackingAttrs('submit_feedback'),
|
||||
},
|
||||
];
|
||||
|
||||
describe('default', () => {
|
||||
beforeEach(() => {
|
||||
createWrapper(sidebarData);
|
||||
});
|
||||
|
||||
it('renders menu items', () => {
|
||||
expect(findDropdownGroup(0).props('group').items).toEqual([
|
||||
{ text: HelpCenter.i18n.help, href: helpPagePath(), extraAttrs: trackingAttrs('help') },
|
||||
{
|
||||
text: HelpCenter.i18n.support,
|
||||
href: sidebarData.support_path,
|
||||
extraAttrs: trackingAttrs('support'),
|
||||
},
|
||||
{
|
||||
text: HelpCenter.i18n.docs,
|
||||
href: 'https://docs.gitlab.com',
|
||||
extraAttrs: trackingAttrs('gitlab_documentation'),
|
||||
},
|
||||
{
|
||||
text: HelpCenter.i18n.plans,
|
||||
href: `${PROMO_URL}/pricing`,
|
||||
extraAttrs: trackingAttrs('compare_gitlab_plans'),
|
||||
},
|
||||
{
|
||||
text: HelpCenter.i18n.forum,
|
||||
href: 'https://forum.gitlab.com/',
|
||||
extraAttrs: trackingAttrs('community_forum'),
|
||||
},
|
||||
{
|
||||
text: HelpCenter.i18n.contribute,
|
||||
href: helpPagePath('', { anchor: 'contributing-to-gitlab' }),
|
||||
extraAttrs: trackingAttrs('contribute_to_gitlab'),
|
||||
},
|
||||
{
|
||||
text: HelpCenter.i18n.feedback,
|
||||
href: 'https://about.gitlab.com/submit-feedback',
|
||||
extraAttrs: trackingAttrs('submit_feedback'),
|
||||
},
|
||||
]);
|
||||
expect(findDropdownGroup(0).props('group').items).toEqual(DEFAULT_HELP_ITEMS);
|
||||
|
||||
expect(findDropdownGroup(1).props('group').items).toEqual([
|
||||
expect.objectContaining({ text: HelpCenter.i18n.shortcuts }),
|
||||
|
|
@ -94,6 +96,23 @@ describe('HelpCenter component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('with show_tanuki_bot true', () => {
|
||||
beforeEach(() => {
|
||||
createWrapper({ ...sidebarData, show_tanuki_bot: true });
|
||||
});
|
||||
|
||||
it('shows Ask the Tanuki Bot with the help items', () => {
|
||||
expect(findDropdownGroup(0).props('group').items).toEqual([
|
||||
expect.objectContaining({
|
||||
icon: 'tanuki',
|
||||
text: HelpCenter.i18n.tanuki,
|
||||
extraAttrs: trackingAttrs('tanuki_bot_help_dropdown'),
|
||||
}),
|
||||
...DEFAULT_HELP_ITEMS,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with Gitlab version check feature enabled', () => {
|
||||
beforeEach(() => {
|
||||
createWrapper({ ...sidebarData, show_version_check: true });
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ describe('ItemsList component', () => {
|
|||
createWrapper({
|
||||
props: {
|
||||
items: [mockProject],
|
||||
editable: true,
|
||||
},
|
||||
mountFn: mountExtended,
|
||||
});
|
||||
|
|
@ -84,7 +83,7 @@ describe('ItemsList component', () => {
|
|||
|
||||
expect(itemRemoveButton.exists()).toBe(true);
|
||||
expect(itemRemoveButton.attributes('title')).toBe('Remove');
|
||||
expect(itemRemoveButton.findComponent(GlIcon).props('name')).toBe('close');
|
||||
expect(itemRemoveButton.findComponent(GlIcon).props('name')).toBe('dash');
|
||||
});
|
||||
|
||||
it('emits `remove-item` event with item param when remove button is clicked', () => {
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ RSpec.describe Banzai::Pipeline::IncidentManagement::TimelineEventPipeline do
|
|||
it 'replaces existing label to a link' do
|
||||
# rubocop:disable Layout/LineLength
|
||||
is_expected.to match(
|
||||
%r(<p>.+<a href="[\w/]+-/issues\?label_name=#{label.name}".+style="background-color: #\d{6}".*>#{label.name}</span></a></span> ~unknown</p>)
|
||||
%r{<p>.+<a href="[\w\-/]+-/issues\?label_name=#{label.name}".+style="background-color: #\d{6}".*>#{label.name}</span></a></span> ~unknown</p>}
|
||||
)
|
||||
# rubocop:enable Layout/LineLength
|
||||
end
|
||||
|
|
@ -95,7 +95,7 @@ RSpec.describe Banzai::Pipeline::IncidentManagement::TimelineEventPipeline do
|
|||
let(:markdown) { "issue ##{issue.iid}" }
|
||||
|
||||
it 'contains a link to the issue' do
|
||||
is_expected.to match(%r(<p>issue <a href="[\w/]+-/issues/#{issue.iid}".*>##{issue.iid}</a></p>))
|
||||
is_expected.to match(%r{<p>issue <a href="[\w\-/]+-/issues/#{issue.iid}".*>##{issue.iid}</a></p>})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ RSpec.describe Banzai::Pipeline::IncidentManagement::TimelineEventPipeline do
|
|||
let(:markdown) { "MR !#{mr.iid}" }
|
||||
|
||||
it 'contains a link to the merge request' do
|
||||
is_expected.to match(%r(<p>MR <a href="[\w/]+-/merge_requests/#{mr.iid}".*>!#{mr.iid}</a></p>))
|
||||
is_expected.to match(%r{<p>MR <a href="[\w\-/]+-/merge_requests/#{mr.iid}".*>!#{mr.iid}</a></p>})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Banzai::Pipeline::WikiPipeline, feature_category: :wiki do
|
||||
let_it_be(:namespace) { create(:namespace, name: "wiki_link_ns") }
|
||||
let_it_be(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) }
|
||||
let_it_be(:namespace) { create(:namespace) }
|
||||
let_it_be(:project) { create(:project, :public, namespace: namespace) }
|
||||
let_it_be(:wiki) { ProjectWiki.new(project, nil) }
|
||||
let_it_be(:page) { build(:wiki_page, wiki: wiki, title: 'nested/twice/start-page') }
|
||||
|
||||
|
|
@ -85,14 +85,14 @@ RSpec.describe Banzai::Pipeline::WikiPipeline, feature_category: :wiki do
|
|||
markdown = "[Page](./page)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/page\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/twice/page\"")
|
||||
end
|
||||
|
||||
it "rewrites file links to be at the scope of the current directory" do
|
||||
markdown = "[Link to Page](./page.md)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/page.md\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/twice/page.md\"")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -101,14 +101,14 @@ RSpec.describe Banzai::Pipeline::WikiPipeline, feature_category: :wiki do
|
|||
markdown = "[Link to Page](../page)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/page\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/page\"")
|
||||
end
|
||||
|
||||
it "rewrites file links to be at the scope of the parent directory" do
|
||||
markdown = "[Link to Page](../page.md)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/page.md\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/page.md\"")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -117,14 +117,14 @@ RSpec.describe Banzai::Pipeline::WikiPipeline, feature_category: :wiki do
|
|||
markdown = "[Link to Page](./subdirectory/page)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/subdirectory/page\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/twice/subdirectory/page\"")
|
||||
end
|
||||
|
||||
it "rewrites file links to be at the scope of the sub-directory" do
|
||||
markdown = "[Link to Page](./subdirectory/page.md)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/subdirectory/page.md\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/twice/subdirectory/page.md\"")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -133,35 +133,35 @@ RSpec.describe Banzai::Pipeline::WikiPipeline, feature_category: :wiki do
|
|||
markdown = "[Link to Page](page)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/page\"")
|
||||
end
|
||||
|
||||
it 'rewrites non-file links (with spaces) to be at the scope of the wiki root' do
|
||||
markdown = "[Link to Page](page slug)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page%20slug\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/page%20slug\"")
|
||||
end
|
||||
|
||||
it "rewrites file links to be at the scope of the current directory" do
|
||||
markdown = "[Link to Page](page.md)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/page.md\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/twice/page.md\"")
|
||||
end
|
||||
|
||||
it 'rewrites links with anchor' do
|
||||
markdown = '[Link to Header](start-page#title)'
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/start-page#title\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/start-page#title\"")
|
||||
end
|
||||
|
||||
it 'rewrites links (with spaces) with anchor' do
|
||||
markdown = '[Link to Header](start page#title)'
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/start%20page#title\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/start%20page#title\"")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -170,14 +170,14 @@ RSpec.describe Banzai::Pipeline::WikiPipeline, feature_category: :wiki do
|
|||
markdown = "[Link to Page](/page)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/page\"")
|
||||
end
|
||||
|
||||
it 'rewrites file links to be at the scope of the wiki root' do
|
||||
markdown = "[Link to Page](/page.md)"
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page.md\"")
|
||||
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/page.md\"")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -278,28 +278,28 @@ RSpec.describe Banzai::Pipeline::WikiPipeline, feature_category: :wiki do
|
|||
markdown = ""
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include('<video src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/video_file_name.mp4"')
|
||||
expect(output).to include(%(<video src="/#{project.full_path}/-/wikis/nested/twice/video_file_name.mp4"))
|
||||
end
|
||||
|
||||
it 'rewrites and replaces video links names with white spaces to %20' do
|
||||
markdown = ""
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include('<video src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/video%20file%20name.mp4"')
|
||||
expect(output).to include(%(<video src="/#{project.full_path}/-/wikis/nested/twice/video%20file%20name.mp4"))
|
||||
end
|
||||
|
||||
it 'generates audio html structure' do
|
||||
markdown = ""
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include('<audio src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/audio_file_name.wav"')
|
||||
expect(output).to include(%(<audio src="/#{project.full_path}/-/wikis/nested/twice/audio_file_name.wav"))
|
||||
end
|
||||
|
||||
it 'rewrites and replaces audio links names with white spaces to %20' do
|
||||
markdown = ""
|
||||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
|
||||
expect(output).to include('<audio src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/audio%20file%20name.wav"')
|
||||
expect(output).to include(%(<audio src="/#{project.full_path}/-/wikis/nested/twice/audio%20file%20name.wav"))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -320,7 +320,7 @@ RSpec.describe Banzai::Pipeline::WikiPipeline, feature_category: :wiki do
|
|||
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
||||
doc = Nokogiri::HTML::DocumentFragment.parse(output)
|
||||
|
||||
full_path = "/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/#{wiki_file.path}"
|
||||
full_path = "/#{project.full_path}/-/wikis/nested/twice/#{wiki_file.path}"
|
||||
expect(doc.css('a')[0].attr('href')).to eq(full_path)
|
||||
expect(doc.css('img')[0].attr('class')).to eq('gfm lazy')
|
||||
expect(doc.css('img')[0].attr('data-src')).to eq(full_path)
|
||||
|
|
|
|||
|
|
@ -552,7 +552,7 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
|
|||
end
|
||||
|
||||
let_it_be(:group) { create(:group, path: 'build') }
|
||||
let_it_be(:project) { create(:project, name: 'cng', namespace: group) }
|
||||
let_it_be(:project) { create(:project, path: 'cng', namespace: group) }
|
||||
let_it_be(:container_repository) { create(:container_repository, project: project, name: "docker-alpine") }
|
||||
|
||||
shared_examples 'fetching the project from container repository and path' do
|
||||
|
|
|
|||
|
|
@ -260,16 +260,16 @@ RSpec.describe Gitlab::Ci::Config::External::File::Project, feature_category: :p
|
|||
}
|
||||
|
||||
context 'when project name and ref include masked variables' do
|
||||
let(:project_name) { 'my_project_name' }
|
||||
let_it_be(:project) { create(:project, :repository, path: 'my_project_path') }
|
||||
|
||||
let(:branch_name) { 'merge-commit-analyze-after' }
|
||||
let(:project) { create(:project, :repository, name: project_name) }
|
||||
let(:namespace_path) { project.namespace.full_path }
|
||||
let(:included_project_sha) { project.commit(branch_name).sha }
|
||||
|
||||
let(:variables) do
|
||||
Gitlab::Ci::Variables::Collection.new(
|
||||
[
|
||||
{ key: 'VAR1', value: project_name, masked: true },
|
||||
{ key: 'VAR1', value: 'my_project_path', masked: true },
|
||||
{ key: 'VAR2', value: branch_name, masked: true }
|
||||
])
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ require 'spec_helper'
|
|||
RSpec.describe Gitlab::Metrics::Dashboard::Stages::GrafanaFormatter do
|
||||
include GrafanaApiHelpers
|
||||
|
||||
let_it_be(:namespace) { create(:namespace, name: 'foo') }
|
||||
let_it_be(:project) { create(:project, namespace: namespace, name: 'bar') }
|
||||
let_it_be(:namespace) { create(:namespace, path: 'foo') }
|
||||
let_it_be(:project) { create(:project, namespace: namespace, path: 'bar') }
|
||||
|
||||
describe '#transform!' do
|
||||
let(:grafana_dashboard) { Gitlab::Json.parse(fixture_file('grafana/simplified_dashboard_response.json'), symbolize_names: true) }
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ RSpec.describe Gitlab::Tracking::Destinations::DatabaseEventsSnowplow, :do_not_s
|
|||
before do
|
||||
allow(SnowplowTracker::AsyncEmitter)
|
||||
.to receive(:new)
|
||||
.with(endpoint: 'localhost:9091',
|
||||
.with(endpoint: endpoint,
|
||||
options:
|
||||
{
|
||||
protocol: 'https',
|
||||
|
|
@ -47,15 +47,38 @@ RSpec.describe Gitlab::Tracking::Destinations::DatabaseEventsSnowplow, :do_not_s
|
|||
end
|
||||
|
||||
describe '#event' do
|
||||
let(:endpoint) { 'localhost:9091' }
|
||||
let(:event_params) do
|
||||
{
|
||||
category: 'category',
|
||||
action: 'action',
|
||||
label: 'label',
|
||||
property: 'property',
|
||||
value: 1.5,
|
||||
context: nil,
|
||||
tstamp: (Time.now.to_f * 1000).to_i
|
||||
}
|
||||
end
|
||||
|
||||
context 'when on gitlab.com environment' do
|
||||
let(:endpoint) { 'db-snowplow.trx.gitlab.net' }
|
||||
|
||||
it 'sends event to tracker' do
|
||||
allow(Gitlab).to receive(:com?).and_return(true)
|
||||
allow(tracker).to receive(:track_struct_event).and_call_original
|
||||
|
||||
subject.event('category', 'action', label: 'label', property: 'property', value: 1.5)
|
||||
|
||||
expect(tracker).to have_received(:track_struct_event).with(event_params)
|
||||
end
|
||||
end
|
||||
|
||||
it 'sends event to tracker' do
|
||||
allow(tracker).to receive(:track_struct_event).and_call_original
|
||||
|
||||
subject.event('category', 'action', label: 'label', property: 'property', value: 1.5)
|
||||
|
||||
expect(tracker)
|
||||
.to have_received(:track_struct_event)
|
||||
.with(category: 'category', action: 'action', label: 'label', property: 'property', value: 1.5, context: nil,
|
||||
tstamp: (Time.now.to_f * 1000).to_i)
|
||||
expect(tracker).to have_received(:track_struct_event).with(event_params)
|
||||
end
|
||||
|
||||
it 'increase total snowplow events counter' do
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ RSpec.describe ContainerRegistry::Event do
|
|||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:group) { create(:group, name: 'group') }
|
||||
let_it_be(:project) { create(:project, name: 'test', namespace: group) }
|
||||
let_it_be(:project) { create(:project, path: 'test', namespace: group) }
|
||||
|
||||
describe '#supported?' do
|
||||
let(:raw_event) { { 'action' => action } }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Releases::Source do
|
||||
let_it_be(:project) { create(:project, :repository, name: 'finance-cal') }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
||||
let(:tag_name) { 'v1.0' }
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ RSpec.describe Releases::Source do
|
|||
|
||||
it 'returns zip archived source url' do
|
||||
is_expected
|
||||
.to eq("#{project.web_url}/-/archive/v1.0/finance-cal-v1.0.zip")
|
||||
.to eq("#{project.web_url}/-/archive/v1.0/#{project.path}-v1.0.zip")
|
||||
end
|
||||
|
||||
context 'when ref is directory structure' do
|
||||
|
|
@ -35,7 +35,7 @@ RSpec.describe Releases::Source do
|
|||
|
||||
it 'converts slash to dash' do
|
||||
is_expected
|
||||
.to eq("#{project.web_url}/-/archive/beta/v1.0/finance-cal-beta-v1.0.zip")
|
||||
.to eq("#{project.web_url}/-/archive/beta/v1.0/#{project.path}-beta-v1.0.zip")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ RSpec.describe IssuePresenter do
|
|||
|
||||
describe '#web_url' do
|
||||
it 'returns correct path' do
|
||||
expect(presenter.web_url).to eq("http://localhost/#{group.name}/#{project.name}/-/issues/#{presented_issue.iid}")
|
||||
expect(presenter.web_url).to eq("http://localhost/#{project.full_path}/-/issues/#{presented_issue.iid}")
|
||||
end
|
||||
|
||||
context 'when issue type is task' do
|
||||
|
|
@ -59,7 +59,7 @@ RSpec.describe IssuePresenter do
|
|||
|
||||
describe '#issue_path' do
|
||||
it 'returns correct path' do
|
||||
expect(presenter.issue_path).to eq("/#{group.name}/#{project.name}/-/issues/#{presented_issue.iid}")
|
||||
expect(presenter.issue_path).to eq("/#{project.full_path}/-/issues/#{presented_issue.iid}")
|
||||
end
|
||||
|
||||
context 'when issue type is task' do
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ RSpec.describe Releases::LinkPresenter do
|
|||
context 'when filepath is provided' do
|
||||
let(:filepath) { '/bin/bigfile.exe' }
|
||||
let(:expected_url) do
|
||||
"http://localhost/#{release.project.namespace.path}/#{release.project.name}" \
|
||||
"http://localhost/#{release.project.full_path}" \
|
||||
"/-/releases/#{release.tag}/downloads/bin/bigfile.exe"
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -951,7 +951,7 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d
|
|||
expect(json_response.length).to eq(8)
|
||||
|
||||
project_names = json_response.map { |proj| proj['name'] }
|
||||
expect(project_names).to contain_exactly(project.name, project2.name, 'second_project', 'public_project', 'Project', 'Test Project', 'Test Public Project', 'Test')
|
||||
expect(project_names).to match_array([project, project2, project3, public_project, project_1, project_2, project_4, project_3].map(&:name))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ RSpec.describe AnalyticsIssueEntity do
|
|||
end
|
||||
|
||||
context 'without subgroup' do
|
||||
let_it_be(:project) { create(:project, name: 'my project') }
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
subject { entity.as_json }
|
||||
|
||||
|
|
@ -80,14 +80,14 @@ RSpec.describe AnalyticsIssueEntity do
|
|||
end
|
||||
|
||||
context 'with subgroup' do
|
||||
let_it_be(:project) { create(:project, :in_subgroup, name: 'my project') }
|
||||
let_it_be(:project) { create(:project, :in_subgroup) }
|
||||
|
||||
subject { entity.as_json }
|
||||
|
||||
it_behaves_like 'generic entity'
|
||||
|
||||
it 'has URL containing subgroup' do
|
||||
expect(subject[:url]).to include("#{project.group.parent.name}/#{project.group.name}/my_project/")
|
||||
expect(subject[:url]).to include("#{project.group.parent.name}/#{project.group.name}/#{project.path}/")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -55,14 +55,16 @@ RSpec.describe Clusters::Cleanup::ServiceAccountService, feature_category: :depl
|
|||
|
||||
context 'when there is a Kubeclient::HttpError' do
|
||||
['Unauthorized', 'forbidden', 'Certificate verify Failed'].each do |message|
|
||||
before do
|
||||
allow(kubeclient_instance_double)
|
||||
.to receive(:delete_service_account)
|
||||
.and_raise(Kubeclient::HttpError.new(401, message, nil))
|
||||
end
|
||||
context "with error:#{message}" do
|
||||
before do
|
||||
allow(kubeclient_instance_double)
|
||||
.to receive(:delete_service_account)
|
||||
.and_raise(Kubeclient::HttpError.new(401, message, nil))
|
||||
end
|
||||
|
||||
it 'destroys cluster' do
|
||||
expect { subject }.to change { Clusters::Cluster.where(id: cluster.id).exists? }.from(true).to(false)
|
||||
it 'destroys cluster' do
|
||||
expect { subject }.to change { Clusters::Cluster.where(id: cluster.id).exists? }.from(true).to(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ RSpec.shared_examples 'packages list' do |check_project_name: false|
|
|||
|
||||
expect(package_row).to have_content(pkg.name)
|
||||
expect(package_row).to have_content(pkg.version)
|
||||
expect(package_row).to have_content(pkg.project.name) if check_project_name
|
||||
expect(package_row).to have_content(pkg.project.path) if check_project_name
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ RSpec.describe Integrations::IrkerWorker, '#perform', feature_category: :integra
|
|||
end
|
||||
|
||||
def wrap_message(text)
|
||||
message = "[#{project.path}] #{push_data['user_name']} #{text}"
|
||||
message = "[#{project.name}] #{push_data['user_name']} #{text}"
|
||||
to_send = { to: channels, privmsg: message }
|
||||
|
||||
Gitlab::Json.dump(to_send)
|
||||
|
|
|
|||
Loading…
Reference in New Issue