From 17c2f5e372f0707f381a8844ea221b16d65f625b Mon Sep 17 00:00:00 2001 From: YaST Bot Date: Sun, 5 Nov 2023 02:43:55 +0000 Subject: [PATCH 01/11] Update PO files Agama-weblate commit: 2d2785a9dd211101e2d3780ea30c9b5c7b418a00 --- web/po/cs.po | 34 +++++++++++++++++----------------- web/po/de.po | 34 +++++++++++++++++----------------- web/po/es.po | 38 +++++++++++++++++++++----------------- web/po/fr.po | 40 ++++++++++++++++++++++------------------ web/po/ja.po | 40 ++++++++++++++++++++++------------------ web/po/mk.po | 34 +++++++++++++++++----------------- web/po/nl.po | 38 +++++++++++++++++++++----------------- web/po/pt_BR.po | 34 +++++++++++++++++----------------- web/po/ru.po | 38 +++++++++++++++++++++----------------- web/po/sv.po | 38 +++++++++++++++++++++----------------- web/po/uk.po | 34 +++++++++++++++++----------------- web/src/manifest.json | 6 +++--- 12 files changed, 216 insertions(+), 192 deletions(-) diff --git a/web/po/cs.po b/web/po/cs.po index d4a7d6ac3d..18fa976e5f 100644 --- a/web/po/cs.po +++ b/web/po/cs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-29 02:08+0000\n" +"POT-Creation-Date: 2023-11-05 02:14+0000\n" "PO-Revision-Date: 2023-07-26 15:03+0000\n" "Last-Translator: Ladislav Slezák \n" "Language-Team: Czech \n" "Language-Team: Spanish \n" "Language-Team: French \n" @@ -72,20 +72,20 @@ msgid "Close" msgstr "Fermer" #. TRANSLATORS: button label -#: src/components/core/DBusError.jsx:40 +#: src/components/core/DBusError.jsx:41 msgid "Reload" msgstr "Recharger" #. TRANSLATORS: page title -#: src/components/core/DBusError.jsx:48 +#: src/components/core/DBusError.jsx:49 msgid "D-Bus Error" msgstr "Erreur D-Bus" -#: src/components/core/DBusError.jsx:54 +#: src/components/core/DBusError.jsx:55 msgid "Cannot connect to D-Bus" msgstr "Connexion au D-Bus impossible" -#: src/components/core/DBusError.jsx:59 +#: src/components/core/DBusError.jsx:60 msgid "" "Could not connect to the D-Bus service. Please, check whether it is running." msgstr "" @@ -340,8 +340,8 @@ msgstr "Popover basique" msgid "language" msgstr "langue" -#. TRANSLATORS: page section #. TRANSLATORS: page header +#. TRANSLATORS: page section #: src/components/l10n/L10nPage.jsx:84 #: src/components/overview/L10nSection.jsx:82 msgid "Localization" @@ -351,11 +351,6 @@ msgstr "Localisation" msgid "Display Language" msgstr "Langue d'affichage" -#: src/components/layout/Icon.jsx:157 -#, c-format -msgid "Icon %s not found!" -msgstr "Icône %s non trouvée!" - #: src/components/layout/Loading.jsx:30 msgid "Loading installation environment, please wait." msgstr "Chargement de l'environnement d'installation, veuillez patienter." @@ -396,8 +391,8 @@ msgstr "Adresses" msgid "Addresses data list" msgstr "Liste des données d'adresses" -#. TRANSLATORS: table header #. TRANSLATORS: input field for the iSCSI initiator name +#. TRANSLATORS: table header #: src/components/network/ConnectionsTable.jsx:57 #: src/components/network/ConnectionsTable.jsx:86 #: src/components/storage/ZFCPPage.jsx:362 @@ -531,8 +526,8 @@ msgstr "Aucune connexion WiFi trouvée" msgid "Connect to a Wi-Fi network" msgstr "Se connecter à un réseau Wi-Fi" -#. TRANSLATORS: page title #. TRANSLATORS: page section title +#. TRANSLATORS: page title #: src/components/network/NetworkPage.jsx:170 #: src/components/overview/NetworkSection.jsx:102 msgid "Network" @@ -614,8 +609,8 @@ msgstr "Connecté" msgid "Disconnecting" msgstr "Déconnexion" -#. TRANSLATORS: Wifi network status #. TRANSLATORS: iSCSI connection status +#. TRANSLATORS: Wifi network status #: src/components/network/WifiNetworkListItem.jsx:50 #: src/components/storage/iscsi/NodesPresenter.jsx:63 msgid "Disconnected" @@ -661,8 +656,8 @@ msgstr "Lecture des dépôts de logiciels" msgid "Refresh the repositories" msgstr "Rafraîchir les dépôts" -#. TRANSLATORS: page title #. TRANSLATORS: page section +#. TRANSLATORS: page title #: src/components/overview/SoftwareSection.jsx:145 #: src/components/software/SoftwarePage.jsx:81 msgid "Software" @@ -685,8 +680,8 @@ msgstr "" msgid "Probing storage devices" msgstr "Sonder les périphériques de stockage" -#. TRANSLATORS: page section title #. TRANSLATORS: page title +#. TRANSLATORS: page section title #: src/components/overview/StorageSection.jsx:182 #: src/components/storage/ProposalPage.jsx:218 msgid "Storage" @@ -772,8 +767,13 @@ msgstr "non sélectionné" msgid "%d errors" msgstr "%d erreurs" +#: src/components/software/PatternSelector.jsx:210 +msgid "Software summary and filter options" +msgstr "Synthèse logiciel et options de filtrage" + #. TRANSLATORS: search field placeholder text -#: src/components/software/PatternSelector.jsx:214 +#: src/components/software/PatternSelector.jsx:215 +#: src/components/software/PatternSelector.jsx:216 msgid "Search" msgstr "Rechercher" @@ -1765,3 +1765,7 @@ msgstr "Utilisateur" #: src/components/users/UsersPage.jsx:34 msgid "Root authentication" msgstr "Authentification root" + +#, c-format +#~ msgid "Icon %s not found!" +#~ msgstr "Icône %s non trouvée!" diff --git a/web/po/ja.po b/web/po/ja.po index e88948c8b7..26db6fb39b 100644 --- a/web/po/ja.po +++ b/web/po/ja.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-29 02:08+0000\n" -"PO-Revision-Date: 2023-10-23 01:15+0000\n" +"POT-Creation-Date: 2023-11-05 02:14+0000\n" +"PO-Revision-Date: 2023-11-01 05:15+0000\n" "Last-Translator: Yasuhiko Kamata \n" "Language-Team: Japanese \n" @@ -70,20 +70,20 @@ msgid "Close" msgstr "閉じる" #. TRANSLATORS: button label -#: src/components/core/DBusError.jsx:40 +#: src/components/core/DBusError.jsx:41 msgid "Reload" msgstr "再読み込み" #. TRANSLATORS: page title -#: src/components/core/DBusError.jsx:48 +#: src/components/core/DBusError.jsx:49 msgid "D-Bus Error" msgstr "D-Bus エラー" -#: src/components/core/DBusError.jsx:54 +#: src/components/core/DBusError.jsx:55 msgid "Cannot connect to D-Bus" msgstr "D-Bus に接続できません" -#: src/components/core/DBusError.jsx:59 +#: src/components/core/DBusError.jsx:60 msgid "" "Could not connect to the D-Bus service. Please, check whether it is running." msgstr "" @@ -335,8 +335,8 @@ msgstr "基本ポップオーバー" msgid "language" msgstr "言語" -#. TRANSLATORS: page section #. TRANSLATORS: page header +#. TRANSLATORS: page section #: src/components/l10n/L10nPage.jsx:84 #: src/components/overview/L10nSection.jsx:82 msgid "Localization" @@ -346,11 +346,6 @@ msgstr "ローカライゼーション" msgid "Display Language" msgstr "表示言語" -#: src/components/layout/Icon.jsx:157 -#, c-format -msgid "Icon %s not found!" -msgstr "アイコン %s が見つかりませんでした!" - #: src/components/layout/Loading.jsx:30 msgid "Loading installation environment, please wait." msgstr "インストール環境を読み込んでいます。しばらくお待ちください。" @@ -391,8 +386,8 @@ msgstr "アドレス" msgid "Addresses data list" msgstr "アドレスデータの一覧" -#. TRANSLATORS: table header #. TRANSLATORS: input field for the iSCSI initiator name +#. TRANSLATORS: table header #: src/components/network/ConnectionsTable.jsx:57 #: src/components/network/ConnectionsTable.jsx:86 #: src/components/storage/ZFCPPage.jsx:362 @@ -527,8 +522,8 @@ msgstr "WiFi 接続が見つかりませんでした" msgid "Connect to a Wi-Fi network" msgstr "Wi-Fi ネットワークへの接続" -#. TRANSLATORS: page title #. TRANSLATORS: page section title +#. TRANSLATORS: page title #: src/components/network/NetworkPage.jsx:170 #: src/components/overview/NetworkSection.jsx:102 msgid "Network" @@ -610,8 +605,8 @@ msgstr "接続済み" msgid "Disconnecting" msgstr "切断中" -#. TRANSLATORS: Wifi network status #. TRANSLATORS: iSCSI connection status +#. TRANSLATORS: Wifi network status #: src/components/network/WifiNetworkListItem.jsx:50 #: src/components/storage/iscsi/NodesPresenter.jsx:63 msgid "Disconnected" @@ -656,8 +651,8 @@ msgstr "ソフトウエアリポジトリを読み込んでいます" msgid "Refresh the repositories" msgstr "リポジトリの更新" -#. TRANSLATORS: page title #. TRANSLATORS: page section +#. TRANSLATORS: page title #: src/components/overview/SoftwareSection.jsx:145 #: src/components/software/SoftwarePage.jsx:81 msgid "Software" @@ -679,8 +674,8 @@ msgstr "デバイス %s の内容を全て削除してインストールしま msgid "Probing storage devices" msgstr "ストレージデバイスを検出しています" -#. TRANSLATORS: page section title #. TRANSLATORS: page title +#. TRANSLATORS: page section title #: src/components/overview/StorageSection.jsx:182 #: src/components/storage/ProposalPage.jsx:218 msgid "Storage" @@ -764,8 +759,13 @@ msgstr "未選択" msgid "%d errors" msgstr "%d 個のエラー" +#: src/components/software/PatternSelector.jsx:210 +msgid "Software summary and filter options" +msgstr "ソフトウエアの概要とフィルタのオプション" + #. TRANSLATORS: search field placeholder text -#: src/components/software/PatternSelector.jsx:214 +#: src/components/software/PatternSelector.jsx:215 +#: src/components/software/PatternSelector.jsx:216 msgid "Search" msgstr "検索" @@ -1750,6 +1750,10 @@ msgstr "ユーザ" msgid "Root authentication" msgstr "root の認証" +#, c-format +#~ msgid "Icon %s not found!" +#~ msgstr "アイコン %s が見つかりませんでした!" + #~ msgid "" #~ "Select the device for installing the system. All the file systems will be " #~ "created on the selected device." diff --git a/web/po/mk.po b/web/po/mk.po index 69891b3d01..80184f36df 100644 --- a/web/po/mk.po +++ b/web/po/mk.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-29 02:08+0000\n" +"POT-Creation-Date: 2023-11-05 02:14+0000\n" "PO-Revision-Date: 2023-10-21 23:15+0000\n" "Last-Translator: Kristijan Fremen Velkovski \n" "Language-Team: Macedonian \n" "Language-Team: Dutch \n" "Language-Team: Portuguese (Brazil) \n" "Language-Team: Russian \n" "Language-Team: Swedish \n" "Language-Team: Ukrainian Date: Mon, 6 Nov 2023 20:25:53 +0100 Subject: [PATCH 02/11] Generate and upload the product POT file --- .../workflows/product_translations/.gitignore | 1 + .../product_translations/package-lock.json | 218 ++++++++++++++++++ .../product_translations/package.json | 6 + .../product_translations/products_pot | 143 ++++++++++++ .../product_translations/template.json | 26 +++ .github/workflows/weblate-update-pot.yml | 56 ++++- 6 files changed, 443 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/product_translations/.gitignore create mode 100644 .github/workflows/product_translations/package-lock.json create mode 100644 .github/workflows/product_translations/package.json create mode 100755 .github/workflows/product_translations/products_pot create mode 100644 .github/workflows/product_translations/template.json diff --git a/.github/workflows/product_translations/.gitignore b/.github/workflows/product_translations/.gitignore new file mode 100644 index 0000000000..c2658d7d1b --- /dev/null +++ b/.github/workflows/product_translations/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/.github/workflows/product_translations/package-lock.json b/.github/workflows/product_translations/package-lock.json new file mode 100644 index 0000000000..c85e3946d9 --- /dev/null +++ b/.github/workflows/product_translations/package-lock.json @@ -0,0 +1,218 @@ +{ + "name": "product_translations", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "gettext-parser": "^7.0.1", + "yaml": "^2.3.4" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/gettext-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-7.0.1.tgz", + "integrity": "sha512-LU+ieGH3L9HmKEArTlX816/iiAlyA0fx/n/QSeQpkAaH/+jxMk/5UtDkAzcVvW+KlY25/U+IE6dnfkJ8ynt8pQ==", + "dev": true, + "dependencies": { + "content-type": "^1.0.5", + "encoding": "^0.1.13", + "readable-stream": "^4.3.0", + "safe-buffer": "^5.2.1" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/readable-stream": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.4.2.tgz", + "integrity": "sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + } + } +} diff --git a/.github/workflows/product_translations/package.json b/.github/workflows/product_translations/package.json new file mode 100644 index 0000000000..f542ad082f --- /dev/null +++ b/.github/workflows/product_translations/package.json @@ -0,0 +1,6 @@ +{ + "devDependencies": { + "gettext-parser": "^7.0.1", + "yaml": "^2.3.4" + } +} diff --git a/.github/workflows/product_translations/products_pot b/.github/workflows/product_translations/products_pot new file mode 100755 index 0000000000..08f143c655 --- /dev/null +++ b/.github/workflows/product_translations/products_pot @@ -0,0 +1,143 @@ +#! /usr/bin/node + +/* +This script generates the POT file with product translations from product +YAML files. + +Requirements: NodeJS, run "npm ci" to install the needed NPM packages + +Usage: + + products_pot *.yaml +*/ + +const fs = require("fs"); +const process = require("process"); + +const { Parser, LineCounter, parseDocument } = require("yaml"); +const gettextParser = require("gettext-parser"); + +/** + * Translatable text with source location + */ +class POEntry { + text; + file; + line; + product; + + /** + * Constructor + * @param {string} text - text of the description + * @param {string} file - file name + * @param {number} line - line location + * @param {string} product - name of the product + */ + constructor(text, file, line, product) { + this.text = text; + this.file = file; + this.line = line; + this.product = product; + } +} + +// collects translatable texts (POEntries) and generates the final POT file +class POFile { + entries = []; + + /** + * generate a time stamp string for the POT file header + * @returns {string} timestamp + */ + timestamp() { + const date = new Date(); + return date.getUTCFullYear() + "-" + date.getUTCMonth() + "-" + + date.getUTCDate() + " " + date.getUTCHours() + ":" + date.getUTCMinutes() + + "+0000"; + } + + /** + * generate the POT file content + * @returns {string} generated POT file or empty string if there are no entries + */ + dump() { + if (this.entries.length === 0) return ""; + + // template file with the default POT file header + const template = require("./template.json"); + template.headers["POT-Creation-Date"] = this.timestamp(); + + const translations = template.translations[""]; + + this.entries.forEach(e => { + translations[e.text] = { + msgid: e.text, + comments: { + translator: `TRANSLATORS: description of product "${e.product}"`, + reference: e.file + ":" + e.line + }, + msgstr: [""] + }; + }); + + // sort the output by the msgid to have consistent results + return String(gettextParser.po.compile(template, { sort: true })); + } +} + +/** + * Reads and parses the YAML product file + */ +class YamlReader { + file; + + /** + * Constructor + * @param {string} file - name of the YAML file to read + */ + constructor(file) { + this.file = file; + } + + /** + * Read and parse the YAML file + * @returns {undefined,POEntry} the found description entry or `undefined` if not found + */ + description() { + const data = fs.readFileSync(this.file, "utf-8"); + + // get the parsed text value + const parsed = parseDocument(data); + const description = parsed.get("description"); + if (!description) return; + + const product = parsed.get("name"); + + const lineCounter = new LineCounter(); + const tokens = new Parser(lineCounter.addNewLine).parse(data); + + for (const token of tokens) { + if (token.type === "document") { + // get the line position of the value + const description_token = token.value.items.find(i => i.key.source === "description"); + const line = lineCounter.linePos(description_token.value.offset).line; + return new POEntry(description, this.file, line, product); + } + } + } +} + +const output = new POFile(); +// script arguments (the first arg is executor path ("/usr/bin/node"), +// the second is name of this script) +const [,, ...params] = process.argv; + +params.forEach(f => { + const reader = new YamlReader(f); + const descriptionEntry = reader.description(); + if (descriptionEntry) { + output.entries.push(descriptionEntry); + } +}); + +console.log(output.dump()); diff --git a/.github/workflows/product_translations/template.json b/.github/workflows/product_translations/template.json new file mode 100644 index 0000000000..a2f3a02074 --- /dev/null +++ b/.github/workflows/product_translations/template.json @@ -0,0 +1,26 @@ +{ + "charset": "utf-8", + "headers": { + "Project-Id-Version": "PACKAGE VERSION", + "Report-Msgid-Bugs-To": "", + "PO-Revision-Date": "YEAR-MO-DA HO:MI+ZONE", + "Last-Translator": "FULL NAME ", + "Language-Team": "LANGUAGE ", + "Language": "", + "MIME-Version": "1.0", + "Content-Type": "text/plain; charset=utf-8", + "Content-Transfer-Encoding": "8bit", + "Plural-Forms": "nplurals=INTEGER; plural=EXPRESSION;" + }, + "translations": { + "": { + "": { + "msgid": "", + "comments": { + "translator": "SOME DESCRIPTIVE TITLE.\nCopyright (C) YEAR SuSE Linux Products GmbH, Nuernberg\nThis file is distributed under the same license as the PACKAGE package.\nFIRST AUTHOR , YEAR.\n", + "flag": "fuzzy" + } + } + } + } +} diff --git a/.github/workflows/weblate-update-pot.yml b/.github/workflows/weblate-update-pot.yml index a833ce1284..08bc1f6123 100644 --- a/.github/workflows/weblate-update-pot.yml +++ b/.github/workflows/weblate-update-pot.yml @@ -24,20 +24,20 @@ jobs: run: zypper modifyrepo -d repo-non-oss repo-openh264 repo-update && zypper ref - name: Install tools - run: zypper --non-interactive install --no-recommends diffutils git gettext-tools + run: zypper --non-interactive install --no-recommends diffutils git gettext-tools npm-default - name: Checkout Agama sources uses: actions/checkout@v3 with: path: agama - - name: Generate POT file + - name: Generate web POT file run: | cd agama/web ./build_pot msgfmt --statistics agama.pot - - name: Validate the generated POT file + - name: Validate the generated web POT file run: msgfmt --check-format agama/web/agama.pot - name: Checkout Weblate sources @@ -52,13 +52,13 @@ jobs: git config --global user.name "YaST Bot" git config --global user.email "yast-devel@opensuse.org" - - name: Update POT file + - name: Update web POT file run: | mkdir -p agama-weblate/web cp agama/web/agama.pot agama-weblate/web/agama.pot # any change besides the timestamp in the POT file? - - name: Check changes + - name: Check web POT changes id: check_changes run: | git -C agama-weblate diff --ignore-matching-lines="POT-Creation-Date:" web/agama.pot > pot.diff @@ -71,11 +71,53 @@ jobs: echo "pot_updated=false" >> $GITHUB_OUTPUT fi - - name: Push updated POT file + - name: Push updated web POT file # run only when the POT file has been updated if: steps.check_changes.outputs.pot_updated == 'true' run: | cd agama-weblate git add web/agama.pot - git commit -m "Update POT file"$'\n\n'"Agama commit: $GITHUB_SHA" + git commit -m "Update web POT file"$'\n\n'"Agama commit: $GITHUB_SHA" + git push + + - name: Install NPM packages + run: | + cd agama/.github/workflows/product_translations + npm ci + + - name: Generate products POT file + run: | + cd agama/products.d + ../.github/workflows/product_translations/products_pot *.yaml > products.pot + msgfmt --statistics products.pot + + - name: Validate the generated products POT file + run: msgfmt --check-format agama/products.d/products.pot + + - name: Update products POT file + run: | + mkdir -p agama-weblate/products + cp agama/products.d/products.pot agama-weblate/products/products.pot + + # any change besides the timestamp in the POT file? + - name: Check products POT changes + id: check_changes_products + run: | + git -C agama-weblate diff --ignore-matching-lines="POT-Creation-Date:" products/products.pot > pot.diff + + if [ -s pot.diff ]; then + echo "POT file updated" + echo "pot_updated=true" >> $GITHUB_OUTPUT + else + echo "POT file unchanged" + echo "pot_updated=false" >> $GITHUB_OUTPUT + fi + + - name: Push updated products POT file + # run only when the POT file has been updated + if: steps.check_changes_products.outputs.pot_updated == 'true' + run: | + cd agama-weblate + git add products/products.pot + git commit -m "Update products POT file"$'\n\n'"Agama commit: $GITHUB_SHA" git push From 26b91aafe093fde1dab959e9170ea016df8da31d Mon Sep 17 00:00:00 2001 From: Josef Reidinger Date: Tue, 7 Nov 2023 11:07:49 +0100 Subject: [PATCH 03/11] fix the latest change when /etc/agama.yaml can be missing --- service/lib/agama/config_reader.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/lib/agama/config_reader.rb b/service/lib/agama/config_reader.rb index da43bc024b..e1dde8ded5 100644 --- a/service/lib/agama/config_reader.rb +++ b/service/lib/agama/config_reader.rb @@ -148,7 +148,7 @@ def config_paths paths.uniq! { |f| File.basename(f) } # Sort files lexicographic paths.sort_by! { |f| File.basename(f) } - paths.prepend(default_path) + paths.prepend(default_path) if File.exist?(default_path) paths end From 08961a13445d357594697c138320189af176545d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Slez=C3=A1k?= Date: Tue, 7 Nov 2023 22:37:10 +0100 Subject: [PATCH 04/11] Merge back the product translations --- .../workflows/product_translations/merge_po | 166 ++++++ .../product_translations/package-lock.json | 475 ++++++++++++++++++ .../product_translations/package.json | 1 + .../product_translations/products_pot | 2 +- .github/workflows/weblate-merge-po.yml | 6 +- .../workflows/weblate-merge-products-po.yml | 106 ++++ products.d/ALP-Dolomite.yaml | 6 + products.d/leap16.yaml | 9 +- products.d/tumbleweed.yaml | 14 +- 9 files changed, 776 insertions(+), 9 deletions(-) create mode 100755 .github/workflows/product_translations/merge_po create mode 100644 .github/workflows/weblate-merge-products-po.yml diff --git a/.github/workflows/product_translations/merge_po b/.github/workflows/product_translations/merge_po new file mode 100755 index 0000000000..ebfb079a37 --- /dev/null +++ b/.github/workflows/product_translations/merge_po @@ -0,0 +1,166 @@ +#! /usr/bin/node + +/* +This script merges the product translations back to the product YAML files. + +Requirements: NodeJS, run "npm ci" to install the needed NPM packages + +Usage: + + merge_po +*/ + +const fs = require("fs"); +const process = require("process"); +const path = require("path"); + +const { parseDocument } = require("yaml"); +const { globSync } = require("glob"); +const gettextParser = require("gettext-parser"); + +/** + * Translation object with original text, its translations and the locale name. + */ +class Translation { + msgid; + msgstr; + locale; + + /** + * Constructor + * @param {string} msgid - the original text + * @param {string} msgstr - the translation + * @param {string} locale - the locale + */ + constructor(msgid, msgstr, locale) { + this.msgid = msgid; + this.msgstr = msgstr; + this.locale = locale; + } + + /** + * Read all translations (PO files) in the specified directory + * @param {string} dir - input directory for reading the the PO files + * @returns {Translation[]} list of found translations + */ + static read(dir) { + const ret = []; + // sort the files so the translations in the YAML files are also sorted + const files = globSync(dir + "/*.po").sort(); + + files.forEach(f => { + console.log(`Reading ${path.basename(f)}`); + + const locale = path.basename(f, ".po"); + const input = fs.readFileSync(f, "utf-8"); + const po = gettextParser.po.parse(input); + + // translations for the default (empty) context + const translations = po.translations[""]; + + Object.values(translations).forEach(t => { + if (t.msgid !== "") { + ret.push(new Translation(t.msgid, t.msgstr[0], locale)); + } + }); + }); + + return ret; + } +} + +/** + * YAML product file + */ +class YamlProduct { + file; + document; + + /** + * Constructor + * @param {string} file - the path to the YAML file + */ + constructor(file) { + this.file = file; + // parse the file + const data = fs.readFileSync(this.file, "utf-8"); + this.document = parseDocument(data); + } + + /** + * Read all product definitions (YAML files) in the specified directory + * @param {string} dir - input directory for reading the the PO files + * @returns {YamlProduct[]} all found products + */ + static read(dir) { + const ret = []; + const files = globSync(dir + "/*.y{a,}ml"); + return files.map(f => { + console.log(`Reading ${path.basename(f)}`); + return new YamlProduct(f); + }); + } + + /** + * Find the matching translations in the list and add them to the YAML document + * @param {Translation[]} translations + */ + addTranslations(translations) { + const description = this.document.get("description"); + const newTranslations = {}; + + translations.forEach(t => { + if (t.msgid === description) { + newTranslations[t.locale] = t.msgstr; + } + }); + + // add or update the translations depending on whether they already exist + if (!this.document.has("translations")) { + this.document.add({key: "translations", value: { description: newTranslations}}); + } else { + const trans = this.document.get("translations"); + if (!trans) { + this.document.set("translations", { description: newTranslations}); + } else { + trans.set("description", newTranslations); + } + } + } + + /** + * Convert back the parsed YAML to String + * @returns {string} new update YAML data + */ + dump() { + return this.document.toString(); + } + + /** + * Save the current YAML data back to the file, the original content is + * overwritten. + */ + save() { + console.log(`Writing ${path.basename(this.file)}`); + fs.writeFileSync(this.file, this.dump(), "utf-8"); + } +} + +// script arguments (the first arg is executor path ("/usr/bin/node"), +// the second is name of this script) +const [, , translations_dir, products_dir] = process.argv; + +if (!translations_dir || !products_dir) { + console.log("ERROR: missing argument"); + process.exit(1); +} + +// read all YAML products and all translations +const translations = Translation.read(translations_dir); +const products = YamlProduct.read(products_dir); + +// inject the translations to the products and save the changes +products.forEach(p => { + p.addTranslations(translations); + p.save(); +}); diff --git a/.github/workflows/product_translations/package-lock.json b/.github/workflows/product_translations/package-lock.json index c85e3946d9..f43a58745c 100644 --- a/.github/workflows/product_translations/package-lock.json +++ b/.github/workflows/product_translations/package-lock.json @@ -6,9 +6,37 @@ "": { "devDependencies": { "gettext-parser": "^7.0.1", + "glob": "^10.3.10", "yaml": "^2.3.4" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -21,6 +49,36 @@ "node": ">=6.5" } }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -41,6 +99,15 @@ } ] }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -65,6 +132,24 @@ "ieee754": "^1.2.1" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", @@ -74,6 +159,32 @@ "node": ">= 0.6" } }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, "node_modules/encoding": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", @@ -101,6 +212,22 @@ "node": ">=0.8.x" } }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/gettext-parser": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-7.0.1.tgz", @@ -113,6 +240,28 @@ "safe-buffer": "^5.2.1" } }, + "node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -145,6 +294,97 @@ } ] }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -196,6 +436,39 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -205,6 +478,208 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yaml": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", diff --git a/.github/workflows/product_translations/package.json b/.github/workflows/product_translations/package.json index f542ad082f..3a098cade0 100644 --- a/.github/workflows/product_translations/package.json +++ b/.github/workflows/product_translations/package.json @@ -1,6 +1,7 @@ { "devDependencies": { "gettext-parser": "^7.0.1", + "glob": "^10.3.10", "yaml": "^2.3.4" } } diff --git a/.github/workflows/product_translations/products_pot b/.github/workflows/product_translations/products_pot index 08f143c655..552e70edda 100755 --- a/.github/workflows/product_translations/products_pot +++ b/.github/workflows/product_translations/products_pot @@ -51,7 +51,7 @@ class POFile { */ timestamp() { const date = new Date(); - return date.getUTCFullYear() + "-" + date.getUTCMonth() + "-" + + return date.getUTCFullYear() + "-" + (date.getUTCMonth() + 1) + "-" + date.getUTCDate() + " " + date.getUTCHours() + ":" + date.getUTCMinutes() + "+0000"; } diff --git a/.github/workflows/weblate-merge-po.yml b/.github/workflows/weblate-merge-po.yml index 57532ae0c4..7d13aeae97 100644 --- a/.github/workflows/weblate-merge-po.yml +++ b/.github/workflows/weblate-merge-po.yml @@ -95,7 +95,7 @@ jobs: web/share/update-manifest.py web/src/manifest.json # use a unique branch to avoid possible conflicts with already existing branches git checkout -b "po_merge_${GITHUB_RUN_ID}" - git commit -a -m "Update PO files"$'\n\n'"Agama-weblate commit: `git -C ../agama-weblate rev-parse HEAD`" + git commit -a -m "Update web PO files"$'\n\n'"Agama-weblate commit: `git -C ../agama-weblate rev-parse HEAD`" git push origin "po_merge_${GITHUB_RUN_ID}" - name: Create pull request @@ -105,7 +105,7 @@ jobs: run: | gh pr create -B master -H "po_merge_${GITHUB_RUN_ID}" \ --label translations --label bot \ - --title "Update PO files" \ - --body "Updating the translation files from the agama-weblate repository" + --title "Update web PO files" \ + --body "Updating the web translation files from the agama-weblate repository" env: GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/weblate-merge-products-po.yml b/.github/workflows/weblate-merge-products-po.yml new file mode 100644 index 0000000000..4d722e3230 --- /dev/null +++ b/.github/workflows/weblate-merge-products-po.yml @@ -0,0 +1,106 @@ +name: Weblate Merge Product PO + +on: + schedule: + # run every Monday at 2:45AM UTC + - cron: "45 2 * * 0" + + # allow running manually + workflow_dispatch: + +jobs: + merge-po: + # allow pushing and creating pull requests + permissions: + contents: write + pull-requests: write + + # do not run in forks + if: github.repository == 'openSUSE/agama' + + runs-on: ubuntu-latest + + container: + image: registry.opensuse.org/opensuse/tumbleweed:latest + + steps: + - name: Configure and refresh repositories + run: | + # install the GitHub command line tool "gh" + zypper addrepo https://cli.github.com/packages/rpm/gh-cli.repo + # disable unused repositories to have a faster refresh + zypper modifyrepo -d repo-non-oss repo-openh264 repo-update && \ + zypper --non-interactive --gpg-auto-import-keys ref + + - name: Install tools + run: zypper --non-interactive install --no-recommends gh git gettext-tools npm-default + + - name: Configure Git + run: | + git config --global user.name "YaST Bot" + git config --global user.email "yast-devel@opensuse.org" + + - name: Checkout sources + uses: actions/checkout@v3 + with: + path: agama + + - name: Checkout Agama-weblate sources + uses: actions/checkout@v3 + with: + path: agama-weblate + repository: openSUSE/agama-weblate + + - name: Validate the product PO files + working-directory: ./agama-weblate + run: ls products/*.po | xargs -n1 msgfmt --check-format -o /dev/null + + - name: Install NPM packages + working-directory: ./agama/.github/workflows/product_translations + run: npm ci + + - name: Update product files with translations + env: + NODE_PATH: ./agama/.github/workflows/product_translations + run: | + ${NODE_PATH}/merge_po agama-weblate/products agama/products.d + + - name: Check changes + id: check_changes + working-directory: ./agama + run: | + git diff products.d > po.diff + + if [ -s po.diff ]; then + echo "Product files updated" + # this is an Output Parameter + # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter + echo "products_updated=true" >> $GITHUB_OUTPUT + else + echo "Product files unchanged" + echo "products_updated=false" >> $GITHUB_OUTPUT + fi + + rm po.diff + + - name: Push updated product files + # run only when a PO file has been updated + if: steps.check_changes.outputs.products_updated == 'true' + working-directory: ./agama + run: | + # use a unique branch to avoid possible conflicts with already existing branches + git checkout -b "products_po_merge_${GITHUB_RUN_ID}" + git commit -a -m "Update translations in the product files"$'\n\n'"Agama-weblate commit: `git -C ../agama-weblate rev-parse HEAD`" + git push origin "products_po_merge_${GITHUB_RUN_ID}" + + - name: Create pull request + # run only when a PO file has been updated + if: steps.check_changes.outputs.products_updated == 'true' + working-directory: ./agama + run: | + gh pr create -B master -H "products_po_merge_${GITHUB_RUN_ID}" \ + --label translations --label bot \ + --title "Update translations in the product files" \ + --body "Updating the product translations from the agama-weblate repository" + env: + GH_TOKEN: ${{ github.token }} diff --git a/products.d/ALP-Dolomite.yaml b/products.d/ALP-Dolomite.yaml index 3e3d9a7463..48d0b2764f 100644 --- a/products.d/ALP-Dolomite.yaml +++ b/products.d/ALP-Dolomite.yaml @@ -1,8 +1,14 @@ id: ALP-Dolomite name: SUSE ALP Dolomite +# ------------------------------------------------------------------------------ +# WARNING: When changing the product description delete the translations located +# at the at translations/description key below to avoid using obsolete +# translations!! +# ------------------------------------------------------------------------------ description: 'SUSE ALP Dolomite is a minimum immutable OS core, focused on security to provide the bare minimum to run workloads and services as containers or virtual machines.' +translations: software: installation_repositories: - url: https://updates.suse.com/SUSE/Products/ALP-Dolomite/1.0/x86_64/product/ diff --git a/products.d/leap16.yaml b/products.d/leap16.yaml index 3ae4dc0a00..de8c13d9b4 100644 --- a/products.d/leap16.yaml +++ b/products.d/leap16.yaml @@ -1,7 +1,14 @@ id: Leap16 name: openSUSE Leap 16.0 archs: x86_64,aarch64 -description: '[Experimental project] openSUSE Leap 16 is built on top of the next generation Adaptable Linux Platform (ALP) from SUSE.' +# ------------------------------------------------------------------------------ +# WARNING: When changing the product description delete the translations located +# at the at translations/description key below to avoid using obsolete +# translations!! +# ------------------------------------------------------------------------------ +description: '[Experimental project] openSUSE Leap 16 is built on top of the + next generation Adaptable Linux Platform (ALP) from SUSE.' +translations: software: installation_repositories: - url: https://download.opensuse.org/repositories/openSUSE:/Leap:/16.0/images/repo/Leap-16.0-x86_64-Media1/ diff --git a/products.d/tumbleweed.yaml b/products.d/tumbleweed.yaml index 732b836815..47cdc29533 100644 --- a/products.d/tumbleweed.yaml +++ b/products.d/tumbleweed.yaml @@ -1,9 +1,15 @@ id: Tumbleweed name: openSUSE Tumbleweed -description: 'The Tumbleweed distribution is a pure rolling release version - of openSUSE containing the latest "stable" versions of all software - instead of relying on rigid periodic release cycles. The project does - this for users that want the newest stable software.' +# ------------------------------------------------------------------------------ +# WARNING: When changing the product description delete the translations located +# at the at translations/description key below to avoid using obsolete +# translations!! +# ------------------------------------------------------------------------------ +description: 'The Tumbleweed distribution is a pure rolling release version of + openSUSE containing the latest "stable" versions of all software instead of + relying on rigid periodic release cycles. The project does this for users that + want the newest stable software.' +translations: software: installation_repositories: - url: https://download.opensuse.org/tumbleweed/repo/oss/ From 747efa31598ce9249c38eb1c74f9cd1fbe435fb9 Mon Sep 17 00:00:00 2001 From: YaST Bot Date: Wed, 8 Nov 2023 10:02:26 +0000 Subject: [PATCH 05/11] Update translations in the product files Agama-weblate commit: e8e766a746f8e16d30be97bd90dd4acce04e8a31 --- products.d/ALP-Dolomite.yaml | 4 ++++ products.d/leap16.yaml | 3 +++ products.d/tumbleweed.yaml | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/products.d/ALP-Dolomite.yaml b/products.d/ALP-Dolomite.yaml index 48d0b2764f..c18f28779a 100644 --- a/products.d/ALP-Dolomite.yaml +++ b/products.d/ALP-Dolomite.yaml @@ -9,6 +9,10 @@ description: 'SUSE ALP Dolomite is a minimum immutable OS core, focused on security to provide the bare minimum to run workloads and services as containers or virtual machines.' translations: + description: + cs: SUSE ALP Dolomite je minimální neměnitelný základní OS, zaměřený na + bezpečnost pro poskytování úplného minima ke spuštění úloh a služeb v + kontejnerech nebo virtuálních strojích. software: installation_repositories: - url: https://updates.suse.com/SUSE/Products/ALP-Dolomite/1.0/x86_64/product/ diff --git a/products.d/leap16.yaml b/products.d/leap16.yaml index de8c13d9b4..8940363097 100644 --- a/products.d/leap16.yaml +++ b/products.d/leap16.yaml @@ -9,6 +9,9 @@ archs: x86_64,aarch64 description: '[Experimental project] openSUSE Leap 16 is built on top of the next generation Adaptable Linux Platform (ALP) from SUSE.' translations: + description: + cs: "[Experimentální projekt] openSUSE Leap 16 je postaven na budoucí generaci + Adaptable Linux Platform (ALP) od SUSE." software: installation_repositories: - url: https://download.opensuse.org/repositories/openSUSE:/Leap:/16.0/images/repo/Leap-16.0-x86_64-Media1/ diff --git a/products.d/tumbleweed.yaml b/products.d/tumbleweed.yaml index 47cdc29533..61fbae4e65 100644 --- a/products.d/tumbleweed.yaml +++ b/products.d/tumbleweed.yaml @@ -10,6 +10,10 @@ description: 'The Tumbleweed distribution is a pure rolling release version of relying on rigid periodic release cycles. The project does this for users that want the newest stable software.' translations: + description: + cs: Tumbleweed je rolující verze distribuce openSUSE obsahující poslední + "stabilní" verze veškerého software namísto pevných pravidelných vydání. + Projekt je určen pro uživatele, kteří chtějí nejnovější stabilní software. software: installation_repositories: - url: https://download.opensuse.org/tumbleweed/repo/oss/ From 62ed31c40287e4b2f8620efec39119b5da3cfc18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Slez=C3=A1k?= Date: Thu, 9 Nov 2023 09:36:04 +0100 Subject: [PATCH 06/11] Use the translated product description if available --- service/lib/agama/dbus/software/manager.rb | 27 +++++++- service/lib/agama/ui_locale.rb | 2 +- .../test/agama/dbus/software/manager_test.rb | 64 +++++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/service/lib/agama/dbus/software/manager.rb b/service/lib/agama/dbus/software/manager.rb index 552a46aa47..25987eea04 100644 --- a/service/lib/agama/dbus/software/manager.rb +++ b/service/lib/agama/dbus/software/manager.rb @@ -123,7 +123,7 @@ def initialize(backend, logger) def available_base_products backend.products.map do |id, data| - [id, data["name"], { "description" => data["description"] }].freeze + [id, data["name"], { "description" => localized_description(data) }].freeze end end @@ -181,6 +181,31 @@ def register_callbacks end end + # find translated product description if available + # @param data [Hash] product configuration from the YAML file + # @return [String,nil] Translated product description (if available) + # or the untranslated description, nil if not found + def localized_description(data) + translations = data["translations"]&.[]("description") + lang = ENV["LANG"] || "" + + # no translations or language not set, return untranslated value + return data["description"] if !translations.is_a?(Hash) || lang.empty? + + # remove the character encoding if present + lang = lang.split(".").first + # full matching (language + country) + return translations[lang] if translations[lang] + + # remove the country part + lang = lang.split("_").first + # partial match (just the language) + return translations[lang] if translations[lang] + + # fallback to original untranslated description + data["description"] + end + USER_SELECTED_PATTERN = 0 AUTO_SELECTED_PATTERN = 1 def compute_patterns diff --git a/service/lib/agama/ui_locale.rb b/service/lib/agama/ui_locale.rb index cc67ba9475..01c1b10564 100644 --- a/service/lib/agama/ui_locale.rb +++ b/service/lib/agama/ui_locale.rb @@ -47,7 +47,7 @@ def initialize(locale_client, &block) def change_locale(locale) # TODO: check if we can use UTF-8 everywhere including strange arch consoles Yast::WFM.SetLanguage(locale, "UTF-8") - # explicitelly set ENV to get localization also from libraries like libstorage + # explicitly set ENV to get localization also from libraries like libstorage ENV["LANG"] = locale + ".UTF-8" log.info "set yast language to #{locale}" # explicit call to textdomain to force fast gettext change of language ASAP diff --git a/service/test/agama/dbus/software/manager_test.rb b/service/test/agama/dbus/software/manager_test.rb index f6eda1223b..b75490ab43 100644 --- a/service/test/agama/dbus/software/manager_test.rb +++ b/service/test/agama/dbus/software/manager_test.rb @@ -140,4 +140,68 @@ expect(installed).to eq(true) end end + + describe "#available_base_products" do + # testing product with translations + products = { + "Tumbleweed" => { + "name" => "openSUSE Tumbleweed", + "description" => "Original description", + "translations" => { + "description" => { + "cs" => "Czech translation", + "es" => "Spanish translation" + } + } + } + } + + it "returns product ID and name" do + expect(backend).to receive(:products).and_return(products) + + product = subject.available_base_products.first + expect(product[0]).to eq("Tumbleweed") + expect(product[1]).to eq("openSUSE Tumbleweed") + end + + it "returns untranslated description when the language is not set" do + allow(ENV).to receive(:[]).with("LANG").and_return(nil) + expect(backend).to receive(:products).and_return(products) + + product = subject.available_base_products.first + expect(product[2]["description"]).to eq("Original description") + end + + it "returns Czech translation if locale is \"cs_CZ.UTF-8\"" do + allow(ENV).to receive(:[]).with("LANG").and_return("cs_CZ.UTF-8") + expect(backend).to receive(:products).and_return(products) + + product = subject.available_base_products.first + expect(product[2]["description"]).to eq("Czech translation") + end + + it "returns Czech translation if locale is \"cs\"" do + allow(ENV).to receive(:[]).with("LANG").and_return("cs") + expect(backend).to receive(:products).and_return(products) + + product = subject.available_base_products.first + expect(product[2]["description"]).to eq("Czech translation") + end + + it "return untranslated description when translation is not available" do + allow(ENV).to receive(:[]).with("LANG").and_return("cs_CZ.UTF-8") + + # testing product without translations + untranslated = { + "Tumbleweed" => { + "name" => "openSUSE Tumbleweed", + "description" => "Original description" + } + } + expect(backend).to receive(:products).and_return(untranslated) + + product = subject.available_base_products.first + expect(product[2]["description"]).to eq("Original description") + end + end end From dad064d4830d7d34cc9062f5ef8916c18fb0212f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Slez=C3=A1k?= Date: Thu, 9 Nov 2023 17:05:11 +0100 Subject: [PATCH 07/11] More documentation for translators --- products.d/ALP-Dolomite.yaml | 1 + products.d/README.md | 17 +++++++++++++++++ products.d/leap16.yaml | 1 + products.d/tumbleweed.yaml | 1 + web/po/README.md | 22 ++++++++++++++++++++++ 5 files changed, 42 insertions(+) create mode 100644 products.d/README.md create mode 100644 web/po/README.md diff --git a/products.d/ALP-Dolomite.yaml b/products.d/ALP-Dolomite.yaml index c18f28779a..345c7a2461 100644 --- a/products.d/ALP-Dolomite.yaml +++ b/products.d/ALP-Dolomite.yaml @@ -8,6 +8,7 @@ name: SUSE ALP Dolomite description: 'SUSE ALP Dolomite is a minimum immutable OS core, focused on security to provide the bare minimum to run workloads and services as containers or virtual machines.' +# Do not manually change any translations! See README.md for more details. translations: description: cs: SUSE ALP Dolomite je minimální neměnitelný základní OS, zaměřený na diff --git a/products.d/README.md b/products.d/README.md new file mode 100644 index 0000000000..fd6f8149d0 --- /dev/null +++ b/products.d/README.md @@ -0,0 +1,17 @@ +# Product Definitions + +This directory contains product definitions for the Agama installer. + +## Contribution + +For updating the translations use the [Agama Weblate +project](https://l10n.opensuse.org/projects/agama/agama-products/). The changes +in the Weblate are automatically saved to the +[agama-weblate](https://github.com/openSUSE/agama-weblate/products) repository +and later a pull request with the changes is automatically created for merging +the changes here. + +Alternatively you can open a pull request against the +[agama-weblate](https://github.com/openSUSE/agama-weblate/products) GitHub +repository. But that requires manual approving and merging, prefer using the +Weblate tool, it merges automatically. diff --git a/products.d/leap16.yaml b/products.d/leap16.yaml index 8940363097..b7913cfb05 100644 --- a/products.d/leap16.yaml +++ b/products.d/leap16.yaml @@ -8,6 +8,7 @@ archs: x86_64,aarch64 # ------------------------------------------------------------------------------ description: '[Experimental project] openSUSE Leap 16 is built on top of the next generation Adaptable Linux Platform (ALP) from SUSE.' +# Do not manually change any translations! See README.md for more details. translations: description: cs: "[Experimentální projekt] openSUSE Leap 16 je postaven na budoucí generaci diff --git a/products.d/tumbleweed.yaml b/products.d/tumbleweed.yaml index 61fbae4e65..e5c72cd2cb 100644 --- a/products.d/tumbleweed.yaml +++ b/products.d/tumbleweed.yaml @@ -9,6 +9,7 @@ description: 'The Tumbleweed distribution is a pure rolling release version of openSUSE containing the latest "stable" versions of all software instead of relying on rigid periodic release cycles. The project does this for users that want the newest stable software.' +# Do not manually change any translations! See README.md for more details. translations: description: cs: Tumbleweed je rolující verze distribuce openSUSE obsahující poslední diff --git a/web/po/README.md b/web/po/README.md new file mode 100644 index 0000000000..7a77b16c90 --- /dev/null +++ b/web/po/README.md @@ -0,0 +1,22 @@ +# Translations + +This directory contains translation files for the web frontend part of the Agama +installer. See more details in the main [i18n](../../doc/i18n.md) documentation. + +## Contribution + +:warning: *WARNING: Do not manually change any files here! The files are +automatically overwritten by the files from the +[agama-weblate](https://github.com/openSUSE/agama-weblate/tree/master/web) Git +repository! Your changes would be lost on the next synchronization!* :warning: + +For updating the translations use the [Agama Weblate +project](https://l10n.opensuse.org/projects/agama/agama-web/). The changes +in the Weblate are automatically saved to the agama-weblate repository +and later a pull request with the changes is automatically created for merging +the changes here. + +Alternatively you can open a pull request against the +[agama-weblate](https://github.com/openSUSE/agama-weblate/web) GitHub +repository. But that requires manual approving and merging, prefer using the +Weblate tool, it merges automatically. From 604f1a5d6cd062660e8aa5ce920c43b85d70b33e Mon Sep 17 00:00:00 2001 From: YaST Bot Date: Sun, 12 Nov 2023 02:44:18 +0000 Subject: [PATCH 08/11] Update web PO files Agama-weblate commit: aac5955f8364cda4da5c956899a3cfc01ea5abfb --- web/po/sv.po | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/web/po/sv.po b/web/po/sv.po index 02d8db2c94..db664c6e06 100644 --- a/web/po/sv.po +++ b/web/po/sv.po @@ -1,14 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR SuSE Linux Products GmbH, Nuernberg # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. +# Luna Jernberg , 2023. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-05 02:14+0000\n" -"PO-Revision-Date: 2023-10-18 18:15+0000\n" +"POT-Creation-Date: 2023-11-06 12:00+0000\n" +"PO-Revision-Date: 2023-11-06 12:01+0000\n" "Last-Translator: Luna Jernberg \n" "Language-Team: Swedish \n" @@ -344,10 +344,9 @@ msgid "Localization" msgstr "Lokalisering" #: src/components/l10n/LanguageSwitcher.jsx:46 -#, fuzzy #| msgid "language" msgid "Display Language" -msgstr "språk" +msgstr "Visningsspråk" #: src/components/layout/Loading.jsx:30 msgid "Loading installation environment, please wait." From c54f77664f87876f8fa57f6ae54679c7b27277d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Slez=C3=A1k?= Date: Fri, 10 Nov 2023 19:05:23 +0100 Subject: [PATCH 09/11] Split CI GitHub Actions --- .github/workflows/ci-rust.yml | 106 +++++++++++++++++++ .github/workflows/ci-service.yml | 93 +++++++++++++++++ .github/workflows/ci-web.yml | 94 +++++++++++++++++ .github/workflows/ci.yml | 169 ------------------------------- 4 files changed, 293 insertions(+), 169 deletions(-) create mode 100644 .github/workflows/ci-rust.yml create mode 100644 .github/workflows/ci-service.yml create mode 100644 .github/workflows/ci-web.yml delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci-rust.yml b/.github/workflows/ci-rust.yml new file mode 100644 index 0000000000..302df173b0 --- /dev/null +++ b/.github/workflows/ci-rust.yml @@ -0,0 +1,106 @@ +name: CI - Rust + +on: + push: + paths: + # NOTE: GitHub Actions do not allow using YAML references, the same path + # list is used below for the pull request event. Keep both lists in sync!! + + # this file as well + - .github/workflows/ci-rust.yml + # any change in the rust subfolder + - rust/** + # except Markdown documentation + - "!rust/**.md" + # except the packaging + - "!rust/package/**" + # except the DBus configuration + - "!rust/share/**" + + pull_request: + paths: + # NOTE: GitHub Actions do not allow using YAML references, the same path + # list is used above for the push event. Keep both lists in sync!! + + # this file as well + - .github/workflows/ci-rust.yml + # any change in the rust subfolder + - rust/** + # except Markdown documentation + - "!rust/**.md" + # except the packaging + - "!rust/package/**" + # except the DBus configuration + - "!rust/share/**" + + # allow running manually + workflow_dispatch: + +jobs: + rust_ci: + runs-on: ubuntu-latest + env: + COVERAGE: 1 + + defaults: + run: + working-directory: ./rust + + strategy: + fail-fast: false + matrix: + distro: [ "tumbleweed" ] + + container: + image: registry.opensuse.org/yast/head/containers_${{matrix.distro}}/yast-ruby + options: --security-opt seccomp=unconfined + + steps: + + - name: Git Checkout + uses: actions/checkout@v3 + + - name: Configure and refresh repositories + # disable unused repositories to have faster refresh + run: zypper modifyrepo -d repo-non-oss repo-openh264 repo-update && ( zypper ref || zypper ref || zypper ref ) + + - name: Install Rust development files + run: zypper --non-interactive install rustup + + - name: Install required packages + run: zypper --non-interactive install python-langtable-data openssl-3 libopenssl-3-devel jq + + - name: Install Rust toolchains + run: rustup toolchain install stable + + - name: Install cargo-binstall + uses: taiki-e/install-action@v2 + with: + tool: cargo-binstall + + - name: Install Tarpaulin (for code coverage) + run: cargo-binstall --no-confirm cargo-tarpaulin + + - name: Run the tests + run: cargo tarpaulin --out xml + + - name: Lint formatting + run: cargo fmt --all -- --check + + # send the code coverage for the Rust part to the coveralls.io + - name: Coveralls GitHub Action + uses: coverallsapp/github-action@v2 + with: + base-path: ./rust + format: cobertura + flag-name: rust + parallel: true + + # close the code coverage and inherit the previous coverage for the Ruby and + # Web parts (it needs a separate step, the "carryforward" flag can be used + # only with the "parallel-finished: true" option) + - name: Coveralls Finished + uses: coverallsapp/github-action@v2 + with: + parallel-finished: true + carryforward: "service,web" diff --git a/.github/workflows/ci-service.yml b/.github/workflows/ci-service.yml new file mode 100644 index 0000000000..620a8bb75c --- /dev/null +++ b/.github/workflows/ci-service.yml @@ -0,0 +1,93 @@ +name: CI - Service + +on: + push: + paths: + # NOTE: GitHub Actions do not allow using YAML references, the same path + # list is used below for the pull request event. Keep both lists in sync!! + + # this file as well + - .github/workflows/ci-service.yml + # any change in the service subfolder + - service/** + # except Markdown documentation + - "!service/**.md" + # except the packaging + - "!service/package/**" + # except the DBus configuration + - "!service/share/**" + + pull_request: + paths: + # NOTE: GitHub Actions do not allow using YAML references, the same path + # list is used above for the push event. Keep both lists in sync!! + + # this file as well + - .github/workflows/ci-service.yml + # any change in the service subfolder + - service/** + # except Markdown documentation + - "!service/**.md" + # except the packaging + - "!service/package/**" + # except the DBus configuration + - "!service/share/**" + + # allow running manually + workflow_dispatch: + +jobs: + ruby_tests: + runs-on: ubuntu-latest + env: + COVERAGE: 1 + + defaults: + run: + working-directory: ./service + + strategy: + fail-fast: false + matrix: + distro: [ "tumbleweed" ] + + container: + image: registry.opensuse.org/yast/head/containers_${{matrix.distro}}/yast-ruby + + steps: + + - name: Git Checkout + uses: actions/checkout@v3 + + - name: Configure and refresh repositories + # disable unused repositories to have faster refresh + run: zypper modifyrepo -d repo-non-oss repo-openh264 repo-update && zypper ref + + - name: Install Ruby development files + run: zypper --non-interactive install gcc gcc-c++ make openssl-devel ruby-devel npm augeas-devel + + - name: Install required packages + run: zypper --non-interactive install yast2-iscsi-client + + - name: Install RubyGems dependencies + run: bundle config set --local with 'development' && bundle install + + - name: Run the tests and generate coverage report + run: bundle exec rspec + + # send the code coverage for the Ruby part to the coveralls.io + - name: Coveralls GitHub Action + uses: coverallsapp/github-action@v2 + with: + base-path: ./service + flag-name: service + parallel: true + + # close the code coverage and inherit the previous coverage for the Web and + # Rust parts (it needs a separate step, the "carryforward" flag can be used + # only with the "parallel-finished: true" option) + - name: Coveralls Finished + uses: coverallsapp/github-action@v2 + with: + parallel-finished: true + carryforward: "rust,web" diff --git a/.github/workflows/ci-web.yml b/.github/workflows/ci-web.yml new file mode 100644 index 0000000000..f003997225 --- /dev/null +++ b/.github/workflows/ci-web.yml @@ -0,0 +1,94 @@ +name: CI - Web + +on: + push: + paths: + # NOTE: GitHub Actions do not allow using YAML references, the same path + # list is used below for the pull request event. Keep both lists in sync!! + + # this file as well + - .github/workflows/ci-web.yml + # any change in the web subfolder + - web/** + # except Markdown documentation + - "!web/**.md" + # except the packaging + - "!web/package/**" + + pull_request: + paths: + # NOTE: GitHub Actions do not allow using YAML references, the same path + # list is used above for the push event. Keep both lists in sync!! + + # this file as well + - .github/workflows/ci-web.yml + # any change in the web subfolder + - web/** + # except Markdown documentation + - "!web/**.md" + # except the packaging + - "!web/package/**" + + # allow running manually + workflow_dispatch: + +jobs: + frontend_build: + runs-on: ubuntu-latest + + defaults: + run: + working-directory: ./web + + strategy: + matrix: + node-version: ["18.x"] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v3 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + cache-dependency-path: 'web/package-lock.json' + + - name: Install dependencies + run: npm install + + - name: Build the application + run: make + + - name: Run check spell + run: npm run cspell + + - name: Check types + run: npm run check-types + + - name: Run ESLint + run: npm run eslint + + - name: Run Stylelint + run: npm run stylelint + + - name: Run the tests and generate coverage report + run: npm test -- --coverage + + # send the code coverage for the web part to the coveralls.io + - name: Coveralls GitHub Action + uses: coverallsapp/github-action@v2 + with: + base-path: ./web + flag-name: web + parallel: true + + # close the code coverage and inherit the previous coverage for the Ruby and + # Rust parts (it needs a separate step, the "carryforward" flag can be used + # only with the "parallel-finished: true" option) + - name: Coveralls Finished + uses: coverallsapp/github-action@v2 + with: + parallel-finished: true + carryforward: "service,rust" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index d941c5d41d..0000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,169 +0,0 @@ -name: CI - -on: [push, pull_request] - -jobs: - frontend_build: - runs-on: ubuntu-latest - - defaults: - run: - working-directory: ./web - - strategy: - matrix: - node-version: ["18.x"] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - cache-dependency-path: 'web/package-lock.json' - - - name: Install dependencies - run: npm install - - - name: Build the application - run: make - - - name: Run check spell - run: npm run cspell - - - name: Check types - run: npm run check-types - - - name: Run ESLint - run: npm run eslint - - - name: Run Stylelint - run: npm run stylelint - - - name: Run the tests and generate coverage report - run: npm test -- --coverage - - - name: Coveralls GitHub Action - uses: coverallsapp/github-action@v2 - with: - base-path: ./web - flag-name: frontend - parallel: true - - ruby_tests: - runs-on: ubuntu-latest - env: - COVERAGE: 1 - - defaults: - run: - working-directory: ./service - - strategy: - fail-fast: false - matrix: - distro: [ "tumbleweed" ] - - container: - image: registry.opensuse.org/yast/head/containers_${{matrix.distro}}/yast-ruby - - steps: - - - name: Git Checkout - uses: actions/checkout@v3 - - - name: Configure and refresh repositories - # disable unused repositories to have faster refresh - run: zypper modifyrepo -d repo-non-oss repo-openh264 repo-update && ( zypper ref || zypper ref || zypper ref ) - - - name: Install Ruby development files - run: zypper --non-interactive install gcc gcc-c++ make openssl-devel ruby-devel npm augeas-devel - - - name: Install required packages - run: zypper --non-interactive install yast2-iscsi-client - - - name: Install RubyGems dependencies - run: bundle config set --local with 'development' && bundle install - - - name: Run the tests and generate coverage report - run: bundle exec rspec - - - name: Coveralls GitHub Action - uses: coverallsapp/github-action@v2 - with: - base-path: ./service - flag-name: backend - parallel: true - - rust_ci: - runs-on: ubuntu-latest - env: - COVERAGE: 1 - - defaults: - run: - working-directory: ./rust - - strategy: - fail-fast: false - matrix: - distro: [ "tumbleweed" ] - - container: - image: registry.opensuse.org/yast/head/containers_${{matrix.distro}}/yast-ruby - options: --security-opt seccomp=unconfined - - steps: - - - name: Git Checkout - uses: actions/checkout@v3 - - - name: Configure and refresh repositories - # disable unused repositories to have faster refresh - run: zypper modifyrepo -d repo-non-oss repo-openh264 repo-update && ( zypper ref || zypper ref || zypper ref ) - - - name: Install Rust development files - run: zypper --non-interactive install rustup - - - name: Install required packages - run: zypper --non-interactive install python-langtable-data openssl-3 libopenssl-3-devel jq - - - name: Install Rust toolchains - run: rustup toolchain install stable - - - name: Install cargo-binstall - uses: taiki-e/install-action@v2 - with: - tool: cargo-binstall - - - name: Install Tarpaulin (for code coverage) - run: cargo-binstall --no-confirm cargo-tarpaulin - - - name: Run the tests - run: cargo tarpaulin --out xml - - - name: Lint formatting - run: cargo fmt --all -- --check - - - name: Coveralls GitHub Action - uses: coverallsapp/github-action@v2 - with: - base-path: ./rust - format: cobertura - flag-name: rust-backend - parallel: true - - finish: - runs-on: ubuntu-latest - - needs: [frontend_build, ruby_tests, rust_ci] - - steps: - - - name: Coveralls Finished - uses: coverallsapp/github-action@v1 - with: - parallel-finished: true From e17cbb80adc876fa7e947b2c1b9702d458ec852b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Slez=C3=A1k?= Date: Tue, 14 Nov 2023 08:50:15 +0100 Subject: [PATCH 10/11] Update badges in the main README.md --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 73ff70dbc2..556d5642b0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ **Checks** -[![CI Status](https://github.com/openSUSE/agama/actions/workflows/ci.yml/badge.svg)](https://github.com/openSUSE/agama/actions/workflows/ci.yml) +[![CI - Rust](https://github.com/openSUSE/agama/actions/workflows/ci-rust.yml/badge.svg)](https://github.com/openSUSE/agama/actions/workflows/ci-rust.yml) +[![CI - Service](https://github.com/openSUSE/agama/actions/workflows/ci-service.yml/badge.svg)](https://github.com/openSUSE/agama/actions/workflows/ci-service.yml) +[![CI - Web](https://github.com/openSUSE/agama/actions/workflows/ci-web.yml/badge.svg)](https://github.com/openSUSE/agama/actions/workflows/ci-web.yml) [![CI - Rubocop](https://github.com/openSUSE/agama/actions/workflows/ci-rubocop.yml/badge.svg)](https://github.com/openSUSE/agama/actions/workflows/ci-rubocop.yml) [![CI - Documentation Check](https://github.com/openSUSE/agama/actions/workflows/ci-doc-check.yml/badge.svg)](https://github.com/openSUSE/agama/actions/workflows/ci-doc-check.yml) [![CI - Integration Tests](https://github.com/openSUSE/agama/actions/workflows/ci-integration-tests.yml/badge.svg)](https://github.com/openSUSE/agama/actions/workflows/ci-integration-tests.yml) @@ -11,6 +13,7 @@ [![Weblate Update POT](https://github.com/openSUSE/agama/actions/workflows/weblate-update-pot.yml/badge.svg)](https://github.com/openSUSE/agama/actions/workflows/weblate-update-pot.yml) [![Weblate Merge PO](https://github.com/openSUSE/agama/actions/workflows/weblate-merge-po.yml/badge.svg)](https://github.com/openSUSE/agama/actions/workflows/weblate-merge-po.yml) +[![Weblate Merge Product PO](https://github.com/openSUSE/agama/actions/workflows/weblate-merge-products-po.yml/badge.svg)](https://github.com/openSUSE/agama/actions/workflows/weblate-merge-products-po.yml) [![Translation Status](https://l10n.opensuse.org/widgets/agama/-/agama-web/svg-badge.svg)](https://l10n.opensuse.org/engage/agama/) **[OBS systemsmanagement:Agama:Staging](https://build.opensuse.org/project/show/systemsmanagement:Agama:Staging)** @@ -23,8 +26,9 @@ [![OBS Staging/agama-cli](https://img.shields.io/obs/systemsmanagement:Agama:Staging/agama-cli/openSUSE_Tumbleweed/x86_64?label=Package%20agama-cli)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Staging/agama-cli) [![OBS Staging/cockpit-agama](https://img.shields.io/obs/systemsmanagement:Agama:Staging/cockpit-agama/openSUSE_Tumbleweed/x86_64?label=Package%20cockpit-agama)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Staging/cockpit-agama) [![OBS Staging/rubygem-agama](https://img.shields.io/obs/systemsmanagement:Agama:Staging/rubygem-agama/openSUSE_Tumbleweed/x86_64?label=Package%20rubygem-agama)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Staging/rubygem-agama) +[![OBS Staging/agama-products-opensuse](https://img.shields.io/obs/systemsmanagement%3AAgama%3AStaging/agama-products-opensuse/openSUSE_Tumbleweed/x86_64?label=Package%20agama-products-opensuse)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Staging/agama-products-opensuse) [![OBS Staging/cockpit-agama-playwright](https://img.shields.io/obs/systemsmanagement:Agama:Staging/cockpit-agama-playwright/openSUSE_Tumbleweed/x86_64?label=Package%20cockpit-agama-playwright)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Staging/cockpit-agama-playwright) -[![OBS Staging/agama-live](https://img.shields.io/obs/systemsmanagement:Agama:Staging/agama-live:default/images/x86_64?label=Live%20ISO)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Staging/agama-live) +[![OBS Staging/agama-live](https://img.shields.io/obs/systemsmanagement:Agama:Staging/agama-live:openSUSE/images/x86_64?label=Live%20ISO)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Staging/agama-live) **[OBS systemsmanagement:Agama:Devel](https://build.opensuse.org/project/show/systemsmanagement:Agama:Devel)** @@ -34,7 +38,7 @@ [![OBS Devel/agama-cli](https://img.shields.io/obs/systemsmanagement:Agama:Devel/agama-cli/openSUSE_Tumbleweed/x86_64?label=Package%20agama-cli)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Devel/agama-cli) [![OBS Devel/cockpit-agama](https://img.shields.io/obs/systemsmanagement:Agama:Devel/cockpit-agama/openSUSE_Tumbleweed/x86_64?label=Package%20cockpit-agama)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Devel/cockpit-agama) [![OBS Devel/rubygem-agama](https://img.shields.io/obs/systemsmanagement:Agama:Devel/rubygem-agama/openSUSE_Tumbleweed/x86_64?label=Package%20rubygem-agama)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Devel/rubygem-agama) -[![OBS Devel/agama-live](https://img.shields.io/obs/systemsmanagement:Agama:Devel/agama-live:default/images/x86_64?label=Live%20ISO)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Devel/agama-live) +[![OBS Devel/agama-live](https://img.shields.io/obs/systemsmanagement:Agama:Devel/agama-live:openSUSE/images/x86_64?label=Live%20ISO)](https://build.opensuse.org/package/show/systemsmanagement:Agama:Devel/agama-live) # Agama: A Service-based Linux Installer From 92c26496668698da766d89bd1c11f81a396ff625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Slez=C3=A1k?= Date: Tue, 14 Nov 2023 13:25:37 +0100 Subject: [PATCH 11/11] Integration test - run only once a day, report failures on IRC --- .github/workflows/ci-integration-tests.yml | 100 ++++----------------- 1 file changed, 16 insertions(+), 84 deletions(-) diff --git a/.github/workflows/ci-integration-tests.yml b/.github/workflows/ci-integration-tests.yml index 2b604d1c73..f2534a6eb0 100644 --- a/.github/workflows/ci-integration-tests.yml +++ b/.github/workflows/ci-integration-tests.yml @@ -1,95 +1,18 @@ name: "CI - Integration Tests" on: - push: - paths: - # NOTE: GitHub Actions do not allow using YAML references, the same path - # list is used below for the pull request event. Keep both lists in sync!! - - # this file itself - - .github/workflows/ci-integration-tests.yml - - # the web frontend - - web/**.json - - web/**.html - - web/**.scss - - web/**.jsx? - # ignore unit tests, we do not run them here - - "!web/**.test.jsx?" - - web/Makefile - - # the service backend - - setup-service.sh - - service/lib/**.rb - - service/bin/agamactl - - service/Gemfile* - - service/*.gemspec - # D-Bus and systemd configs - - service/share/*.conf - - service/share/*.service - # Rust services - - rust/Cargo.lock - - rust/agama-dbus-server/** - - rust/agama-locale-data/** - - rust/agama-lib/** - # ignore the JSON profile and the examples - - "!rust/agama-lib/share/**" - - rust/share/*.service - - # the playwright tests and configs - - playwright/**.ts - - playwright/config/agama.yaml - - pull_request: - paths: - # NOTE: GitHub Actions do not allow using YAML references, the same path - # list is used above for the push event. Keep both lists in sync!! - - # this file itself - - .github/workflows/ci-integration-tests.yml - - # the web frontend - - web/**.json - - web/**.html - - web/**.scss - - web/**.jsx? - # ignore unit tests, we do not run them here - - "!web/**.test.jsx?" - - web/Makefile - - # the service backend - - setup-service.sh - - service/lib/**.rb - - service/bin/agamactl - - service/Gemfile* - - service/*.gemspec - # D-Bus and systemd configs - - service/share/*.conf - - service/share/*.service - # Rust services - - rust/Cargo.lock - - rust/agama-dbus-server/** - - rust/agama-locale-data/** - - rust/agama-lib/** - # ignore the JSON profile and the examples - - "!rust/agama-lib/share/**" - - rust/share/*.service - - # the playwright tests and configs - - playwright/**.ts - - playwright/config/agama.yaml + schedule: + # at 10:50 every day from Monday to Friday + - cron: "50 10 * * 1-5" + + # allow running manually + workflow_dispatch: jobs: integration-tests: timeout-minutes: 60 runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - # TW is needed because of the Cockpit packages - distro: [ "tumbleweed" ] - steps: # TODO: Reuse/share building the frontend and backend with the other steps @@ -154,7 +77,7 @@ jobs: - name: Upload the test results uses: actions/upload-artifact@v3 - # run even when the previous step fails + # run even when any previous step fails if: always() with: name: test-results @@ -162,3 +85,12 @@ jobs: path: | playwright/test-results/**/* /tmp/log/YaST2/y2log + + - name: IRC notification + # see https://github.com/marketplace/actions/irc-message-action + uses: Gottox/irc-message-action@v2 + if: failure() + with: + channel: "#yast" + nickname: github-action + message: "Agama integration test failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"