Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
cc310f2111
commit
ef111ed730
|
|
@ -36,6 +36,7 @@ workflow:
|
|||
GITLAB_ADMIN_USERNAME: root
|
||||
GITLAB_ADMIN_PASSWORD: 5iveL!fe
|
||||
GITLAB_QA_ADMIN_ACCESS_TOKEN: $QA_ADMIN_ACCESS_TOKEN
|
||||
KNAPSACK_TEST_FILE_PATTERN: ""
|
||||
QA_DOCKER_NETWORK: host
|
||||
QA_GENERATE_ALLURE_REPORT: "true"
|
||||
QA_CAN_TEST_PRAEFECT: "false"
|
||||
|
|
@ -50,7 +51,7 @@ workflow:
|
|||
- deploy "${GITLAB_DOMAIN}"
|
||||
- cd qa && bundle install
|
||||
script:
|
||||
- export QA_COMMAND="bundle exec bin/qa ${QA_SCENARIO:=Test::Instance::All} $QA_GITLAB_URL -- $QA_TESTS --force-color --order random --format documentation --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml"
|
||||
- export QA_COMMAND="bundle exec bin/qa ${QA_SCENARIO:=Test::Instance::All} $QA_GITLAB_URL -- --force-color --order random --format documentation --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml"
|
||||
- echo "Running - '$QA_COMMAND'"
|
||||
- eval "$QA_COMMAND"
|
||||
after_script:
|
||||
|
|
|
|||
|
|
@ -1,6 +1 @@
|
|||
import '../main';
|
||||
import { runModules } from '~/run_modules';
|
||||
|
||||
const modules = import.meta.glob('../pages/**/index.js');
|
||||
|
||||
runModules(modules, 'CE');
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
import { runModules } from '~/run_modules';
|
||||
|
||||
const modules = import.meta.glob('../../../../ee/app/assets/javascripts/pages/**/index.js');
|
||||
|
||||
runModules(modules, 'EE');
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
import { runModules } from '~/run_modules';
|
||||
|
||||
const modules = import.meta.glob('../../../../jh/app/assets/javascripts/pages/**/index.js');
|
||||
|
||||
runModules(modules, 'JH');
|
||||
|
|
@ -324,7 +324,9 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="detail-page-header-actions gl-display-flex gl-align-self-start gl-sm-gap-3">
|
||||
<div
|
||||
class="detail-page-header-actions gl-display-flex gl-align-self-start gl-sm-gap-3 gl-w-full gl-md-w-auto"
|
||||
>
|
||||
<div class="gl-md-display-none! gl-w-full">
|
||||
<gl-disclosure-dropdown
|
||||
v-if="hasMobileDropdown"
|
||||
|
|
@ -335,7 +337,7 @@ export default {
|
|||
:auto-close="false"
|
||||
data-testid="mobile-dropdown"
|
||||
:loading="isToggleStateButtonLoading"
|
||||
placement="left"
|
||||
placement="right"
|
||||
>
|
||||
<template v-if="showMovedSidebarOptions && !glFeatures.notificationsTodosButtons">
|
||||
<sidebar-subscriptions-widget
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
const paths = [];
|
||||
const allModules = {};
|
||||
|
||||
const prefixes = {
|
||||
CE: '../pages/',
|
||||
EE: '../../../../ee/app/assets/javascripts/pages/',
|
||||
JH: '../../../../jh/app/assets/javascripts/pages/',
|
||||
};
|
||||
|
||||
const editionExcludes = {
|
||||
JH: [],
|
||||
EE: [prefixes.JH],
|
||||
CE: [prefixes.EE, prefixes.JH],
|
||||
};
|
||||
|
||||
const runWithExcludes = (edition) => {
|
||||
const prefix = prefixes[edition];
|
||||
const excludes = editionExcludes[edition];
|
||||
paths.forEach((path) => {
|
||||
const hasDuplicateEntrypoint = excludes.some(
|
||||
(editionPrefix) => `${editionPrefix}${path}` in allModules,
|
||||
);
|
||||
if (!hasDuplicateEntrypoint) allModules[`${prefix}${path}`]?.();
|
||||
});
|
||||
};
|
||||
|
||||
let pathsPopulated = false;
|
||||
|
||||
const populatePaths = () => {
|
||||
if (pathsPopulated) return;
|
||||
paths.push(
|
||||
...document
|
||||
.querySelector('meta[name="controller-path"]')
|
||||
.content.split('/')
|
||||
.map((part, index, arr) => `${[...arr.slice(0, index), part].join('/')}/index.js`),
|
||||
);
|
||||
pathsPopulated = true;
|
||||
};
|
||||
|
||||
export const runModules = (modules, edition) => {
|
||||
populatePaths();
|
||||
Object.assign(allModules, modules);
|
||||
// wait before all modules have been collected to exclude duplicates between CE and EE\JH
|
||||
// <script> runs as a macrotask, can't schedule with promises here
|
||||
requestAnimationFrame(() => {
|
||||
runWithExcludes(edition);
|
||||
});
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { mockGetProjectStorageStatisticsGraphQLResponse } from 'jest/usage_quotas/storage/mock_data';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import getProjectStorageStatisticsQuery from 'ee_else_ce/usage_quotas/storage/queries/project_storage.query.graphql';
|
||||
import getProjectStorageStatisticsQuery from 'ee_else_ce/usage_quotas/storage/project/queries/project_storage.query.graphql';
|
||||
import ProjectStorageApp from './project_storage_app.vue';
|
||||
|
||||
const meta = {
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import { updateRepositorySize } from '~/api/projects_api';
|
|||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
import SectionedPercentageBar from '~/usage_quotas/components/sectioned_percentage_bar.vue';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import getCostFactoredProjectStorageStatistics from 'ee_else_ce/usage_quotas/storage/queries/cost_factored_project_storage.query.graphql';
|
||||
import getProjectStorageStatistics from 'ee_else_ce/usage_quotas/storage/queries/project_storage.query.graphql';
|
||||
import getProjectStorageStatistics from 'ee_else_ce/usage_quotas/storage/project/queries/project_storage.query.graphql';
|
||||
import getCostFactoredProjectStorageStatistics from 'ee_else_ce/usage_quotas/storage/project/queries/cost_factored_project_storage.query.graphql';
|
||||
import {
|
||||
ERROR_MESSAGE,
|
||||
LEARN_MORE_LABEL,
|
||||
|
|
|
|||
|
|
@ -499,15 +499,6 @@ module ApplicationHelper
|
|||
end
|
||||
end
|
||||
|
||||
def controller_full_path
|
||||
action = case controller.action_name
|
||||
when 'create' then 'new'
|
||||
when 'update' then 'edit'
|
||||
else controller.action_name
|
||||
end
|
||||
"#{controller.controller_path}/#{action}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def browser_id
|
||||
|
|
|
|||
|
|
@ -15,4 +15,17 @@ module ViteHelper
|
|||
def vite_hmr_http_url
|
||||
ViteRuby.env['VITE_HMR_HTTP_URL']
|
||||
end
|
||||
|
||||
def vite_page_entrypoint_paths
|
||||
action = case controller.action_name
|
||||
when 'create' then 'new'
|
||||
when 'update' then 'edit'
|
||||
else controller.action_name
|
||||
end
|
||||
|
||||
parts = (controller.controller_path.split('/') << action)
|
||||
|
||||
parts.map
|
||||
.with_index { |part, idx| "pages.#{(parts[0, idx] << part).join('.')}.js" }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -55,14 +55,9 @@
|
|||
= webpack_bundle_tag 'performance_bar' if performance_bar_enabled?
|
||||
|
||||
- if vite_enabled?
|
||||
%meta{ name: 'controller-path', content: controller_full_path }
|
||||
- if Rails.env.development?
|
||||
= vite_client_tag
|
||||
= vite_javascript_tag "main"
|
||||
- if Gitlab.ee?
|
||||
= vite_javascript_tag "main_ee"
|
||||
- if Gitlab.jh?
|
||||
= vite_javascript_tag "main_jh"
|
||||
= vite_javascript_tag "main", *vite_page_entrypoint_paths
|
||||
|
||||
= yield :page_specific_javascripts
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: pause_clickhouse_workers_during_migration
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138166
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/433389
|
||||
milestone: '16.7'
|
||||
type: development
|
||||
group: group::runner
|
||||
default_enabled: false
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: wait_for_clickhouse_workers_during_migration
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138166
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/433389
|
||||
milestone: '16.7'
|
||||
type: development
|
||||
group: group::runner
|
||||
default_enabled: false
|
||||
|
|
@ -22,7 +22,6 @@ const BABEL_VERSION = require('@babel/core/package.json').version;
|
|||
const BABEL_LOADER_VERSION = require('babel-loader/package.json').version;
|
||||
const CompressionPlugin = require('compression-webpack-plugin');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const glob = require('glob');
|
||||
// eslint-disable-next-line import/no-dynamic-require
|
||||
const { VueLoaderPlugin } = require(VUE_LOADER_MODULE);
|
||||
// eslint-disable-next-line import/no-dynamic-require
|
||||
|
|
@ -45,6 +44,7 @@ const {
|
|||
GITLAB_WEB_IDE_PUBLIC_PATH,
|
||||
copyFilesPatterns,
|
||||
} = require('./webpack.constants');
|
||||
const { generateEntries } = require('./webpack.helpers');
|
||||
|
||||
const createIncrementalWebpackCompiler = require('./helpers/incremental_webpack_compiler');
|
||||
const vendorDllHash = require('./helpers/vendor_dll_hash');
|
||||
|
|
@ -90,10 +90,6 @@ if (WEBPACK_REPORT) {
|
|||
|
||||
const devtool = IS_PRODUCTION ? 'source-map' : 'cheap-module-eval-source-map';
|
||||
|
||||
let autoEntriesCount = 0;
|
||||
let watchAutoEntries = [];
|
||||
const defaultEntries = ['./main'];
|
||||
|
||||
const incrementalCompiler = createIncrementalWebpackCompiler(
|
||||
INCREMENTAL_COMPILER_RECORD_HISTORY,
|
||||
INCREMENTAL_COMPILER_ENABLED,
|
||||
|
|
@ -101,82 +97,6 @@ const incrementalCompiler = createIncrementalWebpackCompiler(
|
|||
INCREMENTAL_COMPILER_TTL,
|
||||
);
|
||||
|
||||
function generateEntries() {
|
||||
// generate automatic entry points
|
||||
const autoEntries = {};
|
||||
const autoEntriesMap = {};
|
||||
const pageEntries = glob.sync('pages/**/index.js', {
|
||||
cwd: path.join(ROOT_PATH, 'app/assets/javascripts'),
|
||||
});
|
||||
watchAutoEntries = [path.join(ROOT_PATH, 'app/assets/javascripts/pages/')];
|
||||
|
||||
function generateAutoEntries(entryPath, prefix = '.') {
|
||||
const chunkPath = entryPath.replace(/\/index\.js$/, '');
|
||||
const chunkName = chunkPath.replace(/\//g, '.');
|
||||
autoEntriesMap[chunkName] = `${prefix}/${entryPath}`;
|
||||
}
|
||||
|
||||
pageEntries.forEach((entryPath) => generateAutoEntries(entryPath));
|
||||
|
||||
if (IS_EE) {
|
||||
const eePageEntries = glob.sync('pages/**/index.js', {
|
||||
cwd: path.join(ROOT_PATH, 'ee/app/assets/javascripts'),
|
||||
});
|
||||
eePageEntries.forEach((entryPath) => generateAutoEntries(entryPath, 'ee'));
|
||||
watchAutoEntries.push(path.join(ROOT_PATH, 'ee/app/assets/javascripts/pages/'));
|
||||
}
|
||||
|
||||
if (IS_JH) {
|
||||
const eePageEntries = glob.sync('pages/**/index.js', {
|
||||
cwd: path.join(ROOT_PATH, 'jh/app/assets/javascripts'),
|
||||
});
|
||||
eePageEntries.forEach((entryPath) => generateAutoEntries(entryPath, 'jh'));
|
||||
watchAutoEntries.push(path.join(ROOT_PATH, 'jh/app/assets/javascripts/pages/'));
|
||||
}
|
||||
|
||||
const autoEntryKeys = Object.keys(autoEntriesMap);
|
||||
autoEntriesCount = autoEntryKeys.length;
|
||||
|
||||
// import ancestor entrypoints within their children
|
||||
autoEntryKeys.forEach((entry) => {
|
||||
const entryPaths = [autoEntriesMap[entry]];
|
||||
const segments = entry.split('.');
|
||||
while (segments.pop()) {
|
||||
const ancestor = segments.join('.');
|
||||
if (autoEntryKeys.includes(ancestor)) {
|
||||
entryPaths.unshift(autoEntriesMap[ancestor]);
|
||||
}
|
||||
}
|
||||
autoEntries[entry] = defaultEntries.concat(entryPaths);
|
||||
});
|
||||
|
||||
/*
|
||||
If you create manual entries, ensure that these import `app/assets/javascripts/webpack.js` right at
|
||||
the top of the entry in order to ensure that the public path is correctly determined for loading
|
||||
assets async. See: https://webpack.js.org/configuration/output/#outputpublicpath
|
||||
|
||||
Note: WebPack 5 has an 'auto' option for the public path which could allow us to remove this option
|
||||
Note 2: If you are using web-workers, you might need to reset the public path, see:
|
||||
https://gitlab.com/gitlab-org/gitlab/-/issues/321656
|
||||
*/
|
||||
|
||||
const manualEntries = {
|
||||
default: defaultEntries,
|
||||
legacy_sentry: './sentry/legacy_index.js',
|
||||
sentry: './sentry/index.js',
|
||||
performance_bar: './performance_bar/index.js',
|
||||
jira_connect_app: './jira_connect/subscriptions/index.js',
|
||||
sandboxed_mermaid: './lib/mermaid.js',
|
||||
redirect_listbox: './entrypoints/behaviors/redirect_listbox.js',
|
||||
sandboxed_swagger: './lib/swagger.js',
|
||||
super_sidebar: './entrypoints/super_sidebar.js',
|
||||
tracker: './entrypoints/tracker.js',
|
||||
analytics: './entrypoints/analytics.js',
|
||||
};
|
||||
|
||||
return Object.assign(manualEntries, incrementalCompiler.filterEntryPoints(autoEntries));
|
||||
}
|
||||
|
||||
const alias = {
|
||||
// Map Apollo client to apollo/client/core to prevent react related imports from being loaded
|
||||
'@apollo/client$': '@apollo/client/core',
|
||||
|
|
@ -318,12 +238,42 @@ if (USE_VUE3) {
|
|||
vueLoaderOptions.compiler = require.resolve('./vue3migration/compiler');
|
||||
}
|
||||
|
||||
const entriesState = {
|
||||
autoEntriesCount: 0,
|
||||
watchAutoEntries: [],
|
||||
};
|
||||
const defaultEntries = ['./main'];
|
||||
|
||||
module.exports = {
|
||||
mode: IS_PRODUCTION ? 'production' : 'development',
|
||||
|
||||
context: path.join(ROOT_PATH, 'app/assets/javascripts'),
|
||||
|
||||
entry: generateEntries,
|
||||
entry: () => {
|
||||
/*
|
||||
If you create manual entries, ensure that these import `app/assets/javascripts/webpack.js` right at
|
||||
the top of the entry in order to ensure that the public path is correctly determined for loading
|
||||
assets async. See: https://webpack.js.org/configuration/output/#outputpublicpath
|
||||
|
||||
Note: WebPack 5 has an 'auto' option for the public path which could allow us to remove this option
|
||||
Note 2: If you are using web-workers, you might need to reset the public path, see:
|
||||
https://gitlab.com/gitlab-org/gitlab/-/issues/321656
|
||||
*/
|
||||
return {
|
||||
default: defaultEntries,
|
||||
legacy_sentry: './sentry/legacy_index.js',
|
||||
sentry: './sentry/index.js',
|
||||
performance_bar: './performance_bar/index.js',
|
||||
jira_connect_app: './jira_connect/subscriptions/index.js',
|
||||
sandboxed_mermaid: './lib/mermaid.js',
|
||||
redirect_listbox: './entrypoints/behaviors/redirect_listbox.js',
|
||||
sandboxed_swagger: './lib/swagger.js',
|
||||
super_sidebar: './entrypoints/super_sidebar.js',
|
||||
tracker: './entrypoints/tracker.js',
|
||||
analytics: './entrypoints/analytics.js',
|
||||
...incrementalCompiler.filterEntryPoints(generateEntries({ defaultEntries, entriesState })),
|
||||
};
|
||||
},
|
||||
|
||||
output: {
|
||||
path: WEBPACK_OUTPUT_PATH,
|
||||
|
|
@ -522,7 +472,7 @@ module.exports = {
|
|||
priority: 20,
|
||||
name: 'main',
|
||||
chunks: 'initial',
|
||||
minChunks: autoEntriesCount * 0.9,
|
||||
minChunks: entriesState.autoEntriesCount * 0.9,
|
||||
}),
|
||||
prosemirror: {
|
||||
priority: 17,
|
||||
|
|
@ -728,14 +678,16 @@ module.exports = {
|
|||
if (hasMissingNodeModules) compilation.contextDependencies.add(nodeModulesPath);
|
||||
|
||||
// watch for changes to automatic entrypoints
|
||||
watchAutoEntries.forEach((watchPath) => compilation.contextDependencies.add(watchPath));
|
||||
entriesState.watchAutoEntries.forEach((watchPath) =>
|
||||
compilation.contextDependencies.add(watchPath),
|
||||
);
|
||||
|
||||
// report our auto-generated bundle count
|
||||
if (incrementalCompiler.enabled) {
|
||||
incrementalCompiler.logStatus(autoEntriesCount);
|
||||
incrementalCompiler.logStatus(entriesState.autoEntriesCount);
|
||||
} else {
|
||||
console.log(
|
||||
`${autoEntriesCount} entries from '/pages' automatically added to webpack output.`,
|
||||
`${entriesState.autoEntriesCount} entries from '/pages' automatically added to webpack output.`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
const path = require('path');
|
||||
const glob = require('glob');
|
||||
const { IS_EE, IS_JH, ROOT_PATH } = require('./webpack.constants');
|
||||
|
||||
function generateEntries({ defaultEntries, entriesState } = { defaultEntries: [] }) {
|
||||
// generate automatic entry points
|
||||
const autoEntries = {};
|
||||
const autoEntriesMap = {};
|
||||
const pageEntries = glob.sync('pages/**/index.js', {
|
||||
cwd: path.join(ROOT_PATH, 'app/assets/javascripts'),
|
||||
});
|
||||
if (entriesState) {
|
||||
Object.assign(entriesState, {
|
||||
watchAutoEntries: [path.join(ROOT_PATH, 'app/assets/javascripts/pages/')],
|
||||
});
|
||||
}
|
||||
|
||||
function generateAutoEntries(entryPath, prefix = '.') {
|
||||
const chunkPath = entryPath.replace(/\/index\.js$/, '');
|
||||
const chunkName = chunkPath.replace(/\//g, '.');
|
||||
autoEntriesMap[chunkName] = `${prefix}/${entryPath}`;
|
||||
}
|
||||
|
||||
pageEntries.forEach((entryPath) => generateAutoEntries(entryPath));
|
||||
|
||||
if (IS_EE) {
|
||||
const eePageEntries = glob.sync('pages/**/index.js', {
|
||||
cwd: path.join(ROOT_PATH, 'ee/app/assets/javascripts'),
|
||||
});
|
||||
eePageEntries.forEach((entryPath) => generateAutoEntries(entryPath, 'ee'));
|
||||
if (entriesState) {
|
||||
entriesState.watchAutoEntries.push(path.join(ROOT_PATH, 'ee/app/assets/javascripts/pages/'));
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_JH) {
|
||||
const eePageEntries = glob.sync('pages/**/index.js', {
|
||||
cwd: path.join(ROOT_PATH, 'jh/app/assets/javascripts'),
|
||||
});
|
||||
eePageEntries.forEach((entryPath) => generateAutoEntries(entryPath, 'jh'));
|
||||
if (entriesState) {
|
||||
entriesState.watchAutoEntries.push(path.join(ROOT_PATH, 'jh/app/assets/javascripts/pages/'));
|
||||
}
|
||||
}
|
||||
|
||||
const autoEntryKeys = Object.keys(autoEntriesMap);
|
||||
if (entriesState) {
|
||||
Object.assign(entriesState, {
|
||||
autoEntriesCount: autoEntryKeys.length,
|
||||
});
|
||||
}
|
||||
|
||||
// import ancestor entrypoints within their children
|
||||
autoEntryKeys.forEach((entry) => {
|
||||
const entryPaths = [autoEntriesMap[entry]];
|
||||
const segments = entry.split('.');
|
||||
while (segments.pop()) {
|
||||
const ancestor = segments.join('.');
|
||||
if (autoEntryKeys.includes(ancestor)) {
|
||||
entryPaths.unshift(autoEntriesMap[ancestor]);
|
||||
}
|
||||
}
|
||||
autoEntries[entry] = defaultEntries.concat(entryPaths);
|
||||
});
|
||||
|
||||
return autoEntries;
|
||||
}
|
||||
|
||||
module.exports = { generateEntries };
|
||||
|
|
@ -67,6 +67,7 @@ GET /groups
|
|||
"emails_enabled": null,
|
||||
"mentions_disabled": null,
|
||||
"lfs_enabled": true,
|
||||
"default_branch": null,
|
||||
"default_branch_protection": 2,
|
||||
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
|
||||
"web_url": "http://localhost:3000/groups/foo-bar",
|
||||
|
|
@ -106,6 +107,7 @@ GET /groups?statistics=true
|
|||
"emails_enabled": null,
|
||||
"mentions_disabled": null,
|
||||
"lfs_enabled": true,
|
||||
"default_branch": null,
|
||||
"default_branch_protection": 2,
|
||||
"avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",
|
||||
"web_url": "http://localhost:3000/groups/foo-bar",
|
||||
|
|
@ -194,6 +196,7 @@ GET /groups/:id/subgroups
|
|||
"emails_enabled": null,
|
||||
"mentions_disabled": null,
|
||||
"lfs_enabled": true,
|
||||
"default_branch": null,
|
||||
"default_branch_protection": 2,
|
||||
"avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/foo.jpg",
|
||||
"web_url": "http://gitlab.example.com/groups/foo-bar",
|
||||
|
|
@ -257,6 +260,7 @@ GET /groups/:id/descendant_groups
|
|||
"emails_enabled": null,
|
||||
"mentions_disabled": null,
|
||||
"lfs_enabled": true,
|
||||
"default_branch": null,
|
||||
"default_branch_protection": 2,
|
||||
"avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/bar.jpg",
|
||||
"web_url": "http://gitlab.example.com/groups/foo/bar",
|
||||
|
|
@ -283,6 +287,7 @@ GET /groups/:id/descendant_groups
|
|||
"emails_enabled": null,
|
||||
"mentions_disabled": null,
|
||||
"lfs_enabled": true,
|
||||
"default_branch": null,
|
||||
"default_branch_protection": 2,
|
||||
"avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/baz.jpg",
|
||||
"web_url": "http://gitlab.example.com/groups/foo/bar/baz",
|
||||
|
|
@ -845,6 +850,7 @@ Parameters:
|
|||
| `path` | string | yes | The path of the group. |
|
||||
| `auto_devops_enabled` | boolean | no | Default to Auto DevOps pipeline for all projects within this group. |
|
||||
| `avatar` | mixed | no | Image file for avatar of the group. [Introduced in GitLab 12.9](https://gitlab.com/gitlab-org/gitlab/-/issues/36681) |
|
||||
| `default_branch` | string | no | The [default branch](../user/project/repository/branches/default.md) name for group's projects. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/442298) in GitLab 16.11. |
|
||||
| `default_branch_protection` | integer | no | See [Options for `default_branch_protection`](#options-for-default_branch_protection). Default to the global level default branch protection setting. |
|
||||
| `default_branch_protection_defaults` | hash | no | See [Options for `default_branch_protection_defaults`](#options-for-default_branch_protection_defaults). |
|
||||
| `description` | string | no | The group's description. |
|
||||
|
|
@ -1018,6 +1024,7 @@ PUT /groups/:id
|
|||
| `path` | string | no | The path of the group. |
|
||||
| `auto_devops_enabled` | boolean | no | Default to Auto DevOps pipeline for all projects within this group. |
|
||||
| `avatar` | mixed | no | Image file for avatar of the group. [Introduced in GitLab 12.9](https://gitlab.com/gitlab-org/gitlab/-/issues/36681) |
|
||||
| `default_branch` | string | no | The [default branch](../user/project/repository/branches/default.md) name for group's projects. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/442298) in GitLab 16.11. |
|
||||
| `default_branch_protection` | integer | no | See [Options for `default_branch_protection`](#options-for-default_branch_protection). |
|
||||
| `default_branch_protection_defaults` | hash | no | See [Options for `default_branch_protection_defaults`](#options-for-default_branch_protection_defaults). |
|
||||
| `description` | string | no | The description of the group. |
|
||||
|
|
|
|||
|
|
@ -482,6 +482,58 @@ Example response:
|
|||
]
|
||||
```
|
||||
|
||||
## List indirect memberships for a billable member of a group
|
||||
|
||||
DETAILS:
|
||||
**Status:** Experiment
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/386583) in GitLab 16.11.
|
||||
|
||||
Gets a list of indirect memberships for a billable member of a group.
|
||||
|
||||
Lists all projects and groups that a user is a member of, that have been invited to the requested root group.
|
||||
For instance, if the requested group is `Root Group`, and the requested user is a direct member of `Other Group / Sub Group Two`, which was invited to `Root Group`, then only `Other Group / Sub Group Two` is returned.
|
||||
|
||||
The response lists only indirect memberships. Direct memberships are not included.
|
||||
|
||||
This API endpoint works on top-level groups only. It does not work on subgroups.
|
||||
|
||||
This API endpoint requires permission to administer memberships for the group.
|
||||
|
||||
This API endpoint takes [pagination](rest/index.md#pagination) parameters `page` and `per_page` to restrict the list of memberships.
|
||||
|
||||
```plaintext
|
||||
GET /groups/:id/billable_members/:user_id/indirect
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
|
||||
| `user_id` | integer | yes | The user ID of the billable member |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/billable_members/:user_id/indirect"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 168,
|
||||
"source_id": 132,
|
||||
"source_full_name": "Invited Group / Sub Group One",
|
||||
"source_members_url": "https://gitlab.example.com/groups/invited-group/sub-group-one/-/group_members",
|
||||
"created_at": "2021-03-31T17:28:44.812Z",
|
||||
"expires_at": "2022-03-21",
|
||||
"access_level": {
|
||||
"string_value": "Developer",
|
||||
"integer_value": 30
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Remove a billable member from a group
|
||||
|
||||
Removes a billable member from a group and its subgroups and projects.
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ your application on different environments.
|
|||
These runners fully integrated with GitLab.com and are enabled by default for all projects, with no configuration required.
|
||||
Your jobs can run on:
|
||||
|
||||
- [Hosted runners on Linux](saas/linux_saas_runner.md)
|
||||
- [GPU-enabled hosted runners](saas/gpu_saas_runner.md)
|
||||
- [Hosted runners on Windows](saas/windows_saas_runner.md) ([Beta](../../policy/experiment-beta-support.md#beta))
|
||||
- [Hosted runners on macOS](saas/macos_saas_runner.md) ([Beta](../../policy/experiment-beta-support.md#beta))
|
||||
- [Hosted runners on Linux](hosted_runners/linux.md)
|
||||
- [GPU-enabled hosted runners](hosted_runners/gpu_enabled.md)
|
||||
- [Hosted runners on Windows](hosted_runners/windows.md) ([Beta](../../policy/experiment-beta-support.md#beta))
|
||||
- [Hosted runners on macOS](hosted_runners/macos.md) ([Beta](../../policy/experiment-beta-support.md#beta))
|
||||
|
||||
For more information about the cost factor applied to the machine type based on size, see [cost factor](../../ci/pipelines/cicd_minutes.md#gitlab-hosted-runner-costs).
|
||||
The number of minutes you can use on these runners depends on the [maximum number of units of compute](../pipelines/cicd_minutes.md)
|
||||
|
|
@ -37,7 +37,7 @@ The objective is to make 90% of CI/CD jobs start executing in 120 seconds or les
|
|||
These runners are created on-demand for GitLab Dedicated customers and are fully integrated with your GitLab Dedicated instance.
|
||||
Your jobs can run on:
|
||||
|
||||
- [Hosted runners on Linux](saas/linux_saas_runner.md) ([Beta](../../policy/experiment-beta-support.md#beta))
|
||||
- [Hosted runners on Linux](hosted_runners/linux.md) ([Beta](../../policy/experiment-beta-support.md#beta))
|
||||
|
||||
## How hosted runners for GitLab.com work
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ When you use hosted runners:
|
|||
NOTE:
|
||||
Jobs handled by hosted runners on GitLab.com **time out after 3 hours**, regardless of the timeout configured in a project.
|
||||
|
||||
## Release cycle for SaaS runner
|
||||
## Release cycle for GitLab-hosted runners
|
||||
|
||||
We aim to update to the latest version of [GitLab Runner](https://docs.gitlab.com/runner/#gitlab-runner-versions) within a week of its release.
|
||||
|
||||
|
|
@ -65,13 +65,13 @@ The [Google Infrastructure Security Design Overview whitepaper](https://cloud.go
|
|||
provides an overview of how Google designs security into its technical infrastructure.
|
||||
The GitLab [Trust Center](https://about.gitlab.com/security/) and
|
||||
[GitLab Security Compliance Controls](https://handbook.gitlab.com/handbook/security/security-assurance/security-compliance/sec-controls/)
|
||||
pages provide an overview of the security and compliance controls that govern the GitLab SaaS runners.
|
||||
pages provide an overview of the security and compliance controls that govern the GitLab-hosted runners.
|
||||
|
||||
The following section provides an overview of the additional built-in layers that harden the security of the GitLab Runner SaaS CI build environment.
|
||||
The following section provides an overview of the additional built-in layers that harden the security of the GitLab Runner build environment.
|
||||
|
||||
### Security of CI job execution
|
||||
|
||||
A dedicated temporary runner VM hosts and runs each CI job. On GitLab SaaS, two CI jobs never run on the same VM.
|
||||
A dedicated temporary runner VM hosts and runs each CI job. On hosted runners for GitLab.com, two CI jobs never run on the same VM.
|
||||
|
||||
In this example, there are three jobs in the project's pipeline. Therefore, there are three temporary VMs used to run that pipeline, or one VM per job.
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ takes over the task of securely deleting the virtual machine and associated data
|
|||
|
||||
## Supported image lifecycle
|
||||
|
||||
SaaS runners on macOS and Windows can only run jobs on supported images. You cannot bring your own image. Supported images have the following lifecycle:
|
||||
Hosted runners on macOS and Windows can only run jobs on supported images. You cannot bring your own image. Supported images have the following lifecycle:
|
||||
|
||||
- Beta
|
||||
- Generally Available
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ If you want to upgrade multiple releases or do not meet these requirements [upgr
|
|||
|
||||
We recommend a "back to front" approach for the order of what components to upgrade with Zero Downtime.
|
||||
Generally this would be stateful backends first, their dependents next and then the frontends accordingly.
|
||||
While the order of deployment can be changed, it is best to deploy the components running GitLab application code (Rails, Sidekiq) together. If possible, upgrade the supporting infrastructure (PostgreSQL, PgBouncer, Consul, Gitaly, Praefect, Redis) separately since these components do not have dependencies on changes made in version updates within a major release.
|
||||
As such, we generally recommend the following order:
|
||||
|
||||
1. Consul
|
||||
|
|
@ -74,10 +75,6 @@ As such, we generally recommend the following order:
|
|||
1. Rails
|
||||
1. Sidekiq
|
||||
|
||||
NOTE:
|
||||
While this order can be changed if desired, a hard requirement is that the Rails nodes are done after PostgreSQL
|
||||
as they drive the upgrades of data on those stateful backends via migrations.
|
||||
|
||||
## Multi-node / HA deployment
|
||||
|
||||
In this section we'll go through the core process of upgrading a multi-node GitLab environment by
|
||||
|
|
|
|||
|
|
@ -365,26 +365,26 @@ are also informational headers with this response detailed in
|
|||
|
||||
The following table describes the rate limits for GitLab.com:
|
||||
|
||||
| Rate limit | Setting |
|
||||
|:---------------------------------------------------------------------------|:-------------------------------------|
|
||||
| **Protected paths** (for a given **IP address**) | **10** requests per minute |
|
||||
| **Raw endpoint** traffic (for a given **project, commit, and file path**) | **300** requests per minute |
|
||||
| **Unauthenticated** traffic (from a given **IP address**) | **500** requests per minute |
|
||||
| **Authenticated** API traffic (for a given **user**) | **2,000** requests per minute |
|
||||
| **Authenticated** non-API HTTP traffic (for a given **user**) | **1,000** requests per minute |
|
||||
| **All** traffic (from a given **IP address**) | **2,000** requests per minute |
|
||||
| **Issue creation** | **200** requests per minute |
|
||||
| **Note creation** (on issues and merge requests) | **60** requests per minute |
|
||||
| **Advanced, project, and group search** API (for a given **IP address**) | **10** requests per minute |
|
||||
| **GitLab Pages** requests (for a given **IP address**) | **1000** requests per **50 seconds** |
|
||||
| **GitLab Pages** requests (for a given **GitLab Pages domain**) | **5000** requests per **10 seconds** |
|
||||
| **GitLab Pages** TLS connections (for a given **IP address**) | **1000** requests per **50 seconds** |
|
||||
| **GitLab Pages** TLS connections (for a given **GitLab Pages domain**) | **400** requests per **10 seconds** |
|
||||
| **Pipeline creation** requests (for a given **project, user, and commit**) | **25** requests per minute |
|
||||
| **Alert integration endpoint** requests (for a given **project**) | **3600** requests per hour |
|
||||
| **[Pull mirroring](../project/repository/mirror/pull.md)** intervals | **5** minutes |
|
||||
| **API Requests** (from a given **user**) to `/api/v4/users/:id` | **300** requests per **10 minutes** |
|
||||
| GitLab package cloud requests for a given IP address ([introduced](https://gitlab.com/gitlab-com/gl-infra/production-engineering/-/issues/24083) in GitLab 16.11) | 3,000 requests per minute |
|
||||
| Rate limit | Setting |
|
||||
|:-----------------------------------------------------------------|:------------------------------|
|
||||
| Protected paths for an IP address | 10 requests per minute |
|
||||
| Raw endpoint traffic for a project, commit, or file path | 300 requests per minute |
|
||||
| Unauthenticated traffic from an IP address | 500 requests per minute |
|
||||
| Authenticated API traffic for a user | 2,000 requests per minute |
|
||||
| Authenticated non-API HTTP traffic for a user | 1,000 requests per minute |
|
||||
| All traffic from an IP address | 2,000 requests per minute |
|
||||
| Issue creation | 200 requests per minute |
|
||||
| Note creation on issues and merge requests | 60 requests per minute |
|
||||
| Advanced, project, or group search API for an IP address | 10 requests per minute |
|
||||
| GitLab Pages requests for an IP address | 1,000 requests per 50 seconds |
|
||||
| GitLab Pages requests for a GitLab Pages domain | 5,000 requests per 10 seconds |
|
||||
| GitLab Pages TLS connections for an IP address | 1,000 requests per 50 seconds |
|
||||
| GitLab Pages TLS connections for a GitLab Pages domain | 400 requests per 10 seconds |
|
||||
| Pipeline creation requests for a project, user, or commit | 25 requests per minute |
|
||||
| Alert integration endpoint requests for a project | 3,600 requests per hour |
|
||||
| [Pull mirroring](../project/repository/mirror/pull.md) intervals | 5 minutes |
|
||||
| API requests from a user to `/api/v4/users/:id` | 300 requests per 10 minutes |
|
||||
| GitLab package cloud requests for an IP address ([introduced](https://gitlab.com/gitlab-com/gl-infra/production-engineering/-/issues/24083) in GitLab 16.11) | 3,000 requests per minute |
|
||||
|
||||
More details are available on the rate limits for
|
||||
[protected paths](#protected-paths-throttle) and
|
||||
|
|
|
|||
|
|
@ -163,6 +163,11 @@ If a user is:
|
|||
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11 from a form to a modal window [with a flag](../../feature_flags.md). Disabled by default.
|
||||
> - Modal window [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 14.8.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) in GitLab 14.9. [Feature flag `invite_members_group_modal`](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) removed.
|
||||
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/219230) to display invited group members on the Members tab of the Members page in GitLab 16.10 [with a flag](../../../administration/feature_flags.md) named `webui_members_inherited_users`. Disabled by default.
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available per user, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `webui_members_inherited_users`.
|
||||
On GitLab.com and GitLab Dedicated, this feature is not available.
|
||||
|
||||
When you add a group to a project, every group member (direct or inherited) gets access to the project.
|
||||
Each member's access is based on the:
|
||||
|
|
@ -192,7 +197,7 @@ To add a group to a project:
|
|||
The invited group is displayed on the **Groups** tab.
|
||||
Private groups are masked from unauthorized users.
|
||||
Private groups are displayed in project settings for protected branches, protected tags, and protected environments.
|
||||
The members of the invited group are not displayed on the **Members** tab.
|
||||
The members of the invited group are not displayed on the **Members** tab, but are displayed if the `webui_members_inherited_users` feature flag is enabled.
|
||||
The **Members** tab shows:
|
||||
|
||||
- Members who were directly added to the project.
|
||||
|
|
|
|||
|
|
@ -17,8 +17,12 @@ You can share by invitation:
|
|||
|
||||
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/219230) to display invited group members on the Members tab of the Members page in GitLab 16.10 behind `webui_members_inherited_users` feature flag. Disabled by default.
|
||||
|
||||
[In GitLab 16.6 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134623),
|
||||
the invited group's name and membership source are masked unless one of the following applies:
|
||||
FLAG:
|
||||
On self-managed GitLab, by default this feature is not available. To make it available per user, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `webui_members_inherited_users`.
|
||||
On GitLab.com and GitLab Dedicated, this feature is not available.
|
||||
|
||||
[In GitLab 16.11 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144638),
|
||||
the invited group's name and membership source are masked on the **Members** and the **Groups** tabs, unless one of the following applies:
|
||||
|
||||
- The invited group is public.
|
||||
- The current user is a member of the invited group.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ module API
|
|||
expose :lfs_enabled?, as: :lfs_enabled
|
||||
expose :math_rendering_limits_enabled, documentation: { type: 'boolean' }
|
||||
expose :lock_math_rendering_limits_enabled, documentation: { type: 'boolean' }
|
||||
expose :default_branch_name, as: :default_branch
|
||||
expose :default_branch_protection
|
||||
expose :default_branch_protection_defaults
|
||||
expose :avatar_url do |group, options|
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ module API
|
|||
optional :mentions_disabled, type: Boolean, desc: 'Disable a group from getting mentioned'
|
||||
optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group'
|
||||
optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
|
||||
optional :default_branch, type: String, desc: "The default branch of group's projects", documentation: { example: 'main' }, as: :default_branch_name
|
||||
optional :default_branch_protection, type: Integer, values: ::Gitlab::Access.protection_values, desc: 'Determine if developers can push to default branch'
|
||||
optional :default_branch_protection_defaults, type: Hash, desc: 'Determine if developers can push to default branch' do
|
||||
optional :allowed_to_push, type: Array, desc: 'An array of access levels allowed to push' do
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ module Banzai
|
|||
modified_footnotes = {}
|
||||
|
||||
doc.xpath(XPATH_FOOTNOTE).each do |link_node|
|
||||
next unless link_node[:id]
|
||||
|
||||
ref_num = link_node[:id].delete_prefix(FOOTNOTE_LINK_ID_PREFIX)
|
||||
ref_num.gsub!(/[[:punct:]]/, '\\\\\&')
|
||||
|
||||
|
|
|
|||
|
|
@ -57,8 +57,6 @@ module ClickHouse
|
|||
workers_active = true
|
||||
|
||||
loop do
|
||||
return if Feature.disabled?(:wait_for_clickhouse_workers_during_migration)
|
||||
|
||||
workers_active = active_sidekiq_workers?
|
||||
break unless workers_active
|
||||
break if Time.current >= worker_wait_ttl
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.87.0'
|
||||
DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.88.0'
|
||||
|
||||
.dast-auto-deploy:
|
||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.87.0'
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.88.0'
|
||||
|
||||
.auto-deploy:
|
||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.87.0'
|
||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.88.0'
|
||||
|
||||
.auto-deploy:
|
||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ module Gitlab
|
|||
class ClickHouseMigration < Base
|
||||
override :should_pause?
|
||||
def should_pause?
|
||||
return false unless Feature.enabled?(:pause_clickhouse_workers_during_migration)
|
||||
|
||||
::ClickHouse::MigrationSupport::ExclusiveLock.pause_workers?
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@
|
|||
"swagger:validate": "swagger-cli validate",
|
||||
"webpack": "NODE_OPTIONS=\"${NODE_OPTIONS:=--max-old-space-size=5120}\" webpack --config config/webpack.config.js",
|
||||
"webpack-vendor": "NODE_OPTIONS=\"${NODE_OPTIONS:=--max-old-space-size=5120}\" webpack --config config/webpack.vendor.config.js",
|
||||
"webpack-prod": "NODE_OPTIONS=\"${NODE_OPTIONS:=--max-old-space-size=5120}\" NODE_ENV=production webpack --config config/webpack.config.js"
|
||||
"webpack-prod": "NODE_OPTIONS=\"${NODE_OPTIONS:=--max-old-space-size=5120}\" NODE_ENV=production webpack --config config/webpack.config.js",
|
||||
"vite-prod": "NODE_OPTIONS=\"${NODE_OPTIONS:=--max-old-space-size=8000}\" NODE_ENV=production vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.10",
|
||||
|
|
|
|||
|
|
@ -109,8 +109,8 @@ RSpec.describe 'Projects (JavaScript fixtures)', type: :controller, feature_cate
|
|||
)
|
||||
end
|
||||
|
||||
base_input_path = 'usage_quotas/storage/queries/'
|
||||
base_output_path = 'graphql/usage_quotas/storage/'
|
||||
base_input_path = 'usage_quotas/storage/project/queries/'
|
||||
base_output_path = 'graphql/usage_quotas/storage/project/'
|
||||
query_name = 'project_storage.query.graphql'
|
||||
|
||||
it "#{base_output_path}#{query_name}.json" do
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import mockGetProjectStorageStatisticsGraphQLResponse from 'test_fixtures/graphql/usage_quotas/storage/project_storage.query.graphql.json';
|
||||
import mockGetProjectStorageStatisticsGraphQLResponse from 'test_fixtures/graphql/usage_quotas/storage/project/project_storage.query.graphql.json';
|
||||
import mockGetNamespaceStorageGraphQLResponse from 'test_fixtures/graphql/usage_quotas/storage/namespace_storage.query.graphql.json';
|
||||
import mockGetProjectListStorageGraphQLResponse from 'test_fixtures/graphql/usage_quotas/storage/project_list_storage.query.graphql.json';
|
||||
import { storageTypeHelpPaths } from '~/usage_quotas/storage/constants';
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ import {
|
|||
NAMESPACE_STORAGE_TYPES,
|
||||
TOTAL_USAGE_DEFAULT_TEXT,
|
||||
} from '~/usage_quotas/storage/constants';
|
||||
import getCostFactoredProjectStorageStatistics from 'ee_else_ce/usage_quotas/storage/queries/cost_factored_project_storage.query.graphql';
|
||||
import getProjectStorageStatistics from 'ee_else_ce/usage_quotas/storage/queries/project_storage.query.graphql';
|
||||
import getCostFactoredProjectStorageStatistics from 'ee_else_ce/usage_quotas/storage/project/queries/cost_factored_project_storage.query.graphql';
|
||||
import getProjectStorageStatistics from 'ee_else_ce/usage_quotas/storage/project/queries/project_storage.query.graphql';
|
||||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
import {
|
||||
mockGetProjectStorageStatisticsGraphQLResponse,
|
||||
|
|
|
|||
|
|
@ -979,38 +979,4 @@ RSpec.describe ApplicationHelper do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#controller_full_path' do
|
||||
let(:path) { 'some_path' }
|
||||
let(:action) { 'show' }
|
||||
|
||||
before do
|
||||
allow(helper.controller).to receive(:controller_path).and_return(path)
|
||||
allow(helper.controller).to receive(:action_name).and_return(action)
|
||||
end
|
||||
|
||||
context 'when is create action' do
|
||||
let(:action) { 'create' }
|
||||
|
||||
it 'transforms to "new" path' do
|
||||
expect(helper.controller_full_path).to eq("#{path}/new")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when is update action' do
|
||||
let(:action) { 'update' }
|
||||
|
||||
it 'transforms to "edit" path' do
|
||||
expect(helper.controller_full_path).to eq("#{path}/edit")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when is show action' do
|
||||
let(:action) { 'show' }
|
||||
|
||||
it 'passes through' do
|
||||
expect(helper.controller_full_path).to eq("#{path}/#{action}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ViteHelper, feature_category: :tooling do
|
||||
describe '#vite_page_entrypoint_path' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:path, :action, :result) do
|
||||
'some_path' | 'create' | %w[pages.some_path.js pages.some_path.new.js]
|
||||
'some_path' | 'new' | %w[pages.some_path.js pages.some_path.new.js]
|
||||
'some_path' | 'update' | %w[pages.some_path.js pages.some_path.edit.js]
|
||||
'some_path' | 'show' | %w[pages.some_path.js pages.some_path.show.js]
|
||||
'some/long' | 'path' | %w[pages.some.js pages.some.long.js pages.some.long.path.js]
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
allow(helper.controller).to receive(:controller_path).and_return(path)
|
||||
allow(helper.controller).to receive(:action_name).and_return(action)
|
||||
end
|
||||
|
||||
it { expect(helper.vite_page_entrypoint_paths).to eq(result) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -17,7 +17,7 @@ RSpec.describe API::Entities::Group, feature_category: :groups_and_projects do
|
|||
:two_factor_grace_period, :project_creation_level, :auto_devops_enabled,
|
||||
:subgroup_creation_level, :emails_disabled, :emails_enabled, :lfs_enabled, :default_branch_protection,
|
||||
:default_branch_protection_defaults, :avatar_url, :request_access_enabled, :full_name, :full_path, :created_at,
|
||||
:parent_id, :organization_id, :shared_runners_setting, :custom_attributes, :statistics
|
||||
:parent_id, :organization_id, :shared_runners_setting, :custom_attributes, :statistics, :default_branch
|
||||
)
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ RSpec.describe Banzai::Filter::FootnoteFilter, feature_category: :team_planning
|
|||
let(:footnote) do
|
||||
<<~EOF.strip_heredoc
|
||||
<p>first<sup><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup> and second<sup><a href="#fn-second" id="fnref-second" data-footnote-ref>2</a></sup> and third<sup><a href="#fn-_%F0%9F%98%84_" id="fnref-_%F0%9F%98%84_" data-footnote-ref>3</a></sup></p>
|
||||
<p>missing id<sup><a href="#fn-10" data-footnote-ref>1</a></sup></p>
|
||||
<section data-footnotes>
|
||||
<ol>
|
||||
<li id="fn-1">
|
||||
|
|
@ -32,6 +33,7 @@ RSpec.describe Banzai::Filter::FootnoteFilter, feature_category: :team_planning
|
|||
let(:filtered_footnote) do
|
||||
<<~EOF.strip_heredoc
|
||||
<p>first<sup class="footnote-ref"><a href="#fn-1-#{identifier}" id="fnref-1-#{identifier}" data-footnote-ref>1</a></sup> and second<sup class="footnote-ref"><a href="#fn-second-#{identifier}" id="fnref-second-#{identifier}" data-footnote-ref>2</a></sup> and third<sup class="footnote-ref"><a href="#fn-_%F0%9F%98%84_-#{identifier}" id="fnref-_%F0%9F%98%84_-#{identifier}" data-footnote-ref>3</a></sup></p>
|
||||
<p>missing id<sup><a href="#fn-10" data-footnote-ref>1</a></sup></p>
|
||||
<section data-footnotes class=\"footnotes\">
|
||||
<ol>
|
||||
<li id="fn-1-#{identifier}">
|
||||
|
|
|
|||
|
|
@ -96,17 +96,6 @@ RSpec.describe ClickHouse::MigrationSupport::ExclusiveLock, feature_category: :d
|
|||
expect(Time.current - started_at).to eq(described_class::DEFAULT_CLICKHOUSE_WORKER_TTL)
|
||||
end
|
||||
|
||||
context 'when wait_for_clickhouse_workers_during_migration FF is disabled' do
|
||||
before do
|
||||
stub_feature_flags(wait_for_clickhouse_workers_during_migration: false)
|
||||
end
|
||||
|
||||
it 'runs migration without waiting for workers' do
|
||||
expect { migration }.not_to raise_error
|
||||
expect(Time.current - started_at).to eq(0.0)
|
||||
end
|
||||
end
|
||||
|
||||
it 'ignores expired workers' do
|
||||
travel(described_class::DEFAULT_CLICKHOUSE_WORKER_TTL + 1.second)
|
||||
|
||||
|
|
|
|||
|
|
@ -55,14 +55,6 @@ RSpec.describe Gitlab::SidekiqMiddleware::PauseControl::Strategies::ClickHouseMi
|
|||
|
||||
expect(worker_class.jobs.count).to eq(0)
|
||||
end
|
||||
|
||||
context 'when pause_clickhouse_workers_during_migration FF is disabled' do
|
||||
before do
|
||||
stub_feature_flags(pause_clickhouse_workers_during_migration: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'a worker being executed'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1041,6 +1041,36 @@ RSpec.describe API::Groups, feature_category: :groups_and_projects do
|
|||
expect(json_response['message']['visibility_level']).to include('internal has been restricted by your GitLab administrator')
|
||||
end
|
||||
|
||||
context 'updating the `default_branch` attribute' do
|
||||
subject do
|
||||
put api("/groups/#{group1.id}", user1), params: { default_branch: default_branch }
|
||||
end
|
||||
|
||||
let(:default_branch) { 'new' }
|
||||
|
||||
it 'updates the attribute', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['default_branch']).to eq(default_branch)
|
||||
end
|
||||
|
||||
context 'when "default_branch" attribute is removed' do
|
||||
before do
|
||||
group1.namespace_settings.update!(default_branch_name: 'new')
|
||||
end
|
||||
|
||||
let(:default_branch) { '' }
|
||||
|
||||
it 'removes the attribute', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['default_branch']).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'updating the `default_branch_protection` attribute' do
|
||||
subject do
|
||||
put api("/groups/#{group1.id}", user1), params: { default_branch_protection: ::Gitlab::Access::PROTECTION_NONE }
|
||||
|
|
@ -2230,6 +2260,19 @@ RSpec.describe API::Groups, feature_category: :groups_and_projects do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when creating a group with "default_branch" attribute' do
|
||||
let(:params) { attributes_for_group_api default_branch: 'main' }
|
||||
|
||||
subject { post api("/groups", user3), params: params }
|
||||
|
||||
it 'creates group with the specified default branch', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
expect(json_response['default_branch']).to eq('main')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when creating a group with `enabled_git_access_protocol' do
|
||||
let(:params) { attributes_for_group_api enabled_git_access_protocol: 'all' }
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import chokidar from 'chokidar';
|
|||
import globby from 'globby';
|
||||
import { viteCommonjs } from '@originjs/vite-plugin-commonjs';
|
||||
import webpackConfig from './config/webpack.config';
|
||||
import { generateEntries } from './config/webpack.helpers';
|
||||
import {
|
||||
IS_EE,
|
||||
IS_JH,
|
||||
|
|
@ -43,6 +44,15 @@ const emptyComponent = path.resolve(javascriptsPath, 'vue_shared/components/empt
|
|||
|
||||
const [rubyPlugin, ...rest] = RubyPlugin();
|
||||
|
||||
const comment = '/* this is a virtual module used by Vite, it exists only in dev mode */\n';
|
||||
|
||||
const virtualEntrypoints = Object.entries(generateEntries()).reduce((acc, [entryName, imports]) => {
|
||||
const modulePath = imports[imports.length - 1];
|
||||
const importPath = modulePath.startsWith('./') ? `~/${modulePath.substring(2)}` : modulePath;
|
||||
acc[`${entryName}.js`] = `${comment}/* ${modulePath} */ import '${importPath}';\n`;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
// We can't use regular 'resolve' which points to sourceCodeDir in vite.json
|
||||
// Because we need for '~' alias to resolve to app/assets/javascripts
|
||||
// We can't use javascripts folder in sourceCodeDir because we also need to resolve other assets
|
||||
|
|
@ -163,6 +173,22 @@ function viteCopyPlugin({ patterns }) {
|
|||
};
|
||||
}
|
||||
|
||||
const entrypointsDir = '/javascripts/entrypoints/';
|
||||
const pageEntrypointsPlugin = {
|
||||
name: 'page-entrypoints',
|
||||
load(id) {
|
||||
if (!id.startsWith('pages.')) {
|
||||
return undefined;
|
||||
}
|
||||
return virtualEntrypoints[id] ?? `/* doesn't exist */`;
|
||||
},
|
||||
resolveId(source) {
|
||||
const fixedSource = source.replace(entrypointsDir, '');
|
||||
if (fixedSource.startsWith('pages.')) return { id: fixedSource };
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: path.resolve(__dirname, 'tmp/cache/vite'),
|
||||
resolve: {
|
||||
|
|
@ -181,6 +207,7 @@ export default defineConfig({
|
|||
],
|
||||
},
|
||||
plugins: [
|
||||
pageEntrypointsPlugin,
|
||||
viteCSSCompilerPlugin({ shouldWatch: viteGDKConfig.hmr !== null }),
|
||||
viteTailwindCompilerPlugin({ shouldWatch: viteGDKConfig.hmr !== null }),
|
||||
viteCopyPlugin({
|
||||
|
|
@ -238,4 +265,12 @@ export default defineConfig({
|
|||
worker: {
|
||||
format: 'es',
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: Object.keys(virtualEntrypoints).reduce((acc, value) => {
|
||||
acc[value] = value;
|
||||
return acc;
|
||||
}, {}),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ require (
|
|||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/smartystreets/goconvey v1.8.1
|
||||
github.com/stretchr/testify v1.9.0
|
||||
gitlab.com/gitlab-org/gitaly/v16 v16.9.1
|
||||
gitlab.com/gitlab-org/gitaly/v16 v16.9.2
|
||||
gitlab.com/gitlab-org/labkit v1.21.0
|
||||
gocloud.dev v0.37.0
|
||||
golang.org/x/image v0.15.0
|
||||
|
|
|
|||
|
|
@ -448,8 +448,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
|||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
gitlab.com/gitlab-org/gitaly/v16 v16.9.1 h1:XFoZyeV3HCGIB6pnQj6r5ZYsUYa34HoVOyod7XegIdI=
|
||||
gitlab.com/gitlab-org/gitaly/v16 v16.9.1/go.mod h1:K2zAXwDEEwnm9NLxboCllREyS4Rx1yRBRxLBC0EcakA=
|
||||
gitlab.com/gitlab-org/gitaly/v16 v16.9.2 h1:FkNYzuezmL9K+3ZzU26BL1m3/0VoWi7Mq0ahuWovTfs=
|
||||
gitlab.com/gitlab-org/gitaly/v16 v16.9.2/go.mod h1:K2zAXwDEEwnm9NLxboCllREyS4Rx1yRBRxLBC0EcakA=
|
||||
gitlab.com/gitlab-org/labkit v1.21.0 h1:hLmdBDtXjD1yOmZ+uJOac3a5Tlo83QaezwhES4IYik4=
|
||||
gitlab.com/gitlab-org/labkit v1.21.0/go.mod h1:zeATDAaSBelPcPLbTTq8J3ZJEHyPTLVBM1q3nva+/W4=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
|
|
|
|||
Loading…
Reference in New Issue