Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 19:05:49 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 19:05:49 +0300
commit43a25d93ebdabea52f99b05e15b06250cd8f07d7 (patch)
treedceebdc68925362117480a5d672bcff122fb625b /scripts/frontend
parent20c84b99005abd1c82101dfeff264ac50d2df211 (diff)
Add latest changes from gitlab-org/gitlab@16-0-stable-eev16.0.0-rc42
Diffstat (limited to 'scripts/frontend')
-rwxr-xr-xscripts/frontend/download_fixtures.sh56
-rw-r--r--scripts/frontend/extract_gettext_all.js10
-rwxr-xr-xscripts/frontend/po_to_json.js208
-rw-r--r--scripts/frontend/startup_css/constants.js4
4 files changed, 271 insertions, 7 deletions
diff --git a/scripts/frontend/download_fixtures.sh b/scripts/frontend/download_fixtures.sh
new file mode 100755
index 00000000000..47a57401bb9
--- /dev/null
+++ b/scripts/frontend/download_fixtures.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+
+#
+# Downloads the most recent frontend fixtures for the current commit, going up the commit parent
+# chain up to max-commits commits (defaults to 50 commits).
+#
+
+source scripts/packages/helpers.sh
+
+print_help() {
+ echo "Usage: scripts/frontend/download_fixtures.sh [--branch <branch-name>] [--max-commits <number>]"
+ echo
+ echo "Looks for a frontend fixture package in the package registry for commits on a local branch."
+ echo
+ echo "If --branch isn't specified, the script will use the current branch as a commit reference."
+ echo "If --max-commits isn't specified, the default is 50 commits."
+
+ return
+}
+
+branch="HEAD"
+max_commits_count=50
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --branch)
+ shift
+ branch="$1"
+ ;;
+ --max-commits)
+ shift
+ max_commits_count="$1"
+ ;;
+ *)
+ print_help
+ exit
+ ;;
+ esac
+ shift
+done
+
+for commit_sha in $(git rev-list ${branch} --max-count="${max_commits_count}"); do
+ API_PACKAGES_BASE_URL=https://gitlab.com/api/v4/projects/278964/packages/generic
+ FIXTURES_PACKAGE="fixtures-${commit_sha}.tar.gz"
+ FIXTURES_PACKAGE_URL="${API_PACKAGES_BASE_URL}/fixtures/${commit_sha}/${FIXTURES_PACKAGE}"
+
+ echo "Looking for frontend fixtures for commit ${commit_sha}..."
+
+ if ! archive_doesnt_exist "${FIXTURES_PACKAGE_URL}" > /dev/null 2>&1; then
+ echo "We have found frontend fixtures at ${FIXTURES_PACKAGE_URL}!"
+
+ read_curl_package "${FIXTURES_PACKAGE_URL}" | extract_package
+
+ break
+ fi
+done
diff --git a/scripts/frontend/extract_gettext_all.js b/scripts/frontend/extract_gettext_all.js
index 922aa85241f..0cd6ab99a3a 100644
--- a/scripts/frontend/extract_gettext_all.js
+++ b/scripts/frontend/extract_gettext_all.js
@@ -19,7 +19,7 @@ extractor.addMessageTransformFunction(ensureSingleLine);
const jsParser = extractor.createJsParser([
// Place all the possible expressions to extract here:
- JsExtractors.callExpression('__', {
+ JsExtractors.callExpression(['__', 's__'], {
arguments: {
text: 0,
},
@@ -30,15 +30,13 @@ const jsParser = extractor.createJsParser([
textPlural: 1,
},
}),
- JsExtractors.callExpression('s__', {
- arguments: {
- text: 0,
- },
- }),
]);
const vueParser = decorateJSParserWithVueSupport(jsParser, {
vue2TemplateCompiler,
+ // All of our expressions contain `__`.
+ // So we can safely ignore parsing files _not_ containing it.
+ guard: '__',
});
function printJson() {
diff --git a/scripts/frontend/po_to_json.js b/scripts/frontend/po_to_json.js
new file mode 100755
index 00000000000..fba68a61814
--- /dev/null
+++ b/scripts/frontend/po_to_json.js
@@ -0,0 +1,208 @@
+#!/usr/bin/env node
+
+const fs = require('fs/promises');
+const path = require('path');
+
+async function isDir(dirPath) {
+ if (!dirPath) {
+ return false;
+ }
+ try {
+ const stat = await fs.stat(dirPath);
+ return stat.isDirectory();
+ } catch (e) {
+ return false;
+ }
+}
+
+/**
+ * This is the main function which starts multiple workers
+ * in order to speed up the po file => app.js
+ * locale conversions
+ */
+async function main({ localeRoot, outputDir } = {}) {
+ if (!(await isDir(localeRoot))) {
+ throw new Error(`Provided localeRoot: '${localeRoot}' doesn't seem to be a folder`);
+ }
+
+ if (!(await isDir(outputDir))) {
+ throw new Error(`Provided outputDir '${outputDir}' doesn't seem to be a folder`);
+ }
+
+ // eslint-disable-next-line global-require
+ const glob = require('glob');
+ // eslint-disable-next-line global-require
+ const { Worker } = require('jest-worker');
+
+ const locales = glob.sync('*/*.po', { cwd: localeRoot });
+
+ const worker = new Worker(__filename, {
+ exposedMethods: ['convertPoFileForLocale'],
+ silent: false,
+ enableWorkerThreads: true,
+ });
+ worker.getStdout().pipe(process.stdout);
+ worker.getStderr().pipe(process.stderr);
+
+ await Promise.all(
+ locales.map((localeFile) => {
+ const locale = path.dirname(localeFile);
+ return worker.convertPoFileForLocale({
+ locale,
+ localeFile: path.join(localeRoot, localeFile),
+ resultDir: path.join(outputDir, locale),
+ });
+ }),
+ );
+
+ await worker.end();
+
+ console.log('Done converting all the po files');
+}
+
+/**
+ * This is the conversion logic for: po => JS object for jed
+ */
+function convertPoToJed(data, locale) {
+ // eslint-disable-next-line global-require
+ const { parse } = require('gettext-parser/lib/poparser');
+ const DEFAULT_CONTEXT = '';
+
+ /**
+ * TODO: This replacer might be unnecessary _or_ even cause bugs.
+ * due to potential unnecessary double escaping.
+ * But for now it is here to ensure that the old and new output
+ * are equivalent.
+ * @param str
+ * @returns {string}
+ */
+ function escapeMsgid(str) {
+ return `${str}`.replace(/([\\"])/g, '\\$1');
+ }
+
+ /**
+ * TODO: This replacer might be unnecessary _or_ even cause bugs.
+ * due to potential unnecessary double escaping.
+ * But for now it is here to ensure that the old and new output
+ * are equivalent.
+ *
+ * NOTE: The replacements of `\n` and `\t` need to be iterated on,
+ * because: In the cases where we see those chars, they:
+ * - likely need or could be trimmed because they do nothing
+ * - they seem to escaped in a way that is broken anyhow
+ * @param str
+ * @returns {string}
+ */
+ function escapeMsgstr(str) {
+ return `${str}`.replace(/[\t\n"\\]/g, (match) => {
+ if (match === '\n') {
+ return '\\n';
+ }
+ if (match === '\t') {
+ return '\\t';
+ }
+ return `\\${match}`;
+ });
+ }
+
+ const { headers = {}, translations: parsed } = parse(data);
+
+ const translations = Object.values(parsed[DEFAULT_CONTEXT] ?? {}).reduce((acc, entry) => {
+ const { msgid, msgstr } = entry;
+
+ /* TODO: If a msgid has no translation, we can just drop the whole key,
+ as jed will just fallback to the keys
+ We are not doing that yet, because we do want to ensure that
+ the results of the new and old way of generating the files matches.
+ if (msgstr.every((x) => x === '')) {
+ return acc;
+ }
+ */
+
+ acc[escapeMsgid(msgid)] = msgstr.map(escapeMsgstr);
+
+ return acc;
+ }, {});
+
+ // Do not bother if the file has no actual translations
+ if (!Object.keys(translations).length) {
+ return { jed: null };
+ }
+
+ if (headers['Plural-Forms']) {
+ headers.plural_forms = headers['Plural-Forms'];
+ }
+
+ // Format required for jed: http://messageformat.github.io/Jed/
+ const jed = {
+ domain: 'app',
+ locale_data: {
+ app: {
+ ...translations,
+ // Ensure that the header data which is attached to a message with id ""
+ // is not accidentally overwritten by an empty externalized string
+ '': {
+ ...headers,
+ domain: 'app',
+ lang: locale,
+ },
+ },
+ },
+ };
+
+ return { jed };
+}
+
+/**
+ * This is the function which the workers actually execute
+ * 1. It reads the po
+ * 2. converts it with convertPoToJed
+ * 3. writes the file to
+ */
+async function convertPoFileForLocale({ locale, localeFile, resultDir }) {
+ const poContent = await fs.readFile(localeFile);
+
+ const { jed } = await convertPoToJed(poContent, locale);
+
+ if (jed === null) {
+ console.log(`${locale}: No translations. Skipping creation of app.js`);
+ return;
+ }
+
+ await fs.mkdir(resultDir, { recursive: true });
+
+ await fs.writeFile(
+ path.join(resultDir, 'app.js'),
+ `window.translations = ${JSON.stringify(jed)}`,
+ 'utf8',
+ );
+ console.log(`Created app.js in ${resultDir}`);
+}
+
+/*
+ Start the main thread only if we are not part of a worker
+ */
+if (!process.env.JEST_WORKER_ID) {
+ // eslint-disable-next-line global-require
+ const argumentsParser = require('commander');
+
+ const args = argumentsParser
+ .option('-l, --locale-root <locale_root>', 'Extract messages from subfolders in this directory')
+ .option('-o, --output-dir <output_dir>', 'Write app.js files into subfolders in this directory')
+ .parse(process.argv);
+
+ main(args).catch((e) => {
+ console.warn(`Something went wrong: ${e.message}`);
+ console.warn(args.printHelp());
+ process.exitCode = 1;
+ });
+}
+
+/*
+ Expose the function for workers
+ */
+module.exports = {
+ main,
+ convertPoToJed,
+ convertPoFileForLocale,
+};
diff --git a/scripts/frontend/startup_css/constants.js b/scripts/frontend/startup_css/constants.js
index 5143c04dc37..bf9774daea5 100644
--- a/scripts/frontend/startup_css/constants.js
+++ b/scripts/frontend/startup_css/constants.js
@@ -51,12 +51,14 @@ const createMainOutput = ({ outFile, cssKeys, type }) => ({
htmlPaths: [
path.join(FIXTURES_ROOT, `startup_css/project-${type}.html`),
path.join(FIXTURES_ROOT, `startup_css/project-${type}-signed-out.html`),
- path.join(FIXTURES_ROOT, `startup_css/project-${type}-search-ff-off.html`),
+ path.join(FIXTURES_ROOT, `startup_css/project-${type}-super-sidebar.html`),
],
cssKeys,
purgeOptions: {
safelist: {
standard: [
+ 'page-with-super-sidebar',
+ 'page-with-super-sidebar-collapsed',
'page-with-icon-sidebar',
'sidebar-collapsed-desktop',
// We want to include the root dropdown-menu style since it should be hidden by default