New upstream version 12.4.6

This commit is contained in:
Pirate Praveen 2019-12-21 20:55:43 +05:30
parent 317968c865
commit 3a6a82fa42
5378 changed files with 256257 additions and 50675 deletions

View file

@ -6,6 +6,7 @@
# - ./config/initializers/0_inject_enterprise_edition_module.rb # - ./config/initializers/0_inject_enterprise_edition_module.rb
# - ./ee/app/models/license.rb # - ./ee/app/models/license.rb
# - ./lib/gitlab.rb # - ./lib/gitlab.rb
# - ./lib/gitlab/utils.rb
# - ./qa/ # - ./qa/
# - ./INSTALLATION_TYPE # - ./INSTALLATION_TYPE
# - ./VERSION # - ./VERSION
@ -49,7 +50,6 @@
/lib/flowdock/ /lib/flowdock/
/lib/generators/ /lib/generators/
/lib/gitaly/ /lib/gitaly/
/lib/gitlab/
/lib/api/ /lib/api/
/lib/token/ /lib/token/
/lib/mattermost/ /lib/mattermost/

View file

@ -1,5 +1,6 @@
extends: extends:
- '@gitlab' - '@gitlab'
- plugin:promise/recommended
globals: globals:
__webpack_public_path__: true __webpack_public_path__: true
gl: false gl: false
@ -10,6 +11,7 @@ plugins:
- import - import
- "@gitlab/i18n" - "@gitlab/i18n"
- "@gitlab/vue-i18n" - "@gitlab/vue-i18n"
- no-jquery
settings: settings:
import/resolver: import/resolver:
webpack: webpack:
@ -36,6 +38,13 @@ rules:
vue/no-use-v-if-with-v-for: off vue/no-use-v-if-with-v-for: off
vue/no-v-html: off vue/no-v-html: off
vue/use-v-on-exact: off vue/use-v-on-exact: off
no-jquery/no-ajax: error
no-jquery/no-ajax-events: error
no-jquery/no-load: error
no-jquery/no-load-shorthand: error
no-jquery/no-serialize: error
promise/always-return: off
promise/no-callback-in-promise: off
overrides: overrides:
files: files:
- '**/spec/**/*' - '**/spec/**/*'

1
.gitattributes vendored
View file

@ -1,3 +1,2 @@
VERSION merge=ours VERSION merge=ours
Dangerfile gitlab-language=ruby Dangerfile gitlab-language=ruby
db/schema.rb merge=merge_db_schema

View file

