diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml index cb35d5ff56d..d5eaa7768ea 100644 --- a/.gitlab/ci/global.gitlab-ci.yml +++ b/.gitlab/ci/global.gitlab-ci.yml @@ -213,296 +213,165 @@ - *node-modules-cache # We don't push this cache as it's already rebuilt by `update-assets-compile-*-cache` - *storybook-node-modules-cache-push -.use-pg12: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-12-pgvector-0.4.1 +.pg-base-variables: + variables: + POSTGRES_HOST_AUTH_METHOD: trust + +.db-services: + services: &db-services + - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-${PG_VERSION}-pgvector-0.4.1 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] alias: postgres - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine + - name: redis:6.2-alpine + +.use-pg12: + extends: + - .pg-base-variables + - .db-services variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "12" .use-pg13: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-13-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.2-alpine + extends: + - .pg-base-variables + - .db-services variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "13" .use-pg14: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-14-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.2-alpine + extends: + - .pg-base-variables + - .db-services variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "14" .use-pg15: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-15-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.2-alpine + extends: + - .pg-base-variables + - .db-services variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "15" +.zoekt-variables: + variables: + ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 + ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 + +.zoekt-services: + services: + - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 + alias: zoekt-ci-image + +.es7-base: + extends: + - .pg-base-variables + - .zoekt-variables + services: + - !reference [.db-services, services] + - !reference [.zoekt-services, services] + - name: elasticsearch:7.17.6 + command: ["elasticsearch", "-E", "discovery.type=single-node", "-E", "xpack.security.enabled=false"] + .use-pg12-es7-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-12-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine - - name: elasticsearch:7.17.6 - command: ["elasticsearch", "-E", "discovery.type=single-node", "-E", "xpack.security.enabled=false"] - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + extends: .es7-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "12" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 .use-pg13-es7-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-13-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.2-alpine - - name: elasticsearch:7.17.6 - command: ["elasticsearch", "-E", "discovery.type=single-node", "-E", "xpack.security.enabled=false"] - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + extends: .es7-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "13" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 .use-pg14-es7-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-14-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.2-alpine - - name: elasticsearch:7.17.6 - command: ["elasticsearch", "-E", "discovery.type=single-node", "-E", "xpack.security.enabled=false"] - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + extends: .es7-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "14" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 .use-pg15-es7-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-15-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.2-alpine - - name: elasticsearch:7.17.6 - command: ["elasticsearch", "-E", "discovery.type=single-node", "-E", "xpack.security.enabled=false"] - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + extends: .es7-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "15" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 + +.es8-base: + extends: + - .pg-base-variables + - .zoekt-variables + services: + - !reference [.db-services, services] + - !reference [.zoekt-services, services] + - name: elasticsearch:8.6.2 + variables: + ES_SETTING_DISCOVERY_TYPE: "single-node" + ES_SETTING_XPACK_SECURITY_ENABLED: "false" .use-pg13-es8-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-13-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine - - name: elasticsearch:8.6.2 - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + extends: .es8-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "13" - ES_SETTING_DISCOVERY_TYPE: "single-node" - ES_SETTING_XPACK_SECURITY_ENABLED: "false" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 .use-pg14-es8-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-14-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine - - name: elasticsearch:8.6.2 - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + extends: .es8-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "14" - ES_SETTING_DISCOVERY_TYPE: "single-node" - ES_SETTING_XPACK_SECURITY_ENABLED: "false" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 .use-pg15-es8-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-15-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine - - name: elasticsearch:8.6.2 - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + extends: .es8-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "15" - ES_SETTING_DISCOVERY_TYPE: "single-node" - ES_SETTING_XPACK_SECURITY_ENABLED: "false" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 + +.os1-base: + extends: + - .pg-base-variables + - .zoekt-variables + services: + - !reference [.db-services, services] + - !reference [.zoekt-services, services] + - name: opensearchproject/opensearch:1.3.5 + alias: elasticsearch + command: ["bin/opensearch", "-E", "discovery.type=single-node", "-E", "plugins.security.disabled=true"] .use-pg13-opensearch1-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-13-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine - - name: opensearchproject/opensearch:1.3.5 - alias: elasticsearch - command: ["bin/opensearch", "-E", "discovery.type=single-node", "-E", "plugins.security.disabled=true"] - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + extends: .os1-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "13" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 - -.use-pg13-opensearch2-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-13-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine - - name: opensearchproject/opensearch:2.2.1 - alias: elasticsearch - command: ["bin/opensearch", "-E", "discovery.type=single-node", "-E", "plugins.security.disabled=true"] - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image - variables: - POSTGRES_HOST_AUTH_METHOD: trust - PG_VERSION: "13" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 .use-pg14-opensearch1-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-14-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine - - name: opensearchproject/opensearch:1.3.5 - alias: elasticsearch - command: ["bin/opensearch", "-E", "discovery.type=single-node", "-E", "plugins.security.disabled=true"] - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + extends: .os1-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "14" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 - -.use-pg14-opensearch2-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-14-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine - - name: opensearchproject/opensearch:2.2.1 - alias: elasticsearch - command: ["bin/opensearch", "-E", "discovery.type=single-node", "-E", "plugins.security.disabled=true"] - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image - variables: - POSTGRES_HOST_AUTH_METHOD: trust - PG_VERSION: "14" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 .use-pg15-opensearch1-ee: - services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-15-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine - - name: opensearchproject/opensearch:1.3.5 - alias: elasticsearch - command: ["bin/opensearch", "-E", "discovery.type=single-node", "-E", "plugins.security.disabled=true"] - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + extends: .os1-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "15" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 -.use-pg15-opensearch2-ee: +.os2-base: + extends: + - .pg-base-variables + - .zoekt-variables services: - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:postgres-15-pgvector-0.4.1 - command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off", "-c", "max_locks_per_transaction=128"] - alias: postgres - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:redis-cluster-6.2.12 - alias: rediscluster # configure connections in config/redis.yml - - name: redis:6.0-alpine + - !reference [.db-services, services] + - !reference [.zoekt-services, services] - name: opensearchproject/opensearch:2.2.1 alias: elasticsearch command: ["bin/opensearch", "-E", "discovery.type=single-node", "-E", "plugins.security.disabled=true"] - - name: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images:zoekt-ci-image-1.1 - alias: zoekt-ci-image + +.use-pg13-opensearch2-ee: + extends: .os2-base + variables: + PG_VERSION: "13" + +.use-pg14-opensearch2-ee: + extends: .os2-base + variables: + PG_VERSION: "14" + +.use-pg15-opensearch2-ee: + extends: .os2-base variables: - POSTGRES_HOST_AUTH_METHOD: trust PG_VERSION: "15" - ZOEKT_INDEX_BASE_URL: http://zoekt-ci-image:6060 - ZOEKT_SEARCH_BASE_URL: http://zoekt-ci-image:6070 .use-kaniko: image: diff --git a/app/assets/javascripts/notes/components/comment_type_dropdown.vue b/app/assets/javascripts/notes/components/comment_type_dropdown.vue index 543be838920..2e4f925194f 100644 --- a/app/assets/javascripts/notes/components/comment_type_dropdown.vue +++ b/app/assets/javascripts/notes/components/comment_type_dropdown.vue @@ -1,16 +1,20 @@ diff --git a/app/assets/javascripts/observability/client.js b/app/assets/javascripts/observability/client.js new file mode 100644 index 00000000000..6e39d2b450b --- /dev/null +++ b/app/assets/javascripts/observability/client.js @@ -0,0 +1,41 @@ +// import axios from '~/lib/utils/axios_utils'; +import * as mockData from './mock_traces.json'; + +function enableTraces(provisioningUrl) { + console.log(`Enabling tracing - ${provisioningUrl}`); // eslint-disable-line no-console + + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, 500); + }); +} + +function isTracingEnabled(provisioningUrl) { + console.log(`Checking status - ${provisioningUrl}`); // eslint-disable-line no-console + + return new Promise((resolve) => { + setTimeout(() => { + resolve(false); + }, 1000); + }); +} + +function fetchTraces(tracingUrl) { + console.log(`Fetching traces from ${tracingUrl}`); // eslint-disable-line no-console + + // axios.get(`${this.endpoint}/v1/jaeger/22/api/services`, { credentials: 'include' }); + return new Promise((resolve) => { + setTimeout(() => { + resolve(mockData.data); + }, 2000); + }); +} + +export function buildClient({ provisioningUrl, tracingUrl }) { + return { + enableTraces: () => enableTraces(provisioningUrl), + isTracingEnabled: () => isTracingEnabled(provisioningUrl), + fetchTraces: () => fetchTraces(tracingUrl), + }; +} diff --git a/app/assets/javascripts/observability/components/observability_container.vue b/app/assets/javascripts/observability/components/observability_container.vue new file mode 100644 index 00000000000..7fb352cc171 --- /dev/null +++ b/app/assets/javascripts/observability/components/observability_container.vue @@ -0,0 +1,86 @@ + + + diff --git a/app/assets/javascripts/observability/components/skeleton/index.vue b/app/assets/javascripts/observability/components/skeleton/index.vue index d91f2874943..75e5ca81939 100644 --- a/app/assets/javascripts/observability/components/skeleton/index.vue +++ b/app/assets/javascripts/observability/components/skeleton/index.vue @@ -61,6 +61,12 @@ export default { this.hideSkeleton(); }, + onError() { + clearTimeout(this.errorTimeout); + clearTimeout(this.loadingTimeout); + + this.showError(); + }, setLoadingTimeout() { this.loadingTimeout = setTimeout(() => { /** @@ -130,7 +136,7 @@ export default {
diff --git a/app/assets/javascripts/observability/mock_traces.json b/app/assets/javascripts/observability/mock_traces.json new file mode 100644 index 00000000000..7b472081a24 --- /dev/null +++ b/app/assets/javascripts/observability/mock_traces.json @@ -0,0 +1,147 @@ +{ + "data": [ + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 100, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + }, + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 343, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + }, + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 343, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + }, + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 343, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + }, + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 343, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + }, + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 343, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + }, + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 343, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + }, + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 343, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + }, + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 343, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + }, + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 343, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + }, + { + "traceID": "668ec7d464968a87", + "date": "Mon, 03 Jul 2023 14:35:37 GMT", + "service": "HealthCheck", + "operation": "/grpc.health.v1.Health/Check", + "duration": 343, + "method": "GET", + "status": 200, + "spans": [ + + ], + "warnings": null + } + ] +} diff --git a/app/assets/javascripts/pages/projects/tracing/index/index.js b/app/assets/javascripts/pages/projects/tracing/index/index.js new file mode 100644 index 00000000000..64ca303f8ba --- /dev/null +++ b/app/assets/javascripts/pages/projects/tracing/index/index.js @@ -0,0 +1,4 @@ +import { initSimpleApp } from '~/helpers/init_simple_app_helper'; +import ListIndex from '~/tracing/list_index.vue'; + +initSimpleApp('#js-tracing', ListIndex); diff --git a/app/assets/javascripts/tracing/components/tracing_list.vue b/app/assets/javascripts/tracing/components/tracing_list.vue new file mode 100644 index 00000000000..38acda8a1b4 --- /dev/null +++ b/app/assets/javascripts/tracing/components/tracing_list.vue @@ -0,0 +1,14 @@ + + + diff --git a/app/assets/javascripts/tracing/list_index.vue b/app/assets/javascripts/tracing/list_index.vue new file mode 100644 index 00000000000..432fbb81506 --- /dev/null +++ b/app/assets/javascripts/tracing/list_index.vue @@ -0,0 +1,37 @@ + + + diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 904c1a51471..7b8d9281148 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -549,3 +549,16 @@ li.note { See https://gitlab.com/gitlab-org/gitlab/issues/36857 for more details. **/ .gl-line-height-14 { line-height: $gl-line-height-14; } + +// TODO: To be removed once `split` option for new dropdowns is implemented. +// See issue at https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2263 +.gl-new-dropdown.split:nth-child(n+2) { + .gl-new-dropdown-toggle { + margin-left: 1px; + + &.btn-tertiary, + &.disabled { + margin-left: -1px; + } + } +} diff --git a/app/controllers/projects/tracing_controller.rb b/app/controllers/projects/tracing_controller.rb index 71ca03deb8c..d1218ebf344 100644 --- a/app/controllers/projects/tracing_controller.rb +++ b/app/controllers/projects/tracing_controller.rb @@ -8,10 +8,7 @@ module Projects before_action :check_tracing_enabled - def index - # TODO frontend changes coming separately https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125014 - render html: helpers.tag.strong('Tracing') - end + def index; end private diff --git a/app/helpers/projects/observability_helper.rb b/app/helpers/projects/observability_helper.rb new file mode 100644 index 00000000000..24bc1928a36 --- /dev/null +++ b/app/helpers/projects/observability_helper.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Projects + module ObservabilityHelper + def observability_tracing_view_model(project) + Gitlab::Json.generate({ + tracingUrl: Gitlab::Observability.tracing_url(project), + provisioningUrl: Gitlab::Observability.provisioning_url(project), + oauthUrl: Gitlab::Observability.oauth_url + }) + end + end +end diff --git a/app/models/concerns/protected_ref_deploy_key_access.rb b/app/models/concerns/protected_ref_deploy_key_access.rb index a62cce1368d..4275476a1ff 100644 --- a/app/models/concerns/protected_ref_deploy_key_access.rb +++ b/app/models/concerns/protected_ref_deploy_key_access.rb @@ -24,7 +24,7 @@ module ProtectedRefDeployKeyAccess end def humanize - return "Deploy key" if deploy_key.present? + return deploy_key.title if deploy_key? super end diff --git a/app/views/projects/tracing/index.html.haml b/app/views/projects/tracing/index.html.haml new file mode 100644 index 00000000000..ae6608cf343 --- /dev/null +++ b/app/views/projects/tracing/index.html.haml @@ -0,0 +1,4 @@ +- page_title _('Tracing') + +#js-tracing{ data: { view_model: observability_tracing_view_model(@project) } } + diff --git a/db/database_connections/ci.yaml b/db/database_connections/ci.yaml index daa155dcb00..5331765214e 100644 --- a/db/database_connections/ci.yaml +++ b/db/database_connections/ci.yaml @@ -4,6 +4,11 @@ gitlab_schemas: - gitlab_internal - gitlab_shared - gitlab_ci +lock_gitlab_schemas: + - gitlab_main + - gitlab_main_clusterwide + - gitlab_main_cell + - gitlab_pm klass: Ci::ApplicationRecord # if CI database is not configured, use this database fallback_database: main diff --git a/db/database_connections/main.yaml b/db/database_connections/main.yaml index dfdd50eb085..9eadd26ec26 100644 --- a/db/database_connections/main.yaml +++ b/db/database_connections/main.yaml @@ -6,6 +6,8 @@ gitlab_schemas: - gitlab_main - gitlab_main_cell - gitlab_pm +lock_gitlab_schemas: + - gitlab_ci # Note that we use ActiveRecord::Base here and not ApplicationRecord. # This is deliberate, as: # - the load balancer must be enabled for _all_ models diff --git a/db/docs/sbom_vulnerable_component_versions.yml b/db/docs/deleted_tables/sbom_vulnerable_component_versions.yml similarity index 75% rename from db/docs/sbom_vulnerable_component_versions.yml rename to db/docs/deleted_tables/sbom_vulnerable_component_versions.yml index 8747b6c6588..7642cb5ea53 100644 --- a/db/docs/sbom_vulnerable_component_versions.yml +++ b/db/docs/deleted_tables/sbom_vulnerable_component_versions.yml @@ -7,4 +7,6 @@ feature_categories: description: Stores information about vulnerable SBoM components introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95622 milestone: '15.4' +removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125426 +removed_in_milestone: '16.2' gitlab_schema: gitlab_main diff --git a/db/docs/vulnerability_advisories.yml b/db/docs/deleted_tables/vulnerability_advisories.yml similarity index 75% rename from db/docs/vulnerability_advisories.yml rename to db/docs/deleted_tables/vulnerability_advisories.yml index 6ce7f30aa7c..613ab678f35 100644 --- a/db/docs/vulnerability_advisories.yml +++ b/db/docs/deleted_tables/vulnerability_advisories.yml @@ -8,4 +8,6 @@ feature_categories: description: Stores vulnerability advisories introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95622 milestone: '15.4' +removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125426 +removed_in_milestone: '16.2' gitlab_schema: gitlab_main diff --git a/db/post_migrate/20230705141703_rollback_vulnerability_advisories_foreign_key_on_vulnerable_component_versions.rb b/db/post_migrate/20230705141703_rollback_vulnerability_advisories_foreign_key_on_vulnerable_component_versions.rb new file mode 100644 index 00000000000..92feca76511 --- /dev/null +++ b/db/post_migrate/20230705141703_rollback_vulnerability_advisories_foreign_key_on_vulnerable_component_versions.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class RollbackVulnerabilityAdvisoriesForeignKeyOnVulnerableComponentVersions < Gitlab::Database::Migration[2.1] + SOURCE_TABLE = :sbom_vulnerable_component_versions + TARGET_TABLE = :vulnerability_advisories + COLUMN = :vulnerability_advisory_id + + disable_ddl_transaction! + + def up + # Foreign key is removed when the table is dropped in the next migration. + end + + def down + add_concurrent_foreign_key SOURCE_TABLE, TARGET_TABLE, column: COLUMN, on_delete: :cascade + end +end diff --git a/db/post_migrate/20230705141733_rollback_component_version_foreign_key_on_vulnerable_component_versions.rb b/db/post_migrate/20230705141733_rollback_component_version_foreign_key_on_vulnerable_component_versions.rb new file mode 100644 index 00000000000..c54d4ebd1e3 --- /dev/null +++ b/db/post_migrate/20230705141733_rollback_component_version_foreign_key_on_vulnerable_component_versions.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class RollbackComponentVersionForeignKeyOnVulnerableComponentVersions < Gitlab::Database::Migration[2.1] + SOURCE_TABLE = :sbom_vulnerable_component_versions + TARGET_TABLE = :sbom_component_versions + COLUMN = :sbom_component_version_id + + disable_ddl_transaction! + + def up + # Foreign key is removed when the table is dropped in the next migration. + end + + def down + add_concurrent_foreign_key SOURCE_TABLE, TARGET_TABLE, column: COLUMN, on_delete: :cascade + end +end diff --git a/db/post_migrate/20230705142241_drop_vulnerable_component_versions.rb b/db/post_migrate/20230705142241_drop_vulnerable_component_versions.rb new file mode 100644 index 00000000000..10432f6b515 --- /dev/null +++ b/db/post_migrate/20230705142241_drop_vulnerable_component_versions.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class DropVulnerableComponentVersions < Gitlab::Database::Migration[2.1] + ADVISORY_INDEX_NAME = "index_vulnerable_component_versions_on_vulnerability_advisory" + SBOM_COMPONENT_INDEX_NAME = "index_vulnerable_component_versions_on_sbom_component_version" + + def up + drop_table :sbom_vulnerable_component_versions + end + + def down + create_table :sbom_vulnerable_component_versions do |t| + t.references :vulnerability_advisory, + index: { name: ADVISORY_INDEX_NAME } + + t.references :sbom_component_version, + index: { name: SBOM_COMPONENT_INDEX_NAME } + + t.timestamps_with_timezone null: false + end + end +end diff --git a/db/post_migrate/20230705142334_drop_vulnerabilities_advisories.rb b/db/post_migrate/20230705142334_drop_vulnerabilities_advisories.rb new file mode 100644 index 00000000000..e6bee52eb0c --- /dev/null +++ b/db/post_migrate/20230705142334_drop_vulnerabilities_advisories.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class DropVulnerabilitiesAdvisories < Gitlab::Database::Migration[2.1] + def up + drop_table :vulnerability_advisories + end + + def down + create_table :vulnerability_advisories, id: false do |t| + t.uuid :uuid, null: false + t.timestamps_with_timezone null: false + t.primary_key :id + t.date :created_date, null: false + t.date :published_date, null: false + t.text :description, limit: 2048 + t.text :title, limit: 2048 + t.text :component_name, limit: 2048 + t.text :solution, limit: 2048 + t.text :not_impacted, limit: 2048 + t.text :cvss_v2, limit: 128 + t.text :cvss_v3, limit: 128 + t.text :affected_range, limit: 32 + t.text :identifiers, array: true, default: [] + t.text :fixed_versions, array: true, default: [] + t.text :urls, array: true, default: [] + t.text :links, array: true, default: [] + end + end +end diff --git a/db/schema_migrations/20230705141703 b/db/schema_migrations/20230705141703 new file mode 100644 index 00000000000..51c3cd350c1 --- /dev/null +++ b/db/schema_migrations/20230705141703 @@ -0,0 +1 @@ +dafb3395a28180da275eceddb87af4deb0008b2d0793dd0ea3f34d2ae8bd5c10 \ No newline at end of file diff --git a/db/schema_migrations/20230705141733 b/db/schema_migrations/20230705141733 new file mode 100644 index 00000000000..2b5870f2ba5 --- /dev/null +++ b/db/schema_migrations/20230705141733 @@ -0,0 +1 @@ +2cea22d62a5a08a643b3043bea1e14e4965f57201db559995cab8616d7586f55 \ No newline at end of file diff --git a/db/schema_migrations/20230705142241 b/db/schema_migrations/20230705142241 new file mode 100644 index 00000000000..4d4ee24d798 --- /dev/null +++ b/db/schema_migrations/20230705142241 @@ -0,0 +1 @@ +ae094cd61e252b30c1ebe0e5369ff2c061aa96079bbc1addde160003e2263886 \ No newline at end of file diff --git a/db/schema_migrations/20230705142334 b/db/schema_migrations/20230705142334 new file mode 100644 index 00000000000..ace38aed2f7 --- /dev/null +++ b/db/schema_migrations/20230705142334 @@ -0,0 +1 @@ +33de9f678eb493070ceaae0e50461cffbcdbb5a542740b9fc595cba2c8c32808 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 239970ac959..633b2943d1a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -22361,23 +22361,6 @@ CREATE SEQUENCE sbom_sources_id_seq ALTER SEQUENCE sbom_sources_id_seq OWNED BY sbom_sources.id; -CREATE TABLE sbom_vulnerable_component_versions ( - id bigint NOT NULL, - vulnerability_advisory_id bigint, - sbom_component_version_id bigint, - created_at timestamp with time zone NOT NULL, - updated_at timestamp with time zone NOT NULL -); - -CREATE SEQUENCE sbom_vulnerable_component_versions_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - -ALTER SEQUENCE sbom_vulnerable_component_versions_id_seq OWNED BY sbom_vulnerable_component_versions.id; - CREATE TABLE scan_result_policies ( id bigint NOT NULL, security_orchestration_policy_configuration_id bigint NOT NULL, @@ -24116,44 +24099,6 @@ CREATE SEQUENCE vulnerabilities_id_seq ALTER SEQUENCE vulnerabilities_id_seq OWNED BY vulnerabilities.id; -CREATE TABLE vulnerability_advisories ( - uuid uuid NOT NULL, - created_at timestamp with time zone NOT NULL, - updated_at timestamp with time zone NOT NULL, - id bigint NOT NULL, - created_date date NOT NULL, - published_date date NOT NULL, - description text, - title text, - component_name text, - solution text, - not_impacted text, - cvss_v2 text, - cvss_v3 text, - affected_range text, - identifiers text[] DEFAULT '{}'::text[], - fixed_versions text[] DEFAULT '{}'::text[], - urls text[] DEFAULT '{}'::text[], - links text[] DEFAULT '{}'::text[], - CONSTRAINT check_3ab0544d19 CHECK ((char_length(title) <= 2048)), - CONSTRAINT check_3b57023409 CHECK ((char_length(affected_range) <= 32)), - CONSTRAINT check_4d5cd7be9c CHECK ((char_length(component_name) <= 2048)), - CONSTRAINT check_962f256a51 CHECK ((char_length(solution) <= 2048)), - CONSTRAINT check_aae93955fb CHECK ((char_length(cvss_v3) <= 128)), - CONSTRAINT check_b8a17497f3 CHECK ((char_length(cvss_v2) <= 128)), - CONSTRAINT check_c05a35f418 CHECK ((char_length(not_impacted) <= 2048)), - CONSTRAINT check_ff9f6483b6 CHECK ((char_length(description) <= 2048)) -); - -CREATE SEQUENCE vulnerability_advisories_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - -ALTER SEQUENCE vulnerability_advisories_id_seq OWNED BY vulnerability_advisories.id; - CREATE TABLE vulnerability_exports ( id bigint NOT NULL, created_at timestamp with time zone NOT NULL, @@ -25935,8 +25880,6 @@ ALTER TABLE ONLY sbom_occurrences ALTER COLUMN id SET DEFAULT nextval('sbom_occu ALTER TABLE ONLY sbom_sources ALTER COLUMN id SET DEFAULT nextval('sbom_sources_id_seq'::regclass); -ALTER TABLE ONLY sbom_vulnerable_component_versions ALTER COLUMN id SET DEFAULT nextval('sbom_vulnerable_component_versions_id_seq'::regclass); - ALTER TABLE ONLY scan_result_policies ALTER COLUMN id SET DEFAULT nextval('scan_result_policies_id_seq'::regclass); ALTER TABLE ONLY schema_inconsistencies ALTER COLUMN id SET DEFAULT nextval('schema_inconsistencies_id_seq'::regclass); @@ -26083,8 +26026,6 @@ ALTER TABLE ONLY value_stream_dashboard_counts ALTER COLUMN id SET DEFAULT nextv ALTER TABLE ONLY vulnerabilities ALTER COLUMN id SET DEFAULT nextval('vulnerabilities_id_seq'::regclass); -ALTER TABLE ONLY vulnerability_advisories ALTER COLUMN id SET DEFAULT nextval('vulnerability_advisories_id_seq'::regclass); - ALTER TABLE ONLY vulnerability_exports ALTER COLUMN id SET DEFAULT nextval('vulnerability_exports_id_seq'::regclass); ALTER TABLE ONLY vulnerability_external_issue_links ALTER COLUMN id SET DEFAULT nextval('vulnerability_external_issue_links_id_seq'::regclass); @@ -28383,9 +28324,6 @@ ALTER TABLE ONLY sbom_occurrences ALTER TABLE ONLY sbom_sources ADD CONSTRAINT sbom_sources_pkey PRIMARY KEY (id); -ALTER TABLE ONLY sbom_vulnerable_component_versions - ADD CONSTRAINT sbom_vulnerable_component_versions_pkey PRIMARY KEY (id); - ALTER TABLE ONLY scan_result_policies ADD CONSTRAINT scan_result_policies_pkey PRIMARY KEY (id); @@ -28650,9 +28588,6 @@ ALTER TABLE ONLY verification_codes ALTER TABLE ONLY vulnerabilities ADD CONSTRAINT vulnerabilities_pkey PRIMARY KEY (id); -ALTER TABLE ONLY vulnerability_advisories - ADD CONSTRAINT vulnerability_advisories_pkey PRIMARY KEY (id); - ALTER TABLE ONLY vulnerability_exports ADD CONSTRAINT vulnerability_exports_pkey PRIMARY KEY (id); @@ -33529,10 +33464,6 @@ CREATE UNIQUE INDEX index_vulnerability_statistics_on_unique_project_id ON vulne CREATE UNIQUE INDEX index_vulnerability_user_mentions_on_note_id ON vulnerability_user_mentions USING btree (note_id) WHERE (note_id IS NOT NULL); -CREATE INDEX index_vulnerable_component_versions_on_sbom_component_version ON sbom_vulnerable_component_versions USING btree (sbom_component_version_id); - -CREATE INDEX index_vulnerable_component_versions_on_vulnerability_advisory ON sbom_vulnerable_component_versions USING btree (vulnerability_advisory_id); - CREATE UNIQUE INDEX index_vulns_user_mentions_on_vulnerability_id ON vulnerability_user_mentions USING btree (vulnerability_id) WHERE (note_id IS NULL); CREATE UNIQUE INDEX index_vulns_user_mentions_on_vulnerability_id_and_note_id ON vulnerability_user_mentions USING btree (vulnerability_id, note_id); @@ -35906,9 +35837,6 @@ ALTER TABLE ONLY issues ALTER TABLE ONLY ci_build_trace_chunks ADD CONSTRAINT fk_89e29fa5ee_p FOREIGN KEY (partition_id, build_id) REFERENCES p_ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE; -ALTER TABLE ONLY sbom_vulnerable_component_versions - ADD CONSTRAINT fk_8a2a1197f9 FOREIGN KEY (sbom_component_version_id) REFERENCES sbom_component_versions(id) ON DELETE CASCADE; - ALTER TABLE ONLY protected_branch_merge_access_levels ADD CONSTRAINT fk_8a3072ccb3 FOREIGN KEY (protected_branch_id) REFERENCES protected_branches(id) ON DELETE CASCADE; @@ -36242,9 +36170,6 @@ ALTER TABLE ONLY lists ALTER TABLE ONLY agent_activity_events ADD CONSTRAINT fk_d6f785c9fc FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL; -ALTER TABLE ONLY sbom_vulnerable_component_versions - ADD CONSTRAINT fk_d720a1959a FOREIGN KEY (vulnerability_advisory_id) REFERENCES vulnerability_advisories(id) ON DELETE CASCADE; - ALTER TABLE ONLY user_achievements ADD CONSTRAINT fk_d7653ef780 FOREIGN KEY (revoked_by_user_id) REFERENCES users(id) ON DELETE SET NULL; diff --git a/doc/administration/settings/index.md b/doc/administration/settings/index.md index 8f349c13bb6..cf7640c75c1 100644 --- a/doc/administration/settings/index.md +++ b/doc/administration/settings/index.md @@ -70,7 +70,7 @@ The **CI/CD** settings contain: ## Security and Compliance settings -- [License compliance settings](../../user/admin_area/settings/security_and_compliance.md#choose-package-registry-metadata-to-sync): Enable or disable synchronization of package metadata by a registry type. +- [License compliance settings](security_and_compliance.md#choose-package-registry-metadata-to-sync): Enable or disable synchronization of package metadata by a registry type. ### Geo **(PREMIUM SELF)** diff --git a/doc/administration/settings/security_and_compliance.md b/doc/administration/settings/security_and_compliance.md new file mode 100644 index 00000000000..2237866ad9c --- /dev/null +++ b/doc/administration/settings/security_and_compliance.md @@ -0,0 +1,25 @@ +--- +stage: Secure +group: Composition Analysis +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments +type: howto +--- + +# Security and Compliance Admin Area settings **(ULTIMATE SELF)** + +The settings for package metadata synchronization are located in the [Admin Area](index.md). + +## Choose package registry metadata to sync + +WARNING: +The full package metadata sync can add up to 30 GB to the PostgreSQL database. Ensure you have provisioned enough disk space for the database before enabling this feature. +We are actively working on reducing this data size in [epic 10415](https://gitlab.com/groups/gitlab-org/-/epics/10415). + +To choose the packages you want to synchronize with the GitLab License Database for [License Compliance](../../user/compliance/license_scanning_of_cyclonedx_files/index.md): + +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. +1. Select **Settings > Security and Compliance**. +1. Expand **License Compliance**. +1. Select or clear checkboxes for the package registries that you want to sync. +1. Select **Save changes**. diff --git a/doc/administration/settings/sidekiq_job_limits.md b/doc/administration/settings/sidekiq_job_limits.md new file mode 100644 index 00000000000..d5cd24c5237 --- /dev/null +++ b/doc/administration/settings/sidekiq_job_limits.md @@ -0,0 +1,35 @@ +--- +stage: none +group: unassigned +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments +type: reference +--- + +# Sidekiq job size limits **(FREE SELF)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68982) in GitLab 14.3. + +[Sidekiq](../sidekiq/index.md) jobs get stored in +Redis. To avoid excessive memory for Redis, we: + +- Compress job arguments before storing them in Redis. +- Reject jobs that exceed the specified threshold limit after compression. + +To access Sidekiq job size limits: + +1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). +1. Select **Admin Area**. +1. Select **Settings > Preferences**. +1. Expand **Sidekiq job size limits**. +1. Adjust the compression threshold or size limit. The compression can + be disabled by selecting the **Track** mode. + +## Available settings + +| Setting | Default | Description | +|-------------------------------------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Limiting mode | Compress | This mode compresses the jobs at the specified threshold and rejects them if they exceed the specified limit after compression. | +| Sidekiq job compression threshold (bytes) | 100 000 (100 KB) | When the size of arguments exceeds this threshold, they are compressed before being stored in Redis. | +| Sidekiq job size limit (bytes) | 0 | The jobs exceeding this size after compression are rejected. This avoids excessive memory usage in Redis leading to instability. Setting it to 0 prevents rejecting jobs. | + +After changing these values, [restart Sidekiq](../restart_gitlab.md). diff --git a/doc/user/admin_area/settings/security_and_compliance.md b/doc/user/admin_area/settings/security_and_compliance.md index 54fd04f6521..8c1e514c575 100644 --- a/doc/user/admin_area/settings/security_and_compliance.md +++ b/doc/user/admin_area/settings/security_and_compliance.md @@ -1,25 +1,11 @@ --- -stage: Secure -group: Composition Analysis -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments -type: howto +redirect_to: '../../../administration/settings/security_and_compliance.md' +remove_date: '2023-10-13' --- -# Security and Compliance Admin Area settings **(ULTIMATE SELF)** +This document was moved to [another location](../../../administration/settings/security_and_compliance.md). -The settings for package metadata synchronization are located in the [Admin Area](index.md). - -## Choose package registry metadata to sync - -WARNING: -The full package metadata sync can add up to 30 GB to the PostgreSQL database. Ensure you have provisioned enough disk space for the database before enabling this feature. -We are actively working on reducing this data size in [epic 10415](https://gitlab.com/groups/gitlab-org/-/epics/10415). - -To choose the packages you want to synchronize with the GitLab License Database for [License Compliance](../../compliance/license_scanning_of_cyclonedx_files/index.md): - -1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). -1. Select **Admin Area**. -1. Select **Settings > Security and Compliance**. -1. Expand **License Compliance**. -1. Select or clear checkboxes for the package registries that you want to sync. -1. Select **Save changes**. + + + + diff --git a/doc/user/admin_area/settings/sidekiq_job_limits.md b/doc/user/admin_area/settings/sidekiq_job_limits.md index 08c3ced4c4e..81be26ec8e0 100644 --- a/doc/user/admin_area/settings/sidekiq_job_limits.md +++ b/doc/user/admin_area/settings/sidekiq_job_limits.md @@ -1,35 +1,11 @@ --- -stage: none -group: unassigned -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments -type: reference +redirect_to: '../../../administration/settings/sidekiq_job_limits.md' +remove_date: '2023-10-13' --- -# Sidekiq job size limits **(FREE SELF)** +This document was moved to [another location](../../../administration/settings/sidekiq_job_limits.md). -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68982) in GitLab 14.3. - -[Sidekiq](../../../administration/sidekiq/index.md) jobs get stored in -Redis. To avoid excessive memory for Redis, we: - -- Compress job arguments before storing them in Redis. -- Reject jobs that exceed the specified threshold limit after compression. - -To access Sidekiq job size limits: - -1. On the left sidebar, expand the top-most chevron (**{chevron-down}**). -1. Select **Admin Area**. -1. Select **Settings > Preferences**. -1. Expand **Sidekiq job size limits**. -1. Adjust the compression threshold or size limit. The compression can - be disabled by selecting the **Track** mode. - -## Available settings - -| Setting | Default | Description | -|-------------------------------------------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Limiting mode | Compress | This mode compresses the jobs at the specified threshold and rejects them if they exceed the specified limit after compression. | -| Sidekiq job compression threshold (bytes) | 100 000 (100 KB) | When the size of arguments exceeds this threshold, they are compressed before being stored in Redis. | -| Sidekiq job size limit (bytes) | 0 | The jobs exceeding this size after compression are rejected. This avoids excessive memory usage in Redis leading to instability. Setting it to 0 prevents rejecting jobs. | - -After changing these values, [restart Sidekiq](../../../administration/restart_gitlab.md). + + + + diff --git a/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md b/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md index 22defd593cd..1fbe67a62b2 100644 --- a/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md +++ b/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md @@ -23,7 +23,7 @@ Licenses not in the SPDX list are reported as "Unknown". License information can Prerequisites: -- On GitLab self-managed only, enable [Synchronization with the GitLab License Database](../../admin_area/settings/security_and_compliance.md#choose-package-registry-metadata-to-sync) in Admin Area for the GitLab instance. On GitLab SaaS this step has already been completed. +- On GitLab self-managed only, enable [Synchronization with the GitLab License Database](../../../administration/settings/security_and_compliance.md#choose-package-registry-metadata-to-sync) in Admin Area for the GitLab instance. On GitLab SaaS this step has already been completed. - Enable [Dependency Scanning](../../application_security/dependency_scanning/index.md#configuration) and ensure that its prerequisites are met. diff --git a/doc/user/group/import/index.md b/doc/user/group/import/index.md index f854dc418d6..eb67223c61f 100644 --- a/doc/user/group/import/index.md +++ b/doc/user/group/import/index.md @@ -208,10 +208,10 @@ Group items that are migrated to the destination GitLab instance include: | Boards | [GitLab 13.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18938) | | Board lists | [GitLab 13.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24863) | | Epics 1 | [GitLab 13.7](https://gitlab.com/gitlab-org/gitlab/-/issues/250281) | -| Group labels | [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/292429) | +| Group labels 2 | [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/292429) | | Iterations | [GitLab 13.10](https://gitlab.com/gitlab-org/gitlab/-/issues/292428) | | Iteration cadences | [GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96570) | -| Members 2 | [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/299415) | +| Members 3 | [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/299415) | | Group milestones | [GitLab 13.10](https://gitlab.com/gitlab-org/gitlab/-/issues/292427) | | Namespace settings | [GitLab 14.10](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85128) | | Release milestones | [GitLab 15.0](https://gitlab.com/gitlab-org/gitlab/-/issues/339422) | @@ -222,6 +222,8 @@ Group items that are migrated to the destination GitLab instance include: associations [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62074) in GitLab 13.12, state and state ID [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28203) in GitLab 13.7, and system note metadata [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63551) in GitLab 14.0. +1. Group Labels cannot retain any associated Label Priorities during import. These labels will need to be re-prioritized manually + once the relevant Project is migrated to the destination instance. 1. Group members are associated with the imported group if the user: - Already exists in the destination GitLab instance. - Has a public email in the source GitLab instance that matches a confirmed email in the destination GitLab instance. @@ -490,7 +492,7 @@ for your version of GitLab to check which items can be imported to the destinati Group items that are exported include: - Milestones -- Labels +- Group Labels (_without_ associated label priorities) - Boards and Board Lists - Badges - Subgroups (including all the aforementioned data) diff --git a/lib/api/ml_model_packages.rb b/lib/api/ml_model_packages.rb index 43a61537aa2..35d231d9fe1 100644 --- a/lib/api/ml_model_packages.rb +++ b/lib/api/ml_model_packages.rb @@ -6,7 +6,7 @@ module API include ::API::Helpers::Authentication ML_MODEL_PACKAGES_REQUIREMENTS = { - package_name: API::NO_SLASH_URL_PART_REGEX, + model_name: API::NO_SLASH_URL_PART_REGEX, file_name: API::NO_SLASH_URL_PART_REGEX }.freeze @@ -47,15 +47,15 @@ module API resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do namespace ':id/packages/ml_models' do params do - requires :package_name, type: String, desc: 'Package name', regexp: Gitlab::Regex.ml_model_name_regex, + requires :model_name, type: String, desc: 'Model name', regexp: Gitlab::Regex.ml_model_name_regex, file_path: true - requires :package_version, type: String, desc: 'Package version', + requires :model_version, type: String, desc: 'Model version', regexp: Gitlab::Regex.ml_model_version_regex requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.ml_model_file_name_regex, file_path: true optional :status, type: String, values: ALLOWED_STATUSES, desc: 'Package status' end - namespace ':package_name/*package_version/:file_name', requirements: ML_MODEL_PACKAGES_REQUIREMENTS do + namespace ':model_name/*model_version/:file_name', requirements: ML_MODEL_PACKAGES_REQUIREMENTS do desc 'Workhorse authorize model package file' do detail 'Introduced in GitLab 16.1' success code: 200 @@ -91,7 +91,12 @@ module API bad_request!('File is too large') if max_file_size_exceeded? - create_package_file_params = declared(params).merge(build: current_authenticated_job) + create_package_file_params = declared(params).merge( + build: current_authenticated_job, + package_name: params[:model_name], + package_version: params[:model_version] + ) + package_file = ::Packages::MlModel::CreatePackageFileService .new(project, current_user, create_package_file_params) .execute @@ -119,7 +124,7 @@ module API authorize_read_package!(project) package = ::Packages::MlModel::PackageFinder.new(project) - .execute!(params[:package_name], params[:package_version]) + .execute!(params[:model_name], params[:model_version]) package_file = ::Packages::PackageFileFinder.new(package, params[:file_name]).execute! present_package_file!(package_file) diff --git a/lib/gitlab/database/database_connection_info.rb b/lib/gitlab/database/database_connection_info.rb index 57ecbcd64ae..f0cafcf041b 100644 --- a/lib/gitlab/database/database_connection_info.rb +++ b/lib/gitlab/database/database_connection_info.rb @@ -6,6 +6,7 @@ module Gitlab :name, :description, :gitlab_schemas, + :lock_gitlab_schemas, :klass, :fallback_database, :db_dir, @@ -20,6 +21,7 @@ module Gitlab self.name = name.to_sym self.gitlab_schemas = gitlab_schemas.map(&:to_sym) self.klass = klass.constantize + self.lock_gitlab_schemas = (lock_gitlab_schemas || []).map(&:to_sym) self.fallback_database = fallback_database&.to_sym self.db_dir = Rails.root.join(db_dir || 'db') end diff --git a/lib/gitlab/database/gitlab_schema.rb b/lib/gitlab/database/gitlab_schema.rb index 9b58284b389..0bd357b7730 100644 --- a/lib/gitlab/database/gitlab_schema.rb +++ b/lib/gitlab/database/gitlab_schema.rb @@ -23,6 +23,21 @@ module Gitlab tables.map { |table| table_schema!(table) }.to_set end + # Mainly used for test tables + # It maps table names prefixes to gitlab_schemas. + # The order of keys matter. Prefixes that contain other prefixes should come first. + IMPLICIT_GITLAB_SCHEMAS = { + '_test_gitlab_main_clusterwide_' => :gitlab_main_clusterwide, + '_test_gitlab_main_cell_' => :gitlab_main_cell, + '_test_gitlab_main_' => :gitlab_main, + '_test_gitlab_ci_' => :gitlab_ci, + '_test_gitlab_embedding_' => :gitlab_embedding, + '_test_gitlab_geo_' => :gitlab_geo, + '_test_gitlab_pm_' => :gitlab_pm, + '_test_' => :gitlab_shared, + 'pg_' => :gitlab_internal + }.freeze + # rubocop:disable Metrics/CyclomaticComplexity def self.table_schema(name) schema_name, table_name = name.split('.', 2) # Strip schema name like: `public.` @@ -54,19 +69,11 @@ module Gitlab # All tables from `information_schema.` are marked as `internal` return :gitlab_internal if schema_name == 'information_schema' - return :gitlab_main if table_name.start_with?('_test_gitlab_main_') + IMPLICIT_GITLAB_SCHEMAS.each do |prefix, gitlab_schema| + return gitlab_schema if table_name.start_with?(prefix) + end - return :gitlab_ci if table_name.start_with?('_test_gitlab_ci_') - - return :gitlab_embedding if table_name.start_with?('_test_gitlab_embedding_') - - return :gitlab_geo if table_name.start_with?('_test_gitlab_geo_') - - # All tables that start with `_test_` without a following schema are shared and ignored - return :gitlab_shared if table_name.start_with?('_test_') - - # All `pg_` tables are marked as `internal` - return :gitlab_internal if table_name.start_with?('pg_') + nil end # rubocop:enable Metrics/CyclomaticComplexity diff --git a/lib/gitlab/database/migration_helpers/automatic_lock_writes_on_tables.rb b/lib/gitlab/database/migration_helpers/automatic_lock_writes_on_tables.rb index 55c4fd6a7af..fe456fab505 100644 --- a/lib/gitlab/database/migration_helpers/automatic_lock_writes_on_tables.rb +++ b/lib/gitlab/database/migration_helpers/automatic_lock_writes_on_tables.rb @@ -11,7 +11,9 @@ module Gitlab end def exec_migration(connection, direction) - return super if %w[main ci].exclude?(Gitlab::Database.db_config_name(connection)) + db_config_name = Gitlab::Database.db_config_name(connection) + db_info = Gitlab::Database.all_database_connections.fetch(db_config_name) + return super if db_info.lock_gitlab_schemas.empty? return super if automatic_lock_on_writes_disabled? # This compares the tables only on the `public` schema. Partitions are not affected @@ -20,7 +22,7 @@ module Gitlab new_tables = connection.tables - tables new_tables.each do |table_name| - lock_writes_on_table(connection, table_name) if should_lock_writes_on_table?(table_name) + lock_writes_on_table(connection, table_name) if should_lock_writes_on_table?(db_info, table_name) end end @@ -39,16 +41,17 @@ module Gitlab end end - def should_lock_writes_on_table?(table_name) - # currently gitlab_schema represents only present existing tables, this is workaround for deleted tables - # that should be skipped as they will be removed in a future migration. + def should_lock_writes_on_table?(db_info, table_name) + # We skip locking writes on tables that are scheduled for deletion in a future migration return false if Gitlab::Database::GitlabSchema.deleted_tables_to_schema[table_name] table_schema = Gitlab::Database::GitlabSchema.table_schema!(table_name.to_s) - return false unless %i[gitlab_main gitlab_ci].include?(table_schema) - - Gitlab::Database.gitlab_schemas_for_connection(connection).exclude?(table_schema) + # This takes into consideration which database mode is used. + # In single-db and single-db-ci-connection the main database includes gitlab_ci tables, + # so we don't lock them there. + Gitlab::Database.gitlab_schemas_for_connection(connection).exclude?(table_schema) && + db_info.lock_gitlab_schemas.include?(table_schema) end # with_retries creates new a transaction. So we set it to false if the connection is diff --git a/lib/gitlab/import_export/group/import_export.yml b/lib/gitlab/import_export/group/import_export.yml index c2a1a1f8575..7a91cfb340a 100644 --- a/lib/gitlab/import_export/group/import_export.yml +++ b/lib/gitlab/import_export/group/import_export.yml @@ -7,12 +7,10 @@ tree: group: - :milestones - :badges - - labels: - - :priorities + - :labels - boards: - lists: - - label: - - :priorities + - :label - :board - members: - :user @@ -126,8 +124,7 @@ ee: - boards: - :board_assignee - :milestone - - labels: - - :priorities + - :labels - lists: - milestone: - events: diff --git a/lib/gitlab/import_export/group/relation_factory.rb b/lib/gitlab/import_export/group/relation_factory.rb index 1b8436c4ed9..664ef5358ef 100644 --- a/lib/gitlab/import_export/group/relation_factory.rb +++ b/lib/gitlab/import_export/group/relation_factory.rb @@ -6,7 +6,6 @@ module Gitlab class RelationFactory < Base::RelationFactory OVERRIDES = { labels: :group_labels, - priorities: :label_priorities, label: :group_label, parent: :epic, iterations_cadences: 'Iterations::Cadence' diff --git a/lib/gitlab/observability.rb b/lib/gitlab/observability.rb index 0e6089e1d21..b500df86363 100644 --- a/lib/gitlab/observability.rb +++ b/lib/gitlab/observability.rb @@ -27,6 +27,15 @@ module Gitlab "#{Gitlab::Observability.observability_url}/v1/auth/start" end + def tracing_url(project) + "#{Gitlab::Observability.observability_url}/query/#{project.group.id}/#{project.id}/v1/traces" + end + + def provisioning_url(_project) + # TODO Change to correct endpoint when API is ready + Gitlab::Observability.observability_url.to_s + end + # Returns true if the GitLab Observability UI (GOUI) feature flag is enabled # # @deprecated diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 21d81d0968c..035a173e9e0 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -881,6 +881,9 @@ msgstr "" msgid "%{linkStart} Learn more%{linkEnd}." msgstr "" +msgid "%{linkStart}%{linkEnd} review summary" +msgstr "" + msgid "%{listToShow}, and %{awardsListLength} more" msgstr "" @@ -11353,6 +11356,9 @@ msgstr "" msgid "Comment templates can be used when creating comments inside issues, merge requests, and epics." msgstr "" +msgid "Comment type" +msgstr "" + msgid "Comment/Reply (quoting selected text)" msgstr "" diff --git a/qa/qa/page/component/note.rb b/qa/qa/page/component/note.rb index 84cc481945f..900dc62f6b7 100644 --- a/qa/qa/page/component/note.rb +++ b/qa/qa/page/component/note.rb @@ -148,7 +148,7 @@ module QA def start_discussion(text) fill_element :comment_field, text - within_element(:comment_button) { click_button(class: 'dropdown-toggle-split') } + within_element(:comment_button) { click_button(class: 'gl-new-dropdown-toggle') } click_element :discussion_menu_item click_element :comment_button diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb index d1e00d730b7..146e4d1265a 100644 --- a/spec/features/merge_request/user_posts_notes_spec.rb +++ b/spec/features/merge_request/user_posts_notes_spec.rb @@ -46,8 +46,8 @@ RSpec.describe 'Merge request > User posts notes', :js, feature_category: :code_ it 'has enable submit button, preview button and saves content to local storage' do page.within('.js-main-target-form') do page.within('[data-testid="comment-button"]') do - expect(page).to have_css('.split-content-button') - expect(page).not_to have_css('.split-content-button[disabled]') + expect(page).to have_css('.gl-button') + expect(page).not_to have_css('.disabled') end expect(page).to have_css('.js-md-preview-button', visible: true) end diff --git a/spec/frontend/notes/components/comment_type_dropdown_spec.js b/spec/frontend/notes/components/comment_type_dropdown_spec.js index b891c1f553d..053542a421c 100644 --- a/spec/frontend/notes/components/comment_type_dropdown_spec.js +++ b/spec/frontend/notes/components/comment_type_dropdown_spec.js @@ -1,4 +1,4 @@ -import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { GlButton, GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import CommentTypeDropdown from '~/notes/components/comment_type_dropdown.vue'; @@ -8,9 +8,9 @@ import { COMMENT_FORM } from '~/notes/i18n'; describe('CommentTypeDropdown component', () => { let wrapper; - const findCommentGlDropdown = () => wrapper.findComponent(GlDropdown); - const findCommentDropdownOption = () => wrapper.findAllComponents(GlDropdownItem).at(0); - const findDiscussionDropdownOption = () => wrapper.findAllComponents(GlDropdownItem).at(1); + const findCommentButton = () => wrapper.findComponent(GlButton); + const findCommentListboxOption = () => wrapper.findAllComponents(GlListboxItem).at(0); + const findDiscussionListboxOption = () => wrapper.findAllComponents(GlListboxItem).at(1); const mountComponent = ({ props = {} } = {}) => { wrapper = extendedWrapper( @@ -20,6 +20,10 @@ describe('CommentTypeDropdown component', () => { noteType: constants.COMMENT, ...props, }, + stubs: { + GlCollapsibleListbox, + GlListboxItem, + }, }), ); }; @@ -33,15 +37,15 @@ describe('CommentTypeDropdown component', () => { ({ isInternalNote, buttonText }) => { mountComponent({ props: { noteType: constants.COMMENT, isInternalNote } }); - expect(findCommentGlDropdown().props()).toMatchObject({ text: buttonText }); + expect(findCommentButton().text()).toBe(buttonText); }, ); it('Should set correct dropdown item checked when comment is selected', () => { mountComponent({ props: { noteType: constants.COMMENT } }); - expect(findCommentDropdownOption().props()).toMatchObject({ isChecked: true }); - expect(findDiscussionDropdownOption().props()).toMatchObject({ isChecked: false }); + expect(findCommentListboxOption().props('isSelected')).toBe(true); + expect(findDiscussionListboxOption().props('isSelected')).toBe(false); }); it.each` @@ -53,32 +57,22 @@ describe('CommentTypeDropdown component', () => { ({ isInternalNote, buttonText }) => { mountComponent({ props: { noteType: constants.DISCUSSION, isInternalNote } }); - expect(findCommentGlDropdown().props()).toMatchObject({ text: buttonText }); + expect(findCommentButton().text()).toBe(buttonText); }, ); it('Should set correct dropdown item option checked when discussion is selected', () => { mountComponent({ props: { noteType: constants.DISCUSSION } }); - expect(findCommentDropdownOption().props()).toMatchObject({ isChecked: false }); - expect(findDiscussionDropdownOption().props()).toMatchObject({ isChecked: true }); + expect(findCommentListboxOption().props('isSelected')).toBe(false); + expect(findDiscussionListboxOption().props('isSelected')).toBe(true); }); it('Should emit `change` event when clicking on an alternate dropdown option', () => { mountComponent({ props: { noteType: constants.DISCUSSION } }); - const event = { - type: 'click', - stopPropagation: jest.fn(), - preventDefault: jest.fn(), - }; - - findCommentDropdownOption().vm.$emit('click', event); - findDiscussionDropdownOption().vm.$emit('click', event); - - // ensure the native events don't trigger anything - expect(event.stopPropagation).toHaveBeenCalledTimes(2); - expect(event.preventDefault).toHaveBeenCalledTimes(2); + findCommentListboxOption().trigger('click'); + findDiscussionListboxOption().trigger('click'); expect(wrapper.emitted('change')[0]).toEqual([constants.COMMENT]); expect(wrapper.emitted('change').length).toEqual(1); @@ -87,7 +81,7 @@ describe('CommentTypeDropdown component', () => { it('Should emit `click` event when clicking on the action button', () => { mountComponent({ props: { noteType: constants.DISCUSSION } }); - findCommentGlDropdown().vm.$emit('click'); + findCommentButton().vm.$emit('click'); expect(wrapper.emitted('click').length > 0).toBe(true); }); diff --git a/spec/frontend/observability/observability_container_spec.js b/spec/frontend/observability/observability_container_spec.js new file mode 100644 index 00000000000..1152df072d4 --- /dev/null +++ b/spec/frontend/observability/observability_container_spec.js @@ -0,0 +1,134 @@ +import { nextTick } from 'vue'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { stubComponent } from 'helpers/stub_component'; +import ObservabilityContainer from '~/observability/components/observability_container.vue'; +import ObservabilitySkeleton from '~/observability/components/skeleton/index.vue'; +import { buildClient } from '~/observability/client'; + +jest.mock('~/observability/client'); + +describe('ObservabilityContainer', () => { + let wrapper; + + const mockSkeletonOnContentLoaded = jest.fn(); + const mockSkeletonOnError = jest.fn(); + + const OAUTH_URL = 'https://example.com/oauth'; + const TRACING_URL = 'https://example.com/tracing'; + const PROVISIONING_URL = 'https://example.com/provisioning'; + + beforeEach(() => { + jest.spyOn(console, 'error').mockImplementation(); + + buildClient.mockReturnValue({}); + + wrapper = shallowMountExtended(ObservabilityContainer, { + propsData: { + oauthUrl: OAUTH_URL, + tracingUrl: TRACING_URL, + provisioningUrl: PROVISIONING_URL, + }, + stubs: { + ObservabilitySkeleton: stubComponent(ObservabilitySkeleton, { + methods: { onContentLoaded: mockSkeletonOnContentLoaded, onError: mockSkeletonOnError }, + }), + }, + slots: { + default: { + render(h) { + h(`
mockedComponent
`); + }, + name: 'MockComponent', + props: { + observabilityClient: { + type: Object, + required: true, + }, + }, + }, + }, + }); + }); + + const dispatchMessageEvent = (status, origin) => + window.dispatchEvent( + new MessageEvent('message', { + data: { + type: 'AUTH_COMPLETION', + status, + }, + origin: origin ?? new URL(OAUTH_URL).origin, + }), + ); + + const findIframe = () => wrapper.findByTestId('observability-oauth-iframe'); + const findSlotComponent = () => wrapper.findComponent({ name: 'MockComponent' }); + + it('should render the oauth iframe', () => { + const iframe = findIframe(); + expect(iframe.exists()).toBe(true); + expect(iframe.attributes('hidden')).toBe('hidden'); + expect(iframe.attributes('src')).toBe(OAUTH_URL); + expect(iframe.attributes('sandbox')).toBe('allow-same-origin allow-forms allow-scripts'); + }); + + it('should render the ObservabilitySkeleton', () => { + const skeleton = wrapper.findComponent(ObservabilitySkeleton); + expect(skeleton.exists()).toBe(true); + }); + + it('should not render the default slot', () => { + expect(findSlotComponent().exists()).toBe(false); + }); + + it('renders the slot content and removes the iframe on oauth success message', async () => { + dispatchMessageEvent('success'); + + await nextTick(); + + expect(mockSkeletonOnContentLoaded).toHaveBeenCalledTimes(1); + + const slotComponent = findSlotComponent(); + expect(slotComponent.exists()).toBe(true); + expect(buildClient).toHaveBeenCalledWith({ + provisioningUrl: PROVISIONING_URL, + tracingUrl: TRACING_URL, + }); + expect(findIframe().exists()).toBe(false); + }); + + it('does not render the slot content and removes the iframe on oauth error message', async () => { + dispatchMessageEvent('error'); + + await nextTick(); + + expect(mockSkeletonOnError).toHaveBeenCalledTimes(1); + + expect(findSlotComponent().exists()).toBe(false); + expect(findIframe().exists()).toBe(false); + expect(buildClient).not.toHaveBeenCalled(); + }); + + it('handles oauth message only once', () => { + dispatchMessageEvent('success'); + dispatchMessageEvent('success'); + + expect(mockSkeletonOnContentLoaded).toHaveBeenCalledTimes(1); + }); + + it('only handles messages from the oauth url', () => { + dispatchMessageEvent('success', 'www.fake-url.com'); + + expect(mockSkeletonOnContentLoaded).toHaveBeenCalledTimes(0); + expect(findSlotComponent().exists()).toBe(false); + expect(findIframe().exists()).toBe(true); + }); + + it('does not handle messages if the component has been destroyed', () => { + wrapper.destroy(); + + dispatchMessageEvent('success'); + + expect(mockSkeletonOnContentLoaded).toHaveBeenCalledTimes(0); + }); +}); diff --git a/spec/frontend/observability/skeleton_spec.js b/spec/frontend/observability/skeleton_spec.js index 65dbb003743..cf9ed814c9f 100644 --- a/spec/frontend/observability/skeleton_spec.js +++ b/spec/frontend/observability/skeleton_spec.js @@ -19,7 +19,7 @@ describe('Skeleton component', () => { const SKELETON_VARIANTS = Object.values(SKELETON_VARIANTS_BY_ROUTE); - const findContentWrapper = () => wrapper.findByTestId('observability-wrapper'); + const findContentWrapper = () => wrapper.findByTestId('content-wrapper'); const findExploreSkeleton = () => wrapper.findComponent(ExploreSkeleton); @@ -42,8 +42,8 @@ describe('Skeleton component', () => { mountComponent({ variant: 'explore' }); }); - describe('loading timers', () => { - it('show Skeleton if content is not loaded within CONTENT_WAIT_MS', async () => { + describe('showing content', () => { + it('shows the skeleton if content is not loaded within CONTENT_WAIT_MS', async () => { expect(findExploreSkeleton().exists()).toBe(false); expect(findContentWrapper().isVisible()).toBe(false); @@ -55,7 +55,7 @@ describe('Skeleton component', () => { expect(findContentWrapper().isVisible()).toBe(false); }); - it('does not show the skeleton if content has loaded within CONTENT_WAIT_MS', async () => { + it('does not show the skeleton if content loads within CONTENT_WAIT_MS', async () => { expect(findExploreSkeleton().exists()).toBe(false); expect(findContentWrapper().isVisible()).toBe(false); @@ -73,9 +73,25 @@ describe('Skeleton component', () => { expect(findContentWrapper().isVisible()).toBe(true); expect(findExploreSkeleton().exists()).toBe(false); }); + + it('hides the skeleton after content loads', async () => { + jest.advanceTimersByTime(DEFAULT_TIMERS.CONTENT_WAIT_MS); + + await nextTick(); + + expect(findExploreSkeleton().exists()).toBe(true); + expect(findContentWrapper().isVisible()).toBe(false); + + wrapper.vm.onContentLoaded(); + + await nextTick(); + + expect(findContentWrapper().isVisible()).toBe(true); + expect(findExploreSkeleton().exists()).toBe(false); + }); }); - describe('error timeout', () => { + describe('error handling', () => { it('shows the error dialog if content has not loaded within TIMEOUT_MS', async () => { expect(findAlert().exists()).toBe(false); jest.advanceTimersByTime(DEFAULT_TIMERS.TIMEOUT_MS); @@ -86,6 +102,17 @@ describe('Skeleton component', () => { expect(findContentWrapper().isVisible()).toBe(false); }); + it('shows the error dialog if content fails to load', async () => { + expect(findAlert().exists()).toBe(false); + + wrapper.vm.onError(); + + await nextTick(); + + expect(findAlert().exists()).toBe(true); + expect(findContentWrapper().isVisible()).toBe(false); + }); + it('does not show the error dialog if content has loaded within TIMEOUT_MS', async () => { wrapper.vm.onContentLoaded(); jest.advanceTimersByTime(DEFAULT_TIMERS.TIMEOUT_MS); diff --git a/spec/frontend/tracing/list_index_spec.js b/spec/frontend/tracing/list_index_spec.js new file mode 100644 index 00000000000..a5759035c2f --- /dev/null +++ b/spec/frontend/tracing/list_index_spec.js @@ -0,0 +1,37 @@ +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import ListIndex from '~/tracing/list_index.vue'; +import TracingList from '~/tracing/components/tracing_list.vue'; +import ObservabilityContainer from '~/observability/components/observability_container.vue'; + +describe('ListIndex', () => { + const props = { + oauthUrl: 'https://example.com/oauth', + tracingUrl: 'https://example.com/tracing', + provisioningUrl: 'https://example.com/provisioning', + }; + + let wrapper; + + const mountComponent = () => { + wrapper = shallowMountExtended(ListIndex, { + propsData: props, + }); + }; + + it('renders ObservabilityContainer component', () => { + mountComponent(); + + const observabilityContainer = wrapper.findComponent(ObservabilityContainer); + expect(observabilityContainer.exists()).toBe(true); + expect(observabilityContainer.props('oauthUrl')).toBe(props.oauthUrl); + expect(observabilityContainer.props('tracingUrl')).toBe(props.tracingUrl); + expect(observabilityContainer.props('provisioningUrl')).toBe(props.provisioningUrl); + }); + + it('renders TracingList component inside ObservabilityContainer', () => { + mountComponent(); + + const observabilityContainer = wrapper.findComponent(ObservabilityContainer); + expect(observabilityContainer.findComponent(TracingList).exists()).toBe(true); + }); +}); diff --git a/spec/helpers/projects/observability_helper_spec.rb b/spec/helpers/projects/observability_helper_spec.rb new file mode 100644 index 00000000000..65b6ddf04ec --- /dev/null +++ b/spec/helpers/projects/observability_helper_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'json' + +RSpec.describe Projects::ObservabilityHelper, type: :helper, feature_category: :tracing do + describe '#observability_tracing_view_model' do + let_it_be(:group) { build_stubbed(:group) } + let_it_be(:project) { build_stubbed(:project, group: group) } + + it 'generates the correct JSON' do + expected_json = { + tracingUrl: Gitlab::Observability.tracing_url(project), + provisioningUrl: Gitlab::Observability.provisioning_url(project), + oauthUrl: Gitlab::Observability.oauth_url + }.to_json + + expect(helper.observability_tracing_view_model(project)).to eq(expected_json) + end + end +end diff --git a/spec/lib/gitlab/database/gitlab_schema_spec.rb b/spec/lib/gitlab/database/gitlab_schema_spec.rb index 48f5cdb995b..1c864239ae6 100644 --- a/spec/lib/gitlab/database/gitlab_schema_spec.rb +++ b/spec/lib/gitlab/database/gitlab_schema_spec.rb @@ -29,6 +29,9 @@ RSpec.describe Gitlab::Database::GitlabSchema, feature_category: :database do 'audit_events_part_5fc467ac26' | :gitlab_main '_test_gitlab_main_table' | :gitlab_main '_test_gitlab_ci_table' | :gitlab_ci + '_test_gitlab_main_clusterwide_table' | :gitlab_main_clusterwide + '_test_gitlab_main_cell_table' | :gitlab_main_cell + '_test_gitlab_pm_table' | :gitlab_pm '_test_my_table' | :gitlab_shared 'pg_attribute' | :gitlab_internal end diff --git a/spec/lib/gitlab/database/migration_helpers/automatic_lock_writes_on_tables_spec.rb b/spec/lib/gitlab/database/migration_helpers/automatic_lock_writes_on_tables_spec.rb index e4241348b54..577bf00ba2f 100644 --- a/spec/lib/gitlab/database/migration_helpers/automatic_lock_writes_on_tables_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers/automatic_lock_writes_on_tables_spec.rb @@ -9,7 +9,10 @@ RSpec.describe Gitlab::Database::MigrationHelpers::AutomaticLockWritesOnTables, let(:schema_class) { Class.new(Gitlab::Database::Migration[2.1]) } let(:skip_automatic_lock_on_writes) { false } let(:gitlab_main_table_name) { :_test_gitlab_main_table } + let(:gitlab_main_clusterwide_table_name) { :_test_gitlab_main_clusterwide_table } + let(:gitlab_main_cell_table_name) { :_test_gitlab_main_cell_table } let(:gitlab_ci_table_name) { :_test_gitlab_ci_table } + let(:gitlab_pm_table_name) { :_test_gitlab_pm_table } let(:gitlab_geo_table_name) { :_test_gitlab_geo_table } let(:gitlab_shared_table_name) { :_test_table } @@ -24,8 +27,11 @@ RSpec.describe Gitlab::Database::MigrationHelpers::AutomaticLockWritesOnTables, # Drop the created test tables, because we use non-transactional tests after do drop_table_if_exists(gitlab_main_table_name) + drop_table_if_exists(gitlab_main_clusterwide_table_name) + drop_table_if_exists(gitlab_main_cell_table_name) drop_table_if_exists(gitlab_ci_table_name) drop_table_if_exists(gitlab_geo_table_name) + drop_table_if_exists(gitlab_pm_table_name) drop_table_if_exists(gitlab_shared_table_name) drop_table_if_exists(renamed_gitlab_main_table_name) drop_table_if_exists(renamed_gitlab_ci_table_name) @@ -82,8 +88,12 @@ RSpec.describe Gitlab::Database::MigrationHelpers::AutomaticLockWritesOnTables, context 'when single database' do let(:config_model) { Gitlab::Database.database_base_models[:main] } let(:create_gitlab_main_table_migration_class) { create_table_migration(gitlab_main_table_name) } + let(:create_gitlab_main_cell_table_migration_class) { create_table_migration(gitlab_main_cell_table_name) } let(:create_gitlab_ci_table_migration_class) { create_table_migration(gitlab_ci_table_name) } let(:create_gitlab_shared_table_migration_class) { create_table_migration(gitlab_shared_table_name) } + let(:create_gitlab_main_clusterwide_table_migration_class) do + create_table_migration(gitlab_main_clusterwide_table_name) + end before do skip_if_database_exists(:ci) @@ -93,13 +103,19 @@ RSpec.describe Gitlab::Database::MigrationHelpers::AutomaticLockWritesOnTables, expect(Gitlab::Database::LockWritesManager).not_to receive(:new) create_gitlab_main_table_migration_class.migrate(:up) + create_gitlab_main_cell_table_migration_class.migrate(:up) + create_gitlab_main_clusterwide_table_migration_class.migrate(:up) create_gitlab_ci_table_migration_class.migrate(:up) create_gitlab_shared_table_migration_class.migrate(:up) expect do create_gitlab_main_table_migration_class.connection.execute("DELETE FROM #{gitlab_main_table_name}") + create_gitlab_main_cell_table_migration_class.connection.execute("DELETE FROM #{gitlab_main_cell_table_name}") create_gitlab_ci_table_migration_class.connection.execute("DELETE FROM #{gitlab_ci_table_name}") create_gitlab_shared_table_migration_class.connection.execute("DELETE FROM #{gitlab_shared_table_name}") + create_gitlab_main_clusterwide_table_migration_class.connection.execute( + "DELETE FROM #{gitlab_main_clusterwide_table_name}" + ) end.not_to raise_error end end @@ -163,6 +179,27 @@ RSpec.describe Gitlab::Database::MigrationHelpers::AutomaticLockWritesOnTables, end end + context 'for creating a gitlab_main_clusterwide table' do + let(:table_name) { gitlab_main_clusterwide_table_name } + + it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main] + it_behaves_like 'locks writes on table', Gitlab::Database.database_base_models[:ci] + end + + context 'for creating a gitlab_main_cell table' do + let(:table_name) { gitlab_main_cell_table_name } + + it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main] + it_behaves_like 'locks writes on table', Gitlab::Database.database_base_models[:ci] + end + + context 'for creating a gitlab_pm table' do + let(:table_name) { gitlab_pm_table_name } + + it_behaves_like 'does not lock writes on table', Gitlab::Database.database_base_models[:main] + it_behaves_like 'locks writes on table', Gitlab::Database.database_base_models[:ci] + end + context 'for creating a gitlab_ci table' do let(:table_name) { gitlab_ci_table_name } diff --git a/spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb index 495cefa002a..9852f6c9652 100644 --- a/spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb @@ -71,20 +71,22 @@ RSpec.describe Gitlab::ImportExport::Group::RelationTreeRestorer, feature_catego before do allow(shared.logger).to receive(:info).and_call_original allow(relation_reader).to receive(:consume_relation).and_call_original - - allow(relation_reader) - .to receive(:consume_relation) - .with(importable_name, 'labels') - .and_return([[label, 0]]) end context 'when relation object is new' do + before do + allow(relation_reader) + .to receive(:consume_relation) + .with(importable_name, 'boards') + .and_return([[board, 0]]) + end + context 'when relation object has invalid subrelations' do - let(:label) do + let(:board) do { - 'title' => 'test', - 'priorities' => [LabelPriority.new, LabelPriority.new], - 'type' => 'GroupLabel' + 'name' => 'test', + 'lists' => [List.new, List.new], + 'group_id' => importable.id } end @@ -94,26 +96,33 @@ RSpec.describe Gitlab::ImportExport::Group::RelationTreeRestorer, feature_catego .with( message: '[Project/Group Import] Invalid subrelation', group_id: importable.id, - relation_key: 'labels', - error_messages: "Project can't be blank, Priority can't be blank, and Priority is not a number" + relation_key: 'boards', + error_messages: "Label can't be blank, Position can't be blank, and Position is not a number" ) subject - label = importable.labels.first + board = importable.boards.last failure = importable.import_failures.first expect(importable.import_failures.count).to eq(2) - expect(label.title).to eq('test') + expect(board.name).to eq('test') expect(failure.exception_class).to eq('ActiveRecord::RecordInvalid') expect(failure.source).to eq('RelationTreeRestorer#save_relation_object') expect(failure.exception_message) - .to eq("Project can't be blank, Priority can't be blank, and Priority is not a number") + .to eq("Label can't be blank, Position can't be blank, and Position is not a number") end end end context 'when relation object is persisted' do + before do + allow(relation_reader) + .to receive(:consume_relation) + .with(importable_name, 'labels') + .and_return([[label, 0]]) + end + context 'when relation object is invalid' do let(:label) { create(:group_label, group: group, title: 'test') } diff --git a/spec/lib/gitlab/observability_spec.rb b/spec/lib/gitlab/observability_spec.rb index 84d591e2520..61f69a0171a 100644 --- a/spec/lib/gitlab/observability_spec.rb +++ b/spec/lib/gitlab/observability_spec.rb @@ -3,6 +3,9 @@ require 'spec_helper' RSpec.describe Gitlab::Observability, feature_category: :error_tracking do + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + describe '.observability_url' do let(:gitlab_url) { 'https://example.com' } @@ -37,6 +40,18 @@ RSpec.describe Gitlab::Observability, feature_category: :error_tracking do it { is_expected.to eq("#{described_class.observability_url}/v1/auth/start") } end + describe '.tracing_url' do + subject { described_class.tracing_url(project) } + + it { is_expected.to eq("#{described_class.observability_url}/query/#{group.id}/#{project.id}/v1/traces") } + end + + describe '.provisioning_url' do + subject { described_class.provisioning_url(project) } + + it { is_expected.to eq(described_class.observability_url.to_s) } + end + describe '.build_full_url' do let_it_be(:group) { build_stubbed(:group, id: 123) } let(:observability_url) { described_class.observability_url } diff --git a/spec/models/bulk_imports/file_transfer/group_config_spec.rb b/spec/models/bulk_imports/file_transfer/group_config_spec.rb index e50f52c728f..9e1e7cf6d6e 100644 --- a/spec/models/bulk_imports/file_transfer/group_config_spec.rb +++ b/spec/models/bulk_imports/file_transfer/group_config_spec.rb @@ -40,7 +40,12 @@ RSpec.describe BulkImports::FileTransfer::GroupConfig, feature_category: :import describe '#top_relation_tree' do it 'returns relation tree of a top level relation' do - expect(subject.top_relation_tree('labels')).to eq('priorities' => {}) + expect(subject.top_relation_tree('boards')).to include( + 'lists' => a_hash_including({ + 'board' => anything, + 'label' => anything + }) + ) end end diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 7cf3981969c..a91ac7a2c20 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -1510,52 +1510,22 @@ RSpec.describe Issue, feature_category: :team_planning do end describe '#publicly_visible?' do - context 'using a public project' do - let(:project) { create(:project, :public) } + let(:project) { build(:project, project_visiblity) } + let(:issue) { build(:issue, confidential: confidential, project: project) } - it 'returns true for a regular issue' do - issue = build(:issue, project: project) + subject { issue.send(:publicly_visible?) } - expect(issue).to be_truthy - end - - it 'returns false for a confidential issue' do - issue = build(:issue, :confidential, project: project) - - expect(issue).not_to be_falsy - end + where(:project_visiblity, :confidential, :expected_value) do + :public | false | true + :public | true | false + :internal | false | false + :internal | true | false + :private | false | false + :private | true | false end - context 'using an internal project' do - let(:project) { create(:project, :internal) } - - it 'returns false for a regular issue' do - issue = build(:issue, project: project) - - expect(issue).not_to be_falsy - end - - it 'returns false for a confidential issue' do - issue = build(:issue, :confidential, project: project) - - expect(issue).not_to be_falsy - end - end - - context 'using a private project' do - let(:project) { create(:project, :private) } - - it 'returns false for a regular issue' do - issue = build(:issue, project: project) - - expect(issue).not_to be_falsy - end - - it 'returns false for a confidential issue' do - issue = build(:issue, :confidential, project: project) - - expect(issue).not_to be_falsy - end + with_them do + it { is_expected.to eq(expected_value) } end end diff --git a/spec/requests/api/ml_model_packages_spec.rb b/spec/requests/api/ml_model_packages_spec.rb index a559f1642e8..3166298b430 100644 --- a/spec/requests/api/ml_model_packages_spec.rb +++ b/spec/requests/api/ml_model_packages_spec.rb @@ -124,18 +124,18 @@ RSpec.describe ::API::MlModelPackages, feature_category: :mlops do project.send("add_#{user_role}", user) if member && user_role != :anonymous end - describe 'PUT /api/v4/projects/:id/packages/ml_models/:package_name/:package_version/:file_name/authorize' do + describe 'PUT /api/v4/projects/:id/packages/ml_models/:model_name/:model_version/:file_name/authorize' do include_context 'ml model authorize permissions table' let(:token) { tokens[:personal_access_token] } let(:user_headers) { { 'HTTP_AUTHORIZATION' => token } } let(:headers) { user_headers.merge(workhorse_headers) } let(:request) { authorize_upload_file(headers) } - let(:package_name) { 'my_package' } + let(:model_name) { 'my_package' } let(:file_name) { 'myfile.tar.gz' } subject(:api_response) do - url = "/projects/#{project.id}/packages/ml_models/#{package_name}/0.0.1/#{file_name}/authorize" + url = "/projects/#{project.id}/packages/ml_models/#{model_name}/0.0.1/#{file_name}/authorize" put api(url), headers: headers @@ -162,7 +162,7 @@ RSpec.describe ::API::MlModelPackages, feature_category: :mlops do end describe 'application security' do - where(:package_name, :file_name) do + where(:model_name, :file_name) do 'my-package/../' | 'myfile.tar.gz' 'my-package%2f%2e%2e%2f' | 'myfile.tar.gz' 'my_package' | '../.ssh%2fauthorized_keys' @@ -177,7 +177,7 @@ RSpec.describe ::API::MlModelPackages, feature_category: :mlops do end end - describe 'PUT /api/v4/projects/:id/packages/ml_models/:package_name/:package_version/:file_name' do + describe 'PUT /api/v4/projects/:id/packages/ml_models/:model_name/:model_version/:file_name' do include_context 'ml model authorize permissions table' let_it_be(:file_name) { 'model.md5' } @@ -188,10 +188,10 @@ RSpec.describe ::API::MlModelPackages, feature_category: :mlops do let(:params) { { file: temp_file(file_name) } } let(:file_key) { :file } let(:send_rewritten_field) { true } - let(:package_name) { 'my_package' } + let(:model_name) { 'my_package' } subject(:api_response) do - url = "/projects/#{project.id}/packages/ml_models/#{package_name}/0.0.1/#{file_name}" + url = "/projects/#{project.id}/packages/ml_models/#{model_name}/0.0.1/#{file_name}" workhorse_finalize( api(url), @@ -236,14 +236,14 @@ RSpec.describe ::API::MlModelPackages, feature_category: :mlops do end end - describe 'GET /api/v4/projects/:project_id/packages/ml_models/:package_name/:package_version/:file_name' do + describe 'GET /api/v4/projects/:project_id/packages/ml_models/:model_name/:model_version/:file_name' do include_context 'ml model authorize permissions table' let_it_be(:package) { create(:ml_model_package, project: project, name: 'model', version: '0.0.1') } let_it_be(:package_file) { create(:package_file, :generic, package: package, file_name: 'model.md5') } - let(:package_name) { package.name } - let(:package_version) { package.version } + let(:model_name) { package.name } + let(:model_version) { package.version } let(:file_name) { package_file.file_name } let(:token) { tokens[:personal_access_token] } @@ -251,7 +251,7 @@ RSpec.describe ::API::MlModelPackages, feature_category: :mlops do let(:headers) { user_headers.merge(workhorse_headers) } subject(:api_response) do - url = "/projects/#{project.id}/packages/ml_models/#{package_name}/#{package_version}/#{file_name}" + url = "/projects/#{project.id}/packages/ml_models/#{model_name}/#{model_version}/#{file_name}" get api(url), headers: headers diff --git a/spec/requests/api/protected_branches_spec.rb b/spec/requests/api/protected_branches_spec.rb index 04d5f7ac20a..ad3a69fec9d 100644 --- a/spec/requests/api/protected_branches_spec.rb +++ b/spec/requests/api/protected_branches_spec.rb @@ -121,7 +121,7 @@ RSpec.describe API::ProtectedBranches, feature_category: :source_code_management get api(route, user) expect(json_response['push_access_levels']).to include( - a_hash_including('access_level_description' => 'Deploy key', 'deploy_key_id' => deploy_key.id) + a_hash_including('access_level_description' => deploy_key.title, 'deploy_key_id' => deploy_key.id) ) end end diff --git a/spec/requests/api/protected_tags_spec.rb b/spec/requests/api/protected_tags_spec.rb index c6398e624f8..4e7227b2294 100644 --- a/spec/requests/api/protected_tags_spec.rb +++ b/spec/requests/api/protected_tags_spec.rb @@ -95,7 +95,7 @@ RSpec.describe API::ProtectedTags, feature_category: :source_code_management do get api(route, user) expect(json_response['create_access_levels']).to include( - a_hash_including('access_level_description' => 'Deploy key', 'deploy_key_id' => deploy_key.id) + a_hash_including('access_level_description' => deploy_key.title, 'deploy_key_id' => deploy_key.id) ) end end diff --git a/spec/requests/projects/tracing_controller_spec.rb b/spec/requests/projects/tracing_controller_spec.rb index 520e99b120a..eecaa0d962a 100644 --- a/spec/requests/projects/tracing_controller_spec.rb +++ b/spec/requests/projects/tracing_controller_spec.rb @@ -3,7 +3,8 @@ require 'spec_helper' RSpec.describe Projects::TracingController, feature_category: :tracing do - let_it_be(:project) { create(:project, :repository) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } let_it_be(:user) { create(:user) } let(:path) { nil } let(:observability_tracing_ff) { true } @@ -44,6 +45,17 @@ RSpec.describe Projects::TracingController, feature_category: :tracing do expect(subject).to have_gitlab_http_status(:ok) end + it 'renders the js-tracing element correctly' do + element = Nokogiri::HTML.parse(subject.body).at_css('#js-tracing') + + expected_view_model = { + tracingUrl: Gitlab::Observability.tracing_url(project), + provisioningUrl: Gitlab::Observability.provisioning_url(project), + oauthUrl: Gitlab::Observability.oauth_url + }.to_json + expect(element.attributes['data-view-model'].value).to eq(expected_view_model) + end + context 'when feature is disabled' do let(:observability_tracing_ff) { false } diff --git a/spec/support/shared_examples/features/discussion_comments_shared_example.rb b/spec/support/shared_examples/features/discussion_comments_shared_example.rb index ac8055138d7..ba520d0c609 100644 --- a/spec/support/shared_examples/features/discussion_comments_shared_example.rb +++ b/spec/support/shared_examples/features/discussion_comments_shared_example.rb @@ -3,8 +3,8 @@ RSpec.shared_examples 'thread comments for commit and snippet' do |resource_name| let(:form_selector) { '.js-main-target-form' } let(:dropdown_selector) { "#{form_selector} .comment-type-dropdown" } - let(:toggle_selector) { "#{dropdown_selector} .gl-dropdown-toggle" } - let(:menu_selector) { "#{dropdown_selector} .dropdown-menu" } + let(:toggle_selector) { "#{dropdown_selector} .gl-new-dropdown-toggle" } + let(:menu_selector) { "#{dropdown_selector} .gl-new-dropdown-contents" } let(:submit_selector) { "#{form_selector} .js-comment-submit-button > button:first-child" } let(:close_selector) { "#{form_selector} .btn-comment-and-close" } let(:comments_selector) { '.timeline > .note.timeline-entry:not(.being-posted)' } @@ -63,33 +63,6 @@ RSpec.shared_examples 'thread comments for commit and snippet' do |resource_name expect(page).not_to have_selector menu_selector end - it 'clicking the ul padding or divider should not change the text' do - execute_script("document.querySelector('#{menu_selector}').click()") - - # on issues page, the menu closes when clicking anywhere, on other pages it will - # remain open if clicking divider or menu padding, but should not change button action - # - # if dropdown menu is not toggled (and also not present), - # it's "issue-type" dropdown - if first(menu_selector, minimum: 0).nil? - expect(find(dropdown_selector)).to have_content 'Comment' - - find(toggle_selector).click - execute_script("document.querySelector('#{menu_selector} .dropdown-divider').click()") - else - execute_script("document.querySelector('#{menu_selector}').click()") - - expect(page).to have_selector menu_selector - expect(find(dropdown_selector)).to have_content 'Comment' - - execute_script("document.querySelector('#{menu_selector} .dropdown-divider').click()") - - expect(page).to have_selector menu_selector - end - - expect(find(dropdown_selector)).to have_content 'Comment' - end - describe 'when selecting "Start thread"' do before do find("#{menu_selector} li", match: :first) @@ -178,10 +151,10 @@ end RSpec.shared_examples 'thread comments for issue, epic and merge request' do |resource_name| let(:form_selector) { '.js-main-target-form' } - let(:dropdown_selector) { "#{form_selector} [data-testid='comment-button']" } - let(:submit_button_selector) { "#{dropdown_selector} .split-content-button" } - let(:toggle_selector) { "#{dropdown_selector} .dropdown-toggle-split" } - let(:menu_selector) { "#{dropdown_selector} .dropdown-menu" } + let(:dropdown_selector) { "#{form_selector} .comment-type-dropdown" } + let(:toggle_selector) { "#{dropdown_selector} .gl-new-dropdown-toggle" } + let(:menu_selector) { "#{dropdown_selector} .gl-new-dropdown-contents" } + let(:submit_selector) { "#{form_selector} .js-comment-submit-button > button:first-child" } let(:close_selector) { "#{form_selector} .btn-comment-and-close" } let(:comments_selector) { '.timeline > .note.timeline-entry:not(.being-posted)' } let(:comment) { 'My comment' } @@ -191,7 +164,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re find("#{form_selector} .note-textarea").send_keys(comment) - find(submit_button_selector).click + find(submit_selector).click wait_for_all_requests @@ -260,7 +233,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re describe 'creating a thread' do before do - find(submit_button_selector).click + find(submit_selector).click wait_for_requests find(comments_selector, match: :first) @@ -366,7 +339,7 @@ RSpec.shared_examples 'thread comments for issue, epic and merge request' do |re end it 'updates the submit button text and closes the dropdown' do - button = find(submit_button_selector) + button = find(submit_selector) expect(button).to have_content 'Comment' diff --git a/spec/tasks/gitlab/feature_categories_rake_spec.rb b/spec/tasks/gitlab/feature_categories_rake_spec.rb index 33f4bca4c85..f495c7e8911 100644 --- a/spec/tasks/gitlab/feature_categories_rake_spec.rb +++ b/spec/tasks/gitlab/feature_categories_rake_spec.rb @@ -40,7 +40,8 @@ RSpec.describe 'gitlab:feature_categories:index', :silence_stdout, feature_categ ) ), 'database_tables' => a_hash_including( - 'container_scanning' => a_collection_including('vulnerability_advisories') + 'continuous_integration' => a_collection_including('ci_pipelines'), + 'user_profile' => a_collection_including('users') ) } diff --git a/vendor/project_templates/typo3_distribution.tar.gz b/vendor/project_templates/typo3_distribution.tar.gz index 13c158d1462..1de92d781af 100644 Binary files a/vendor/project_templates/typo3_distribution.tar.gz and b/vendor/project_templates/typo3_distribution.tar.gz differ