@ -1,3 +1,3 @@
Were closing our issue tracker on GitHub so we can focus on the GitLab.com project and respond to issues more quickly. Were closing our issue tracker on GitHub so we can focus on the GitLab.com project and respond to issues more quickly.
We encourage you to open an issue on the [GitLab.com issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues). You can log into GitLab.com using your GitHub account. We encourage you to open an issue on the [GitLab.com issue tracker](https://gitlab.com/gitlab-org/gitlab/issues). You can log into GitLab.com using your GitHub account.

View file

@ -1,3 +1,3 @@
Thank you for taking the time to contribute back to GitLab! Thank you for taking the time to contribute back to GitLab!
Please open a merge request [on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests), we look forward to reviewing your contribution! You can log into GitLab.com using your GitHub account. Please open a merge request [on GitLab.com](https://gitlab.com/gitlab-org/gitlab/merge_requests), we look forward to reviewing your contribution! You can log into GitLab.com using your GitHub account.

1
.gitignore vendored
View file

@ -81,3 +81,4 @@ package-lock.json
jsdoc/ jsdoc/
**/tmp/rubocop_cache/** **/tmp/rubocop_cache/**
.overcommit.yml .overcommit.yml
.projections.json

View file

@ -1,4 +1,4 @@
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33" image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33"
stages: stages:
- prepare - prepare
@ -8,17 +8,17 @@ stages:
- review - review
- qa - qa
- post-test - post-test
- notification
- pages - pages
variables: variables:
RAILS_ENV: "test" RAILS_ENV: "test"
NODE_ENV: "test" NODE_ENV: "test"
SIMPLECOV: "true" SIMPLECOV: "true"
GIT_DEPTH: "20" GIT_DEPTH: "50"
GIT_SUBMODULE_STRATEGY: "none" GIT_SUBMODULE_STRATEGY: "none"
GET_SOURCES_ATTEMPTS: "3" GET_SOURCES_ATTEMPTS: "3"
KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/report-master.json
EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master-ee.json
FLAKY_RSPEC_SUITE_REPORT_PATH: rspec_flaky/report-suite.json FLAKY_RSPEC_SUITE_REPORT_PATH: rspec_flaky/report-suite.json
BUILD_ASSETS_IMAGE: "false" BUILD_ASSETS_IMAGE: "false"
ES_JAVA_OPTS: "-Xms256m -Xmx256m" ES_JAVA_OPTS: "-Xms256m -Xmx256m"
@ -28,11 +28,12 @@ after_script:
- date - date
include: include:
- local: .gitlab/ci/global.gitlab-ci.yml
- local: .gitlab/ci/cng.gitlab-ci.yml - local: .gitlab/ci/cng.gitlab-ci.yml
- local: .gitlab/ci/docs.gitlab-ci.yml - local: .gitlab/ci/docs.gitlab-ci.yml
- local: .gitlab/ci/frontend.gitlab-ci.yml - local: .gitlab/ci/frontend.gitlab-ci.yml
- local: .gitlab/ci/global.gitlab-ci.yml
- local: .gitlab/ci/memory.gitlab-ci.yml - local: .gitlab/ci/memory.gitlab-ci.yml
- local: .gitlab/ci/notifications.gitlab-ci.yml
- local: .gitlab/ci/pages.gitlab-ci.yml - local: .gitlab/ci/pages.gitlab-ci.yml
- local: .gitlab/ci/qa.gitlab-ci.yml - local: .gitlab/ci/qa.gitlab-ci.yml
- local: .gitlab/ci/reports.gitlab-ci.yml - local: .gitlab/ci/reports.gitlab-ci.yml

View file

@ -6,8 +6,8 @@
/doc/ @axil @marcia @eread @mikelewis /doc/ @axil @marcia @eread @mikelewis
# Frontend maintainers should see everything in `app/assets/` # Frontend maintainers should see everything in `app/assets/`
app/assets/ @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter app/assets/ @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter @wortschi @ntepluhina
*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter *.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter @wortschi @ntepluhina
# Database maintainers should review changes in `db/` # Database maintainers should review changes in `db/`
db/ @gitlab-org/maintainers/database db/ @gitlab-org/maintainers/database
@ -23,6 +23,13 @@ lib/gitlab/github_import/ @gitlab-org/maintainers/database
/lib/gitlab/auth/ldap/ @dblessing @mkozono /lib/gitlab/auth/ldap/ @dblessing @mkozono
/lib/gitlab/ci/templates/ @nolith @zj /lib/gitlab/ci/templates/ @nolith @zj
/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah /lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah
/lib/gitlab/ci/templates/Security/ @plafoucriere @gonzoyumo @twoodham /lib/gitlab/ci/templates/Security/ @plafoucriere @gonzoyumo @twoodham @sethgitlab
/ee/app/models/project_alias.rb @patrickbajao /ee/app/models/project_alias.rb @patrickbajao
/ee/lib/api/project_aliases.rb @patrickbajao /ee/lib/api/project_aliases.rb @patrickbajao
# Engineering Productivity owned files
/.gitlab-ci.yml @gl-quality/eng-prod
/.gitlab/ci/ @gl-quality/eng-prod
Dangerfile @gl-quality/eng-prod
/danger/ @gl-quality/eng-prod
/scripts/ @gl-quality/eng-prod

View file

@ -14,10 +14,10 @@
variables: variables:
GIT_STRATEGY: none GIT_STRATEGY: none
environment: environment:
name: review-docs/$CI_COMMIT_REF_SLUG name: review-docs/$DOCS_GITLAB_REPO_SUFFIX-$CI_MERGE_REQUEST_IID
# DOCS_REVIEW_APPS_DOMAIN and DOCS_GITLAB_REPO_SUFFIX are CI variables # DOCS_REVIEW_APPS_DOMAIN and DOCS_GITLAB_REPO_SUFFIX are CI variables
# Discussion: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/14236/diffs#note_40140693 # Discussion: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/14236/diffs#note_40140693
url: http://$CI_ENVIRONMENT_SLUG.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX url: http://docs-preview-$DOCS_GITLAB_REPO_SUFFIX-$CI_MERGE_REQUEST_IID.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
on_stop: review-docs-cleanup on_stop: review-docs-cleanup
before_script: before_script:
# We don't clone the repo by using GIT_STRATEGY: none and only download the # We don't clone the repo by using GIT_STRATEGY: none and only download the
@ -39,7 +39,7 @@ review-docs-deploy:
review-docs-cleanup: review-docs-cleanup:
extends: .review-docs extends: .review-docs
environment: environment:
name: review-docs/$CI_COMMIT_REF_SLUG name: review-docs/$DOCS_GITLAB_REPO_SUFFIX-$CI_MERGE_REQUEST_IID
action: stop action: stop
script: script:
- ./trigger-build-docs cleanup - ./trigger-build-docs cleanup
@ -67,3 +67,19 @@ docs lint:
- bundle exec nanoc check internal_links - bundle exec nanoc check internal_links
# Check the internal anchor links # Check the internal anchor links
- bundle exec nanoc check internal_anchors - bundle exec nanoc check internal_anchors
graphql-docs-verify:
extends:
- .only-ee
- .default-tags
- .default-retry
- .default-cache
- .default-only
- .default-before_script
- .only-graphql-changes
variables:
SETUP_DB: "false"
stage: test
needs: ["setup-test-env"]
script:
- bundle exec rake gitlab:graphql:check_docs

View file

@ -13,7 +13,7 @@
- .default-before_script - .default-before_script
- .assets-compile-cache - .assets-compile-cache
- .only-code-qa-changes - .only-code-qa-changes
image: dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-git-2.22-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-18.06.1 image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-git-2.22-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-18.06.1
stage: test stage: test
dependencies: ["setup-test-env"] dependencies: ["setup-test-env"]
needs: ["setup-test-env"] needs: ["setup-test-env"]
@ -47,13 +47,13 @@
- rm -f /etc/apt/sources.list.d/google*.list # We don't need to update Chrome here - rm -f /etc/apt/sources.list.d/google*.list # We don't need to update Chrome here
only: only:
variables: variables:
- $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" - $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/)/ # Matches the gitlab-org group and its subgroups
- $CI_SERVER_HOST == "dev.gitlab.org" - $CI_SERVER_HOST == "dev.gitlab.org"
tags: tags:
- gitlab-org - gitlab-org
- docker - docker
gitlab:assets:compile: gitlab:assets:compile pull-push-cache:
extends: .gitlab:assets:compile-metadata extends: .gitlab:assets:compile-metadata
only: only:
refs: refs:
@ -63,9 +63,6 @@ gitlab:assets:compile:
gitlab:assets:compile pull-cache: gitlab:assets:compile pull-cache:
extends: .gitlab:assets:compile-metadata extends: .gitlab:assets:compile-metadata
except:
refs:
- master
cache: cache:
policy: pull policy: pull
@ -77,7 +74,7 @@ gitlab:assets:compile pull-cache:
- .default-before_script - .default-before_script
- .assets-compile-cache - .assets-compile-cache
- .only-code-qa-changes - .only-code-qa-changes
- .use-pg - .use-pg9
stage: prepare stage: prepare
script: script:
- node --version - node --version
@ -89,14 +86,14 @@ gitlab:assets:compile pull-cache:
# we override the max_old_space_size to prevent OOM errors # we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584 NODE_OPTIONS: --max_old_space_size=3584
cache: cache:
key: "assets-compile:test:vendor_ruby:.yarn-cache:tmp_cache_assets_sprockets:v6" key: "assets-compile:v7"
artifacts: artifacts:
expire_in: 7d expire_in: 7d
paths: paths:
- node_modules - node_modules
- public/assets - public/assets
compile-assets: compile-assets pull-push-cache:
extends: .compile-assets-metadata extends: .compile-assets-metadata
only: only:
refs: refs:
@ -104,14 +101,26 @@ compile-assets:
cache: cache:
policy: pull-push policy: pull-push
compile-assets pull-cache: compile-assets pull-push-cache foss:
extends: .compile-assets-metadata extends: [".compile-assets-metadata", ".only-ee-as-if-foss"]
except: only:
refs: refs:
- master - master
cache:
policy: pull-push
key: "assets-compile:v7:foss"
compile-assets pull-cache:
extends: .compile-assets-metadata
cache: cache:
policy: pull policy: pull
compile-assets pull-cache foss:
extends: [".compile-assets-metadata", ".only-ee-as-if-foss"]
cache:
policy: pull
key: "assets-compile:v7:foss"
.only-code-frontend-job-base: .only-code-frontend-job-base:
extends: extends:
- .default-tags - .default-tags
@ -120,10 +129,12 @@ compile-assets pull-cache:
- .default-only - .default-only
- .default-before_script - .default-before_script
- .only-code-changes - .only-code-changes
- .use-pg - .use-pg9
dependencies: ["compile-assets", "compile-assets pull-cache", "setup-test-env"] stage: test
needs: ["setup-test-env", "compile-assets pull-cache"]
dependencies: ["setup-test-env", "compile-assets pull-cache"]
karma: .karma-base:
extends: .only-code-frontend-job-base extends: .only-code-frontend-job-base
variables: variables:
# we override the max_old_space_size to prevent OOM errors # we override the max_old_space_size to prevent OOM errors
@ -134,6 +145,9 @@ karma:
- scripts/gitaly-test-spawn - scripts/gitaly-test-spawn
- date - date
- bundle exec rake karma - bundle exec rake karma
karma:
extends: .karma-base
coverage: '/^Statements *: (\d+\.\d+%)/' coverage: '/^Statements *: (\d+\.\d+%)/'
artifacts: artifacts:
name: coverage-javascript name: coverage-javascript
@ -146,7 +160,12 @@ karma:
reports: reports:
junit: junit_karma.xml junit: junit_karma.xml
jest: karma-foss:
extends:
- .karma-base
- .only-ee-as-if-foss
.jest-base:
extends: .only-code-frontend-job-base extends: .only-code-frontend-job-base
script: script:
- scripts/gitaly-test-spawn - scripts/gitaly-test-spawn
@ -154,6 +173,14 @@ jest:
- bundle exec rake frontend:fixtures - bundle exec rake frontend:fixtures
- date - date
- yarn jest --ci --coverage - yarn jest --ci --coverage
cache:
key: jest
paths:
- tmp/jest/jest/
policy: pull-push
jest:
extends: .jest-base
artifacts: artifacts:
name: coverage-frontend name: coverage-frontend
expire_in: 31d expire_in: 31d
@ -164,34 +191,13 @@ jest:
- tmp/tests/frontend/ - tmp/tests/frontend/
reports: reports:
junit: junit_jest.xml junit: junit_jest.xml
cache:
key: jest
paths:
- tmp/jest/jest/
policy: pull-push
.qa-job-base: jest-foss:
extends: extends:
- .default-tags - .jest-base
- .default-retry - .only-ee-as-if-foss
- .default-cache cache:
- .default-only policy: pull
- .only-code-qa-changes
dependencies: []
stage: test
before_script:
- cd qa/
- bundle install
qa:internal:
extends: .qa-job-base
script:
- bundle exec rspec
qa:selectors:
extends: .qa-job-base
script:
- bundle exec bin/qa Test::Sanity::Selectors
.qa-frontend-node: .qa-frontend-node:
extends: extends:
@ -200,6 +206,7 @@ qa:selectors:
- .default-cache - .default-cache
- .default-only - .default-only
- .only-code-changes - .only-code-changes
stage: test
dependencies: [] dependencies: []
cache: cache:
key: "$CI_JOB_NAME" key: "$CI_JOB_NAME"
@ -232,7 +239,9 @@ webpack-dev-server:
- .default-cache - .default-cache
- .default-only - .default-only
- .only-code-changes - .only-code-changes
dependencies: ["setup-test-env", "compile-assets", "compile-assets pull-cache"] stage: test
needs: ["setup-test-env", "compile-assets pull-cache"]
dependencies: ["setup-test-env", "compile-assets pull-cache"]
variables: variables:
WEBPACK_MEMORY_TEST: "true" WEBPACK_MEMORY_TEST: "true"
script: script:

View file

@ -13,6 +13,8 @@
.default-before_script: .default-before_script:
before_script: before_script:
- date - date
- export GOPATH=$CI_PROJECT_DIR/.go
- mkdir -p $GOPATH
- source scripts/utils.sh - source scripts/utils.sh
- source scripts/prepare_build.sh - source scripts/prepare_build.sh
- date - date
@ -22,6 +24,7 @@
cache: cache:
key: "debian-stretch-ruby-2.6.3-node-12.x" key: "debian-stretch-ruby-2.6.3-node-12.x"
paths: paths:
- .go/pkg/mod
- vendor/ruby - vendor/ruby
- .yarn-cache/ - .yarn-cache/
- vendor/gitaly-ruby - vendor/gitaly-ruby
@ -33,6 +36,7 @@
- master - master
- /^[\d-]+-stable(-ee)?$/ - /^[\d-]+-stable(-ee)?$/
- /^\d+-\d+-auto-deploy-\d+$/ - /^\d+-\d+-auto-deploy-\d+$/
- /^security\//
- merge_requests - merge_requests
- tags - tags
@ -51,7 +55,7 @@
- "{babel.config,jest.config}.js" - "{babel.config,jest.config}.js"
- "config.ru" - "config.ru"
- "{package.json,yarn.lock}" - "{package.json,yarn.lock}"
- "{app,bin,config,danger,db,ee,fixtures,haml_lint,lib,public,rubocop,scripts,spec,symbol,vendor}/**/*" - "{app,bin,config,danger,db,ee,fixtures,haml_lint,lib,locale,public,rubocop,scripts,spec,symbol,vendor}/**/*"
- "doc/README.md" # Some RSpec test rely on this file - "doc/README.md" # Some RSpec test rely on this file
.only-qa-changes: .only-qa-changes:
@ -67,6 +71,12 @@
- "doc/**/*" - "doc/**/*"
- ".markdownlint.json" - ".markdownlint.json"
.only-graphql-changes:
only:
changes:
- "{,ee/}app/graphql/**/*"
- "{,ee/}lib/gitlab/graphql/**/*"
.only-code-qa-changes: .only-code-qa-changes:
only: only:
changes: changes:
@ -82,7 +92,7 @@
- "{babel.config,jest.config}.js" - "{babel.config,jest.config}.js"
- "config.ru" - "config.ru"
- "{package.json,yarn.lock}" - "{package.json,yarn.lock}"
- "{app,bin,config,danger,db,ee,fixtures,haml_lint,lib,public,rubocop,scripts,spec,symbol,vendor}/**/*" - "{app,bin,config,danger,db,ee,fixtures,haml_lint,lib,locale,public,rubocop,scripts,spec,symbol,vendor}/**/*"
- "doc/README.md" # Some RSpec test rely on this file - "doc/README.md" # Some RSpec test rely on this file
- ".dockerignore" - ".dockerignore"
- "qa/**/*" - "qa/**/*"
@ -96,30 +106,57 @@
refs: refs:
- master - master
- /^\d+-\d+-auto-deploy-\d+$/ - /^\d+-\d+-auto-deploy-\d+$/
- /^[\d-]+-stable(-ee)?$/
.only-review-schedules: .only-review-schedules:
only: only:
refs: refs:
- schedules - schedules
variables: variables:
- $REVIEW_APP_CLEANUP && $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" - $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org"
kubernetes: active kubernetes: active
.use-pg: .only-canonical-schedules:
only:
refs:
- schedules@gitlab-org/gitlab
- schedules@gitlab-org/gitlab-foss
.use-pg9:
services: services:
- name: postgres:9.6.14 - name: postgres:9.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:alpine
.use-pg-10: .use-pg10:
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.33" image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.33"
services: services:
- name: postgres:10.9 - name: postgres:10.9
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:alpine
.use-pg9-ee:
services:
- name: postgres:9.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine
- name: docker.elastic.co/elasticsearch/elasticsearch:5.6.12
.use-pg10-ee:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.33"
services:
- name: postgres:10.9
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine
- name: docker.elastic.co/elasticsearch/elasticsearch:5.6.12
.only-ee: .only-ee:
only: only:
variables: variables:
- $CI_PROJECT_NAME == "gitlab" - $CI_PROJECT_NAME == "gitlab"
- $CI_PROJECT_NAME == "gitlab-ee" # Support former project name for forks/mirrors - $CI_PROJECT_NAME == "gitlab-ee" # Support former project name for forks/mirrors
.only-ee-as-if-foss:
extends: .only-ee
variables:
FOSS_ONLY: '1'

View file

@ -36,7 +36,7 @@ memory-static:
memory-on-boot: memory-on-boot:
extends: extends:
- .only-code-memory-job-base - .only-code-memory-job-base
- .use-pg-10 - .use-pg10
variables: variables:
NODE_ENV: "production" NODE_ENV: "production"
RAILS_ENV: "production" RAILS_ENV: "production"

View file

@ -0,0 +1,29 @@
.notify:
image: alpine
stage: notification
dependencies: []
cache: {}
before_script:
- apk update && apk add git curl bash
schedule:package-and-qa:notify-success:
extends:
- .only-canonical-schedules
- .notify
variables:
COMMIT_NOTES_URL: "https://$CI_SERVER_HOST/$CI_PROJECT_PATH/commit/$CI_COMMIT_SHA#notes-list"
script:
- 'scripts/notify-slack qa-master ":tada: Scheduled QA against master passed! :tada: See $CI_PIPELINE_URL. For downstream pipelines, see $COMMIT_NOTES_URL" ci_passing'
needs: ["schedule:package-and-qa"]
when: on_success
schedule:package-and-qa:notify-failure:
extends:
- .only-canonical-schedules
- .notify
variables:
COMMIT_NOTES_URL: "https://$CI_SERVER_HOST/$CI_PROJECT_PATH/commit/$CI_COMMIT_SHA#notes-list"
script:
- 'scripts/notify-slack qa-master ":skull_and_crossbones: Scheduled QA against master failed! :skull_and_crossbones: See $CI_PIPELINE_URL. For downstream pipelines, see $COMMIT_NOTES_URL" ci_failing'
needs: ["schedule:package-and-qa"]
when: on_failure

View file

@ -11,7 +11,7 @@ pages:
variables: variables:
- $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" - $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org"
stage: pages stage: pages
dependencies: ["coverage", "karma", "gitlab:assets:compile"] dependencies: ["coverage", "karma", "gitlab:assets:compile pull-cache"]
script: script:
- mv public/ .public/ - mv public/ .public/
- mkdir public/ - mkdir public/

View file

@ -1,10 +1,40 @@
.qa-job-base:
extends:
- .default-tags
- .default-retry
- .default-only
- .only-code-qa-changes
stage: test
dependencies: []
cache:
key: "qa-framework-jobs:v1"
paths:
- vendor/ruby
before_script:
- cd qa/
- bundle install --clean --jobs=$(nproc) --path=vendor --retry=3 --quiet
- bundle check
qa:internal:
extends: .qa-job-base
script:
- bundle exec rspec
qa:selectors:
extends: .qa-job-base
script:
- bundle exec bin/qa Test::Sanity::Selectors
qa:selectors-foss:
extends:
- qa:selectors
- .only-ee-as-if-foss
.package-and-qa-base: .package-and-qa-base:
extends: .default-only extends: .default-only
image: ruby:2.6-alpine image: ruby:2.6-alpine
stage: qa stage: qa
dependencies: [] dependencies: []
variables:
GIT_DEPTH: "1"
retry: 0 retry: 0
script: script:
- source scripts/utils.sh - source scripts/utils.sh
@ -12,7 +42,7 @@
- ./scripts/trigger-build omnibus - ./scripts/trigger-build omnibus
only: only:
variables: variables:
- $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" - $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/)/ # Matches the gitlab-org group or its subgroups
package-and-qa-manual: package-and-qa-manual:
extends: extends:
@ -21,20 +51,10 @@ package-and-qa-manual:
except: except:
refs: refs:
- master - master
- /^\d+-\d+-auto-deploy-\d+$/
when: manual when: manual
needs: ["build-qa-image", "gitlab:assets:compile pull-cache"] needs: ["build-qa-image", "gitlab:assets:compile pull-cache"]
package-and-qa-manual:master:
extends:
- .package-and-qa-base
- .only-code-qa-changes
only:
refs:
- master@gitlab-org/gitlab-foss
- master@gitlab-org/gitlab
when: manual
needs: ["build-qa-image", "gitlab:assets:compile"]
package-and-qa: package-and-qa:
extends: extends:
- .package-and-qa-base - .package-and-qa-base
@ -42,5 +62,13 @@ package-and-qa:
except: except:
refs: refs:
- master - master
- /^\d+-\d+-auto-deploy-\d+$/
needs: ["build-qa-image", "gitlab:assets:compile pull-cache"] needs: ["build-qa-image", "gitlab:assets:compile pull-cache"]
allow_failure: true allow_failure: true
schedule:package-and-qa:
extends:
- .package-and-qa-base
- .only-code-qa-changes
- .only-canonical-schedules
needs: ["build-qa-image", "gitlab:assets:compile pull-cache"]

View file

@ -33,31 +33,31 @@
- .default-before_script - .default-before_script
- .only-code-qa-changes - .only-code-qa-changes
setup-test-env:
extends:
- .only-code-qa-rails-job-base
- .use-pg9
stage: prepare
script:
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
- scripts/gitaly-test-build # Do not use 'bundle exec' here
artifacts:
expire_in: 7d
paths:
- tmp/tests
- config/secrets.yml
- vendor/gitaly-ruby
cache:
policy: pull-push
.rspec-base: .rspec-base:
extends: .only-code-rails-job-base extends: .only-code-rails-job-base
stage: test stage: test
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-assets pull-cache"]
dependencies: ["setup-test-env", "retrieve-tests-metadata", "compile-assets pull-cache"]
script: script:
- JOB_NAME=( $CI_JOB_NAME ) - source scripts/rspec_helpers.sh
- TEST_TOOL=${JOB_NAME[0]} - rspec_paralellized_job "--tag ~quarantine --tag ~geo"
- TEST_LEVEL=${JOB_NAME[1]}
- DATABASE=${JOB_NAME[2]}
- export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export KNAPSACK_GENERATE_REPORT=true KNAPSACK_LOG_LEVEL=debug KNAPSACK_TEST_DIR=spec
- export SUITE_FLAKY_RSPEC_REPORT_PATH=${FLAKY_RSPEC_SUITE_REPORT_PATH}
- export FLAKY_RSPEC_REPORT_PATH=rspec_flaky/all_${TEST_TOOL}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export NEW_FLAKY_RSPEC_REPORT_PATH=rspec_flaky/new_${TEST_TOOL}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export FLAKY_RSPEC_GENERATE_REPORT=true
- export CACHE_CLASSES=true
- cp ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
- '[[ -f $FLAKY_RSPEC_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_REPORT_PATH}'
- '[[ -f $NEW_FLAKY_RSPEC_REPORT_PATH ]] || echo "{}" > ${NEW_FLAKY_RSPEC_REPORT_PATH}'
- scripts/gitaly-test-spawn
- date
- 'export KNAPSACK_TEST_FILE_PATTERN=$(ruby -r./lib/quality/test_level.rb -e "puts Quality::TestLevel.new.pattern(:${TEST_LEVEL})")'
- mkdir -p tmp/memory_test
- export MEMORY_TEST_PATH="tmp/memory_test/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_memory.csv"
- knapsack rspec "--color --format documentation --format RspecJunitFormatter --out junit_rspec.xml --tag level:${TEST_LEVEL} --tag ~geo"
- date
artifacts: artifacts:
expire_in: 31d expire_in: 31d
when: always when: always
@ -71,79 +71,172 @@
reports: reports:
junit: junit_rspec.xml junit: junit_rspec.xml
.rspec-base-pg: .rspec-base-foss:
extends: [".rspec-base", ".only-ee-as-if-foss"]
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-assets pull-cache foss"]
dependencies: ["setup-test-env", "retrieve-tests-metadata", "compile-assets pull-cache foss"]
.rspec-base-pg9:
extends: extends:
- .rspec-base - .rspec-base
- .use-pg - .use-pg9
.rspec-base-pg-10: .rspec-base-pg9-foss:
extends:
- .rspec-base-foss
- .use-pg9
.rspec-base-pg10:
extends: extends:
- .rspec-base - .rspec-base
- .use-pg-10 - .use-pg10
- .only-master
setup-test-env: rspec unit pg9:
extends: extends: .rspec-base-pg9
- .only-code-qa-rails-job-base
- .use-pg
stage: prepare
script:
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
- scripts/gitaly-test-build # Do not use 'bundle exec' here
artifacts:
expire_in: 7d
paths:
- tmp/tests
- config/secrets.yml
- vendor/gitaly-ruby
rspec unit pg:
extends: .rspec-base-pg
parallel: 20 parallel: 20
rspec integration pg: rspec unit pg9-foss:
extends: .rspec-base-pg extends: .rspec-base-pg9-foss
parallel: 6
rspec system pg:
extends: .rspec-base-pg
parallel: 24
rspec unit pg-10:
extends:
- .rspec-base-pg-10
- .only-master
parallel: 20 parallel: 20
rspec integration pg-10: rspec integration pg9:
extends: extends: .rspec-base-pg9
- .rspec-base-pg-10
- .only-master
parallel: 6 parallel: 6
rspec system pg-10: rspec integration pg9-foss:
extends: extends: .rspec-base-pg9-foss
- .rspec-base-pg-10 parallel: 6
- .only-master
rspec system pg9:
extends: .rspec-base-pg9
parallel: 24 parallel: 24
rspec-fast-spec-helper: rspec system pg9-foss:
extends: .rspec-base-pg extends: .rspec-base-pg9-foss
script: parallel: 24
- bundle exec rspec spec/fast_spec_helper.rb
rspec quarantine pg: rspec unit pg10:
extends: .rspec-base-pg10
parallel: 20
rspec integration pg10:
extends: .rspec-base-pg10
parallel: 6
rspec system pg10:
extends: .rspec-base-pg10
parallel: 24
.rspec-ee-base-pg9:
extends: extends:
- .rspec-base-pg - .rspec-base
- .only-ee
- .use-pg9-ee
.rspec-ee-base-pg10:
extends:
- .rspec-base
- .only-ee
- .use-pg10-ee
rspec-ee unit pg9:
extends: .rspec-ee-base-pg9
parallel: 7
rspec-ee integration pg9:
extends: .rspec-ee-base-pg9
parallel: 3
rspec-ee system pg9:
extends: .rspec-ee-base-pg9
parallel: 5
rspec-ee unit pg10:
extends:
- .rspec-ee-base-pg10
- .only-master - .only-master
parallel: 7
rspec-ee integration pg10:
extends:
- .rspec-ee-base-pg10
- .only-master
parallel: 3
rspec-ee system pg10:
extends:
- .rspec-ee-base-pg10
- .only-master
parallel: 5
.rspec-ee-base-geo:
extends:
- .rspec-base
- .only-ee
script: script:
- export NO_KNAPSACK=1 CACHE_CLASSES=true - source scripts/rspec_helpers.sh
- scripts/gitaly-test-spawn - scripts/prepare_postgres_fdw.sh
- bin/rspec --color --format documentation --tag quarantine -- spec/ - rspec_paralellized_job "--tag ~quarantine --tag geo"
.rspec-ee-base-geo-pg9:
extends:
- .rspec-ee-base-geo
- .use-pg9-ee
.rspec-ee-base-geo-pg10:
extends:
- .rspec-ee-base-geo
- .use-pg10-ee
rspec-ee unit pg9 geo:
extends: .rspec-ee-base-geo-pg9
parallel: 2
rspec-ee integration pg9 geo:
extends: .rspec-ee-base-geo-pg9
rspec-ee system pg9 geo:
extends: .rspec-ee-base-geo-pg9
rspec-ee unit pg10 geo:
extends: .rspec-ee-base-geo-pg10
parallel: 2
rspec-ee integration pg10 geo:
extends: .rspec-ee-base-geo-pg10
rspec-ee system pg10 geo:
extends: .rspec-ee-base-geo-pg10
rspec quarantine pg9:
extends:
- .rspec-base-pg9
- .only-master
variables:
RSPEC_OPTS: "--tag quarantine -- spec/"
script:
- source scripts/rspec_helpers.sh
- rspec_simple_job "${RSPEC_OPTS}"
allow_failure: true allow_failure: true
rspec-ee quarantine pg9:
extends:
- rspec quarantine pg9
- .only-ee
variables:
RSPEC_OPTS: "--tag quarantine -- ee/spec/"
rspec fast_spec_helper:
extends: .rspec-base-pg9
script:
- bin/rspec spec/fast_spec_helper.rb
static-analysis: static-analysis:
extends: .only-code-qa-rails-job-base extends: .only-code-qa-rails-job-base
dependencies: ["setup-test-env", "compile-assets", "compile-assets pull-cache"] stage: test
needs: ["setup-test-env", "compile-assets pull-cache"]
dependencies: ["setup-test-env", "compile-assets pull-cache"]
variables: variables:
SETUP_DB: "false" SETUP_DB: "false"
script: script:
@ -166,16 +259,16 @@ downtime_check:
variables: variables:
- $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ - $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/
stage: test stage: test
dependencies: ["setup-test-env"]
needs: ["setup-test-env"] needs: ["setup-test-env"]
dependencies: ["setup-test-env"]
.db-job-base: .db-job-base:
extends: extends:
- .only-code-rails-job-base - .only-code-rails-job-base
- .use-pg - .use-pg9
stage: test stage: test
dependencies: ["setup-test-env"]
needs: ["setup-test-env"] needs: ["setup-test-env"]
dependencies: ["setup-test-env"]
# DB migration, rollback, and seed jobs # DB migration, rollback, and seed jobs
db:migrate:reset: db:migrate:reset:
@ -256,108 +349,6 @@ coverage:
- coverage/assets/ - coverage/assets/
- tmp/memory_test/ - tmp/memory_test/
## EE-specific content
.rspec-base-ee:
extends:
- .rspec-base
- .only-ee
script:
- JOB_NAME=( $CI_JOB_NAME )
- TEST_TOOL=${JOB_NAME[0]}
- TEST_LEVEL=${JOB_NAME[1]}
- DATABASE=${JOB_NAME[2]}
- export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_ee_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export KNAPSACK_GENERATE_REPORT=true KNAPSACK_LOG_LEVEL=debug KNAPSACK_TEST_DIR=spec
- export CACHE_CLASSES=true
- cp ${EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
- scripts/gitaly-test-spawn
- date
- 'export KNAPSACK_TEST_FILE_PATTERN=$(ruby -r./lib/quality/test_level.rb -e "puts Quality::TestLevel.new(%(ee/)).pattern(:${TEST_LEVEL})")'
- mkdir -p tmp/memory_test
- export MEMORY_TEST_PATH="tmp/memory_test/ee_${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_memory.csv"
- knapsack rspec "--color --format documentation --format RspecJunitFormatter --out junit_rspec.xml --tag level:${TEST_LEVEL} --tag ~geo"
- date
.rspec-base-pg-ee:
extends: .rspec-base-ee
services:
- name: postgres:9.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine
- name: docker.elastic.co/elasticsearch/elasticsearch:5.6.12
rspec unit pg ee:
extends: .rspec-base-pg-ee
parallel: 7
rspec integration pg ee:
extends: .rspec-base-pg-ee
parallel: 3
rspec system pg ee:
extends: .rspec-base-pg-ee
parallel: 5
.rspec-base-geo:
extends: .rspec-base-ee
parallel: 3
script:
- JOB_NAME=( $CI_JOB_NAME )
- TEST_TOOL=${JOB_NAME[0]}
- TEST_LEVEL=${JOB_NAME[1]}
- DATABASE=${JOB_NAME[2]}
- export KNAPSACK_TEST_FILE_PATTERN="ee/spec/**{,/*/**}/*_spec.rb" KNAPSACK_GENERATE_REPORT=true CACHE_CLASSES=true
- export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${TEST_TOOL}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- cp ${EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
- source scripts/prepare_postgres_fdw.sh
- scripts/gitaly-test-spawn
- mkdir -p tmp/memory_test
- export MEMORY_TEST_PATH="tmp/memory_test/ee_${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_memory.csv"
- knapsack rspec "-Ispec --color --format documentation --format RspecJunitFormatter --out junit_rspec.xml --tag geo"
rspec geo pg ee:
extends:
- .rspec-base-geo
- .use-pg
except:
variables:
- $CI_COMMIT_REF_NAME =~ /(^geo[\/-].*|.*-geo$)/
rspec geo pg-10 ee:
extends:
- .rspec-base-geo
- .use-pg-10
except:
variables:
- $CI_COMMIT_REF_NAME =~ /(^geo[\/-].*|.*-geo$)/
quick-rspec geo pg ee:
extends:
- .rspec-base-geo
- .use-pg
stage: quick-test
only:
variables:
- $CI_COMMIT_REF_NAME =~ /(^geo[\/-].*|.*-geo$)/
quick-rspec geo pg-10 ee:
extends:
- .rspec-base-geo
- .use-pg-10
stage: quick-test
only:
variables:
- $CI_COMMIT_REF_NAME =~ /(^geo[\/-].*|.*-geo$)/
rspec quarantine pg ee:
extends:
- rspec quarantine pg
- .only-ee
script:
- export NO_KNAPSACK=1 CACHE_CLASSES=true
- scripts/gitaly-test-spawn
- bin/rspec --color --format documentation --format RspecJunitFormatter --out junit_rspec.xml --tag quarantine -- ee/spec/
db:rollback geo: db:rollback geo:
extends: extends:
- db:rollback - db:rollback
@ -365,5 +356,3 @@ db:rollback geo:
script: script:
- bundle exec rake geo:db:migrate VERSION=20170627195211 - bundle exec rake geo:db:migrate VERSION=20170627195211
- bundle exec rake geo:db:migrate - bundle exec rake geo:db:migrate
## END of EE-specific content

View file

@ -44,6 +44,8 @@ code_quality:
# We need to duplicate this job's definition because it seems it's impossible to # We need to duplicate this job's definition because it seems it's impossible to
# override an included `only.refs`. # override an included `only.refs`.
# See https://gitlab.com/gitlab-org/gitlab/issues/31371. # See https://gitlab.com/gitlab-org/gitlab/issues/31371.
# Once https://gitlab.com/gitlab-org/gitlab/merge_requests/16487 will be deployed
# to GitLab.com, we should be able to use the template and set SAST_DISABLE_DIND: "true".
sast: sast:
extends: extends:
- .default-retry - .default-retry
@ -196,6 +198,7 @@ dast:
- .only-code-qa-changes - .only-code-qa-changes
- .only-review - .only-review
stage: qa stage: qa
needs: ["review-deploy"]
dependencies: ["review-deploy"] dependencies: ["review-deploy"]
before_script: before_script:
- export DAST_WEBSITE="$(cat review_app_url.txt)" - export DAST_WEBSITE="$(cat review_app_url.txt)"

View file

@ -1,20 +1,14 @@
.review-base: .except-deploys:
extends: except:
- .default-tags refs:
- .default-retry - /^\d+-\d+-auto-deploy-\d+$/
- .default-only
- .only-review
- .only-code-qa-changes
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base
dependencies: []
before_script:
- source scripts/utils.sh
.review-docker: .review-docker:
extends: extends:
- .default-tags - .default-tags
- .default-retry - .default-retry
- .default-only - .default-only
- .except-deploys
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine
services: services:
- docker:19.03.0-dind - docker:19.03.0-dind
@ -41,10 +35,31 @@ build-qa-image:
- echo "${CI_JOB_TOKEN}" | docker login --username gitlab-ci-token --password-stdin ${CI_REGISTRY} - echo "${CI_JOB_TOKEN}" | docker login --username gitlab-ci-token --password-stdin ${CI_REGISTRY}
- time docker push ${QA_IMAGE} - time docker push ${QA_IMAGE}
schedule:review-cleanup:
extends:
- .default-tags
- .default-retry
- .default-only
- .only-code-qa-changes
- .only-review-schedules
- .except-deploys
stage: prepare
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base
allow_failure: true
environment:
name: review/auto-cleanup
action: stop
before_script:
- source scripts/utils.sh
- install_gitlab_gem
script:
- ruby -rrubygems scripts/review_apps/automated_cleanup.rb
.review-build-cng-base: .review-build-cng-base:
extends: extends:
- .default-only - .default-only
- .only-code-qa-changes - .only-code-qa-changes
- .except-deploys
image: ruby:2.6-alpine image: ruby:2.6-alpine
stage: review-prepare stage: review-prepare
before_script: before_script:
@ -65,16 +80,23 @@ schedule:review-build-cng:
extends: extends:
- .review-build-cng-base - .review-build-cng-base
- .only-review-schedules - .only-review-schedules
needs: ["gitlab:assets:compile"] needs: ["gitlab:assets:compile pull-cache"]
.review-deploy-base: .review-deploy-base:
extends: .review-base extends:
allow_failure: true - .default-tags
- .default-retry
- .default-only
- .only-code-qa-changes
- .except-deploys
stage: review stage: review
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base
dependencies: []
allow_failure: true
variables: variables:
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}" HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}" DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
GITLAB_HELM_CHART_REF: "master" GITLAB_HELM_CHART_REF: "v2.3.7"
GITLAB_EDITION: "ce" GITLAB_EDITION: "ce"
environment: environment:
name: review/${CI_COMMIT_REF_NAME} name: review/${CI_COMMIT_REF_NAME}
@ -90,13 +112,21 @@ schedule:review-build-cng:
- install_api_client_dependencies_with_apk - install_api_client_dependencies_with_apk
- source scripts/review_apps/review-apps.sh - source scripts/review_apps/review-apps.sh
script: script:
- date
- check_kube_domain - check_kube_domain
- date
- ensure_namespace - ensure_namespace
- date
- install_tiller - install_tiller
- date
- install_external_dns - install_external_dns
- date
- download_chart - download_chart
- date
- deploy || (display_deployment_debug && exit 1) - deploy || (display_deployment_debug && exit 1)
- date
- add_license - add_license
- date
artifacts: artifacts:
paths: [review_app_url.txt] paths: [review_app_url.txt]
expire_in: 2 days expire_in: 2 days
@ -105,6 +135,7 @@ schedule:review-build-cng:
review-deploy: review-deploy:
extends: extends:
- .review-deploy-base - .review-deploy-base
- .only-review
needs: ["review-build-cng"] needs: ["review-build-cng"]
schedule:review-deploy: schedule:review-deploy:
@ -116,6 +147,7 @@ schedule:review-deploy:
review-stop: review-stop:
extends: extends:
- .review-deploy-base - .review-deploy-base
- .only-review
when: manual when: manual
environment: environment:
action: stop action: stop
@ -148,6 +180,7 @@ review-cleanup-failed-deployment:
- .only-review - .only-review
- .only-code-qa-changes - .only-code-qa-changes
stage: qa stage: qa
allow_failure: true
variables: variables:
QA_ARTIFACTS_DIR: "${CI_PROJECT_DIR}/qa" QA_ARTIFACTS_DIR: "${CI_PROJECT_DIR}/qa"
QA_CAN_TEST_GIT_PROTOCOL_V2: "false" QA_CAN_TEST_GIT_PROTOCOL_V2: "false"
@ -158,6 +191,7 @@ review-cleanup-failed-deployment:
GITLAB_ADMIN_PASSWORD: "${REVIEW_APPS_ROOT_PASSWORD}" GITLAB_ADMIN_PASSWORD: "${REVIEW_APPS_ROOT_PASSWORD}"
GITHUB_ACCESS_TOKEN: "${REVIEW_APPS_QA_GITHUB_ACCESS_TOKEN}" GITHUB_ACCESS_TOKEN: "${REVIEW_APPS_QA_GITHUB_ACCESS_TOKEN}"
EE_LICENSE: "${REVIEW_APPS_EE_LICENSE}" EE_LICENSE: "${REVIEW_APPS_EE_LICENSE}"
needs: ["review-deploy"]
dependencies: ["review-deploy"] dependencies: ["review-deploy"]
artifacts: artifacts:
paths: paths:
@ -176,26 +210,76 @@ review-cleanup-failed-deployment:
review-qa-smoke: review-qa-smoke:
extends: .review-qa-base extends: .review-qa-base
allow_failure: true
script: script:
- gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}" - gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}"
review-qa-all: review-qa-all:
extends: .review-qa-base extends: .review-qa-base
allow_failure: true
when: manual when: manual
parallel: 5 parallel: 5
script: script:
- export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/review-qa-all_master_report.json - export KNAPSACK_REPORT_PATH=knapsack/master_report.json
- export KNAPSACK_TEST_FILE_PATTERN=qa/specs/features/**/*_spec.rb - export KNAPSACK_TEST_FILE_PATTERN=qa/specs/features/**/*_spec.rb
- gitlab-qa Test::Instance::Any "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}" -- --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml --format html --out tmp/rspec.htm --color --format documentation - gitlab-qa Test::Instance::Any "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}" -- --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml --format html --out tmp/rspec.htm --color --format documentation
.review-performance-base:
extends:
- .review-docker
- .only-code-qa-changes
stage: qa
allow_failure: true
before_script:
- export CI_ENVIRONMENT_URL="$(cat review_app_url.txt)"
- echo "${CI_ENVIRONMENT_URL}"
- mkdir -p gitlab-exporter
- wget -O ./gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/master/index.js
- mkdir -p sitespeed-results
script:
- docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io:6.3.1 --plugins.add ./gitlab-exporter --outputFolder sitespeed-results "${CI_ENVIRONMENT_URL}"
after_script:
- mv sitespeed-results/data/performance.json performance.json
artifacts:
paths:
- sitespeed-results/
reports:
performance: performance.json
review-performance:
extends:
- .review-performance-base
- .only-review
needs: ["review-deploy"]
dependencies: ["review-deploy"]
before_script:
- export CI_ENVIRONMENT_URL="$(cat review_app_url.txt)"
- echo "${CI_ENVIRONMENT_URL}"
- mkdir -p gitlab-exporter
- wget -O ./gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/master/index.js
- mkdir -p sitespeed-results
script:
- docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io:6.3.1 --plugins.add ./gitlab-exporter --outputFolder sitespeed-results "${CI_ENVIRONMENT_URL}"
after_script:
- mv sitespeed-results/data/performance.json performance.json
artifacts:
paths:
- sitespeed-results/
reports:
performance: performance.json
schedule:review-performance:
extends:
- .review-performance-base
- .only-review-schedules
needs: ["schedule:review-deploy"]
dependencies: ["schedule:review-deploy"]
parallel-spec-reports: parallel-spec-reports:
extends: extends:
- .default-tags - .default-tags
- .default-only - .default-only
- .only-code-qa-changes - .only-code-qa-changes
- .only-review - .only-review
- .except-deploys
image: ruby:2.6-alpine image: ruby:2.6-alpine
stage: post-test stage: post-test
dependencies: ["review-qa-all"] dependencies: ["review-qa-all"]
@ -220,46 +304,6 @@ parallel-spec-reports:
- '[[ -f $NEW_PARALLEL_SPECS_REPORT ]] || echo "{}" > ${NEW_PARALLEL_SPECS_REPORT}' - '[[ -f $NEW_PARALLEL_SPECS_REPORT ]] || echo "{}" > ${NEW_PARALLEL_SPECS_REPORT}'
- scripts/merge-html-reports ${NEW_PARALLEL_SPECS_REPORT} ${BASE_ARTIFACT_URL}${ARTIFACT_DIRS} qa/gitlab-qa-run-*/**/rspec.htm - scripts/merge-html-reports ${NEW_PARALLEL_SPECS_REPORT} ${BASE_ARTIFACT_URL}${ARTIFACT_DIRS} qa/gitlab-qa-run-*/**/rspec.htm
review-performance:
extends: .review-qa-base
allow_failure: true
before_script:
- export CI_ENVIRONMENT_URL="$(cat review_app_url.txt)"
- echo "${CI_ENVIRONMENT_URL}"
- mkdir -p gitlab-exporter
- wget -O ./gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/master/index.js
- mkdir -p sitespeed-results
script:
- docker run --shm-size=1g --rm -v "$(pwd)":/sitespeed.io sitespeedio/sitespeed.io:6.3.1 --plugins.add ./gitlab-exporter --outputFolder sitespeed-results "${CI_ENVIRONMENT_URL}"
after_script:
- mv sitespeed-results/data/performance.json performance.json
artifacts:
paths:
- sitespeed-results/
reports:
performance: performance.json
schedule:review-performance:
extends:
- review-performance
- .only-review-schedules
dependencies: ["schedule:review-deploy"]
schedule:review-cleanup:
extends:
- .review-base
- .only-review-schedules
stage: prepare
allow_failure: true
environment:
name: review/auto-cleanup
action: stop
before_script:
- source scripts/utils.sh
- install_gitlab_gem
script:
- ruby -rrubygems scripts/review_apps/automated_cleanup.rb
danger-review: danger-review:
extends: extends:
- .default-tags - .default-tags

View file

@ -1,10 +1,16 @@
.tests-metadata-state: .tests-metadata-state:
extends: extends:
- .default-only - .default-only
- .only-code-changes
variables: variables:
TESTS_METADATA_S3_BUCKET: "gitlab-ce-cache" TESTS_METADATA_S3_BUCKET: "gitlab-ce-cache"
before_script: before_script:
- source scripts/utils.sh - source scripts/utils.sh
cache:
key: tests_metadata
paths:
- knapsack/
- rspec_flaky/
artifacts: artifacts:
expire_in: 31d expire_in: 31d
paths: paths:
@ -13,55 +19,29 @@
- rspec_profiling/ - rspec_profiling/
retrieve-tests-metadata: retrieve-tests-metadata:
extends: extends: .tests-metadata-state
- .tests-metadata-state
- .only-code-changes
stage: prepare stage: prepare
cache: cache:
key: tests_metadata
policy: pull policy: pull
script: script:
- mkdir -p knapsack/${CI_PROJECT_NAME}/ - source scripts/rspec_helpers.sh
- wget -O $KNAPSACK_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_RSPEC_SUITE_REPORT_PATH || rm $KNAPSACK_RSPEC_SUITE_REPORT_PATH - retrieve_tests_metadata
- '[[ -f $KNAPSACK_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${KNAPSACK_RSPEC_SUITE_REPORT_PATH}'
- mkdir -p rspec_flaky/
- mkdir -p rspec_profiling/
- wget -O $FLAKY_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$FLAKY_RSPEC_SUITE_REPORT_PATH || rm $FLAKY_RSPEC_SUITE_REPORT_PATH
- '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}'
- '[[ ! -d "ee/" ]] || wget -O $EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH || rm $EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH'
- '[[ ! -d "ee/" ]] || [[ -f $EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH}'
update-tests-metadata: update-tests-metadata:
extends: extends: .tests-metadata-state
- .tests-metadata-state
- .only-code-changes
stage: post-test stage: post-test
cache: cache:
key: tests_metadata
paths:
- knapsack/
- rspec_flaky/
policy: push policy: push
script: script:
- retry gem install fog-aws mime-types activesupport rspec_profiling postgres-copy --no-document - retry gem install fog-aws mime-types activesupport rspec_profiling postgres-copy --no-document
- echo "{}" > ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} - source scripts/rspec_helpers.sh
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec_*_pg_node_*.json - update_tests_metadata
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH'
- '[[ ! -d "ee/" ]] || echo "{}" > ${EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH}'
- '[[ ! -d "ee/" ]] || scripts/merge-reports ${EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec_*_pg_ee_*node_*.json'
- '[[ ! -d "ee/" ]] || [[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $EE_KNAPSACK_RSPEC_SUITE_REPORT_PATH'
- rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json
- scripts/merge-reports ${FLAKY_RSPEC_SUITE_REPORT_PATH} rspec_flaky/all_*_*.json
- FLAKY_RSPEC_GENERATE_REPORT=1 scripts/prune-old-flaky-specs ${FLAKY_RSPEC_SUITE_REPORT_PATH}
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $FLAKY_RSPEC_SUITE_REPORT_PATH'
- rm -f rspec_flaky/all_*.json rspec_flaky/new_*.json
- scripts/insert-rspec-profiling-data
only: only:
refs: refs:
- master - schedules
variables: variables:
- $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" # Only update the Knapsack metadata on GitLab.com/gitlab-org/gitlab
- $CI_SERVER_HOST == "dev.gitlab.org" - $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_PATH == "gitlab-org/gitlab"
flaky-examples-check: flaky-examples-check:
extends: extends:

View file

@ -25,7 +25,7 @@ Then leave running while monitoring and performing some testing through web, api
- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) - [ ] [Monitor Using Grafana](https://dashboards.gitlab.net)
- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) - [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana)
- [ ] [Check for errors in GitLab Dev Sentry](https://sentry.gitlap.com/gitlab/devgitlaborg/?query=is%3Aunresolved) - [ ] [Check for errors in GitLab Dev Sentry](https://sentry.gitlab.net/gitlab/devgitlaborg/?query=is%3Aunresolved)
## 2. Staging Trial ## 2. Staging Trial
@ -41,7 +41,7 @@ Then leave running while monitoring for at least **15 minutes** while performing
- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) - [ ] [Monitor Using Grafana](https://dashboards.gitlab.net)
- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) - [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana)
- [ ] [Check for errors in GitLab Sentry](https://sentry.gitlap.com/gitlab/gitlabcom/?query=is%3Aunresolved) - [ ] [Check for errors in GitLab Sentry](https://sentry.gitlab.net/gitlab/gitlabcom/?query=is%3Aunresolved)
## 4. Production Server Version Check ## 4. Production Server Version Check
@ -57,7 +57,7 @@ Then leave running while monitoring for at least **15 minutes** while performing
- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) - [ ] [Monitor Using Grafana](https://dashboards.gitlab.net)
- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) - [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana)
- [ ] [Check for errors in GitLab Sentry](https://sentry.gitlap.com/gitlab/gitlabcom/?query=is%3Aunresolved) - [ ] [Check for errors in GitLab Sentry](https://sentry.gitlab.net/gitlab/gitlabcom/?query=is%3Aunresolved)
## 6. Low Impact Check ## 6. Low Impact Check
@ -69,7 +69,7 @@ Then leave running while monitoring for at least **30 minutes** while performing
- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) - [ ] [Monitor Using Grafana](https://dashboards.gitlab.net)
- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) - [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana)
- [ ] [Check for errors in GitLab Sentry](https://sentry.gitlap.com/gitlab/gitlabcom/?query=is%3Aunresolved) - [ ] [Check for errors in GitLab Sentry](https://sentry.gitlab.net/gitlab/gitlabcom/?query=is%3Aunresolved)
## 7. Mid Impact Trial ## 7. Mid Impact Trial
@ -81,7 +81,7 @@ Then leave running while monitoring for at least **12 hours** while performing s
- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) - [ ] [Monitor Using Grafana](https://dashboards.gitlab.net)
- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) - [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana)
- [ ] [Check for errors in GitLab Sentry](https://sentry.gitlap.com/gitlab/gitlabcom/?query=is%3Aunresolved) - [ ] [Check for errors in GitLab Sentry](https://sentry.gitlab.net/gitlab/gitlabcom/?query=is%3Aunresolved)
## 8. Full Impact Trial ## 8. Full Impact Trial
@ -93,7 +93,7 @@ Then leave running while monitoring for at least **1 week**.
- [ ] [Monitor Using Grafana](https://dashboards.gitlab.net) - [ ] [Monitor Using Grafana](https://dashboards.gitlab.net)
- [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana) - [ ] [Inspect logs in ELK](https://log.gitlab.net/app/kibana)
- [ ] [Check for errors in GitLab Dev Sentry](https://sentry.gitlap.com/gitlab/devgitlaborg/?query=is%3Aunresolved) - [ ] [Check for errors in GitLab Dev Sentry](https://sentry.gitlab.net/gitlab/devgitlaborg/?query=is%3Aunresolved)
#### Success? #### Success?

View file

@ -2,17 +2,10 @@
Please read this! Please read this!
Before opening a new issue, make sure to search for keywords in the issues Before opening a new issue, make sure to search for keywords in the issues
filtered by the "regression" or "bug" label. filtered by the "regression" or "bug" label:
For the Community Edition issue tracker: - https://gitlab.com/gitlab-org/gitlab/issues?label_name%5B%5D=regression
- https://gitlab.com/gitlab-org/gitlab/issues?label_name%5B%5D=bug
- https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=regression
- https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=bug
For the Enterprise Edition issue tracker:
- https://gitlab.com/gitlab-org/gitlab-ee/issues?label_name%5B%5D=regression
- https://gitlab.com/gitlab-org/gitlab-ee/issues?label_name%5B%5D=bug
and verify the issue you're about to submit isn't a duplicate. and verify the issue you're about to submit isn't a duplicate.
---> --->

View file

@ -11,6 +11,6 @@ Please describe the proposal and add a link to the source (for example, http://w
/label ~"development guidelines" /label ~"development guidelines"
/label ~"Style decision" /label ~"Style decision"
/label ~Documentation /label ~documentation
/cc @gitlab-org/maintainers/rails-backend /cc @gitlab-org/maintainers/rails-backend

View file

@ -17,4 +17,4 @@ Related issue(s):
<!-- Any additional context, questions, or notes for the technical writer. --> <!-- Any additional context, questions, or notes for the technical writer. -->
/label ~Documentation ~docs-review /label ~documentation ~"Technical Writing"

View file

@ -9,16 +9,6 @@
* For information about documentation content and process, see * For information about documentation content and process, see
https://docs.gitlab.com/ee/development/documentation/ --> https://docs.gitlab.com/ee/development/documentation/ -->
<!-- Type of issue -->
<!-- Un-comment the line for the applicable doc issue type to add its label.
Note that all text on that line is deleted upon issue creation. -->
<!-- /label ~"docs:fix" - Correction or clarification needed. -->
<!-- /label ~"docs:new" - New doc needed to cover a new topic or use case. -->
<!-- /label ~"docs:improvement" - Improving an existing doc; e.g. adding a diagram, adding or rewording text, resolving redundancies, cross-linking, etc. -->
<!-- /label ~"docs:revamp" - Review a page or group of pages in order to plan and implement major improvements/rewrites. -->
<!-- /label ~"docs:other" - Anything else. -->
### Problem to solve ### Problem to solve
<!-- Include the following detail as necessary: <!-- Include the following detail as necessary:
@ -50,4 +40,4 @@
<!-- E.g. related GitLab issues/MRs --> <!-- E.g. related GitLab issues/MRs -->
/label ~Documentation /label ~documentation

View file

@ -24,7 +24,7 @@ Remove the `:feature_name` feature flag ...
If applicable, any groups/projects that are happy to have this feature turned on early. Some organizations may wish to test big changes they are interested in with a small subset of users ahead of time for example. If applicable, any groups/projects that are happy to have this feature turned on early. Some organizations may wish to test big changes they are interested in with a small subset of users ahead of time for example.
- `gitlab-org/gitlab-ce`/`gitlab-org/gitlab-ee` projects - `gitlab-org/gitlab` project
- `gitlab-org`/`gitlab-com` groups - `gitlab-org`/`gitlab-com` groups
- ... - ...
@ -34,6 +34,7 @@ If applicable, any groups/projects that are happy to have this feature turned on
- [ ] Test on staging - [ ] Test on staging
- [ ] Ensure that documentation has been updated - [ ] Ensure that documentation has been updated
- [ ] Enable on GitLab.com for individual groups/projects listed above and verify behaviour - [ ] Enable on GitLab.com for individual groups/projects listed above and verify behaviour
- [ ] Coordinate a time to enable the flag with `#production` and `#g_delivery` on slack.
- [ ] Announce on the issue an estimated time this will be enabled on GitLab.com - [ ] Announce on the issue an estimated time this will be enabled on GitLab.com
- [ ] Enable on GitLab.com by running chatops command in `#production` - [ ] Enable on GitLab.com by running chatops command in `#production`
- [ ] Cross post chatops slack command to `#support_gitlab-com` and in your team channel - [ ] Cross post chatops slack command to `#support_gitlab-com` and in your team channel

View file

@ -38,4 +38,4 @@
For example, if the solution will take a product manager, designer, and engineer two weeks of effort - you may quantify this as 1.5 (based on 0.5 months x 3 people). --> For example, if the solution will take a product manager, designer, and engineer two weeks of effort - you may quantify this as 1.5 (based on 0.5 months x 3 people). -->
/label ~"workflow::problem backlog" /label ~"workflow::validation backlog" ~devops:: ~category: ~group::

View file

@ -18,13 +18,7 @@ Set the title to: `Security Release: 12.2.X, 12.1.X, and 12.0.X`
## Security Issues: ## Security Issues:
### CE * {https://gitlab.com/gitlab-org/gitlab/issues link}
* {https://gitlab.com/gitlab-org/gitlab-ce/issues link}
### EE
* {https://gitlab.com/gitlab-org/gitlab-ee/issues link}
## Security Issues in dev.gitlab.org: ## Security Issues in dev.gitlab.org:

View file

@ -2,7 +2,7 @@
<!-- This issue outlines testing activities related to a particular issue or epic. <!-- This issue outlines testing activities related to a particular issue or epic.
[Here is an example test plan](https://gitlab.com/gitlab-org/gitlab-ce/issues/50353) [Here is an example test plan](https://gitlab.com/gitlab-org/gitlab-foss/issues/50353)
This and other comments should be removed as you write the plan --> This and other comments should be removed as you write the plan -->
@ -63,7 +63,7 @@ intersection of Components and Attributes.
Some features might be simple enough that they only involve one Component, while Some features might be simple enough that they only involve one Component, while
more complex features could involve multiple or even all. more complex features could involve multiple or even all.
Example (from https://gitlab.com/gitlab-org/gitlab-ce/issues/50353): Example (from https://gitlab.com/gitlab-org/gitlab-foss/issues/50353):
* Repository is * Repository is
* Intuitive * Intuitive
* It's easy to select the desired file template * It's easy to select the desired file template

View file

@ -15,7 +15,7 @@ Closes
## Moving docs to a new location? ## Moving docs to a new location?
Read the guidelines: Read the guidelines:
https://docs.gitlab.com/ce/development/documentation/index.html#changing-document-location https://docs.gitlab.com/ee/development/documentation/index.html#changing-document-location
- [ ] Make sure the old link is not removed and has its contents replaced with - [ ] Make sure the old link is not removed and has its contents replaced with
a link to the new location. a link to the new location.
@ -29,4 +29,4 @@ https://docs.gitlab.com/ce/development/documentation/index.html#changing-documen
with the changes as well (https://docs.gitlab.com/ce/development/documentation/index.html#cherry-picking-from-ce-to-ee). with the changes as well (https://docs.gitlab.com/ce/development/documentation/index.html#cherry-picking-from-ce-to-ee).
- [ ] Ping one of the technical writers for review. - [ ] Ping one of the technical writers for review.
/label ~Documentation /label ~documentation

View file

@ -24,6 +24,7 @@ When adding migrations:
- [ ] Added a `down` method so the migration can be reverted - [ ] Added a `down` method so the migration can be reverted
- [ ] Added the output of the migration(s) to the MR body - [ ] Added the output of the migration(s) to the MR body
- [ ] Added tests for the migration in `spec/migrations` if necessary (e.g. when migrating data) - [ ] Added tests for the migration in `spec/migrations` if necessary (e.g. when migrating data)
- [ ] Added rollback procedure. Include either a rollback procedure or description how to rollback changes
When adding or modifying queries to improve performance: When adding or modifying queries to improve performance:
@ -37,7 +38,7 @@ When adding foreign keys to existing tables:
When adding tables: When adding tables:
- [ ] Ordered columns based on the [Ordering Table Columns](https://docs.gitlab.com/ee/development/ordering_table_columns.html#ordering-table-columns) guidelines - [ ] Ordered columns based on the [Ordering Table Columns](https://docs.gitlab.com/ee/development/ordering_table_columns.html) guidelines
- [ ] Added foreign keys to any columns pointing to data in other tables - [ ] Added foreign keys to any columns pointing to data in other tables
- [ ] Added indexes for fields that are used in statements such as `WHERE`, `ORDER BY`, `GROUP BY`, and `JOIN`s - [ ] Added indexes for fields that are used in statements such as `WHERE`, `ORDER BY`, `GROUP BY`, and `JOIN`s

View file

@ -17,7 +17,7 @@
- [ ] Follow the [Documentation Guidelines](https://docs.gitlab.com/ee/development/documentation/) and [Style Guide](https://docs.gitlab.com/ee/development/documentation/styleguide.html). - [ ] Follow the [Documentation Guidelines](https://docs.gitlab.com/ee/development/documentation/) and [Style Guide](https://docs.gitlab.com/ee/development/documentation/styleguide.html).
- [ ] If applicable, update the [permissions table](https://docs.gitlab.com/ee/user/permissions.html). - [ ] If applicable, update the [permissions table](https://docs.gitlab.com/ee/user/permissions.html).
- [ ] Link docs to and from the higher-level index page, plus other related docs where helpful. - [ ] Link docs to and from the higher-level index page, plus other related docs where helpful.
- [ ] Apply the ~Documentation label. - [ ] Apply the ~documentation label.
## Review checklist ## Review checklist
@ -35,6 +35,6 @@ All reviewers can help ensure accuracy, clarity, completeness, and adherence to
1. [ ] Review by assigned maintainer, who can always request/require the above reviews. Maintainer's review can occur before or after a technical writer review. 1. [ ] Review by assigned maintainer, who can always request/require the above reviews. Maintainer's review can occur before or after a technical writer review.
1. [ ] Ensure a release milestone is set and that you merge the equivalent EE MR before the CE MR if both exist. 1. [ ] Ensure a release milestone is set and that you merge the equivalent EE MR before the CE MR if both exist.
1. [ ] If there has not been a technical writer review, [create an issue for one using the Doc Review template](https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issuable_template=Doc%20Review). 1. [ ] If there has not been a technical writer review, [create an issue for one using the Doc Review template](https://gitlab.com/gitlab-org/gitlab/issues/new?issuable_template=Doc%20Review).
/label ~Documentation /label ~documentation

View file

@ -208,6 +208,8 @@ linters:
- 'app/views/projects/_md_preview.html.haml' - 'app/views/projects/_md_preview.html.haml'
- 'app/views/projects/_new_project_fields.html.haml' - 'app/views/projects/_new_project_fields.html.haml'
- 'app/views/projects/_readme.html.haml' - 'app/views/projects/_readme.html.haml'
- 'app/views/projects/artifacts/_artifact.html.haml'
- 'app/views/projects/artifacts/_search_bar.html.haml'
- 'app/views/projects/artifacts/_tree_file.html.haml' - 'app/views/projects/artifacts/_tree_file.html.haml'
- 'app/views/projects/artifacts/browse.html.haml' - 'app/views/projects/artifacts/browse.html.haml'
- 'app/views/projects/blame/_age_map_legend.html.haml' - 'app/views/projects/blame/_age_map_legend.html.haml'
@ -354,6 +356,7 @@ linters:
- 'app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml' - 'app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml'
- 'app/views/shared/_commit_message_container.html.haml' - 'app/views/shared/_commit_message_container.html.haml'
- 'app/views/shared/_confirm_modal.html.haml' - 'app/views/shared/_confirm_modal.html.haml'
- 'app/views/shared/_confirm_fork_modal.html.haml'
- 'app/views/shared/_delete_label_modal.html.haml' - 'app/views/shared/_delete_label_modal.html.haml'
- 'app/views/shared/_group_form.html.haml' - 'app/views/shared/_group_form.html.haml'
- 'app/views/shared/_group_tips.html.haml' - 'app/views/shared/_group_tips.html.haml'

36
.projections.json.example Normal file
View file

@ -0,0 +1,36 @@
{
"app/*.rb": {
"alternate": "spec/{}_spec.rb",
"type": "source"
},
"spec/*_spec.rb": {
"alternate": "app/{}.rb",
"type": "test"
},
"lib/*.rb": {
"alternate": "spec/lib/{}_spec.rb",
"type": "source"
},
"spec/lib/*_spec.rb": {
"alternate": "lib/{}.rb",
"type": "test"
},
"ee/app/*.rb": {
"alternate": "ee/spec/{}_spec.rb",
"type": "source"
},
"ee/spec/*_spec.rb": {
"alternate": "ee/app/{}.rb",
"type": "test"
},
"ee/lib/*.rb": {
"alternate": "ee/spec/lib/{}_spec.rb",
"type": "source"
},
"ee/spec/lib/*_spec.rb": {
"alternate": "ee/lib/{}.rb",
"type": "test"
},
"*.rb": {"dispatch": "bundle exec rubocop {file}"},
"*_spec.rb": {"dispatch": "bundle exec rspec {file}"}
}

View file

@ -51,7 +51,6 @@ Style/FrozenStringLiteralComment:
- 'danger/**/*' - 'danger/**/*'
- 'db/**/*' - 'db/**/*'
- 'ee/db/**/*' - 'ee/db/**/*'
- 'ee/spec/**/*'
- 'ee/lib/tasks/**/*' - 'ee/lib/tasks/**/*'
- 'lib/tasks/**/*' - 'lib/tasks/**/*'
- 'qa/**/*' - 'qa/**/*'
@ -179,6 +178,11 @@ Gitlab/ModuleWithInstanceVariables:
- spec/support/**/*.rb - spec/support/**/*.rb
- features/steps/**/*.rb - features/steps/**/*.rb
Gitlab/ConstGetInheritFalse:
Enabled: true
Exclude:
- 'qa/bin/*'
Gitlab/HTTParty: Gitlab/HTTParty:
Enabled: true Enabled: true
Exclude: Exclude:
@ -218,6 +222,12 @@ ActiveRecordAssociationReload:
- 'spec/**/*' - 'spec/**/*'
- 'ee/spec/**/*' - 'ee/spec/**/*'
Naming/PredicateName:
Enabled: true
Exclude:
- 'spec/**/*'
- 'ee/spec/**/*'
RSpec/FactoriesInMigrationSpecs: RSpec/FactoriesInMigrationSpecs:
Enabled: true Enabled: true
Include: Include:

View file

@ -273,11 +273,6 @@ RSpec/ContextWording:
RSpec/EmptyLineAfterFinalLet: RSpec/EmptyLineAfterFinalLet:
Enabled: false Enabled: false
# Offense count: 232
# Cop supports --auto-correct.
RSpec/EmptyLineAfterSubject:
Enabled: false
# Offense count: 719 # Offense count: 719
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
@ -442,19 +437,6 @@ Rails/LinkToBlank:
- 'ee/app/helpers/ee/user_callouts_helper.rb' - 'ee/app/helpers/ee/user_callouts_helper.rb'
- 'ee/app/helpers/license_helper.rb' - 'ee/app/helpers/license_helper.rb'
# Offense count: 11
# Cop supports --auto-correct.
Rails/Presence:
Exclude:
- 'app/models/ci/pipeline.rb'
- 'app/models/concerns/mentionable.rb'
- 'app/models/project_services/hipchat_service.rb'
- 'app/models/project_services/irker_service.rb'
- 'app/models/project_services/jira_service.rb'
- 'app/models/project_services/packagist_service.rb'
- 'app/models/wiki_page.rb'
- 'lib/gitlab/github_import/importer/releases_importer.rb'
# Offense count: 1 # Offense count: 1
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: Include. # Configuration parameters: Include.

View file

@ -1,5 +0,0 @@
---
title: Render xml artifact files in GitLab
merge_request: 16790
author:
type: added

View file

@ -1,10 +1,10 @@
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
## 12.3.8 ## 12.4.5
- No changes. - No changes.
## 12.3.7 ## 12.4.4
### Security (6 changes) ### Security (6 changes)
@ -16,19 +16,143 @@ Please view this file on the master branch, on stable branches it's out of date.
- Prevent IDOR when adding users to protected environments. - Prevent IDOR when adding users to protected environments.
## 12.3.6 ## 12.4.3
### Security (4 changes) ### Fixed (2 changes)
- Fix admin welcome image not found. !19676
- Revert ES support for public/internal project snippets. !19715
## 12.4.2
### Fixed (1 change)
- Fix feature flag check for productivity analytics. !19025
## 12.4.1
### Security (6 changes)
- Do not display project labels that are not visible for user accessing group labels.
- Do not index system notes for issue update. - Do not index system notes for issue update.
- Redact search results based on Ability.allowed?. - Redact search results based on Ability.allowed?.
- Do not show private cross references in epic notes. - Do not show private cross references in epic notes.
- Filter out packages the user does'nt have permission to see at group level. - Filter out packages the user does'nt have permission to see at group level.
- Fixes a Open Redirect issue in `InternalRedirect`.
## 12.3.5 ## 12.4.0
### Security (2 changes)
- Prevent IDOR when adding groups to protected environments.
- Hide approvers if a rule has any hidden groups.
### Removed (1 change)
- Remove db_load_balancing_index gauge metric. !17561
### Fixed (26 changes, 1 of them is from the community)
- Admin settings errors now shown in the correct panel. !14374
- Add missing error handling for epic quick actions. !15648
- Fix project exports clobbering concurrent export paths. !16280
- Fixes scroll handle icon in time series. !16354
- Remove hardcoded Medium confidence for Container Scanning vulnerabilities. !16395
- Fixed renaming changed files. !16539
- Fix project-defined metrics dashboards not rendering. !16589
- Remove duplication of Licenses in Dependency List page. !16946
- Backfill SPDX identifiers in software_licenses table. !17004
- Monitor charts: Validate form for creating an alert before submitting. !17109
- Hide Push rules link when you dont have a license installed. !17530
- Operations Dashboard: fix minimum query message. !17574
- Fix page layout for sidebar on designs view. !17579
- Display error for invalid insights config. !17589
- Display appropriate approval status icon next to license. !17613
- Fix deduplication of WASC vulnerabilities in the Security dashboard. !17778
- Fix burndown negative count edge case. !18053
- Change design management empty state button style. !18060 (George Tsiolis)
- Decouple dependency list parser from v1.0 license scanning report. !18103
- Respect Group SSO Enforcement on projects where the user is an owner. !18154
- Scoped labels do not remove old label in board sidebar. !18313
- Restrict number of users input to positive numbers. !18381
- Fix undefined method log_geo_deleted_event for MergeRequestDiff. !18405
- Add default empty values to prevent parser errors from approving the Vulnerability-Check rule. !18423
- Fix time tracking info when the sidebar is collapsed.
- Fix Discussion tab counter on Issues.
### Changed (18 changes, 1 of them is from the community)
- Style burndown charts with gitlab-ui. !15463
- Add epic_iid parameter to issues API. !15640
- Use a single badge to show number of active alerts on metrics dashboards. !15789
- Allow files with .svg extensions to be uploaded as designs for Design Management. !16160
- Implement dismissal behaviour when dismissed vulnerabilities are hidden. !16207
- Remove environment_metrics_show_multiple_dashboards feature flag. !16640
- Make name an optional parameter of releases. !16647
- Expose epics closed_at on API. !17156
- Add static_context API param when editing GitHub project service. !17397
- Support variable expansion in branch property of bridge jobs. !17430
- Add environment dropdown to pod logs screen. !17532
- Parse v2 license scanning reports. !17646
- Remove broken HTML5 routing behaviour from Pipeline Security Dashboard. !17767
- Change Prometheus Alert details list from bulleted to description list. !18116 (Vitali Tatarintev)
- Check for software license violations using SPDX identifiers. !18300
- Move 'Advanced search' message to search page title. !18349
- Add alert message for feature 'require approval from code owners' being moved. !18715
- Enable Productivity Analytics feature by default. !18754
### Performance (1 change)
- Reduce excessive GC on pull mirrors. !17931
### Added (35 changes)
- Allow Design Management files and data to be included in the project exporter/importer. !14702
- Create system notes for design events. !14791
- Paginate SCIM responses using count and startIndex. !14892
- Front-End UI for design deletion. !15034
- Add max issue count to lists. !15116
- Sign in / sign up step for trial. !15289
- Add notification for updated privacy policy. !15435
- Show Billing Plan as Cards in profile and groups. !15437
- Add Audit Event API. !15698
- Add configurable Code Owner approvals for protected branches. !15862
- Add Alerts Service to Projects. !16117
- Add Conan check_credentials API endpoint. !16215
- Initial endpoint for exposing Cycle Analytics stages for the new frontend. !16240
- Add ability to multi select issue board cards. !16317
- Add License-Check approval UI. !16371
- Add links to associated releases on Tags page. !16479
- Frontend implementation for improved trial sign-up experience for GitLab.com (SaaS) users. !16732
- Return Todos for Designs via the REST API. !16885
- Set active insights dashboard tab from hash fragment. !16904
- Extend group IP restriction to Git activity. !16980
- Inactivate pipeline retries for Merge Trains. !17065
- Expose time when the build was generated. !17113
- Add new table for recording commit counts per file. !17277
- Add vendored template for Browser Performance Testing. !17319
- Link Gitlab managed Prometheus alerts and issues. !17477
- Disable insights tab navigation whilst current page loads. !17678
- Drop all merge requests from merge trains when the project-level setting is disabled. !17774
- Implement DAST for default branches. !17789
- Add rack attack settings for prometheus and generic alert endpoint. !17859
- Add Licenses list backend usage ping. !17925
- Associate self-managed Prometheus Alerts and Issues. !18046
- Operator can see all projects using an instance level cluster. !18173
- Expose subscribed attribute for Epics in GraphQL. !18607
- Expose epic participants on GraphQL. !18691
- Adds a generic alert integration which can accept alerts from any source via a generic webhook receiver.
### Other (4 changes)
- Productivity analytics: Add scatterplot. !15569
- Updated sidebar navigation icons to be horizontally centered when bar is condensed. !16820
- Pin major version of SAST analyzers. !17110
- Docs for protected branch code owner approval API. !17132
- No changes.
## 12.3.4 ## 12.3.4
@ -38,13 +162,6 @@ Please view this file on the master branch, on stable branches it's out of date.
- Geo: LFS not being synced. !17633 - Geo: LFS not being synced. !17633
## 12.3.3
### Security (1 change)
- Restrict access for security reports in MR widget.
## 12.3.2 ## 12.3.2
### Security (2 changes) ### Security (2 changes)
@ -240,6 +357,29 @@ Please view this file on the master branch, on stable branches it's out of date.
- Fixes style-lint errors and warnings for EE builds.scss file. - Fixes style-lint errors and warnings for EE builds.scss file.
## 12.2.8
### Fixed (1 change)
- Geo: LFS not being synced. !17633
## 12.2.7
### Security (1 change)
- Restrict access for security reports in MR widget.
## 12.2.6
### Security (3 changes)
- Hide approvers if a rule has any hidden groups.
- Fix Gitaly SearchBlobs flag RPC injection [Gitaly v1.59.3].
- Prevent IDOR when adding groups to protected environments.
## 12.2.5 ## 12.2.5
### Security (1 change) ### Security (1 change)
@ -492,6 +632,27 @@ Please view this file on the master branch, on stable branches it's out of date.
- Fix alignment of activity dropdown in epic tabs; add counter to discussion tab. - Fix alignment of activity dropdown in epic tabs; add counter to discussion tab.
## 12.1.14
### Fixed (1 change)
- Geo: LFS not being synced. !17633
## 12.1.12
### Security (4 changes)
- Hide approvers if a rule has any hidden groups.
- Fix Gitaly SearchBlobs flag RPC injection [Gitaly v1.53.4].
- Prevent IDOR when adding groups to protected environments.
- Upgrade mermaid to prevent XSS.
## 12.1.10
- No changes.
## 12.1.5 ## 12.1.5
- No changes. - No changes.
@ -4264,7 +4425,7 @@ Please view this file on the master branch, on stable branches it's out of date.
## 8.14.0 (2016-11-22) ## 8.14.0 (2016-11-22)
- Added Backfill service for Geo. !861 - Added Backfill service for Geo. !861
- Fix for autosuggested approvers(https://gitlab.com/gitlab-org/gitlab-ee/issues/1273). - Fix for autosuggested approvers(https://gitlab.com/gitlab-org/gitlab/issues/1273).
- Gracefully recover from previously failed rebase. - Gracefully recover from previously failed rebase.
- Disable retries for remote mirror update worker. !848 - Disable retries for remote mirror update worker. !848
- Fix Approvals API documentation. - Fix Approvals API documentation.

View file

@ -2,15 +2,15 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 12.3.9 ## 12.4.6
- No changes. - No changes.
## 12.3.8 ## 12.4.5
- No changes. - No changes.
## 12.3.7 ## 12.4.4
### Security (12 changes) ### Security (12 changes)
@ -28,13 +28,43 @@ entry.
- Add authorization to using filter vulnerable in Dependency List. - Add authorization to using filter vulnerable in Dependency List.
## 12.3.6 ## 12.4.3
### Security (15 changes) ### Fixed (2 changes)
- Only enable protected paths for POST requests. !19184
- Fix Bitbucket Cloud importer pull request state. !19734
## 12.4.2
### Fixed (10 changes)
- Increase timeout for FetchInternalRemote RPC call. !18908
- Clean up duplicate indexes on ci_trigger_requests. !19053
- Fix project imports not working with serialized data. !19124
- Fixed welcome screen icons not showing. !19148
- Disable protected path throttling by default. !19185
- Fix Prometheus duplicate metrics. !19327
- Fix ref switcher not working on Microsoft Edge. !19335
- Extend gRPC timeouts for Rake tasks. !19461
- Disable upload HTTP caching to fix case when object storage is enabled and proxy_download is disabled. !19494
- Removes arrow icons for old collapsible sections.
### Changed (2 changes)
- Increased deactivation threshold to 180 days. !18902
- Add extra sentence about registry to AutoDevOps popup. !19092
## 12.4.1
### Security (14 changes)
- Standardize error response when route is missing. - Standardize error response when route is missing.
- Do not display project labels that are not visible for user accessing group labels. - Do not display project labels that are not visible for user accessing group labels.
- Show cross-referenced label and milestones in issues' activities only to authorized users. - Show cross-referenced label and milestones in issues' activities only to authorized users.
- Show cross-referenced label and milestones in issues' activities only to authorized users.
- Analyze incoming GraphQL queries and check for recursion. - Analyze incoming GraphQL queries and check for recursion.
- Disallow unprivileged users from commenting on private repository commits. - Disallow unprivileged users from commenting on private repository commits.
- Don't allow maintainers of a target project to delete the source branch of a merge request from a fork. - Don't allow maintainers of a target project to delete the source branch of a merge request from a fork.
@ -44,16 +74,326 @@ entry.
- Mask sentry auth token in Error Tracking dashboard. - Mask sentry auth token in Error Tracking dashboard.
- Fixes a Open Redirect issue in `InternalRedirect`. - Fixes a Open Redirect issue in `InternalRedirect`.
- Remove deploy access level when project/group link is deleted. - Remove deploy access level when project/group link is deleted.
- Sanitize search text to prevent XSS.
- Sanitize all wiki markup formats with GitLab sanitization pipelines. - Sanitize all wiki markup formats with GitLab sanitization pipelines.
- Fix stored XSS issue for grafana_url.
## 12.3.5 ## 12.4.0
### Security (1 change) ### Security (14 changes)
- HTML-escape search term in empty message. !18319
- Fix private feature Elasticsearch leak.
- Prevent bypassing email verification using Salesforce.
- Fix new project path being disclosed through unsubscribe link of issue/merge requests.
- Do not show resource label events referencing not accessible labels.
- Check permissions before showing head pipeline blocking merge requests.
- Cancel all running CI jobs triggered by the user who is just blocked.
- Do not disclose project milestones on group milestones page when project milestones access is disabled in project settings.
- Display only participants that user has permission to see on milestone page.
- Fix Gitaly SearchBlobs flag RPC injection.
- Add a policy check for system notes that may not be visible due to cross references to private items.
- Limit search for IID to a type to avoid leaking records with the same IID that the user does not have access to. - Limit search for IID to a type to avoid leaking records with the same IID that the user does not have access to.
- Prevent GitLab accounts takeover if SAML is configured.
- Only render fixed number of mermaid blocks.
### Fixed (103 changes, 12 of them are from the community)
- When user toggles task list item, keep details open until user closes the details manually. !16153
- Fix formatting welcome screen external users. !16667
- Fix signup link in admin area not being disabled. !16726 (Illya Klymov)
- Fix routing bugs in security dashboards. !16738
- Fix Jira integration favicon image with relative URL. !16802
- Add timeout mechanism for CI config validation. !16807
- Fix for count in todo badge when user has over 1,000 todos. Will now correctly display todo count after user marks some todos as done. !16844 (Jesse Hall @jessehall3)
- Naming a project "shared" will no longer automatically open the "Shared Projects" tab. !16847 (Jesse Hall @jessehall3)
- Adds the ability to delete single tags from the docker registry. Fix the issue that caused all related tags and image to be deleted at the same time. !16886
- Changed confidential quick action to only be available on non confidential issues. !16902 (Marc Schwede)
- Stop sidebar icons from jumping when expanded & collapsed. !16971
- Set name and updated_at properly in GitHub ReleaseImporter. !17020
- Remove thin white line at top of diff view code blocks. !17026
- Show correct CI indicator when build succeeded with warnings. !17034
- Create a persistent ref per pipeline for keeping pipelines run from force-push and merged results. !17043
- Move SMAU usage counters to the UsageData count field. !17074
- Allow maintainers to toggle write permission for public deploy keys. !17210
- Fix GraphQL for read-only instances. !17225
- Fix visibility level error when updating group from API. !17227 (Mathieu Parent)
- Fix stylelint errors in epics.scss. !17243
- Fix new discussion replies sometimes showing up twice. !17255
- Adjust unnapliable suggestions in expanded lines. !17286
- Show all groups user belongs to in Notification settings. !17303
- Alphabetically sorts selected sidebar labels. !17309
- Show issue weight when weight is 0. !17329 (briankabiro)
- Generate LFS token authorization for user LFS requests. !17332
- Backfill releases table updated_at column and add not null constraints to created_at and updated_at. !17400
- Log Sidekiq exceptions properly in JSON format. !17412
- Redo fix for related issues border radius. !17480
- Show the original branch name and link of merge request in pipeline emails. !17513
- Fixes issues with the security reports migration. !17519
- Users can view the blame or history of a file with newlines in its filename. !17543 (Jesse Hall @jessehall3)
- Display reCAPTCHA modal when making issue public. !17553
- Fix css selector for details in issue description. !17557
- Prevents a group path change when a project inside the group has container registry images. !17583
- Show 20 labels in dropdown instead of 5. !17596
- Nullify platform Kubernetes namespace if blank. !17657
- Fix Issue: WebIDE asks for confirmation to leave the page when committing and creating a new MR. !17671
- Catch unhandled exceptions in health checks. !17694
- Suppress error messages shown when navigating to a new page. !17706
- Specify sort order explicitly for Group and Project audit events. !17739
- Merge Request: Close JIRA issues when issues are disabled. !17743
- Disable gitlab-workhorse static error page on health endpoints. !17770
- Fix notes race condition when linking to specific note. !17777
- Fix relative positioning when moving items down and there is no space. !17781
- Fix project imports for pipelines for merge requests. !17799
- Increase the limit of includes in CI file to 100. !17807
- Geo: Fix race condition for container synchronization. !17823
- Geo: Invalidate cache after refreshing foreign tables. !17885
- Abort Merge When Pipeline Succeeds when Fast Forward merge is impossible. !17886
- Fix viewing merge reqeust from a fork that's being deleted. !17894
- Fix empty security dashboard for public projects. !17915
- Fix inline rendering of videos for uploads with uppercase file extensions. !17924
- Hide redundant labels in issue boards. !17937
- Time window filter in monitor dashboard gets reset. !17972
- Use cache_method_asymmetrically with Repository#has_visible_content?. !17975
- Allow users to compare Git revisions on a read-only instance. !18038
- Enable Google API retries for uploads. !18040
- Fix bug with new wiki not being indexed. !18051
- Stops the expand button in reports from expanding. !18064
- Make sure project insights stick on its own. !18082
- Embed metrics time window scroll no longer affects other embeds. !18109
- Fix broken notes avatar rendering in Chrome 77. !18110
- Ignore incoming emails with X-Autoreply header. !18118
- Enable grid, frame and stripes styling on AsciiDoc tables. !18165 (Guillaume Grossetie)
- Add backend support for selecting custom templates by ID. !18178
- Fix notifications for private group mentions in Notes, Issues, and Merge Requests. !18183
- Do not strip forwarded message body when creating an issue from Service Desk email. !18196
- Fix protected branch detection used by notification service. !18221
- Fix error where helper was incorrectly returning `true`. !18231
- Adjust placeholder to solve misleading regex. !18235
- Fix Flaky spec/finders/members_finder_spec.rb:85. !18257 (Jacopo Beschi @jacopo-beschi)
- Fix 500 error on clicking to LetsEncrypt Terms of Service. !18263
- Fix error tracking table layout on small screens. !18325
- GitHub import: Handle nil published_at dates. !18355
- Do not allow deactivated users to use slash commands. !18365
- Fix creating epics with dates from api. !18393
- JIRA Service: Improve username/email validation. !18397
- Stopped CRD apply retrying from allowing silent failures. !18421
- Fix erroneous "No activities found" message. !18434
- Support ES searches for project snippets. !18459
- Fix styling of set status emoji picker. !18509
- Fix showing diff when it has legacy diff notes. !18510
- JIRA Integration API URL works having a trailing slash. !18526
- Fixes embedded metrics chart tooltip spacing. !18543
- Bump GITLAB_ELASTICSEARCH_INDEXER_VERSION=v1.4.0. !18558
- Fix pod logs failure when pod contains more than 1 container. !18574
- Prevent the slash command parser from removing leading whitespace from content that is unrelated to slash commands. !18589 (Jared Deckard)
- Fix inability to set snippet visibility via API. !18612
- Fix Web IDE tree not updating modified status. !18647
- Fix button link foreground color. !18669
- Resolve missing design system notes icons. !18693
- Remove duplicate primary button in dashboard snippets. !32048 (George Tsiolis)
- Allow to view productivity analytics page without a license. !33876
- Fix container registry delete tag modal title and button. !34032
- Fixes variables overflowing in sm screens.
- Update top nav bar to fit all content in at all screen sizes.
- Fix permissions for group milestones.
- Removes Collapsible Sections from Job Log.
- Fixes job overflow in stages dropdown.
- Fix moved help URL for monitoring performance.
- Fix issue with wiki TOC links being treated as external links. (Oren Kanner)
- Show error message when setting an invalid group ID for the performance bar.
### Deprecated (1 change)
- Removing cleanup:repo, cleanup:dirs. !18087
### Changed (51 changes, 3 of them are from the community)
- Links on Releases page to commits and tags. !16128
- Add status to deployments and state to environments in API responses. !16242
- Use search scope label in empty results message. !16324
- Add step 2 of the experimental signup flow. !16583
- Add property to enable metrics dashboards to be rearranged. !16605
- Allow intra-project MR dependencies. !16799
- Use scope param instead of hide_dismissed. !16834
- Add empty state in file search. !16851
- Warn before applying issue templates. !16865
- MR Test Summary now shows errors as failures. !17039
- Add support for the association of multiple milestones to the Releases page. !17091
- Display if an issue was moved in issue list. !17102
- Improve UI for admin/projects and group/settings/projects pages. !17247
- Update registry tag delete popup message. !17257
- Show the "Set up CI/CD" prompt in empty repositories when applicable. !17274 (Ben McCormick)
- Knative version bump 0.6 -> 0.7. !17367 (Chris Baumbauer)
- Fix usability problems with the file template picker. !17522
- Make commit status created for any pipelines. !17524 (Aufar Gilbran)
- Add warnings to performance bar when page shows signs of poor performance. !17612
- Banners should only be dismissable by clicking x button. !17642
- Changes response body of liveness check to be more accurate. !17655
- Enable Request Access functionality by default for new projects and groups. !17662
- Add more attributes to issues GraphQL endpoint. !17802
- Improve admin/system_info page ui. !17829
- Adds management project for a cluster. !17866
- Upgrade gitlab-workhorse to 8.12.0. !17892
- Geo: Fix instruction from rake geo:gitlab:check. !17895
- Upgrade to Gitaly v1.66.0. !17900
- Do not start mirroring via API when paused. !17930
- Use MR links in PipelinePresenter#ref_text for branch pipelines. !17947
- Avoid knative and prometheus uninstall race condition. !18020
- Deprecate usage of state column for issues and merge requests. !18099
- Add missing page title to projects/container-registry. !18114
- Port over EE pipeline functionality to CE. !18136
- Aggregate push events when there are too many. !18239
- Cleanup background migrations for any approval rules. !18256
- Container registry tag(s) delete button pluralization. !18260
- Create clusters with VPC-Native enabled. !18284
- Update cluster link text. !18322
- Upgrade to Gitaly v1.67.0. !18326
- Improve UI of documentation under /help. !18331
- Cross-link unreplicated Geo types to issues. !18443
- Make designs read-only if the issue has been moved, or if its discussion has been locked. !18551
- Do not show new issue button on archived projects. !18590
- Increase group avatar size to 40px. !18654
- Sort vulnerabilities by severity then confidence for dashboard and pipeline views. !18675
- Add timeouts for each RPC call. !31766
- Add more specific message to clarify the role of empty images in container registry. !32919
- Embed Jaeger in Gitlab UI.
- Use text instead of icon for recent searches dropdown.
- Export liveness and readiness probes.
### Performance (25 changes, 1 of them is from the community)
- Limit diverging commit counts requests. !16737
- Use GetBlobs RPC for uri type. !16824
- Reduce Gitaly calls when viewing a commit. !17095
- Limit snippets search count. !17585
- Narrow snippet search scope in GitLab.com. !17625
- Handle wiki and graphql attachments in gitlab-workhorse. !17690
- Reduce lock contention of deployment creation by allocating IID outside of the pipeline transaction. !17696
- Update PumaWorkerKiller defaults. !17758
- Add trigram index on snippet content. !17806
- Fix Gitaly N+1 queries in related merge requests API. !17850
- Don't execute webhooks/services when above limit. !17874
- Only schedule updating push-mirrors once per push. !17902
- Show only personal snippets on explore page. !18092
- Priority bump authorized_projects sidekiq queue. !18125
- Avoid dumping files on disk when direct_upload is enabled. !18135
- Check if mapping is empty before caching in File Collections. !18290 (briankabiro)
- Avoid unnecessary locks on internal_ids. !18328
- Fix N+1 queries in Jira Development Panel API endpoint. !18329
- Optimize SQL requests for BlameController and CommitsController. !18342
- Remove N+1 for fetching commits signatures. !18389
- Reduce idle in transaction time when updating a merge request. !18493
- Use cascading deletes for deleting logs upon deleting a webhook. !18642
- Replace index on ci_triggers. !18652
- Hide license breakdown in /admin if user count is high. !18825
- Cache branch and tag names as Redis sets. !30476
### Added (78 changes, 12 of them are from the community)
- Adds sorting of packages at the project level. !15448
- Add projects.only option to Insights. !15930
- Add kubernetes section to group runner settings. !16338
- Enable Cloud Run on GKE cluster creation. !16566
- Add file matching rule to flexible CI rules. !16574
- Enable preview of private artifacts. !16675 (Tuomo Ala-Vannesluoma)
- Upgrade Gitaly to v1.64. !16788
- Render xml artifact files in GitLab. !16790
- Add GitHub & Gitea importers project filtering. !16823
- Add project filtering to Bitbucket Cloud import. !16828
- Provides internationalization support to chart legends. !16832
- Expose name property in imports API. !16848
- Add allowFilter and allowAnySHA1InWant for partial clones. !16850
- [ObjectStorage] Allow migrating back to local storage. !16868
- Require admins to enter admin-mode by re-authenticating before performing administrative operations. !16981 (Roger Rüttimann & Diego Louzán)
- Deactivate a user (with self-service reactivation). !17037
- Add database tables to store AWS roles and cluster providers. !17057
- Collect docker registry related metrics. !17063
- Allow releases to be targeted by URL anchor links on the Releases page. !17150
- Add project_pages_metadata DB table. !17197
- Add index on ci_builds for successful Pages deploys. !17204
- Creation of Evidence collection of new releases. !17217
- API: Add missing group parameters. !17220 (Mathieu Parent)
- Allow to exclude ancestor groups on group labels API. !17221 (Mathieu Parent)
- Added 'copy link' in epic comment dropdown. !17224
- Add columns for per project/group max pages/artifacts sizes. !17231
- Create table for grafana api token for metrics embeds. !17234
- Add proper label REST API for update, delete and promote. !17239 (Mathieu Parent)
- Allow cross-project pipeline triggering with CI_JOB_TOKEN in core. !17251
- Add user_id and created_at columns to design_management_versions table. !17316
- Add pull_mirror_branch_prefix column on projects table. !17368
- Expose web_url for epics on API. !17380
- Improve time window filtering on metrics dashboard. !17554
- Group level Container Registry browser. !17615
- Add API for manually creating and updating deployments. !17620
- Introduce diffs_batch JSON endpoint for paginated diffs. !17651
- Web IDE button should fork and open forked project when selected from read-only project. !17672
- Allow users to be searched with a @ prefix. !17742
- Add individual inherited member lookup API. !17744
- Preserve custom .gitlab-ci.yml config path when forking. !17817 (Mathieu Parent)
- Introduce CI_PROJECT_TITLE as predefined environment variable. !17849 (Nejc Habjan)
- Feature enabling embedded audio elements in markdown. !17860 (Jesse Hall @jessehall3)
- Add 'New release' to the project custom notifications. !17877
- Added timestamps (created_at and updated_at) to API pipelines response. !17911
- Added timestamp (updated_at) to API deployments response. !17913
- Add pipeline preparing status icons. !17923
- Creates Vue and Vuex app to render exposed artifacts. !17934
- Add web_exporter to expose Prometheus metrics. !17943
- Schedule background migration to populate pages metadata. !17993
- Add "Edit Release" page. !18033
- Unpin ingress image version, upgrade chart to 1.22.1. !18047
- Adds sorting of packages at the group level. !18062
- Introduce a lightweight diffs_metadata endpoint. !18104
- Limit the number of comments on an issue, MR, or commit. !18111
- Introduce new Ansi2json parser to convert job logs to JSON. !18133
- Use new Ansi2json job log converter via feature flag. !18134
- Snowplow custom events for Monitor: Health Product Categories. !18157
- Support Create/Read/Destroy operations in Feature Flag API. !18198
- Add two new predefined stages to pipelines. !18205
- Add endpoint to proxy requests to grafana's proxy endpoint. !18210
- Add ability to query todos using GraphQL. !18218
- Include in the callout message a list of jobs that caused missing dependencies failure. !18219
- Adds login input with copy box and supporting copy to empty container registry view. !18244 (nate geslin)
- Add max_artifacts_size fields under project and group settings. !18286
- Provide Merge requests and Issue links through the Release API. !18311
- Adds separate parsers for mentions of users, groups, projects in markdown content. !18318
- Add matching branch info to branch column. !18352
- Users can preview audio files in a repository. !18354 (Jesse Hall @jessehall3)
- Add edit button to release blocks on Releases page. !18411
- Add "Custom HTTP Git clone URL root" setting. !18422
- Add support for epic update through GraphQL API. !18440
- Expose subscribed attribute for epic on API. !18475
- Geo: Enable replicating uploads, LFS objects, and artifacts in Object Storage. !18482
- Show related merge requests in pipeline view. !18697
- Allow users to configure protected paths from Admin panel. !31246
- persist the refs when open the link of refs in a new tab of browser. !31998 (minghuan lei)
- Add first_parent option to list commits api. !32410 (jhenkens)
- Allow users to add and remove zoom rooms on an issue using quick action commands.
### Other (23 changes, 5 of them are from the community)
- Sync issuables state_id with null values. !16480
- Experimental separate sign up flow. !16482
- Upgrade Rouge to v3.11.0. !17011
- Better job naming for Docker.gitlab-ci.yml. !17218 (luca.orlandi@gmail.com)
- Update GitLab Runner Helm Chart to 0.9.0. !17326
- Change welcome message and make translatable. !17391
- Remove map-get($grid-breakpoints, xs) for max-width. !17420 (Takuya Noguchi)
- Document Git LFS and max file size interaction. !17609
- Refactor email notification code. !17741 (briankabiro)
- Ignore id column of ci_build_trace_sections table. !17805
- Extend graphql query endpoint for merge requests to return more attributes to support sidebar implementation. !17813
- Project list: Align star icons. !17833
- Moves the license compliance reports to the Backend. !17905
- Fixes wrong link on Protected paths admin settings. !17945
- Update Pages to v1.11.0. !18010
- Refactor checksum code in uploads. !18065 (briankabiro)
- Make instance configuration user friendly. !18363 (Takuya Noguchi)
- Update Workhorse to v8.14.0. !18391
- Attribute each Sidekiq worker to a feature category. !18462
- Update GitLab Shell to v10.2.0. !18735
- Use correct icons for issue actions.
- Increase color contrast of select option path.
- Remove Postgresql specific setup tasks and move to schema.rb.
## 12.3.4 ## 12.3.4
@ -64,13 +404,6 @@ entry.
- Fix pipelines for merge requests in project exports. !17844 - Fix pipelines for merge requests in project exports. !17844
## 12.3.3
### Security (1 change)
- Fix private feature Elasticsearch leak.
## 12.3.2 ## 12.3.2
### Security (12 changes) ### Security (12 changes)
@ -368,6 +701,37 @@ entry.
- Updates tooltip of 'detached' label/state. - Updates tooltip of 'detached' label/state.
## 12.2.8
### Security (1 change)
- Limit search for IID to a type to avoid leaking records with the same IID that the user does not have access to.
## 12.2.7
### Security (1 change)
- Fix private feature Elasticsearch leak.
## 12.2.6
### Security (11 changes)
- Add a policy check for system notes that may not be visible due to cross references to private items.
- Display only participants that user has permission to see on milestone page.
- Do not disclose project milestones on group milestones page when project milestones access is disabled in project settings.
- Check permissions before showing head pipeline blocking merge requests.
- Fix new project path being disclosed through unsubscribe link of issue/merge requests.
- Prevent bypassing email verification using Salesforce.
- Do not show resource label events referencing not accessible labels.
- Cancel all running CI jobs triggered by the user who is just blocked.
- Fix Gitaly SearchBlobs flag RPC injection [Gitaly v1.59.3].
- Only render fixed number of mermaid blocks.
- Prevent GitLab accounts takeover if SAML is configured.
## 12.2.5 ## 12.2.5
### Security (1 change) ### Security (1 change)
@ -686,6 +1050,35 @@ entry.
- Update Packer.gitlab-ci.yml to use latest image. (Kelly Hair) - Update Packer.gitlab-ci.yml to use latest image. (Kelly Hair)
## 12.1.14
### Security (1 change)
- Limit search for IID to a type to avoid leaking records with the same IID that the user does not have access to.
## 12.1.12
### Security (12 changes)
- Add a policy check for system notes that may not be visible due to cross references to private items.
- Display only participants that user has permission to see on milestone page.
- Do not disclose project milestones on group milestones page when project milestones access is disabled in project settings.
- Check permissions before showing head pipeline blocking merge requests.
- Fix new project path being disclosed through unsubscribe link of issue/merge requests.
- Prevent bypassing email verification using Salesforce.
- Do not show resource label events referencing not accessible labels.
- Cancel all running CI jobs triggered by the user who is just blocked.
- Fix Gitaly SearchBlobs flag RPC injection.
- Only render fixed number of mermaid blocks.
- Prevent GitLab accounts takeover if SAML is configured.
- Upgrade mermaid to prevent XSS.
## 12.1.10
- No changes.
## 12.1.5 ## 12.1.5
### Security (2 changes) ### Security (2 changes)
@ -8450,7 +8843,7 @@ entry.
- Reinstate is_admin flag in users api when authenticated user is an admin. !12211 (rickettm) - Reinstate is_admin flag in users api when authenticated user is an admin. !12211 (rickettm)
- Fix edit button for deploy keys available from other projects. !12301 (Alexander Randa) - Fix edit button for deploy keys available from other projects. !12301 (Alexander Randa)
- Fix passing CI_ENVIRONMENT_NAME and CI_ENVIRONMENT_SLUG for CI_ENVIRONMENT_URL. !12344 - Fix passing CI_ENVIRONMENT_NAME and CI_ENVIRONMENT_SLUG for CI_ENVIRONMENT_URL. !12344
- Disable environment list refresh due to bug https://gitlab.com/gitlab-org/gitlab-ee/issues/2677. !12347 - Disable environment list refresh due to bug https://gitlab.com/gitlab-org/gitlab/issues/2677. !12347
- Standardize timeline note margins across different viewport sizes. !12364 - Standardize timeline note margins across different viewport sizes. !12364
- Fix Ordered Task List Items. !31483 (Jared Deckard <jared.deckard@gmail.com>) - Fix Ordered Task List Items. !31483 (Jared Deckard <jared.deckard@gmail.com>)
- Upgrade dependency to Go 1.8.3. !31943 - Upgrade dependency to Go 1.8.3. !31943

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative 'lib/gitlab_danger' require_relative 'lib/gitlab_danger'
require_relative 'lib/gitlab/danger/request_helper'
danger.import_plugin('danger/plugins/helper.rb') danger.import_plugin('danger/plugins/helper.rb')
danger.import_plugin('danger/plugins/roulette.rb') danger.import_plugin('danger/plugins/roulette.rb')

View file

@ -1 +1 @@
1.65.2 1.67.1

View file

@ -1 +1 @@
1.3.0 1.4.0

View file

@ -1 +1 @@
1.9.0 1.11.0

View file

@ -1 +1 @@
10.0.0 10.2.0

View file

@ -1 +1 @@
8.10.1 8.14.1

16
Gemfile
View file

@ -87,9 +87,9 @@ gem 'rack-cors', '~> 1.0.0', require: 'rack/cors'
# GraphQL API # GraphQL API
gem 'graphql', '~> 1.9.11' gem 'graphql', '~> 1.9.11'
# NOTE: graphiql-rails v1.5+ doesn't work: https://gitlab.com/gitlab-org/gitlab-ce/issues/67293 # NOTE: graphiql-rails v1.5+ doesn't work: https://gitlab.com/gitlab-org/gitlab/issues/31771
# TODO: remove app/views/graphiql/rails/editors/show.html.erb when https://github.com/rmosolgo/graphiql-rails/pull/71 is released: # TODO: remove app/views/graphiql/rails/editors/show.html.erb when https://github.com/rmosolgo/graphiql-rails/pull/71 is released:
# https://gitlab.com/gitlab-org/gitlab-ce/issues/67263 # https://gitlab.com/gitlab-org/gitlab/issues/31747
gem 'graphiql-rails', '~> 1.4.10' gem 'graphiql-rails', '~> 1.4.10'
gem 'apollo_upload_server', '~> 2.0.0.beta3' gem 'apollo_upload_server', '~> 2.0.0.beta3'
gem 'graphql-docs', '~> 1.6.0', group: [:development, :test] gem 'graphql-docs', '~> 1.6.0', group: [:development, :test]
@ -148,7 +148,7 @@ gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 2.0.10' gem 'asciidoctor', '~> 2.0.10'
gem 'asciidoctor-include-ext', '~> 0.3.1', require: false gem 'asciidoctor-include-ext', '~> 0.3.1', require: false
gem 'asciidoctor-plantuml', '0.0.9' gem 'asciidoctor-plantuml', '0.0.9'
gem 'rouge', '~> 3.7' gem 'rouge', '~> 3.11.0'
gem 'truncato', '~> 0.7.11' gem 'truncato', '~> 0.7.11'
gem 'bootstrap_form', '~> 4.2.0' gem 'bootstrap_form', '~> 4.2.0'
gem 'nokogiri', '~> 1.10.4' gem 'nokogiri', '~> 1.10.4'
@ -311,7 +311,7 @@ gem 'gettext', '~> 3.2.2', require: false, group: :development
gem 'batch-loader', '~> 1.4.0' gem 'batch-loader', '~> 1.4.0'
# Perf bar # Perf bar
# https://gitlab.com/gitlab-org/gitlab-ee/issues/13996 # https://gitlab.com/gitlab-org/gitlab/issues/13996
gem 'gitlab-peek', '~> 0.0.1', require: 'peek' gem 'gitlab-peek', '~> 0.0.1', require: 'peek'
# Snowplow events tracking # Snowplow events tracking
@ -355,7 +355,7 @@ group :development, :test do
gem 'fuubar', '~> 2.2.0' gem 'fuubar', '~> 2.2.0'
gem 'database_cleaner', '~> 1.7.0' gem 'database_cleaner', '~> 1.7.0'
gem 'factory_bot_rails', '~> 4.8.2' gem 'factory_bot_rails', '~> 5.1.0'
gem 'rspec-rails', '~> 3.8.0' gem 'rspec-rails', '~> 3.8.0'
gem 'rspec-retry', '~> 0.6.1' gem 'rspec-retry', '~> 0.6.1'
gem 'rspec_profiling', '~> 0.0.5' gem 'rspec_profiling', '~> 0.0.5'
@ -405,7 +405,7 @@ group :test do
gem 'webmock', '~> 3.5.1' gem 'webmock', '~> 3.5.1'
gem 'rails-controller-testing' gem 'rails-controller-testing'
gem 'concurrent-ruby', '~> 1.1' gem 'concurrent-ruby', '~> 1.1'
gem 'test-prof', '~> 0.2.5' gem 'test-prof', '~> 0.10.0'
gem 'rspec_junit_formatter' gem 'rspec_junit_formatter'
end end
@ -446,7 +446,7 @@ group :ed25519 do
end end
# Gitaly GRPC protocol definitions # Gitaly GRPC protocol definitions
gem 'gitaly', '~> 1.58.0' gem 'gitaly', '~> 1.65.0'
gem 'grpc', '~> 1.19.0' gem 'grpc', '~> 1.19.0'
@ -465,7 +465,7 @@ gem 'lograge', '~> 0.5'
gem 'grape_logging', '~> 1.7' gem 'grape_logging', '~> 1.7'
# DNS Lookup # DNS Lookup
gem 'net-dns', '~> 0.9.0' gem 'gitlab-net-dns', '~> 0.9.1'
# Countries list # Countries list
gem 'countries', '~> 3.0' gem 'countries', '~> 3.0'

View file

@ -108,7 +108,7 @@ GEM
binding_ninja (0.2.3) binding_ninja (0.2.3)
binding_of_caller (0.8.0) binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
bootsnap (1.4.4) bootsnap (1.4.5)
msgpack (~> 1.0) msgpack (~> 1.0)
bootstrap_form (4.2.0) bootstrap_form (4.2.0)
actionpack (>= 5.0) actionpack (>= 5.0)
@ -209,10 +209,10 @@ GEM
descendants_tracker (0.0.4) descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
device_detector (1.0.0) device_detector (1.0.0)
devise (4.6.2) devise (4.7.1)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0, < 6.0) railties (>= 4.1.0)
responders responders
warden (~> 1.2.3) warden (~> 1.2.3)
devise-two-factor (3.0.0) devise-two-factor (3.0.0)
@ -254,7 +254,7 @@ GEM
mail (~> 2.7) mail (~> 2.7)
encryptor (3.0.0) encryptor (3.0.0)
equalizer (0.0.11) equalizer (0.0.11)
erubi (1.8.0) erubi (1.9.0)
escape_utils (1.2.1) escape_utils (1.2.1)
et-orbi (1.2.1) et-orbi (1.2.1)
tzinfo tzinfo
@ -264,11 +264,11 @@ GEM
expression_parser (0.9.0) expression_parser (0.9.0)
extended-markdown-filter (0.6.0) extended-markdown-filter (0.6.0)
html-pipeline (~> 2.0) html-pipeline (~> 2.0)
factory_bot (4.8.2) factory_bot (5.1.0)
activesupport (>= 3.0.0) activesupport (>= 4.2.0)
factory_bot_rails (4.8.2) factory_bot_rails (5.1.0)
factory_bot (~> 4.8.2) factory_bot (~> 5.1.0)
railties (>= 3.0.0) railties (>= 4.2.0)
faraday (0.12.2) faraday (0.12.2)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
faraday-http-cache (2.0.0) faraday-http-cache (2.0.0)
@ -358,7 +358,7 @@ GEM
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
git (1.5.0) git (1.5.0)
gitaly (1.58.0) gitaly (1.65.0)
grpc (~> 1.0) grpc (~> 1.0)
github-markup (1.7.0) github-markup (1.7.0)
gitlab-labkit (0.5.2) gitlab-labkit (0.5.2)
@ -370,6 +370,7 @@ GEM
redis (> 3.0.0, < 5.0.0) redis (> 3.0.0, < 5.0.0)
gitlab-license (1.0.0) gitlab-license (1.0.0)
gitlab-markup (1.7.0) gitlab-markup (1.7.0)
gitlab-net-dns (0.9.1)
gitlab-peek (0.0.1) gitlab-peek (0.0.1)
railties (>= 4.0.0) railties (>= 4.0.0)
gitlab-sidekiq-fetcher (0.5.2) gitlab-sidekiq-fetcher (0.5.2)
@ -487,7 +488,7 @@ GEM
mime-types (~> 3.0) mime-types (~> 3.0)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
httpclient (2.8.3) httpclient (2.8.3)
i18n (1.6.0) i18n (1.7.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n_data (0.8.0) i18n_data (0.8.0)
icalendar (2.4.1) icalendar (2.4.1)
@ -565,7 +566,7 @@ GEM
activesupport (>= 4) activesupport (>= 4)
railties (>= 4) railties (>= 4)
request_store (~> 1.0) request_store (~> 1.0)
loofah (2.2.3) loofah (2.3.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.7.1) mail (2.7.1)
@ -586,7 +587,7 @@ GEM
mini_mime (1.0.1) mini_mime (1.0.1)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
minitest (5.11.3) minitest (5.11.3)
msgpack (1.3.0) msgpack (1.3.1)
multi_json (1.13.1) multi_json (1.13.1)
multi_xml (0.6.0) multi_xml (0.6.0)
multipart-post (2.0.0) multipart-post (2.0.0)
@ -596,7 +597,6 @@ GEM
mustermann (~> 1.0.0) mustermann (~> 1.0.0)
nakayoshi_fork (0.0.4) nakayoshi_fork (0.0.4)
nap (1.1.0) nap (1.1.0)
net-dns (0.9.0)
net-ldap (0.16.0) net-ldap (0.16.0)
net-ntp (2.1.3) net-ntp (2.1.3)
net-ssh (5.2.0) net-ssh (5.2.0)
@ -770,8 +770,8 @@ GEM
rails-dom-testing (2.0.3) rails-dom-testing (2.0.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.2.0) rails-html-sanitizer (1.3.0)
loofah (~> 2.2, >= 2.2.2) loofah (~> 2.3)
rails-i18n (5.1.1) rails-i18n (5.1.1)
i18n (>= 0.7, < 2) i18n (>= 0.7, < 2)
railties (>= 5.0, < 6) railties (>= 5.0, < 6)
@ -783,7 +783,7 @@ GEM
thor (>= 0.19.0, < 2.0) thor (>= 0.19.0, < 2.0)
rainbow (3.0.0) rainbow (3.0.0)
raindrops (0.19.0) raindrops (0.19.0)
rake (12.3.2) rake (12.3.3)
rb-fsevent (0.10.2) rb-fsevent (0.10.2)
rb-inotify (0.9.10) rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2) ffi (>= 0.5.0, < 2)
@ -824,9 +824,9 @@ GEM
declarative-option (< 0.2.0) declarative-option (< 0.2.0)
uber (< 0.2.0) uber (< 0.2.0)
request_store (1.3.1) request_store (1.3.1)
responders (2.4.0) responders (2.4.1)
actionpack (>= 4.2.0, < 5.3) actionpack (>= 4.2.0, < 6.0)
railties (>= 4.2.0, < 5.3) railties (>= 4.2.0, < 6.0)
rest-client (2.0.2) rest-client (2.0.2)
http-cookie (>= 1.0.2, < 2.0) http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0) mime-types (>= 1.16, < 4.0)
@ -834,7 +834,7 @@ GEM
retriable (3.1.2) retriable (3.1.2)
rinku (2.0.0) rinku (2.0.0)
rotp (2.1.2) rotp (2.1.2)
rouge (3.7.0) rouge (3.11.0)
rqrcode (0.7.0) rqrcode (0.7.0)
chunky_png chunky_png
rqrcode-rails3 (0.1.7) rqrcode-rails3 (0.1.7)
@ -994,7 +994,7 @@ GEM
temple (0.8.1) temple (0.8.1)
terminal-table (1.8.0) terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1) unicode-display_width (~> 1.1, >= 1.1.1)
test-prof (0.2.5) test-prof (0.10.0)
text (1.3.1) text (1.3.1)
thin (1.7.2) thin (1.7.2)
daemons (~> 1.0, >= 1.0.9) daemons (~> 1.0, >= 1.0.9)
@ -1058,8 +1058,8 @@ GEM
descendants_tracker (~> 0.0, >= 0.0.3) descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9) equalizer (~> 0.0, >= 0.0.9)
vmstat (2.3.0) vmstat (2.3.0)
warden (1.2.7) warden (1.2.8)
rack (>= 1.0) rack (>= 2.0.6)
webfinger (1.1.0) webfinger (1.1.0)
activesupport activesupport
httpclient (>= 2.4) httpclient (>= 2.4)
@ -1144,7 +1144,7 @@ DEPENDENCIES
email_reply_trimmer (~> 0.1) email_reply_trimmer (~> 0.1)
email_spec (~> 2.2.0) email_spec (~> 2.2.0)
escape_utils (~> 1.1) escape_utils (~> 1.1)
factory_bot_rails (~> 4.8.2) factory_bot_rails (~> 5.1.0)
faraday (~> 0.12) faraday (~> 0.12)
faraday_middleware-aws-signers-v4 faraday_middleware-aws-signers-v4
fast_blank fast_blank
@ -1168,11 +1168,12 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3) gettext_i18n_rails_js (~> 1.3)
gitaly (~> 1.58.0) gitaly (~> 1.65.0)
github-markup (~> 1.7.0) github-markup (~> 1.7.0)
gitlab-labkit (~> 0.5) gitlab-labkit (~> 0.5)
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
gitlab-markup (~> 1.7.0) gitlab-markup (~> 1.7.0)
gitlab-net-dns (~> 0.9.1)
gitlab-peek (~> 0.0.1) gitlab-peek (~> 0.0.1)
gitlab-sidekiq-fetcher (= 0.5.2) gitlab-sidekiq-fetcher (= 0.5.2)
gitlab-styles (~> 2.7) gitlab-styles (~> 2.7)
@ -1222,7 +1223,6 @@ DEPENDENCIES
mini_magick mini_magick
minitest (~> 5.11.0) minitest (~> 5.11.0)
nakayoshi_fork (~> 0.0.4) nakayoshi_fork (~> 0.0.4)
net-dns (~> 0.9.0)
net-ldap net-ldap
net-ntp net-ntp
net-ssh (~> 5.2) net-ssh (~> 5.2)
@ -1276,7 +1276,7 @@ DEPENDENCIES
redis-rails (~> 5.0.2) redis-rails (~> 5.0.2)
request_store (~> 1.3) request_store (~> 1.3)
responders (~> 2.0) responders (~> 2.0)
rouge (~> 3.7) rouge (~> 3.11.0)
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-parameterized rspec-parameterized
rspec-rails (~> 3.8.0) rspec-rails (~> 3.8.0)
@ -1314,7 +1314,7 @@ DEPENDENCIES
stackprof (~> 0.2.10) stackprof (~> 0.2.10)
state_machines-activerecord (~> 0.5.1) state_machines-activerecord (~> 0.5.1)
sys-filesystem (~> 1.1.6) sys-filesystem (~> 1.1.6)
test-prof (~> 0.2.5) test-prof (~> 0.10.0)
thin (~> 1.7.0) thin (~> 1.7.0)
timecop (~> 0.8.0) timecop (~> 0.8.0)
toml-rb (~> 1.0.0) toml-rb (~> 1.0.0)

View file

@ -11,15 +11,6 @@
- [Merge request coaching](#merge-request-coaching) - [Merge request coaching](#merge-request-coaching)
- [Assigning issues](#assigning-issues) - [Assigning issues](#assigning-issues)
- [Be kind](#be-kind) - [Be kind](#be-kind)
- [Feature freeze on the 7th for the release on the 22nd](#feature-freeze-on-the-7th-for-the-release-on-the-22nd)
- [Feature flags](#feature-flags)
- [Between the 1st and the 7th](#between-the-1st-and-the-7th)
- [What happens if these deadlines are missed?](#what-happens-if-these-deadlines-are-missed)
- [On the 7th](#on-the-7th)
- [Feature merge requests](#feature-merge-requests)
- [Documentation merge requests](#documentation-merge-requests)
- [After the 7th](#after-the-7th)
- [Asking for an exception](#asking-for-an-exception)
- [Bugs](#bugs) - [Bugs](#bugs)
- [Regressions](#regressions) - [Regressions](#regressions)
- [Managing bugs](#managing-bugs) - [Managing bugs](#managing-bugs)
@ -100,135 +91,6 @@ Product Managers must have their proposal for that milestone ready by the 22nd o
This proposal will be shared with Engineering for discussion, feedback, and planning. This proposal will be shared with Engineering for discussion, feedback, and planning.
The plan for the upcoming milestone must be finalized by the 1st of the month, one week before kickoff on the 8th. The plan for the upcoming milestone must be finalized by the 1st of the month, one week before kickoff on the 8th.
## Feature freeze on the 7th for the release on the 22nd
The feature freeze on the 7th has been discontinued. [Transition period overview](https://gitlab.com/gitlab-org/release/docs/blob/21cbd409dd5f157fe252f254f3e897f01908abe2/general/deploy/auto-deploy-transition.md#transition)
describes the change to this process. During the transition period, the only guarantee that
a change will be included in the release on the 22nd is if the change has been
deployed to GitLab.com prior to this date.
### Between the 1st and the 7th
These types of merge requests for the upcoming release need special consideration:
* **Large features**: a large feature is one that is highlighted in the kick-off
and the release blogpost; typically this will have its own channel in Slack
and a dedicated team with front-end, back-end, and UX.
* **Small features**: any other feature request.
It is strongly recommended that **large features** be with a maintainer **by the
1st**. This means that:
* There is a merge request (even if it's WIP).
* The person (or people, if it needs a frontend and backend maintainer) who will
ultimately be responsible for merging this have been pinged on the MR.
It's OK if merge request isn't completely done, but this allows the maintainer
enough time to make the decision about whether this can make it in before the
freeze. If the maintainer doesn't think it will make it, they should inform the
developers working on it and the Product Manager responsible for the feature.
The maintainer can also choose to assign a reviewer to perform an initial
review, but this way the maintainer is unlikely to be surprised by receiving an
MR later in the cycle.
It is strongly recommended that **small features** be with a reviewer (not
necessarily a maintainer) **by the 3rd**.
Most merge requests from the community do not have a specific release
target. However, if one does and falls into either of the above categories, it's
the reviewer's responsibility to manage the above communication and assignment
on behalf of the community member.
Every new feature or change should be shipped with its corresponding documentation
in accordance with the
[documentation process](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html)
and [structure](https://docs.gitlab.com/ee/development/documentation/structure.html) guides.
Note that a technical writer will review all changes to documentation. This can occur
in the same MR as the feature code, but [if there is not sufficient time or need,
it can be planned via a follow-up issue for doc review](https://docs.gitlab.com/ee/development/documentation/feature-change-workflow.html#1-product-managers-role),
and another MR, if needed. Regardless, complete docs must be merged with code by the freeze.
#### What happens if these deadlines are missed?
If a small or large feature is _not_ with a maintainer or reviewer by the
recommended date, this does _not_ mean that maintainers or reviewers will refuse
to review or merge it, or that the feature will definitely not make it in before
the feature freeze.
However, with every day that passes without review, it will become more likely
that the feature will slip, because maintainers and reviewers may not have
enough time to do a thorough review, and developers may not have enough time to
adequately address any feedback that may come back.
A maintainer or reviewer may also determine that it will not be possible to
finish the current scope of the feature in time, but that it is possible to
reduce the scope so that something can still ship this month, with the remaining
scope moving to the next release. The sooner this decision is made, in
conversation with the Product Manager and developer, the more time there is to
extract that which is now out of scope, and to finish that which remains in scope.
For these reasons, it is strongly recommended to follow the guidelines above,
to maximize the chances of your feature making it in before the feature freeze,
and to prevent any last minute surprises.
### On the 7th
Merge requests should still be complete, following the [definition of done][done].
If a merge request is not ready, but the developers and Product Manager
responsible for the feature think it is essential that it is in the release,
they can [ask for an exception](#asking-for-an-exception) in advance. This is
preferable to merging something that we are not confident in, but should still
be a rare case: most features can be allowed to slip a release.
All Community Edition merge requests from GitLab team members merged on the
freeze date (the 7th) should have a corresponding Enterprise Edition merge
request, even if there are no conflicts. This is to reduce the size of the
subsequent EE merge, as we often merge a lot to CE on the release date. For more
information, see
[Automatic CE->EE merge][automatic_ce_ee_merge] and
[Guidelines for implementing Enterprise Edition features][ee_features].
### After the 7th
Once the stable branch is frozen, the only MRs that can be cherry-picked into
the stable branch are:
* Fixes for [regressions](#regressions) where the affected version `xx.x` in `regression:xx.x` is the current release. See [Managing bugs](#managing-bugs) section.
* Fixes for security issues.
* Fixes or improvements to automated QA scenarios.
* [Documentation improvements](https://docs.gitlab.com/ee/development/documentation/workflow.html) for feature changes made in the same release, though initial docs for these features should have already been merged by the freeze, as required.
* New or updated translations (as long as they do not touch application code).
* Changes that are behind a feature flag and have the ~"feature flag" label.
During the feature freeze all merge requests that are meant to go into the
upcoming release should have the correct milestone assigned _and_ the
`Pick into X.Y` label where `X.Y` is equal to the milestone, so that release
managers can find and pick them.
Merge requests without this label will not be picked into the stable release.
For example, if the upcoming release is `10.2.0` you will need to set the
`Pick into 10.2` label.
Fixes marked like this will be shipped in the next RC (before the 22nd), or the
next patch release.
If a merge request is to be picked into more than one release it will need one
`Pick into X.Y` label per release where the merge request should be back-ported
to. For example:
- `Pick into 10.1`
- `Pick into 10.0`
- `Pick into 9.5`
### Asking for an exception
If you think a merge request should go into an RC or patch even though it does not meet these requirements,
you can ask for an exception to be made.
Check [this guide](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md) about how to open an exception request before opening one.
## Bugs ## Bugs
A ~bug is a defect, error, failure which causes the system to behave incorrectly or prevents it from fulfilling the product requirements. A ~bug is a defect, error, failure which causes the system to behave incorrectly or prevents it from fulfilling the product requirements.
@ -256,13 +118,6 @@ Regressions should be considered high priority issues that should be solved as s
### Managing bugs ### Managing bugs
**Prioritization:** We give higher priority to regressions on features that worked in the last recent monthly release and the current release candidates. **Prioritization:** We give higher priority to regressions on features that worked in the last recent monthly release and the current release candidates.
The two scenarios below can [bypass the exception request in the release process](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md#after-the-7th), where the affected regression version matches the current monthly release version.
* A regression which worked in the **Last monthly release**
* **Example:** In 11.0 we released a new `feature X` that is verified as working. Then in release 11.1 the feature no longer works, this is regression for 11.1. The issue should have the `regression:11.1` label.
* *Note:* When we say `the last recent monthly release`, this can refer to either the version currently running on GitLab.com, or the most recent version available in the package repositories.
* A regression which worked in the **Current release candidates**
* **Example:** In 11.1-RC3 we shipped a new feature which has been verified as working. Then in 11.1-RC5 the feature no longer works, this is regression for 11.1. The issue should have the `regression:11.1` label.
* *Note:* Because GitLab.com runs release candidates of new releases, a regression can be reported in a release before its 'official' release date on the 22nd of the month.
When a bug is found: When a bug is found:
1. Create an issue describing the problem in the most detailed way possible. 1. Create an issue describing the problem in the most detailed way possible.
@ -328,7 +183,7 @@ Thanks for the issue report. This issue has already been fixed in newer versions
Due to the size of this project and our limited resources we are only able to support the Due to the size of this project and our limited resources we are only able to support the
latest stable release as outlined in our [contributing guidelines](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html). latest stable release as outlined in our [contributing guidelines](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html).
In order to get this bug fix and enjoy many new features please In order to get this bug fix and enjoy many new features please
[upgrade](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update). [upgrade](https://gitlab.com/gitlab-org/gitlab/tree/master/doc/update).
If you still experience issues at that time please open a new issue following our issue If you still experience issues at that time please open a new issue following our issue
tracker guidelines found in the [contributing guidelines](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#issue-tracker-guidelines). tracker guidelines found in the [contributing guidelines](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#issue-tracker-guidelines).
``` ```
@ -337,14 +192,14 @@ tracker guidelines found in the [contributing guidelines](https://docs.gitlab.co
``` ```
Thanks for your interest in improving the GitLab codebase! Thanks for your interest in improving the GitLab codebase!
Please update your merge request according to the [contributing guidelines](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/contributing/merge_request_workflow.md#merge-request-guidelines). Please update your merge request according to the [contributing guidelines](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/contributing/merge_request_workflow.md#merge-request-guidelines).
``` ```
### Accepting merge requests ### Accepting merge requests
``` ```
Is there an issue on the Is there an issue on the
[issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues) that is [issue tracker](https://gitlab.com/gitlab-org/gitlab/issues) that is
similar to this? Could you please link it here? similar to this? Could you please link it here?
Please be aware that new functionality that is not marked Please be aware that new functionality that is not marked
[`Accepting merge requests`](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#label-for-community-contributors) [`Accepting merge requests`](https://docs.gitlab.com/ee/development/contributing/issue_workflow.html#label-for-community-contributors)

View file

@ -2,9 +2,9 @@
## Canonical source ## Canonical source
The canonical source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/). The canonical source of GitLab where all development takes place is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab).
The source of GitLab Enterprise Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ee). If you wish to clone a copy of GitLab without proprietary code, you can use the read-only mirror of GitLab located at https://gitlab.com/gitlab-org/gitlab-foss/. Please do not submit any issues and/or merge requests to this project.
## Free trial ## Free trial

View file

@ -1 +1 @@
12.3.9 12.4.6

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,11 +0,0 @@
export default {
data() {
return {
isCustomStageForm: false,
};
},
methods: {
showAddStageForm: () => {},
hideAddStageForm: () => {},
},
};

View file

@ -36,6 +36,7 @@ const Api = {
branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch', branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch',
createBranchPath: '/api/:version/projects/:id/repository/branches', createBranchPath: '/api/:version/projects/:id/repository/branches',
releasesPath: '/api/:version/projects/:id/releases', releasesPath: '/api/:version/projects/:id/releases',
releasePath: '/api/:version/projects/:id/releases/:tag_name',
mergeRequestsPipeline: '/api/:version/projects/:id/merge_requests/:merge_request_iid/pipelines', mergeRequestsPipeline: '/api/:version/projects/:id/merge_requests/:merge_request_iid/pipelines',
adminStatisticsPath: 'api/:version/application/statistics', adminStatisticsPath: 'api/:version/application/statistics',
@ -74,6 +75,11 @@ const Api = {
}); });
}, },
groupLabels(namespace) {
const url = Api.buildUrl(Api.groupLabelsPath).replace(':namespace_path', namespace);
return axios.get(url).then(({ data }) => data);
},
// Return namespaces list. Filtered by query // Return namespaces list. Filtered by query
namespaces(query, callback) { namespaces(query, callback) {
const url = Api.buildUrl(Api.namespacesPath); const url = Api.buildUrl(Api.namespacesPath);
@ -386,6 +392,22 @@ const Api = {
return axios.get(url); return axios.get(url);
}, },
release(projectPath, tagName) {
const url = Api.buildUrl(this.releasePath)
.replace(':id', encodeURIComponent(projectPath))
.replace(':tag_name', encodeURIComponent(tagName));
return axios.get(url);
},
updateRelease(projectPath, tagName, release) {
const url = Api.buildUrl(this.releasePath)
.replace(':id', encodeURIComponent(projectPath))
.replace(':tag_name', encodeURIComponent(tagName));
return axios.put(url, release);
},
adminStatistics() { adminStatistics() {
const url = Api.buildUrl(this.adminStatisticsPath); const url = Api.buildUrl(this.adminStatisticsPath);
return axios.get(url); return axios.get(url);

View file

@ -1,4 +1,4 @@
/* eslint-disable no-param-reassign, prefer-template, no-void, consistent-return */ /* eslint-disable no-param-reassign, no-void, consistent-return */
import AccessorUtilities from './lib/utils/accessor'; import AccessorUtilities from './lib/utils/accessor';
@ -10,7 +10,7 @@ export default class Autosave {
if (key.join != null) { if (key.join != null) {
key = key.join('/'); key = key.join('/');
} }
this.key = 'autosave/' + key; this.key = `autosave/${key}`;
this.field.data('autosave', this); this.field.data('autosave', this);
this.restore(); this.restore();
this.field.on('input', () => this.save()); this.field.on('input', () => this.save());

View file

@ -2,7 +2,7 @@
import { mapState, mapActions } from 'vuex'; import { mapState, mapActions } from 'vuex';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import GlModal from '~/vue_shared/components/gl_modal.vue'; import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import Badge from './badge.vue'; import Badge from './badge.vue';
import BadgeForm from './badge_form.vue'; import BadgeForm from './badge_form.vue';
import BadgeList from './badge_list.vue'; import BadgeList from './badge_list.vue';
@ -13,7 +13,7 @@ export default {
Badge, Badge,
BadgeForm, BadgeForm,
BadgeList, BadgeList,
GlModal, GlModal: DeprecatedModal2,
}, },
computed: { computed: {
...mapState(['badgeInModal', 'isEditing']), ...mapState(['badgeInModal', 'isEditing']),

View file

@ -21,6 +21,7 @@ import Reference from './nodes/reference';
import TableOfContents from './nodes/table_of_contents'; import TableOfContents from './nodes/table_of_contents';
import Video from './nodes/video'; import Video from './nodes/video';
import Audio from './nodes/audio';
import BulletList from './nodes/bullet_list'; import BulletList from './nodes/bullet_list';
import OrderedList from './nodes/ordered_list'; import OrderedList from './nodes/ordered_list';
@ -78,6 +79,7 @@ export default [
new TableOfContents(), new TableOfContents(),
new Video(), new Video(),
new Audio(),
new BulletList(), new BulletList(),
new OrderedList(), new OrderedList(),

View file

@ -0,0 +1,53 @@
/* eslint-disable class-methods-use-this */
import { Node } from 'tiptap';
import { defaultMarkdownSerializer } from 'prosemirror-markdown';
// Transforms generated HTML back to GFM for Banzai::Filter::AudioLinkFilter
export default class Audio extends Node {
get name() {
return 'audio';
}
get schema() {
return {
attrs: {
src: {},
alt: {
default: null,
},
},
group: 'block',
draggable: true,
parseDOM: [
{
tag: '.audio-container',
skip: true,
},
{
tag: '.audio-container p',
priority: 51,
ignore: true,
},
{
tag: 'audio[src]',
getAttrs: el => ({ src: el.getAttribute('src'), alt: el.dataset.title }),
},
],
toDOM: node => [
'audio',
{
src: node.attrs.src,
controls: true,
'data-setup': '{}',
'data-title': node.attrs.alt,
},
],
};
}
toMarkdown(state, node) {
defaultMarkdownSerializer.nodes.image(state, node);
state.closeBlock(node);
}
}

View file

@ -1,4 +1,4 @@
/* eslint-disable func-names, no-var, prefer-arrow-callback */ /* eslint-disable func-names, no-var */
import $ from 'jquery'; import $ from 'jquery';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
@ -45,26 +45,22 @@ MarkdownPreview.prototype.showPreview = function($form) {
this.hideReferencedUsers($form); this.hideReferencedUsers($form);
} else { } else {
preview.addClass('md-preview-loading').text(__('Loading...')); preview.addClass('md-preview-loading').text(__('Loading...'));
this.fetchMarkdownPreview( this.fetchMarkdownPreview(mdText, url, response => {
mdText, var body;
url, if (response.body.length > 0) {
function(response) { ({ body } = response);
var body; } else {
if (response.body.length > 0) { body = this.emptyMessage;
({ body } = response); }
} else {
body = this.emptyMessage;
}
preview.removeClass('md-preview-loading').html(body); preview.removeClass('md-preview-loading').html(body);
preview.renderGFM(); preview.renderGFM();
this.renderReferencedUsers(response.references.users, $form); this.renderReferencedUsers(response.references.users, $form);
if (response.references.commands) { if (response.references.commands) {
this.renderReferencedCommands(response.references.commands, $form); this.renderReferencedCommands(response.references.commands, $form);
} }
}.bind(this), });
);
} }
}; };
@ -132,12 +128,12 @@ const markdownToolbar = $('.md-header-toolbar');
$.fn.setupMarkdownPreview = function() { $.fn.setupMarkdownPreview = function() {
var $form = $(this); var $form = $(this);
$form.find('textarea.markdown-area').on('input', function() { $form.find('textarea.markdown-area').on('input', () => {
markdownPreview.hideReferencedUsers($form); markdownPreview.hideReferencedUsers($form);
}); });
}; };
$(document).on('markdown-preview:show', function(e, $form) { $(document).on('markdown-preview:show', (e, $form) => {
if (!$form) { if (!$form) {
return; return;
} }
@ -162,7 +158,7 @@ $(document).on('markdown-preview:show', function(e, $form) {
markdownPreview.showPreview($form); markdownPreview.showPreview($form);
}); });
$(document).on('markdown-preview:hide', function(e, $form) { $(document).on('markdown-preview:hide', (e, $form) => {
if (!$form) { if (!$form) {
return; return;
} }
@ -191,7 +187,7 @@ $(document).on('markdown-preview:hide', function(e, $form) {
markdownPreview.hideReferencedCommands($form); markdownPreview.hideReferencedCommands($form);
}); });
$(document).on('markdown-preview:toggle', function(e, keyboardEvent) { $(document).on('markdown-preview:toggle', (e, keyboardEvent) => {
var $target; var $target;
$target = $(keyboardEvent.target); $target = $(keyboardEvent.target);
if ($target.is('textarea.markdown-area')) { if ($target.is('textarea.markdown-area')) {

View file

@ -26,7 +26,7 @@ $.fn.requiresInput = function requiresInput() {
const values = _.map($(fieldSelector, $form), field => field.value); const values = _.map($(fieldSelector, $form), field => field.value);
// Disable the button if any required fields are empty // Disable the button if any required fields are empty
if (values.length && _.any(values, _.isEmpty)) { if (values.length && _.some(values, _.isEmpty)) {
$button.disable(); $button.disable();
} else { } else {
$button.enable(); $button.enable();

View file

@ -1,5 +1,7 @@
import sqljs from 'sql.js'; import sqljs from 'sql.js';
import { template as _template } from 'underscore'; import { template as _template } from 'underscore';
import axios from '~/lib/utils/axios_utils';
import { successCodes } from '~/lib/utils/http_status';
const PREVIEW_TEMPLATE = _template(` const PREVIEW_TEMPLATE = _template(`
<div class="card"> <div class="card">
@ -16,30 +18,25 @@ class BalsamiqViewer {
} }
loadFile(endpoint) { loadFile(endpoint) {
return new Promise((resolve, reject) => { return axios
const xhr = new XMLHttpRequest(); .get(endpoint, {
responseType: 'arraybuffer',
xhr.open('GET', endpoint, true); validateStatus(status) {
xhr.responseType = 'arraybuffer'; return status !== successCodes.OK;
xhr.onload = loadEvent => this.fileLoaded(loadEvent, resolve, reject); },
xhr.onerror = reject; })
.then(({ data }) => {
xhr.send(); this.renderFile(data);
}); })
.catch(e => {
throw new Error(e);
});
} }
fileLoaded(loadEvent, resolve, reject) { renderFile(fileBuffer) {
if (loadEvent.target.status !== 200) return reject();
this.renderFile(loadEvent);
return resolve();
}
renderFile(loadEvent) {
const container = document.createElement('ul'); const container = document.createElement('ul');
this.initDatabase(loadEvent.target.response); this.initDatabase(fileBuffer);
const previews = this.getPreviews(); const previews = this.getPreviews();
previews.forEach(preview => { previews.forEach(preview => {

View file

@ -1,4 +1,4 @@
/* eslint-disable func-names, prefer-arrow-callback */ /* eslint-disable func-names */
import $ from 'jquery'; import $ from 'jquery';
import Dropzone from 'dropzone'; import Dropzone from 'dropzone';
@ -43,18 +43,18 @@ export default class BlobFileDropzone {
previewsContainer: '.dropzone-previews', previewsContainer: '.dropzone-previews',
headers: csrf.headers, headers: csrf.headers,
init() { init() {
this.on('addedfile', function() { this.on('addedfile', () => {
toggleLoading(submitButton, submitButtonLoadingIcon, false); toggleLoading(submitButton, submitButtonLoadingIcon, false);
dropzoneMessage.addClass(HIDDEN_CLASS); dropzoneMessage.addClass(HIDDEN_CLASS);
$('.dropzone-alerts') $('.dropzone-alerts')
.html('') .html('')
.hide(); .hide();
}); });
this.on('removedfile', function() { this.on('removedfile', () => {
toggleLoading(submitButton, submitButtonLoadingIcon, false); toggleLoading(submitButton, submitButtonLoadingIcon, false);
dropzoneMessage.removeClass(HIDDEN_CLASS); dropzoneMessage.removeClass(HIDDEN_CLASS);
}); });
this.on('success', function(header, response) { this.on('success', (header, response) => {
$('#modal-upload-blob').modal('hide'); $('#modal-upload-blob').modal('hide');
visitUrl(response.filePath); visitUrl(response.filePath);
}); });
@ -62,7 +62,7 @@ export default class BlobFileDropzone {
dropzoneMessage.addClass(HIDDEN_CLASS); dropzoneMessage.addClass(HIDDEN_CLASS);
this.removeFile(file); this.removeFile(file);
}); });
this.on('sending', function(file, xhr, formData) { this.on('sending', (file, xhr, formData) => {
formData.append('branch_name', form.find('.js-branch-name').val()); formData.append('branch_name', form.find('.js-branch-name').val());
formData.append('create_merge_request', form.find('.js-create-merge-request').val()); formData.append('create_merge_request', form.find('.js-create-merge-request').val());
formData.append('commit_message', form.find('.js-commit-message').val()); formData.append('commit_message', form.find('.js-commit-message').val());

View file

@ -7,6 +7,8 @@ import BlobCiYamlSelector from './template_selectors/ci_yaml_selector';
import DockerfileSelector from './template_selectors/dockerfile_selector'; import DockerfileSelector from './template_selectors/dockerfile_selector';
import GitignoreSelector from './template_selectors/gitignore_selector'; import GitignoreSelector from './template_selectors/gitignore_selector';
import LicenseSelector from './template_selectors/license_selector'; import LicenseSelector from './template_selectors/license_selector';
import toast from '~/vue_shared/plugins/global_toast';
import { __ } from '~/locale';
export default class FileTemplateMediator { export default class FileTemplateMediator {
constructor({ editor, currentAction, projectId }) { constructor({ editor, currentAction, projectId }) {
@ -19,6 +21,7 @@ export default class FileTemplateMediator {
this.initDomElements(); this.initDomElements();
this.initDropdowns(); this.initDropdowns();
this.initPageEvents(); this.initPageEvents();
this.cacheFileContents();
} }
initTemplateSelectors() { initTemplateSelectors() {
@ -40,6 +43,7 @@ export default class FileTemplateMediator {
return { return {
name: cfg.name, name: cfg.name,
key: cfg.key, key: cfg.key,
id: cfg.key,
}; };
}), }),
}); });
@ -58,6 +62,7 @@ export default class FileTemplateMediator {
this.$fileContent = $fileEditor.find('#file-content'); this.$fileContent = $fileEditor.find('#file-content');
this.$commitForm = $fileEditor.find('form'); this.$commitForm = $fileEditor.find('form');
this.$navLinks = $fileEditor.find('.nav-links'); this.$navLinks = $fileEditor.find('.nav-links');
this.$templateTypes = this.$templateSelectors.find('.template-type-selector');
} }
initDropdowns() { initDropdowns() {
@ -113,7 +118,11 @@ export default class FileTemplateMediator {
} }
}); });
this.typeSelector.setToggleText(item.name); this.setFilename(item.name);
if (this.editor.getValue() !== '') {
this.setTypeSelectorToggleText(item.name);
}
this.cacheToggleText(); this.cacheToggleText();
} }
@ -123,15 +132,24 @@ export default class FileTemplateMediator {
} }
selectTemplateFile(selector, query, data) { selectTemplateFile(selector, query, data) {
const self = this;
selector.renderLoading(); selector.renderLoading();
// in case undo menu is already there
this.destroyUndoMenu();
this.fetchFileTemplate(selector.config.type, query, data) this.fetchFileTemplate(selector.config.type, query, data)
.then(file => { .then(file => {
this.showUndoMenu();
this.setEditorContent(file); this.setEditorContent(file);
this.setFilename(selector.config.name);
selector.renderLoaded(); selector.renderLoaded();
this.typeSelector.setToggleText(selector.config.name);
toast(__(`${query} template applied`), {
action: {
text: __('Undo'),
onClick: (e, toastObj) => {
self.restoreFromCache();
toastObj.goAway(0);
},
},
});
}) })
.catch(err => new Flash(`An error occurred while fetching the template: ${err}`)); .catch(err => new Flash(`An error occurred while fetching the template: ${err}`));
} }
@ -173,22 +191,6 @@ export default class FileTemplateMediator {
return this.templateSelectors.find(selector => selector.config.key === key); return this.templateSelectors.find(selector => selector.config.key === key);
} }
showUndoMenu() {
this.$undoMenu.removeClass('hidden');
this.$undoBtn.on('click', () => {
this.restoreFromCache();
this.destroyUndoMenu();
});
}
destroyUndoMenu() {
this.cacheFileContents();
this.cacheToggleText();
this.$undoMenu.addClass('hidden');
this.$undoBtn.off('click');
}
hideTemplateSelectorMenu() { hideTemplateSelectorMenu() {
this.$templatesMenu.hide(); this.$templatesMenu.hide();
} }
@ -210,6 +212,7 @@ export default class FileTemplateMediator {
this.setEditorContent(this.cachedContent); this.setEditorContent(this.cachedContent);
this.setFilename(this.cachedFilename); this.setFilename(this.cachedFilename);
this.setTemplateSelectorToggleText(); this.setTemplateSelectorToggleText();
this.setTypeSelectorToggleText(__('Select a template type'));
} }
getTemplateSelectorToggleText() { getTemplateSelectorToggleText() {
@ -228,6 +231,10 @@ export default class FileTemplateMediator {
return this.typeSelector.getToggleText(); return this.typeSelector.getToggleText();
} }
setTypeSelectorToggleText(text) {
this.typeSelector.setToggleText(text);
}
getFilename() { getFilename() {
return this.$filenameInput.val(); return this.$filenameInput.val();
} }

View file

@ -1,6 +1,7 @@
/* eslint-disable class-methods-use-this */ /* eslint-disable class-methods-use-this */
import $ from 'jquery'; import $ from 'jquery';
import '~/gl_dropdown';
export default class TemplateSelector { export default class TemplateSelector {
constructor({ dropdown, data, pattern, wrapper, editor, $input } = {}) { constructor({ dropdown, data, pattern, wrapper, editor, $input } = {}) {
@ -26,11 +27,16 @@ export default class TemplateSelector {
search: { search: {
fields: ['name'], fields: ['name'],
}, },
clicked: options => this.fetchFileTemplate(options), clicked: options => this.onDropdownClicked(options),
text: item => item.name, text: item => item.name,
}); });
} }
// Subclasses can override this method to conditionally prevent fetching file templates
onDropdownClicked(options) {
this.fetchFileTemplate(options);
}
initAutosizeUpdateEvent() { initAutosizeUpdateEvent() {
this.autosizeUpdateEvent = document.createEvent('Event'); this.autosizeUpdateEvent = document.createEvent('Event');
this.autosizeUpdateEvent.initEvent('autosize:update', true, false); this.autosizeUpdateEvent.initEvent('autosize:update', true, false);
@ -77,9 +83,14 @@ export default class TemplateSelector {
if (this.editor instanceof $) { if (this.editor instanceof $) {
this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent); this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent);
this.editor.trigger('input');
} }
} }
getEditorContent() {
return this.editor.getValue();
}
startLoadingSpinner() { startLoadingSpinner() {
this.$dropdownIcon.addClass('fa-spinner fa-spin').removeClass('fa-chevron-down'); this.$dropdownIcon.addClass('fa-spinner fa-spin').removeClass('fa-chevron-down');
} }

View file

@ -19,7 +19,6 @@ export default class BlobCiYamlSelector extends FileTemplateSelector {
data: this.$dropdown.data('data'), data: this.$dropdown.data('data'),
filterable: true, filterable: true,
selectable: true, selectable: true,
toggleLabel: item => item.name,
search: { search: {
fields: ['name'], fields: ['name'],
}, },

View file

@ -20,7 +20,6 @@ export default class DockerfileSelector extends FileTemplateSelector {
data: this.$dropdown.data('data'), data: this.$dropdown.data('data'),
filterable: true, filterable: true,
selectable: true, selectable: true,
toggleLabel: item => item.name,
search: { search: {
fields: ['name'], fields: ['name'],
}, },

View file

@ -18,7 +18,6 @@ export default class BlobGitignoreSelector extends FileTemplateSelector {
data: this.$dropdown.data('data'), data: this.$dropdown.data('data'),
filterable: true, filterable: true,
selectable: true, selectable: true,
toggleLabel: item => item.name,
search: { search: {
fields: ['name'], fields: ['name'],
}, },

View file

@ -18,7 +18,6 @@ export default class BlobLicenseSelector extends FileTemplateSelector {
data: this.$dropdown.data('data'), data: this.$dropdown.data('data'),
filterable: true, filterable: true,
selectable: true, selectable: true,
toggleLabel: item => item.name,
search: { search: {
fields: ['name'], fields: ['name'],
}, },

View file

@ -16,7 +16,6 @@ export default class FileTemplateTypeSelector extends FileTemplateSelector {
data: this.config.dropdownData, data: this.config.dropdownData,
filterable: false, filterable: false,
selectable: true, selectable: true,
toggleLabel: item => item.name,
clicked: options => this.mediator.selectTemplateTypeOptions(options), clicked: options => this.mediator.selectTemplateTypeOptions(options),
text: item => item.name, text: item => item.name,
}); });

View file

@ -107,18 +107,18 @@ export default class BlobViewer {
toggleCopyButtonState() { toggleCopyButtonState() {
if (!this.copySourceBtn) return; if (!this.copySourceBtn) return;
if (this.simpleViewer.getAttribute('data-loaded')) { if (this.simpleViewer.getAttribute('data-loaded')) {
this.copySourceBtn.setAttribute('title', __('Copy source to clipboard')); this.copySourceBtn.setAttribute('title', __('Copy file contents'));
this.copySourceBtn.classList.remove('disabled'); this.copySourceBtn.classList.remove('disabled');
} else if (this.activeViewer === this.simpleViewer) { } else if (this.activeViewer === this.simpleViewer) {
this.copySourceBtn.setAttribute( this.copySourceBtn.setAttribute(
'title', 'title',
__('Wait for the source to load to copy it to the clipboard'), __('Wait for the file to load to copy its contents'),
); );
this.copySourceBtn.classList.add('disabled'); this.copySourceBtn.classList.add('disabled');
} else { } else {
this.copySourceBtn.setAttribute( this.copySourceBtn.setAttribute(
'title', 'title',
__('Switch to the source to copy it to the clipboard'), __('Switch to the source to copy the file contents'),
); );
this.copySourceBtn.classList.add('disabled'); this.copySourceBtn.classList.add('disabled');
} }

View file

@ -29,25 +29,25 @@ export default {
}); });
}); });
const loadListIssues = listObj => {
const list = boardsStore.findList('title', listObj.title);
if (!list) {
return null;
}
list.id = listObj.id;
list.label.id = listObj.label.id;
return list.getIssues().catch(() => {
// TODO: handle request error
});
};
// Save the labels // Save the labels
boardsStore boardsStore
.generateDefaultLists() .generateDefaultLists()
.then(res => res.data) .then(res => res.data)
.then(data => { .then(data => Promise.all(data.map(loadListIssues)))
data.forEach(listObj => {
const list = boardsStore.findList('title', listObj.title);
if (!list) {
return;
}
list.id = listObj.id;
list.label.id = listObj.label.id;
list.getIssues().catch(() => {
// TODO: handle request error
});
});
})
.catch(() => { .catch(() => {
boardsStore.removeList(undefined, 'label'); boardsStore.removeList(undefined, 'label');
Cookies.remove('issue_board_welcome_hidden', { Cookies.remove('issue_board_welcome_hidden', {

View file

@ -42,12 +42,19 @@ export default {
return { return {
showDetail: false, showDetail: false,
detailIssue: boardsStore.detail, detailIssue: boardsStore.detail,
multiSelect: boardsStore.multiSelect,
}; };
}, },
computed: { computed: {
issueDetailVisible() { issueDetailVisible() {
return this.detailIssue.issue && this.detailIssue.issue.id === this.issue.id; return this.detailIssue.issue && this.detailIssue.issue.id === this.issue.id;
}, },
multiSelectVisible() {
return this.multiSelect.list.findIndex(issue => issue.id === this.issue.id) > -1;
},
canMultiSelect() {
return gon.features && gon.features.multiSelectBoard;
},
}, },
methods: { methods: {
mouseDown() { mouseDown() {
@ -58,14 +65,20 @@ export default {
}, },
showIssue(e) { showIssue(e) {
if (e.target.classList.contains('js-no-trigger')) return; if (e.target.classList.contains('js-no-trigger')) return;
if (this.showDetail) { if (this.showDetail) {
this.showDetail = false; this.showDetail = false;
// If CMD or CTRL is clicked
const isMultiSelect = this.canMultiSelect && (e.ctrlKey || e.metaKey);
if (boardsStore.detail.issue && boardsStore.detail.issue.id === this.issue.id) { if (boardsStore.detail.issue && boardsStore.detail.issue.id === this.issue.id) {
eventHub.$emit('clearDetailIssue'); eventHub.$emit('clearDetailIssue', isMultiSelect);
if (isMultiSelect) {
eventHub.$emit('newDetailIssue', this.issue, isMultiSelect);
}
} else { } else {
eventHub.$emit('newDetailIssue', this.issue); eventHub.$emit('newDetailIssue', this.issue, isMultiSelect);
boardsStore.setListDetail(this.list); boardsStore.setListDetail(this.list);
} }
} }
@ -77,6 +90,7 @@ export default {
<template> <template>
<li <li
:class="{ :class="{
'multi-select': multiSelectVisible,
'user-can-drag': !disabled && issue.id, 'user-can-drag': !disabled && issue.id,
'is-disabled': disabled || !issue.id, 'is-disabled': disabled || !issue.id,
'is-active': issueDetailVisible, 'is-active': issueDetailVisible,

View file

@ -194,6 +194,7 @@ export default {
ref="name" ref="name"
v-model="board.name" v-model="board.name"
class="form-control" class="form-control"
data-qa-selector="board_name_field"
type="text" type="text"
:placeholder="__('Enter board name')" :placeholder="__('Enter board name')"
@keyup.enter="submit" @keyup.enter="submit"

View file

@ -1,12 +1,22 @@
<script> <script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */ import { Sortable, MultiDrag } from 'sortablejs';
import Sortable from 'sortablejs';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import _ from 'underscore';
import boardNewIssue from './board_new_issue.vue'; import boardNewIssue from './board_new_issue.vue';
import boardCard from './board_card.vue'; import boardCard from './board_card.vue';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import boardsStore from '../stores/boards_store'; import boardsStore from '../stores/boards_store';
import { getBoardSortableDefaultOptions, sortableStart } from '../mixins/sortable_default_options'; import { sprintf, __ } from '~/locale';
import createFlash from '~/flash';
import {
getBoardSortableDefaultOptions,
sortableStart,
sortableEnd,
} from '../mixins/sortable_default_options';
if (gon.features && gon.features.multiSelectBoard) {
Sortable.mount(new MultiDrag());
}
export default { export default {
name: 'BoardList', name: 'BoardList',
@ -54,6 +64,14 @@ export default {
showIssueForm: false, showIssueForm: false,
}; };
}, },
computed: {
paginatedIssueText() {
return sprintf(__('Showing %{pageSize} of %{total} issues'), {
pageSize: this.list.issues.length,
total: this.list.issuesSize,
});
},
},
watch: { watch: {
filters: { filters: {
handler() { handler() {
@ -87,11 +105,20 @@ export default {
eventHub.$on(`scroll-board-list-${this.list.id}`, this.scrollToTop); eventHub.$on(`scroll-board-list-${this.list.id}`, this.scrollToTop);
}, },
mounted() { mounted() {
const multiSelectOpts = {};
if (gon.features && gon.features.multiSelectBoard) {
multiSelectOpts.multiDrag = true;
multiSelectOpts.selectedClass = 'js-multi-select';
multiSelectOpts.animation = 500;
}
const options = getBoardSortableDefaultOptions({ const options = getBoardSortableDefaultOptions({
scroll: true, scroll: true,
disabled: this.disabled, disabled: this.disabled,
filter: '.board-list-count, .is-disabled', filter: '.board-list-count, .is-disabled',
dataIdAttr: 'data-issue-id', dataIdAttr: 'data-issue-id',
removeCloneOnHide: false,
...multiSelectOpts,
group: { group: {
name: 'issues', name: 'issues',
/** /**
@ -145,25 +172,66 @@ export default {
card.showDetail = false; card.showDetail = false;
const { list } = card; const { list } = card;
const issue = list.findIssue(Number(e.item.dataset.issueId)); const issue = list.findIssue(Number(e.item.dataset.issueId));
boardsStore.startMoving(list, issue); boardsStore.startMoving(list, issue);
sortableStart(); sortableStart();
}, },
onAdd: e => { onAdd: e => {
boardsStore.moveIssueToList( const { items = [], newIndicies = [] } = e;
boardsStore.moving.list, if (items.length) {
this.list, // Not using e.newIndex here instead taking a min of all
boardsStore.moving.issue, // the newIndicies. Basically we have to find that during
e.newIndex, // a drop what is the index we're going to start putting
); // all the dropped elements from.
const newIndex = Math.min(...newIndicies.map(obj => obj.index).filter(i => i !== -1));
const issues = items.map(item =>
boardsStore.moving.list.findIssue(Number(item.dataset.issueId)),
);
this.$nextTick(() => { boardsStore.moveMultipleIssuesToList({
e.item.remove(); listFrom: boardsStore.moving.list,
}); listTo: this.list,
issues,
newIndex,
});
} else {
boardsStore.moveIssueToList(
boardsStore.moving.list,
this.list,
boardsStore.moving.issue,
e.newIndex,
);
this.$nextTick(() => {
e.item.remove();
});
}
}, },
onUpdate: e => { onUpdate: e => {
const sortedArray = this.sortable.toArray().filter(id => id !== '-1'); const sortedArray = this.sortable.toArray().filter(id => id !== '-1');
const { items = [], newIndicies = [], oldIndicies = [] } = e;
if (items.length) {
const newIndex = Math.min(...newIndicies.map(obj => obj.index));
const issues = items.map(item =>
boardsStore.moving.list.findIssue(Number(item.dataset.issueId)),
);
boardsStore.moveMultipleIssuesInList({
list: this.list,
issues,
oldIndicies: oldIndicies.map(obj => obj.index),
newIndex,
idArray: sortedArray,
});
e.items.forEach(el => {
Sortable.utils.deselect(el);
});
boardsStore.clearMultiSelect();
return;
}
boardsStore.moveIssueInList( boardsStore.moveIssueInList(
this.list, this.list,
boardsStore.moving.issue, boardsStore.moving.issue,
@ -172,9 +240,133 @@ export default {
sortedArray, sortedArray,
); );
}, },
onEnd: e => {
const { items = [], clones = [], to } = e;
// This is not a multi select operation
if (!items.length && !clones.length) {
sortableEnd();
return;
}
let toList;
if (to) {
const containerEl = to.closest('.js-board-list');
toList = boardsStore.findList('id', Number(containerEl.dataset.board));
}
/**
* onEnd is called irrespective if the cards were moved in the
* same list or the other list. Don't remove items if it's same list.
*/
const isSameList = toList && toList.id === this.list.id;
if (toList && !isSameList && boardsStore.shouldRemoveIssue(this.list, toList)) {
const issues = items.map(item => this.list.findIssue(Number(item.dataset.issueId)));
if (_.compact(issues).length && !boardsStore.issuesAreContiguous(this.list, issues)) {
const indexes = [];
const ids = this.list.issues.map(i => i.id);
issues.forEach(issue => {
const index = ids.indexOf(issue.id);
if (index > -1) {
indexes.push(index);
}
});
// Descending sort because splice would cause index discrepancy otherwise
const sortedIndexes = indexes.sort((a, b) => (a < b ? 1 : -1));
sortedIndexes.forEach(i => {
/**
* **setTimeout and splice each element one-by-one in a loop
* is intended.**
*
* The problem here is all the indexes are in the list but are
* non-contiguous. Due to that, when we splice all the indexes,
* at once, Vue -- during a re-render -- is unable to find reference
* nodes and the entire app crashes.
*
* If the indexes are contiguous, this piece of code is not
* executed. If it is, this is a possible regression. Only when
* issue indexes are far apart, this logic should ever kick in.
*/
setTimeout(() => {
this.list.issues.splice(i, 1);
}, 0);
});
}
}
if (!toList) {
createFlash(__('Something went wrong while performing the action.'));
}
if (!isSameList) {
boardsStore.clearMultiSelect();
// Since Vue's list does not re-render the same keyed item, we'll
// remove `multi-select` class to express it's unselected
if (clones && clones.length) {
clones.forEach(el => el.classList.remove('multi-select'));
}
// Due to some bug which I am unable to figure out
// Sortable does not deselect some pending items from the
// source list.
// We'll just do it forcefully here.
Array.from(document.querySelectorAll('.js-multi-select') || []).forEach(item => {
Sortable.utils.deselect(item);
});
/**
* SortableJS leaves all the moving items "as is" on the DOM.
* Vue picks up and rehydrates the DOM, but we need to explicity
* remove the "trash" items from the DOM.
*
* This is in parity to the logic on single item move from a list/in
* a list. For reference, look at the implementation of onAdd method.
*/
this.$nextTick(() => {
if (items && items.length) {
items.forEach(item => {
item.remove();
});
}
});
}
sortableEnd();
},
onMove(e) { onMove(e) {
return !e.related.classList.contains('board-list-count'); return !e.related.classList.contains('board-list-count');
}, },
onSelect(e) {
const {
item: { classList },
} = e;
if (
classList &&
classList.contains('js-multi-select') &&
!classList.contains('multi-select')
) {
Sortable.utils.deselect(e.item);
}
},
onDeselect: e => {
const {
item: { dataset, classList },
} = e;
if (
classList &&
classList.contains('multi-select') &&
!classList.contains('js-multi-select')
) {
const issue = this.list.findIssue(Number(dataset.issueId));
boardsStore.toggleMultiSelect(issue);
}
},
}); });
this.sortable = Sortable.create(this.$refs.list, options); this.sortable = Sortable.create(this.$refs.list, options);
@ -260,7 +452,7 @@ export default {
<li v-if="showCount" class="board-list-count text-center" data-issue-id="-1"> <li v-if="showCount" class="board-list-count text-center" data-issue-id="-1">
<gl-loading-icon v-show="list.loadingMore" label="Loading more issues" /> <gl-loading-icon v-show="list.loadingMore" label="Loading more issues" />
<span v-if="list.issues.length === list.issuesSize">{{ __('Showing all issues') }}</span> <span v-if="list.issues.length === list.issuesSize">{{ __('Showing all issues') }}</span>
<span v-else> Showing {{ list.issues.length }} of {{ list.issuesSize }} issues </span> <span v-else>{{ paginatedIssueText }}</span>
</li> </li>
</ul> </ul>
</div> </div>

View file

@ -305,13 +305,18 @@ export default {
<div v-if="canAdminBoard"> <div v-if="canAdminBoard">
<gl-dropdown-divider /> <gl-dropdown-divider />
<gl-dropdown-item v-if="multipleIssueBoardsAvailable" @click.prevent="showPage('new')"> <gl-dropdown-item
v-if="multipleIssueBoardsAvailable"
data-qa-selector="create_new_board_button"
@click.prevent="showPage('new')"
>
{{ s__('IssueBoards|Create new board') }} {{ s__('IssueBoards|Create new board') }}
</gl-dropdown-item> </gl-dropdown-item>
<gl-dropdown-item <gl-dropdown-item
v-if="showDelete" v-if="showDelete"
class="text-danger" class="text-danger"
data-qa-selector="delete_board_button"
@click.prevent="showPage('delete')" @click.prevent="showPage('delete')"
> >
{{ s__('IssueBoards|Delete board') }} {{ s__('IssueBoards|Delete board') }}

View file

@ -99,7 +99,10 @@ export default {
return !groupId ? referencePath.split('#')[0] : null; return !groupId ? referencePath.split('#')[0] : null;
}, },
orderedLabels() { orderedLabels() {
return _.sortBy(this.issue.labels, 'title'); return _.chain(this.issue.labels)
.filter(this.isNonListLabel)
.sortBy('title')
.value();
}, },
helpLink() { helpLink() {
return boardsStore.scopedLabels.helpLink; return boardsStore.scopedLabels.helpLink;
@ -130,6 +133,9 @@ export default {
if (!label.id) return false; if (!label.id) return false;
return true; return true;
}, },
isNonListLabel(label) {
return label.id && !(this.list.type === 'label' && this.list.title === label.title);
},
filterByLabel(label) { filterByLabel(label) {
if (!this.updateFilters) return; if (!this.updateFilters) return;
const labelTitle = encodeURIComponent(label.title); const labelTitle = encodeURIComponent(label.title);
@ -167,7 +173,7 @@ export default {
</h4> </h4>
</div> </div>
<div v-if="showLabelFooter" class="board-card-labels prepend-top-4 d-flex flex-wrap"> <div v-if="showLabelFooter" class="board-card-labels prepend-top-4 d-flex flex-wrap">
<template v-for="label in orderedLabels" v-if="showLabel(label)"> <template v-for="label in orderedLabels">
<issue-card-inner-scoped-label <issue-card-inner-scoped-label
v-if="showScopedLabel(label)" v-if="showScopedLabel(label)"
:key="label.id" :key="label.id"
@ -212,7 +218,7 @@ export default {
<issue-due-date v-if="issue.dueDate" :date="issue.dueDate" /> <issue-due-date v-if="issue.dueDate" :date="issue.dueDate" />
<issue-time-estimate v-if="issue.timeEstimate" :estimate="issue.timeEstimate" /> <issue-time-estimate v-if="issue.timeEstimate" :estimate="issue.timeEstimate" />
<issue-card-weight <issue-card-weight
v-if="issue.weight" v-if="validIssueWeight"
:weight="issue.weight" :weight="issue.weight"
@click="filterByWeight(issue.weight)" @click="filterByWeight(issue.weight)"
/> />

View file

@ -34,7 +34,7 @@ export default {
<template> <template>
<span> <span>
<span ref="issueTimeEstimate" class="board-card-info card-number"> <span ref="issueTimeEstimate" class="board-card-info card-number">
<icon name="hourglass" css-classes="board-card-info-icon align-top" /><time <icon name="hourglass" class="board-card-info-icon align-top" /><time
class="board-card-info-text" class="board-card-info-text"
>{{ timeEstimate }}</time >{{ timeEstimate }}</time
> >

View file

@ -0,0 +1,11 @@
export const ListType = {
assignee: 'assignee',
milestone: 'milestone',
backlog: 'backlog',
closed: 'closed',
label: 'label',
};
export default {
ListType,
};

View file

@ -22,7 +22,6 @@ import Board from 'ee_else_ce/boards/components/board';
import BoardSidebar from 'ee_else_ce/boards/components/board_sidebar'; import BoardSidebar from 'ee_else_ce/boards/components/board_sidebar';
import initNewListDropdown from 'ee_else_ce/boards/components/new_list_dropdown'; import initNewListDropdown from 'ee_else_ce/boards/components/new_list_dropdown';
import BoardAddIssuesModal from '~/boards/components/modal/index.vue'; import BoardAddIssuesModal from '~/boards/components/modal/index.vue';
import '~/vue_shared/vue_resource_interceptor';
import { import {
NavigationType, NavigationType,
convertObjectPropsToCamelCase, convertObjectPropsToCamelCase,
@ -147,7 +146,7 @@ export default () => {
updateTokens() { updateTokens() {
this.filterManager.updateTokens(); this.filterManager.updateTokens();
}, },
updateDetailIssue(newIssue) { updateDetailIssue(newIssue, multiSelect = false) {
const { sidebarInfoEndpoint } = newIssue; const { sidebarInfoEndpoint } = newIssue;
if (sidebarInfoEndpoint && newIssue.subscribed === undefined) { if (sidebarInfoEndpoint && newIssue.subscribed === undefined) {
newIssue.setFetchingState('subscriptions', true); newIssue.setFetchingState('subscriptions', true);
@ -186,9 +185,23 @@ export default () => {
}); });
} }
if (multiSelect) {
boardsStore.toggleMultiSelect(newIssue);
if (boardsStore.detail.issue) {
boardsStore.clearDetailIssue();
return;
}
return;
}
boardsStore.setIssueDetail(newIssue); boardsStore.setIssueDetail(newIssue);
}, },
clearDetailIssue() { clearDetailIssue(multiSelect = false) {
if (multiSelect) {
boardsStore.clearMultiSelect();
}
boardsStore.clearDetailIssue(); boardsStore.clearDetailIssue();
}, },
toggleSubscription(id) { toggleSubscription(id) {

View file

@ -1,4 +1,9 @@
export default { export default {
computed: {
validIssueWeight() {
return false;
},
},
methods: { methods: {
filterByWeight() {}, filterByWeight() {},
}, },

View file

@ -5,6 +5,7 @@ import ListLabel from './label';
import ListAssignee from './assignee'; import ListAssignee from './assignee';
import ListIssue from 'ee_else_ce/boards/models/issue'; import ListIssue from 'ee_else_ce/boards/models/issue';
import { urlParamsToObject } from '~/lib/utils/common_utils'; import { urlParamsToObject } from '~/lib/utils/common_utils';
import flash from '~/flash';
import boardsStore from '../stores/boards_store'; import boardsStore from '../stores/boards_store';
import ListMilestone from './milestone'; import ListMilestone from './milestone';
@ -176,6 +177,53 @@ class List {
}); });
} }
addMultipleIssues(issues, listFrom, newIndex) {
let moveBeforeId = null;
let moveAfterId = null;
const listHasIssues = issues.every(issue => this.findIssue(issue.id));
if (!listHasIssues) {
if (newIndex !== undefined) {
if (this.issues[newIndex - 1]) {
moveBeforeId = this.issues[newIndex - 1].id;
}
if (this.issues[newIndex]) {
moveAfterId = this.issues[newIndex].id;
}
this.issues.splice(newIndex, 0, ...issues);
} else {
this.issues.push(...issues);
}
if (this.label) {
issues.forEach(issue => issue.addLabel(this.label));
}
if (this.assignee) {
if (listFrom && listFrom.type === 'assignee') {
issues.forEach(issue => issue.removeAssignee(listFrom.assignee));
}
issues.forEach(issue => issue.addAssignee(this.assignee));
}
if (IS_EE && this.milestone) {
if (listFrom && listFrom.type === 'milestone') {
issues.forEach(issue => issue.removeMilestone(listFrom.milestone));
}
issues.forEach(issue => issue.addMilestone(this.milestone));
}
if (listFrom) {
this.issuesSize += issues.length;
this.updateMultipleIssues(issues, listFrom, moveBeforeId, moveAfterId);
}
}
}
addIssue(issue, listFrom, newIndex) { addIssue(issue, listFrom, newIndex) {
let moveBeforeId = null; let moveBeforeId = null;
let moveAfterId = null; let moveAfterId = null;
@ -230,6 +278,23 @@ class List {
}); });
} }
moveMultipleIssues({ issues, oldIndicies, newIndex, moveBeforeId, moveAfterId }) {
oldIndicies.reverse().forEach(index => {
this.issues.splice(index, 1);
});
this.issues.splice(newIndex, 0, ...issues);
gl.boardService
.moveMultipleIssues({
ids: issues.map(issue => issue.id),
fromListId: null,
toListId: null,
moveBeforeId,
moveAfterId,
})
.catch(() => flash(__('Something went wrong while moving issues.')));
}
updateIssueLabel(issue, listFrom, moveBeforeId, moveAfterId) { updateIssueLabel(issue, listFrom, moveBeforeId, moveAfterId) {
gl.boardService gl.boardService
.moveIssue(issue.id, listFrom.id, this.id, moveBeforeId, moveAfterId) .moveIssue(issue.id, listFrom.id, this.id, moveBeforeId, moveAfterId)
@ -238,10 +303,37 @@ class List {
}); });
} }
updateMultipleIssues(issues, listFrom, moveBeforeId, moveAfterId) {
gl.boardService
.moveMultipleIssues({
ids: issues.map(issue => issue.id),
fromListId: listFrom.id,
toListId: this.id,
moveBeforeId,
moveAfterId,
})
.catch(() => flash(__('Something went wrong while moving issues.')));
}
findIssue(id) { findIssue(id) {
return this.issues.find(issue => issue.id === id); return this.issues.find(issue => issue.id === id);
} }
removeMultipleIssues(removeIssues) {
const ids = removeIssues.map(issue => issue.id);
this.issues = this.issues.filter(issue => {
const matchesRemove = ids.includes(issue.id);
if (matchesRemove) {
this.issuesSize -= 1;
issue.removeLabel(this.label);
}
return !matchesRemove;
});
}
removeIssue(removeIssue) { removeIssue(removeIssue) {
this.issues = this.issues.filter(issue => { this.issues = this.issues.filter(issue => {
const matchesRemove = removeIssue.id === issue.id; const matchesRemove = removeIssue.id === issue.id;

View file

@ -48,6 +48,16 @@ export default class BoardService {
return boardsStore.moveIssue(id, fromListId, toListId, moveBeforeId, moveAfterId); return boardsStore.moveIssue(id, fromListId, toListId, moveBeforeId, moveAfterId);
} }
moveMultipleIssues({
ids,
fromListId = null,
toListId = null,
moveBeforeId = null,
moveAfterId = null,
}) {
return boardsStore.moveMultipleIssues({ ids, fromListId, toListId, moveBeforeId, moveAfterId });
}
newIssue(id, issue) { newIssue(id, issue) {
return boardsStore.newIssue(id, issue); return boardsStore.newIssue(id, issue);
} }

View file

@ -11,6 +11,7 @@ import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility'; import { mergeUrlParams } from '~/lib/utils/url_utility';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import { ListType } from '../constants';
const boardsStore = { const boardsStore = {
disabled: false, disabled: false,
@ -39,6 +40,7 @@ const boardsStore = {
issue: {}, issue: {},
list: {}, list: {},
}, },
multiSelect: { list: [] },
setEndpoints({ boardsEndpoint, listsEndpoint, bulkUpdatePath, boardId, recentBoardsEndpoint }) { setEndpoints({ boardsEndpoint, listsEndpoint, bulkUpdatePath, boardId, recentBoardsEndpoint }) {
const listsEndpointGenerate = `${listsEndpoint}/generate.json`; const listsEndpointGenerate = `${listsEndpoint}/generate.json`;
@ -51,7 +53,6 @@ const boardsStore = {
recentBoardsEndpoint: `${recentBoardsEndpoint}.json`, recentBoardsEndpoint: `${recentBoardsEndpoint}.json`,
}; };
}, },
create() { create() {
this.state.lists = []; this.state.lists = [];
this.filter.path = getUrlParamsArray().join('&'); this.filter.path = getUrlParamsArray().join('&');
@ -134,6 +135,107 @@ const boardsStore = {
Object.assign(this.moving, { list, issue }); Object.assign(this.moving, { list, issue });
}, },
moveMultipleIssuesToList({ listFrom, listTo, issues, newIndex }) {
const issueTo = issues.map(issue => listTo.findIssue(issue.id));
const issueLists = _.flatten(issues.map(issue => issue.getLists()));
const listLabels = issueLists.map(list => list.label);
const hasMoveableIssues = _.compact(issueTo).length > 0;
if (!hasMoveableIssues) {
// Check if target list assignee is already present in this issue
if (
listTo.type === ListType.assignee &&
listFrom.type === ListType.assignee &&
issues.some(issue => issue.findAssignee(listTo.assignee))
) {
const targetIssues = issues.map(issue => listTo.findIssue(issue.id));
targetIssues.forEach(targetIssue => targetIssue.removeAssignee(listFrom.assignee));
} else if (listTo.type === 'milestone') {
const currentMilestones = issues.map(issue => issue.milestone);
const currentLists = this.state.lists
.filter(list => list.type === 'milestone' && list.id !== listTo.id)
.filter(list =>
list.issues.some(listIssue => issues.some(issue => listIssue.id === issue.id)),
);
issues.forEach(issue => {
currentMilestones.forEach(milestone => {
issue.removeMilestone(milestone);
});
});
issues.forEach(issue => {
issue.addMilestone(listTo.milestone);
});
currentLists.forEach(currentList => {
issues.forEach(issue => {
currentList.removeIssue(issue);
});
});
listTo.addMultipleIssues(issues, listFrom, newIndex);
} else {
// Add to new lists issues if it doesn't already exist
listTo.addMultipleIssues(issues, listFrom, newIndex);
}
} else {
listTo.updateMultipleIssues(issues, listFrom);
issues.forEach(issue => {
issue.removeLabel(listFrom.label);
});
}
if (listTo.type === ListType.closed && listFrom.type !== ListType.backlog) {
issueLists.forEach(list => {
issues.forEach(issue => {
list.removeIssue(issue);
});
});
issues.forEach(issue => {
issue.removeLabels(listLabels);
});
} else if (listTo.type === ListType.backlog && listFrom.type === ListType.assignee) {
issues.forEach(issue => {
issue.removeAssignee(listFrom.assignee);
});
issueLists.forEach(list => {
issues.forEach(issue => {
list.removeIssue(issue);
});
});
} else if (listTo.type === ListType.backlog && listFrom.type === ListType.milestone) {
issues.forEach(issue => {
issue.removeMilestone(listFrom.milestone);
});
issueLists.forEach(list => {
issues.forEach(issue => {
list.removeIssue(issue);
});
});
} else if (
this.shouldRemoveIssue(listFrom, listTo) &&
this.issuesAreContiguous(listFrom, issues)
) {
listFrom.removeMultipleIssues(issues);
}
},
issuesAreContiguous(list, issues) {
// When there's only 1 issue selected, we can return early.
if (issues.length === 1) return true;
// Create list of ids for issues involved.
const listIssueIds = list.issues.map(issue => issue.id);
const movedIssueIds = issues.map(issue => issue.id);
// Check if moved issue IDs is sub-array
// of source list issue IDs (i.e. contiguous selection).
return listIssueIds.join('|').includes(movedIssueIds.join('|'));
},
moveIssueToList(listFrom, listTo, issue, newIndex) { moveIssueToList(listFrom, listTo, issue, newIndex) {
const issueTo = listTo.findIssue(issue.id); const issueTo = listTo.findIssue(issue.id);
const issueLists = issue.getLists(); const issueLists = issue.getLists();
@ -195,6 +297,17 @@ const boardsStore = {
list.moveIssue(issue, oldIndex, newIndex, beforeId, afterId); list.moveIssue(issue, oldIndex, newIndex, beforeId, afterId);
}, },
moveMultipleIssuesInList({ list, issues, oldIndicies, newIndex, idArray }) {
const beforeId = parseInt(idArray[newIndex - 1], 10) || null;
const afterId = parseInt(idArray[newIndex + issues.length], 10) || null;
list.moveMultipleIssues({
issues,
oldIndicies,
newIndex,
moveBeforeId: beforeId,
moveAfterId: afterId,
});
},
findList(key, val, type = 'label') { findList(key, val, type = 'label') {
const filteredList = this.state.lists.filter(list => { const filteredList = this.state.lists.filter(list => {
const byType = type const byType = type
@ -260,6 +373,10 @@ const boardsStore = {
}`; }`;
}, },
generateMultiDragPath(boardId) {
return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues/bulk_move`;
},
all() { all() {
return axios.get(this.state.endpoints.listsEndpoint); return axios.get(this.state.endpoints.listsEndpoint);
}, },
@ -309,6 +426,16 @@ const boardsStore = {
}); });
}, },
moveMultipleIssues({ ids, fromListId, toListId, moveBeforeId, moveAfterId }) {
return axios.put(this.generateMultiDragPath(this.state.endpoints.boardId), {
from_list_id: fromListId,
to_list_id: toListId,
move_before_id: moveBeforeId,
move_after_id: moveAfterId,
ids,
});
},
newIssue(id, issue) { newIssue(id, issue) {
return axios.post(this.generateIssuesPath(id), { return axios.post(this.generateIssuesPath(id), {
issue, issue,
@ -379,6 +506,25 @@ const boardsStore = {
setCurrentBoard(board) { setCurrentBoard(board) {
this.state.currentBoard = board; this.state.currentBoard = board;
}, },
toggleMultiSelect(issue) {
const selectedIssueIds = this.multiSelect.list.map(issue => issue.id);
const index = selectedIssueIds.indexOf(issue.id);
if (index === -1) {
this.multiSelect.list.push(issue);
return;
}
this.multiSelect.list = [
...this.multiSelect.list.slice(0, index),
...this.multiSelect.list.slice(index + 1),
];
},
clearMultiSelect() {
this.multiSelect.list = [];
},
}; };
BoardsStoreEE.initEESpecific(boardsStore); BoardsStoreEE.initEESpecific(boardsStore);

View file

@ -1,4 +1,4 @@
/* eslint-disable func-names, prefer-arrow-callback */ /* eslint-disable func-names */
import $ from 'jquery'; import $ from 'jquery';
import { visitUrl } from './lib/utils/url_utility'; import { visitUrl } from './lib/utils/url_utility';
@ -12,11 +12,11 @@ export default class BuildArtifacts {
} }
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
disablePropagation() { disablePropagation() {
$('.top-block').on('click', '.download', function(e) { $('.top-block').on('click', '.download', e => {
return e.stopPropagation(); e.stopPropagation();
}); });
return $('.tree-holder').on('click', 'tr[data-link] a', function(e) { return $('.tree-holder').on('click', 'tr[data-link] a', e => {
return e.stopImmediatePropagation(); e.stopImmediatePropagation();
}); });
} }
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this

View file

@ -41,6 +41,8 @@ export default class Clusters {
managePrometheusPath, managePrometheusPath,
clusterEnvironmentsPath, clusterEnvironmentsPath,
hasRbac, hasRbac,
providerType,
preInstalledKnative,
clusterType, clusterType,
clusterStatus, clusterStatus,
clusterStatusReason, clusterStatusReason,
@ -50,6 +52,7 @@ export default class Clusters {
environmentsHelpPath, environmentsHelpPath,
clustersHelpPath, clustersHelpPath,
deployBoardsHelpPath, deployBoardsHelpPath,
cloudRunHelpPath,
clusterId, clusterId,
} = document.querySelector('.js-edit-cluster-form').dataset; } = document.querySelector('.js-edit-cluster-form').dataset;
@ -65,10 +68,13 @@ export default class Clusters {
environmentsHelpPath, environmentsHelpPath,
clustersHelpPath, clustersHelpPath,
deployBoardsHelpPath, deployBoardsHelpPath,
cloudRunHelpPath,
); );
this.store.setManagePrometheusPath(managePrometheusPath); this.store.setManagePrometheusPath(managePrometheusPath);
this.store.updateStatus(clusterStatus); this.store.updateStatus(clusterStatus);
this.store.updateStatusReason(clusterStatusReason); this.store.updateStatusReason(clusterStatusReason);
this.store.updateProviderType(providerType);
this.store.updatePreInstalledKnative(preInstalledKnative);
this.store.updateRbac(hasRbac); this.store.updateRbac(hasRbac);
this.service = new ClustersService({ this.service = new ClustersService({
endpoint: statusPath, endpoint: statusPath,
@ -153,6 +159,9 @@ export default class Clusters {
ingressHelpPath: this.state.ingressHelpPath, ingressHelpPath: this.state.ingressHelpPath,
managePrometheusPath: this.state.managePrometheusPath, managePrometheusPath: this.state.managePrometheusPath,
ingressDnsHelpPath: this.state.ingressDnsHelpPath, ingressDnsHelpPath: this.state.ingressDnsHelpPath,
cloudRunHelpPath: this.state.cloudRunHelpPath,
providerType: this.state.providerType,
preInstalledKnative: this.state.preInstalledKnative,
rbac: this.state.rbac, rbac: this.state.rbac,
}, },
}); });

View file

@ -78,6 +78,10 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
installedVia: {
type: String,
required: false,
},
version: { version: {
type: String, type: String,
required: false, required: false,
@ -311,6 +315,11 @@ export default {
> >
<span v-else class="js-cluster-application-title">{{ title }}</span> <span v-else class="js-cluster-application-title">{{ title }}</span>
</strong> </strong>
<span
v-if="installedVia"
class="js-cluster-application-installed-via"
v-html="installedVia"
></span>
<slot name="description"></slot> <slot name="description"></slot>
<div v-if="hasError" class="cluster-application-error text-danger prepend-top-10"> <div v-if="hasError" class="cluster-application-error text-danger prepend-top-10">
<p class="js-cluster-application-general-error-message append-bottom-0"> <p class="js-cluster-application-general-error-message append-bottom-0">

View file

@ -16,7 +16,7 @@ import { s__, sprintf } from '../../locale';
import applicationRow from './application_row.vue'; import applicationRow from './application_row.vue';
import clipboardButton from '../../vue_shared/components/clipboard_button.vue'; import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
import KnativeDomainEditor from './knative_domain_editor.vue'; import KnativeDomainEditor from './knative_domain_editor.vue';
import { CLUSTER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants'; import { CLUSTER_TYPE, PROVIDER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants';
import LoadingButton from '~/vue_shared/components/loading_button.vue'; import LoadingButton from '~/vue_shared/components/loading_button.vue';
import eventHub from '~/clusters/event_hub'; import eventHub from '~/clusters/event_hub';
@ -54,11 +54,26 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
cloudRunHelpPath: {
type: String,
required: false,
default: '',
},
managePrometheusPath: { managePrometheusPath: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
}, },
providerType: {
type: String,
required: false,
default: '',
},
preInstalledKnative: {
type: Boolean,
required: false,
default: false,
},
rbac: { rbac: {
type: Boolean, type: Boolean,
required: false, required: false,
@ -156,6 +171,25 @@ export default {
knative() { knative() {
return this.applications.knative; return this.applications.knative;
}, },
cloudRun() {
return this.providerType === PROVIDER_TYPE.GCP && this.preInstalledKnative;
},
installedVia() {
if (this.cloudRun) {
return sprintf(
_.escape(s__(`ClusterIntegration|installed via %{installed_via}`)),
{
installed_via: `<a href="${
this.cloudRunHelpPath
}" target="_blank" rel="noopener noreferrer">${_.escape(
s__('ClusterIntegration|Cloud Run'),
)}</a>`,
},
false,
);
}
return null;
},
}, },
created() { created() {
this.helmInstallIllustration = helmInstallIllustration; this.helmInstallIllustration = helmInstallIllustration;
@ -260,7 +294,7 @@ export default {
<span class="input-group-append"> <span class="input-group-append">
<clipboard-button <clipboard-button
:text="ingressExternalEndpoint" :text="ingressExternalEndpoint"
:title="s__('ClusterIntegration|Copy Ingress Endpoint to clipboard')" :title="s__('ClusterIntegration|Copy Ingress Endpoint')"
class="input-group-text js-clipboard-btn" class="input-group-text js-clipboard-btn"
/> />
</span> </span>
@ -438,7 +472,7 @@ export default {
<span class="input-group-btn"> <span class="input-group-btn">
<clipboard-button <clipboard-button
:text="jupyterHostname" :text="jupyterHostname"
:title="s__('ClusterIntegration|Copy Jupyter Hostname to clipboard')" :title="s__('ClusterIntegration|Copy Jupyter Hostname')"
class="js-clipboard-btn" class="js-clipboard-btn"
/> />
</span> </span>
@ -468,6 +502,7 @@ export default {
:installed="applications.knative.installed" :installed="applications.knative.installed"
:install-failed="applications.knative.installFailed" :install-failed="applications.knative.installFailed"
:install-application-request-params="{ hostname: applications.knative.hostname }" :install-application-request-params="{ hostname: applications.knative.hostname }"
:installed-via="installedVia"
:uninstallable="applications.knative.uninstallable" :uninstallable="applications.knative.uninstallable"
:uninstall-successful="applications.knative.uninstallSuccessful" :uninstall-successful="applications.knative.uninstallSuccessful"
:uninstall-failed="applications.knative.uninstallFailed" :uninstall-failed="applications.knative.uninstallFailed"
@ -499,7 +534,7 @@ export default {
</p> </p>
<knative-domain-editor <knative-domain-editor
v-if="knative.installed || (helmInstalled && rbac)" v-if="(knative.installed || (helmInstalled && rbac)) && !preInstalledKnative"
:knative="knative" :knative="knative"
:ingress-dns-help-path="ingressDnsHelpPath" :ingress-dns-help-path="ingressDnsHelpPath"
@save="saveKnativeDomain" @save="saveKnativeDomain"

View file

@ -103,7 +103,7 @@ export default {
<span class="input-group-append"> <span class="input-group-append">
<clipboard-button <clipboard-button
:text="knativeExternalEndpoint" :text="knativeExternalEndpoint"
:title="s__('ClusterIntegration|Copy Knative Endpoint to clipboard')" :title="s__('ClusterIntegration|Copy Knative Endpoint')"
class="input-group-text js-knative-endpoint-clipboard-btn" class="input-group-text js-knative-endpoint-clipboard-btn"
/> />
</span> </span>

View file

@ -5,8 +5,14 @@ import trackUninstallButtonClickMixin from 'ee_else_ce/clusters/mixins/track_uni
import { HELM, INGRESS, CERT_MANAGER, PROMETHEUS, RUNNER, KNATIVE, JUPYTER } from '../constants'; import { HELM, INGRESS, CERT_MANAGER, PROMETHEUS, RUNNER, KNATIVE, JUPYTER } from '../constants';
const CUSTOM_APP_WARNING_TEXT = { const CUSTOM_APP_WARNING_TEXT = {
[HELM]: s__( [HELM]: sprintf(
'ClusterIntegration|The associated Tiller pod will be deleted and cannot be restored.', s__(
'ClusterIntegration|The associated Tiller pod, the %{gitlabManagedAppsNamespace} namespace, and all of its resources will be deleted and cannot be restored.',
),
{
gitlabManagedAppsNamespace: '<code>gitlab-managed-apps</code>',
},
false,
), ),
[INGRESS]: s__( [INGRESS]: s__(
'ClusterIntegration|The associated load balancer and IP will be deleted and cannot be restored.', 'ClusterIntegration|The associated load balancer and IP will be deleted and cannot be restored.',
@ -76,6 +82,7 @@ export default {
:modal-id="modalId" :modal-id="modalId"
:title="title" :title="title"
@ok="confirmUninstall()" @ok="confirmUninstall()"
>{{ warningText }} {{ customAppWarningText }}</gl-modal
> >
{{ warningText }} <span v-html="customAppWarningText"></span>
</gl-modal>
</template> </template>

View file

@ -5,6 +5,11 @@ export const CLUSTER_TYPE = {
PROJECT: 'project_type', PROJECT: 'project_type',
}; };
// These need to match the available providers in app/models/clusters/providers/
export const PROVIDER_TYPE = {
GCP: 'gcp',
};
// These need to match what is returned from the server // These need to match what is returned from the server
export const APPLICATION_STATUS = { export const APPLICATION_STATUS = {
NO_STATUS: null, NO_STATUS: null,
@ -19,6 +24,7 @@ export const APPLICATION_STATUS = {
UNINSTALLING: 'uninstalling', UNINSTALLING: 'uninstalling',
UNINSTALL_ERRORED: 'uninstall_errored', UNINSTALL_ERRORED: 'uninstall_errored',
ERROR: 'errored', ERROR: 'errored',
PRE_INSTALLED: 'pre_installed',
}; };
/* /*
@ -29,6 +35,7 @@ export const APPLICATION_INSTALLED_STATUSES = [
APPLICATION_STATUS.INSTALLED, APPLICATION_STATUS.INSTALLED,
APPLICATION_STATUS.UPDATING, APPLICATION_STATUS.UPDATING,
APPLICATION_STATUS.UNINSTALLING, APPLICATION_STATUS.UNINSTALLING,
APPLICATION_STATUS.PRE_INSTALLED,
]; ];
// These are only used client-side // These are only used client-side

View file

@ -13,6 +13,7 @@ const {
UPDATE_ERRORED, UPDATE_ERRORED,
UNINSTALLING, UNINSTALLING,
UNINSTALL_ERRORED, UNINSTALL_ERRORED,
PRE_INSTALLED,
} = APPLICATION_STATUS; } = APPLICATION_STATUS;
const applicationStateMachine = { const applicationStateMachine = {
@ -63,6 +64,9 @@ const applicationStateMachine = {
uninstallFailed: true, uninstallFailed: true,
}, },
}, },
[PRE_INSTALLED]: {
target: PRE_INSTALLED,
},
}, },
}, },
[NOT_INSTALLABLE]: { [NOT_INSTALLABLE]: {
@ -123,6 +127,27 @@ const applicationStateMachine = {
}, },
}, },
}, },
[PRE_INSTALLED]: {
on: {
[UPDATE_EVENT]: {
target: UPDATING,
effects: {
updateFailed: false,
updateSuccessful: false,
},
},
[NOT_INSTALLABLE]: {
target: NOT_INSTALLABLE,
},
[UNINSTALL_EVENT]: {
target: UNINSTALLING,
effects: {
uninstallFailed: false,
uninstallSuccessful: false,
},
},
},
},
[UPDATING]: { [UPDATING]: {
on: { on: {
[UPDATED]: { [UPDATED]: {

View file

@ -35,7 +35,10 @@ export default class ClusterStore {
environmentsHelpPath: null, environmentsHelpPath: null,
clustersHelpPath: null, clustersHelpPath: null,
deployBoardsHelpPath: null, deployBoardsHelpPath: null,
cloudRunHelpPath: null,
status: null, status: null,
providerType: null,
preInstalledKnative: false,
rbac: false, rbac: false,
statusReason: null, statusReason: null,
applications: { applications: {
@ -95,6 +98,7 @@ export default class ClusterStore {
environmentsHelpPath, environmentsHelpPath,
clustersHelpPath, clustersHelpPath,
deployBoardsHelpPath, deployBoardsHelpPath,
cloudRunHelpPath,
) { ) {
this.state.helpPath = helpPath; this.state.helpPath = helpPath;
this.state.ingressHelpPath = ingressHelpPath; this.state.ingressHelpPath = ingressHelpPath;
@ -102,6 +106,7 @@ export default class ClusterStore {
this.state.environmentsHelpPath = environmentsHelpPath; this.state.environmentsHelpPath = environmentsHelpPath;
this.state.clustersHelpPath = clustersHelpPath; this.state.clustersHelpPath = clustersHelpPath;
this.state.deployBoardsHelpPath = deployBoardsHelpPath; this.state.deployBoardsHelpPath = deployBoardsHelpPath;
this.state.cloudRunHelpPath = cloudRunHelpPath;
} }
setManagePrometheusPath(managePrometheusPath) { setManagePrometheusPath(managePrometheusPath) {
@ -112,6 +117,14 @@ export default class ClusterStore {
this.state.status = status; this.state.status = status;
} }
updateProviderType(providerType) {
this.state.providerType = providerType;
}
updatePreInstalledKnative(preInstalledKnative) {
this.state.preInstalledKnative = parseBoolean(preInstalledKnative);
}
updateRbac(rbac) { updateRbac(rbac) {
this.state.rbac = parseBoolean(rbac); this.state.rbac = parseBoolean(rbac);
} }

View file

@ -1,4 +1,4 @@
/* eslint-disable func-names, no-var, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, one-var, no-return-assign, no-unused-expressions, no-sequences */ /* eslint-disable func-names, no-var, no-else-return, consistent-return, one-var, no-return-assign, no-unused-expressions, no-sequences */
import $ from 'jquery'; import $ from 'jquery';
@ -13,14 +13,14 @@ export default class ImageFile {
$('.two-up.view .frame.deleted img', this.file), $('.two-up.view .frame.deleted img', this.file),
(function(_this) { (function(_this) {
return function() { return function() {
return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function() { return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), () => {
_this.initViewModes(); _this.initViewModes();
// Load two-up view after images are loaded // Load two-up view after images are loaded
// so that we can display the correct width and height information // so that we can display the correct width and height information
const $images = $('.two-up.view img', _this.file); const $images = $('.two-up.view img', _this.file);
$images.waitForImages(function() { $images.waitForImages(() => {
_this.initView('two-up'); _this.initView('two-up');
}); });
}); });
@ -49,13 +49,13 @@ export default class ImageFile {
activateViewMode(viewMode) { activateViewMode(viewMode) {
$('.view-modes-menu li', this.file) $('.view-modes-menu li', this.file)
.removeClass('active') .removeClass('active')
.filter('.' + viewMode) .filter(`.${viewMode}`)
.addClass('active'); .addClass('active');
return $('.view:visible:not(.' + viewMode + ')', this.file).fadeOut( return $(`.view:visible:not(.${viewMode})`, this.file).fadeOut(
200, 200,
(function(_this) { (function(_this) {
return function() { return function() {
$('.view.' + viewMode, _this.file).fadeIn(200); $(`.view.${viewMode}`, _this.file).fadeIn(200);
return _this.initView(viewMode); return _this.initView(viewMode);
}; };
})(this), })(this),
@ -138,9 +138,9 @@ export default class ImageFile {
return $(this).width(availWidth / 2); return $(this).width(availWidth / 2);
} }
}); });
return _this.requestImageInfo($('img', wrap), function(width, height) { return _this.requestImageInfo($('img', wrap), (width, height) => {
$('.image-info .meta-width', wrap).text(width + 'px'); $('.image-info .meta-width', wrap).text(`${width}px`);
$('.image-info .meta-height', wrap).text(height + 'px'); $('.image-info .meta-height', wrap).text(`${height}px`);
return $('.image-info', wrap).removeClass('hide'); return $('.image-info', wrap).removeClass('hide');
}); });
}; };
@ -175,7 +175,7 @@ export default class ImageFile {
wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10); wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10);
_this.initDraggable($swipeBar, wrapPadding, function(e, left) { _this.initDraggable($swipeBar, wrapPadding, (e, left) => {
if (left > 0 && left < $swipeFrame.width() - wrapPadding * 2) { if (left > 0 && left < $swipeFrame.width() - wrapPadding * 2) {
$swipeWrap.width(maxWidth + 1 - left); $swipeWrap.width(maxWidth + 1 - left);
$swipeBar.css('left', left); $swipeBar.css('left', left);
@ -215,7 +215,7 @@ export default class ImageFile {
$frameAdded.css('opacity', 1); $frameAdded.css('opacity', 1);
framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10); framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10);
_this.initDraggable($dragger, framePadding, function(e, left) { _this.initDraggable($dragger, framePadding, (e, left) => {
var opacity = left / dragTrackWidth; var opacity = left / dragTrackWidth;
if (opacity >= 0 && opacity <= 1) { if (opacity >= 0 && opacity <= 1) {

View file

@ -1,6 +1,8 @@
import Vue from 'vue'; import Vue from 'vue';
import '../vue_shared/vue_resource_interceptor'; import GlFeatureFlagsPlugin from '~/vue_shared/gl_feature_flags_plugin';
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
Vue.config.productionTip = false; Vue.config.productionTip = false;
} }
Vue.use(GlFeatureFlagsPlugin);

View file

@ -3,6 +3,8 @@ import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_searc
import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue'; import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue';
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue'; import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
const findItem = (items, valueProp, value) => items.find(item => item[valueProp] === value);
export default { export default {
components: { components: {
DropdownButton, DropdownButton,
@ -26,7 +28,7 @@ export default {
default: '', default: '',
}, },
value: { value: {
type: Object, type: [Object, String],
required: false, required: false,
default: () => null, default: () => null,
}, },
@ -93,8 +95,8 @@ export default {
}, },
data() { data() {
return { return {
selectedItem: findItem(this.items, this.value),
searchQuery: '', searchQuery: '',
selectedItem: null,
}; };
}, },
computed: { computed: {
@ -127,10 +129,15 @@ export default {
return (this.selectedItem && this.selectedItem[this.valueProperty]) || ''; return (this.selectedItem && this.selectedItem[this.valueProperty]) || '';
}, },
}, },
watch: {
value(value) {
this.selectedItem = findItem(this.items, this.valueProperty, value);
},
},
methods: { methods: {
select(item) { select(item) {
this.selectedItem = item; this.selectedItem = item;
this.$emit('input', item); this.$emit('input', item[this.valueProperty]);
}, },
}, },
}; };

View file

@ -7,8 +7,23 @@ export default {
ServiceCredentialsForm, ServiceCredentialsForm,
EksClusterConfigurationForm, EksClusterConfigurationForm,
}, },
props: {
gitlabManagedClusterHelpPath: {
type: String,
required: true,
},
kubernetesIntegrationHelpPath: {
type: String,
required: true,
},
},
}; };
</script> </script>
<template> <template>
<eks-cluster-configuration-form /> <div class="js-create-eks-cluster">
<eks-cluster-configuration-form
:gitlab-managed-cluster-help-path="gitlabManagedClusterHelpPath"
:kubernetes-integration-help-path="kubernetesIntegrationHelpPath"
/>
</div>
</template> </template>

View file

@ -1,25 +1,394 @@
<script> <script>
import RoleNameDropdown from './role_name_dropdown.vue'; import { createNamespacedHelpers, mapState, mapActions } from 'vuex';
import SecurityGroupDropdown from './security_group_dropdown.vue'; import { sprintf, s__ } from '~/locale';
import SubnetDropdown from './subnet_dropdown.vue'; import _ from 'underscore';
import VPCDropdown from './vpc_dropdown.vue'; import { GlFormInput, GlFormCheckbox } from '@gitlab/ui';
import ClusterFormDropdown from './cluster_form_dropdown.vue';
import RegionDropdown from './region_dropdown.vue';
import { KUBERNETES_VERSIONS } from '../constants';
const { mapState: mapRolesState, mapActions: mapRolesActions } = createNamespacedHelpers('roles');
const { mapState: mapRegionsState, mapActions: mapRegionsActions } = createNamespacedHelpers(
'regions',
);
const { mapState: mapKeyPairsState, mapActions: mapKeyPairsActions } = createNamespacedHelpers(
'keyPairs',
);
const { mapState: mapVpcsState, mapActions: mapVpcActions } = createNamespacedHelpers('vpcs');
const { mapState: mapSubnetsState, mapActions: mapSubnetActions } = createNamespacedHelpers(
'subnets',
);
const {
mapState: mapSecurityGroupsState,
mapActions: mapSecurityGroupsActions,
} = createNamespacedHelpers('securityGroups');
export default { export default {
components: { components: {
RoleNameDropdown, ClusterFormDropdown,
SecurityGroupDropdown, RegionDropdown,
SubnetDropdown, GlFormInput,
VPCDropdown, GlFormCheckbox,
},
props: {
gitlabManagedClusterHelpPath: {
type: String,
required: true,
},
kubernetesIntegrationHelpPath: {
type: String,
required: true,
},
},
computed: {
...mapState([
'clusterName',
'environmentScope',
'kubernetesVersion',
'selectedRegion',
'selectedKeyPair',
'selectedVpc',
'selectedSubnet',
'selectedRole',
'selectedSecurityGroup',
'gitlabManagedCluster',
]),
...mapRolesState({
roles: 'items',
isLoadingRoles: 'isLoadingItems',
loadingRolesError: 'loadingItemsError',
}),
...mapRegionsState({
regions: 'items',
isLoadingRegions: 'isLoadingItems',
loadingRegionsError: 'loadingItemsError',
}),
...mapKeyPairsState({
keyPairs: 'items',
isLoadingKeyPairs: 'isLoadingItems',
loadingKeyPairsError: 'loadingItemsError',
}),
...mapVpcsState({
vpcs: 'items',
isLoadingVpcs: 'isLoadingItems',
loadingVpcsError: 'loadingItemsError',
}),
...mapSubnetsState({
subnets: 'items',
isLoadingSubnets: 'isLoadingItems',
loadingSubnetsError: 'loadingItemsError',
}),
...mapSecurityGroupsState({
securityGroups: 'items',
isLoadingSecurityGroups: 'isLoadingItems',
loadingSecurityGroupsError: 'loadingItemsError',
}),
kubernetesVersions() {
return KUBERNETES_VERSIONS;
},
vpcDropdownDisabled() {
return !this.selectedRegion;
},
keyPairDropdownDisabled() {
return !this.selectedRegion;
},
subnetDropdownDisabled() {
return !this.selectedVpc;
},
securityGroupDropdownDisabled() {
return !this.selectedVpc;
},
kubernetesIntegrationHelpText() {
const escapedUrl = _.escape(this.kubernetesIntegrationHelpPath);
return sprintf(
s__(
'ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration.',
),
{
link_start: `<a href="${escapedUrl}" target="_blank" rel="noopener noreferrer">`,
link_end: '</a>',
},
false,
);
},
roleDropdownHelpText() {
return sprintf(
s__(
'ClusterIntegration|Select the IAM Role to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role name, first create one on %{startLink}Amazon Web Services%{endLink}.',
),
{
startLink:
'<a href="https://console.aws.amazon.com/iam/home?#roles" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
keyPairDropdownHelpText() {
return sprintf(
s__(
'ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services%{endLink}.',
),
{
startLink:
'<a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#having-ec2-create-your-key-pair" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
vpcDropdownHelpText() {
return sprintf(
s__(
'ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services%{endLink}.',
),
{
startLink:
'<a href="https://console.aws.amazon.com/vpc/home?#vpc" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
subnetDropdownHelpText() {
return sprintf(
s__(
'ClusterIntegration|Choose the %{startLink}subnets%{endLink} in your VPC where your worker nodes will run.',
),
{
startLink:
'<a href="https://console.aws.amazon.com/vpc/home?#subnets" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
securityGroupDropdownHelpText() {
return sprintf(
s__(
'ClusterIntegration|Choose the %{startLink}security groups%{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets.',
),
{
startLink:
'<a href="https://console.aws.amazon.com/vpc/home?#securityGroups" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
gitlabManagedHelpText() {
const escapedUrl = _.escape(this.gitlabManagedClusterHelpPath);
return sprintf(
s__(
'ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}',
),
{
startLink: `<a href="${escapedUrl}" target="_blank" rel="noopener noreferrer">`,
endLink: '</a>',
},
false,
);
},
},
mounted() {
this.fetchRegions();
this.fetchRoles();
},
methods: {
...mapActions([
'setClusterName',
'setEnvironmentScope',
'setKubernetesVersion',
'setRegion',
'setVpc',
'setSubnet',
'setRole',
'setKeyPair',
'setSecurityGroup',
'setGitlabManagedCluster',
]),
...mapRegionsActions({ fetchRegions: 'fetchItems' }),
...mapVpcActions({ fetchVpcs: 'fetchItems' }),
...mapSubnetActions({ fetchSubnets: 'fetchItems' }),
...mapRolesActions({ fetchRoles: 'fetchItems' }),
...mapKeyPairsActions({ fetchKeyPairs: 'fetchItems' }),
...mapSecurityGroupsActions({ fetchSecurityGroups: 'fetchItems' }),
setRegionAndFetchVpcsAndKeyPairs(region) {
this.setRegion({ region });
this.fetchVpcs({ region });
this.fetchKeyPairs({ region });
},
setVpcAndFetchSubnets(vpc) {
this.setVpc({ vpc });
this.fetchSubnets({ vpc });
this.fetchSecurityGroups({ vpc });
},
}, },
}; };
</script> </script>
<template> <template>
<form name="eks-cluster-configuration-form"> <form name="eks-cluster-configuration-form">
<h2>
{{ s__('ClusterIntegration|Enter the details for your Amazon EKS Kubernetes cluster') }}
</h2>
<p v-html="kubernetesIntegrationHelpText"></p>
<div class="form-group"> <div class="form-group">
<label class="label-bold" name="role" for="eks-role"> <label class="label-bold" for="eks-cluster-name">{{
{{ s__('ClusterIntegration|Role name') }} s__('ClusterIntegration|Kubernetes cluster name')
</label> }}</label>
<role-name-dropdown /> <gl-form-input
id="eks-cluster-name"
:value="clusterName"
@input="setClusterName({ clusterName: $event })"
/>
</div>
<div class="form-group">
<label class="label-bold" for="eks-environment-scope">{{
s__('ClusterIntegration|Environment scope')
}}</label>
<gl-form-input
id="eks-environment-scope"
:value="environmentScope"
@input="setEnvironmentScope({ environmentScope: $event })"
/>
</div>
<div class="form-group">
<label class="label-bold" for="eks-kubernetes-version">{{
s__('ClusterIntegration|Kubernetes version')
}}</label>
<cluster-form-dropdown
field-id="eks-kubernetes-version"
field-name="eks-kubernetes-version"
:value="kubernetesVersion"
:items="kubernetesVersions"
:empty-text="s__('ClusterIntegration|Kubernetes version not found')"
@input="setKubernetesVersion({ kubernetesVersion: $event })"
/>
<p class="form-text text-muted" v-html="roleDropdownHelpText"></p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Role name') }}</label>
<cluster-form-dropdown
field-id="eks-role"
field-name="eks-role"
:input="selectedRole"
:items="roles"
:loading="isLoadingRoles"
:loading-text="s__('ClusterIntegration|Loading IAM Roles')"
:placeholder="s__('ClusterIntergation|Select role name')"
:search-field-placeholder="s__('ClusterIntegration|Search IAM Roles')"
:empty-text="s__('ClusterIntegration|No IAM Roles found')"
:has-errors="Boolean(loadingRolesError)"
:error-message="s__('ClusterIntegration|Could not load IAM roles')"
@input="setRole({ role: $event })"
/>
<p class="form-text text-muted" v-html="roleDropdownHelpText"></p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Region') }}</label>
<region-dropdown
:value="selectedRegion"
:regions="regions"
:error="loadingRegionsError"
:loading="isLoadingRegions"
@input="setRegionAndFetchVpcsAndKeyPairs($event)"
/>
</div>
<div class="form-group">
<label class="label-bold" for="eks-key-pair">{{
s__('ClusterIntegration|Key pair name')
}}</label>
<cluster-form-dropdown
field-id="eks-key-pair"
field-name="eks-key-pair"
:input="selectedKeyPair"
:items="keyPairs"
:disabled="keyPairDropdownDisabled"
:disabled-text="s__('ClusterIntegration|Select a region to choose a Key Pair')"
:loading="isLoadingKeyPairs"
:loading-text="s__('ClusterIntegration|Loading Key Pairs')"
:placeholder="s__('ClusterIntergation|Select key pair')"
:search-field-placeholder="s__('ClusterIntegration|Search Key Pairs')"
:empty-text="s__('ClusterIntegration|No Key Pairs found')"
:has-errors="Boolean(loadingKeyPairsError)"
:error-message="s__('ClusterIntegration|Could not load Key Pairs')"
@input="setKeyPair({ keyPair: $event })"
/>
<p class="form-text text-muted" v-html="keyPairDropdownHelpText"></p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-vpc">{{ s__('ClusterIntegration|VPC') }}</label>
<cluster-form-dropdown
field-id="eks-vpc"
field-name="eks-vpc"
:input="selectedVpc"
:items="vpcs"
:loading="isLoadingVpcs"
:disabled="vpcDropdownDisabled"
:disabled-text="s__('ClusterIntegration|Select a region to choose a VPC')"
:loading-text="s__('ClusterIntegration|Loading VPCs')"
:placeholder="s__('ClusterIntergation|Select a VPC')"
:search-field-placeholder="s__('ClusterIntegration|Search VPCs')"
:empty-text="s__('ClusterIntegration|No VPCs found')"
:has-errors="Boolean(loadingVpcsError)"
:error-message="s__('ClusterIntegration|Could not load VPCs for the selected region')"
@input="setVpcAndFetchSubnets($event)"
/>
<p class="form-text text-muted" v-html="vpcDropdownHelpText"></p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Subnet') }}</label>
<cluster-form-dropdown
field-id="eks-subnet"
field-name="eks-subnet"
:input="selectedSubnet"
:items="subnets"
:loading="isLoadingSubnets"
:disabled="subnetDropdownDisabled"
:disabled-text="s__('ClusterIntegration|Select a VPC to choose a subnet')"
:loading-text="s__('ClusterIntegration|Loading subnets')"
:placeholder="s__('ClusterIntergation|Select a subnet')"
:search-field-placeholder="s__('ClusterIntegration|Search subnets')"
:empty-text="s__('ClusterIntegration|No subnet found')"
:has-errors="Boolean(loadingSubnetsError)"
:error-message="s__('ClusterIntegration|Could not load subnets for the selected VPC')"
@input="setSubnet({ subnet: $event })"
/>
<p class="form-text text-muted" v-html="subnetDropdownHelpText"></p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-security-group">{{
s__('ClusterIntegration|Security groups')
}}</label>
<cluster-form-dropdown
field-id="eks-security-group"
field-name="eks-security-group"
:input="selectedSecurityGroup"
:items="securityGroups"
:loading="isLoadingSecurityGroups"
:disabled="securityGroupDropdownDisabled"
:disabled-text="s__('ClusterIntegration|Select a VPC to choose a security group')"
:loading-text="s__('ClusterIntegration|Loading security groups')"
:placeholder="s__('ClusterIntergation|Select a security group')"
:search-field-placeholder="s__('ClusterIntegration|Search security groups')"
:empty-text="s__('ClusterIntegration|No security group found')"
:has-errors="Boolean(loadingSecurityGroupsError)"
:error-message="
s__('ClusterIntegration|Could not load security groups for the selected VPC')
"
@input="setSecurityGroup({ securityGroup: $event })"
/>
<p class="form-text text-muted" v-html="securityGroupDropdownHelpText"></p>
</div>
<div class="form-group">
<gl-form-checkbox
:checked="gitlabManagedCluster"
@input="setGitlabManagedCluster({ gitlabManagedCluster: $event })"
>{{ s__('ClusterIntegration|GitLab-managed cluster') }}</gl-form-checkbox
>
<p class="form-text text-muted" v-html="gitlabManagedHelpText"></p>
</div> </div>
</form> </form>
</template> </template>

View file

@ -0,0 +1,63 @@
<script>
import { sprintf, s__ } from '~/locale';
import ClusterFormDropdown from './cluster_form_dropdown.vue';
export default {
components: {
ClusterFormDropdown,
},
props: {
regions: {
type: Array,
required: false,
default: () => [],
},
loading: {
type: Boolean,
required: false,
default: false,
},
error: {
type: Object,
required: false,
default: null,
},
},
computed: {
hasErrors() {
return Boolean(this.error);
},
helpText() {
return sprintf(
s__('ClusterIntegration|Learn more about %{startLink}Regions%{endLink}.'),
{
startLink:
'<a href="https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
},
};
</script>
<template>
<div>
<cluster-form-dropdown
field-id="eks-region"
field-name="eks-region"
:items="regions"
:loading="loading"
:loading-text="s__('ClusterIntegration|Loading Regions')"
:placeholder="s__('ClusterIntergation|Select a region')"
:search-field-placeholder="s__('ClusterIntegration|Search regions')"
:empty-text="s__('ClusterIntegration|No region found')"
:has-errors="hasErrors"
:error-message="s__('ClusterIntegration|Could not load regions from your AWS account')"
v-bind="$attrs"
v-on="$listeners"
/>
<p class="form-text text-muted" v-html="helpText"></p>
</div>
</template>

View file

@ -1,53 +0,0 @@
<script>
import { sprintf, s__ } from '~/locale';
import ClusterFormDropdown from './cluster_form_dropdown.vue';
export default {
components: {
ClusterFormDropdown,
},
props: {
roles: {
type: Array,
required: false,
default: () => [],
},
loading: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
helpText() {
return sprintf(
s__(
'ClusterIntegration|Select the IAM Role to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role name, first create one on %{startLink}Amazon Web Services%{endLink}.',
),
{
startLink:
'<a href="https://console.aws.amazon.com/iam/home?#roles" target="_blank" rel="noopener noreferrer">',
endLink: '</a>',
},
false,
);
},
},
};
</script>
<template>
<div>
<cluster-form-dropdown
field-id="eks-role-name"
field-name="eks-role-name"
:items="roles"
:loading="loading"
:loading-text="s__('ClusterIntegration|Loading IAM Roles')"
:placeholder="s__('ClusterIntergation|Select role name')"
:search-field-placeholder="s__('ClusterIntegration|Search IAM Roles')"
:empty-text="s__('ClusterIntegration|No IAM Roles found')"
/>
<p class="form-text text-muted" v-html="helpText"></p>
</div>
</template>

Some files were not shown because too many files have changed in this diff Show more