Merge branch 'develop' into johannes/webpack-5

This commit is contained in:
Johannes Marbach 2023-11-16 19:20:22 +01:00
commit a56a2268f0
14 changed files with 881 additions and 1023 deletions

View file

@ -91,7 +91,7 @@ jobs:
running-workflow-name: "Build & Deploy develop.element.io" running-workflow-name: "Build & Deploy develop.element.io"
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10 wait-interval: 10
check-regexp: ^((?!SonarCloud|SonarQube|issue|board|label).)*$ check-regexp: ^((?!SonarCloud|SonarQube|issue|board|label|Release).)*$
# We keep the latest develop.tar.gz on R2 instead of relying on the github artifact uploaded earlier # We keep the latest develop.tar.gz on R2 instead of relying on the github artifact uploaded earlier
# as the expires after 24h and requires auth to download. # as the expires after 24h and requires auth to download.

View file

@ -9,7 +9,7 @@ jobs:
name: Tidy closed issues name: Tidy closed issues
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/github-script@v6 - uses: actions/github-script@v7
id: main id: main
with: with:
# PAT needed as the GITHUB_TOKEN won't be able to see cross-references from other orgs (matrix-org) # PAT needed as the GITHUB_TOKEN won't be able to see cross-references from other orgs (matrix-org)
@ -141,7 +141,7 @@ jobs:
}); });
} }
} }
- uses: actions/github-script@v6 - uses: actions/github-script@v7
name: Close duplicate as Not Planned name: Close duplicate as Not Planned
if: steps.main.outputs.closeAsNotPlanned if: steps.main.outputs.closeAsNotPlanned
with: with:

View file

@ -13,7 +13,7 @@ jobs:
URL: "https://github.com/pulls?q=is%3Apr+is%3Aopen+repo%3Amatrix-org%2Fmatrix-js-sdk+repo%3Amatrix-org%2Fmatrix-react-sdk+repo%3Avector-im%2Felement-web+repo%3Avector-im%2Felement-desktop+review-requested%3A%40me+sort%3Aupdated-desc+" URL: "https://github.com/pulls?q=is%3Apr+is%3Aopen+repo%3Amatrix-org%2Fmatrix-js-sdk+repo%3Amatrix-org%2Fmatrix-react-sdk+repo%3Avector-im%2Felement-web+repo%3Avector-im%2Felement-desktop+review-requested%3A%40me+sort%3Aupdated-desc+"
RELEASE_BLOCKERS_URL: "https://github.com/pulls?q=is%3Aopen+repo%3Amatrix-org%2Fmatrix-js-sdk+repo%3Amatrix-org%2Fmatrix-react-sdk+repo%3Avector-im%2Felement-web+repo%3Avector-im%2Felement-desktop+sort%3Aupdated-desc+label%3AX-Release-Blocker+" RELEASE_BLOCKERS_URL: "https://github.com/pulls?q=is%3Aopen+repo%3Amatrix-org%2Fmatrix-js-sdk+repo%3Amatrix-org%2Fmatrix-react-sdk+repo%3Avector-im%2Felement-web+repo%3Avector-im%2Felement-desktop+sort%3Aupdated-desc+label%3AX-Release-Blocker+"
steps: steps:
- uses: actions/github-script@v6 - uses: actions/github-script@v7
env: env:
HS_URL: ${{ secrets.BETABOT_HS_URL }} HS_URL: ${{ secrets.BETABOT_HS_URL }}
ROOM_ID: ${{ secrets.ROOM_ID }} ROOM_ID: ${{ secrets.ROOM_ID }}

View file

@ -2,13 +2,20 @@ name: Release Drafter
on: on:
push: push:
branches: [staging] branches: [staging]
workflow_dispatch:
inputs:
previous-version:
description: What release to use as a base for release note purposes
required: false
type: string
concurrency: ${{ github.workflow }} concurrency: ${{ github.workflow }}
jobs: jobs:
draft: draft:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: release-drafter/release-drafter@dabcf3767562210392d862070ed2ef6434b9bc6f # v5 - uses: release-drafter/release-drafter@e64b19c4c46173209ed9f2e5a2f4ca7de89a0e86 # v5
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
disable-autolabeler: true disable-autolabeler: true
previous-version: ${{ inputs.previous-version }}

View file

@ -24,7 +24,10 @@ concurrency: ${{ github.workflow }}
jobs: jobs:
release: release:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-action.yml@develop uses: matrix-org/matrix-js-sdk/.github/workflows/release-action.yml@develop
secrets: inherit secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
with: with:
final: ${{ inputs.mode == 'final' }} final: ${{ inputs.mode == 'final' }}
include-changes: matrix-react-sdk include-changes: matrix-react-sdk

View file

@ -27,7 +27,7 @@ jobs:
contains(github.event.issue.labels.*.name, 'A-Element-Call') || contains(github.event.issue.labels.*.name, 'A-Element-Call') ||
contains(github.event.issue.labels.*.name, 'A-Element-R') contains(github.event.issue.labels.*.name, 'A-Element-R')
steps: steps:
- uses: actions/github-script@v6 - uses: actions/github-script@v7
with: with:
script: | script: |
github.rest.issues.addLabels({ github.rest.issues.addLabels({
@ -44,7 +44,7 @@ jobs:
contains(github.event.issue.labels.*.name, 'good first issue') || contains(github.event.issue.labels.*.name, 'good first issue') ||
contains(github.event.issue.labels.*.name, 'Hacktoberfest') contains(github.event.issue.labels.*.name, 'Hacktoberfest')
steps: steps:
- uses: actions/github-script@v6 - uses: actions/github-script@v7
with: with:
script: | script: |
github.rest.issues.addLabels({ github.rest.issues.addLabels({

View file

@ -60,7 +60,7 @@ jobs:
contains(github.event.issue.labels.*.name, 'A-Element-Call')) && contains(github.event.issue.labels.*.name, 'A-Element-Call')) &&
contains(github.event.issue.labels.*.name, 'Z-Labs') contains(github.event.issue.labels.*.name, 'Z-Labs')
steps: steps:
- uses: actions/github-script@v6 - uses: actions/github-script@v7
with: with:
script: | script: |
github.rest.issues.removeLabel({ github.rest.issues.removeLabel({

View file

@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: Matrix environment: Matrix
steps: steps:
- uses: actions/github-script@v6 - uses: actions/github-script@v7
env: env:
HS_URL: ${{ secrets.BETABOT_HS_URL }} HS_URL: ${{ secrets.BETABOT_HS_URL }}
LOBBY_ROOM_ID: ${{ secrets.ROOM_ID }} LOBBY_ROOM_ID: ${{ secrets.ROOM_ID }}

View file

@ -23,6 +23,8 @@ electron/pub
src/vector/index.html src/vector/index.html
src/vector/modernizr.js src/vector/modernizr.js
/docs/lib /docs/lib
/book
/debian/tmp
# This file is owned, parsed, and generated by allchange, which doesn't comply with prettier # This file is owned, parsed, and generated by allchange, which doesn't comply with prettier
/CHANGELOG.md /CHANGELOG.md

View file

@ -45,9 +45,9 @@
"build:bundle-stats": "webpack --progress --mode production --json > webpack-stats.json", "build:bundle-stats": "webpack --progress --mode production --json > webpack-stats.json",
"build:module_system": "tsc --project ./tsconfig.module_system.json && node ./lib/module_system/scripts/install.js", "build:module_system": "tsc --project ./tsconfig.module_system.json && node ./lib/module_system/scripts/install.js",
"dist": "scripts/package.sh", "dist": "scripts/package.sh",
"start": "yarn build:module_system && concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n res,element-js \"yarn start:res\" \"yarn start:js\"", "start": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n modules,res,jitsi \"yarn build:module_system\" \"yarn build:res\" \"yarn build:jitsi\" && concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n res,element-js \"yarn start:res\" \"yarn start:js\"",
"start:https": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n res,element-js \"yarn start:res\" \"yarn start:js --https\"", "start:https": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n res,element-js \"yarn start:res\" \"yarn start:js --https\"",
"start:res": "yarn build:jitsi && ts-node scripts/copy-res.ts -w", "start:res": "ts-node scripts/copy-res.ts -w",
"start:js": "webpack serve --output-path webapp --output-filename=bundles/_dev_/[name].js --output-chunk-filename=bundles/_dev_/[name].js --mode development", "start:js": "webpack serve --output-path webapp --output-filename=bundles/_dev_/[name].js --output-chunk-filename=bundles/_dev_/[name].js --mode development",
"lint": "yarn lint:types && yarn lint:js && yarn lint:style", "lint": "yarn lint:types && yarn lint:js && yarn lint:style",
"lint:js": "yarn lint:js:src && yarn lint:js:module_system", "lint:js": "yarn lint:js:src && yarn lint:js:module_system",
@ -123,12 +123,12 @@
"buffer": "^6.0.3", "buffer": "^6.0.3",
"chokidar": "^3.5.1", "chokidar": "^3.5.1",
"concurrently": "^8.0.0", "concurrently": "^8.0.0",
"cpx": "1.5.0", "copy-webpack-plugin": "^6.0.0",
"cronstrue": "^2.41.0", "cronstrue": "^2.41.0",
"css-loader": "^4", "css-loader": "^4",
"css-minimizer-webpack-plugin": "^5.0.1", "css-minimizer-webpack-plugin": "^5.0.1",
"dotenv": "^16.0.2", "dotenv": "^16.0.2",
"eslint": "8.52.0", "eslint": "8.53.0",
"eslint-config-google": "^0.14.0", "eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-deprecate": "0.8.4", "eslint-plugin-deprecate": "0.8.4",
@ -138,16 +138,15 @@
"eslint-plugin-react-hooks": "^4.3.0", "eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-unicorn": "^49.0.0", "eslint-plugin-unicorn": "^49.0.0",
"fake-indexeddb": "^5.0.0", "fake-indexeddb": "^5.0.0",
"fetch-mock": "9.11.0",
"fetch-mock-jest": "^1.5.1", "fetch-mock-jest": "^1.5.1",
"file-loader": "^6.0.0", "file-loader": "^6.0.0",
"fs-extra": "^11.0.0",
"html-webpack-plugin": "^5.5.3", "html-webpack-plugin": "^5.5.3",
"jest": "^29.0.0", "jest": "^29.0.0",
"jest-canvas-mock": "2.5.2", "jest-canvas-mock": "2.5.2",
"jest-environment-jsdom": "^29.0.0", "jest-environment-jsdom": "^29.0.0",
"jest-mock": "^29.0.0", "jest-mock": "^29.0.0",
"jest-raw-loader": "^1.0.1", "jest-raw-loader": "^1.0.1",
"json-loader": "^0.5.7",
"matrix-mock-request": "^2.5.0", "matrix-mock-request": "^2.5.0",
"matrix-web-i18n": "^3.1.3", "matrix-web-i18n": "^3.1.3",
"mini-css-extract-plugin": "^2.7.6", "mini-css-extract-plugin": "^2.7.6",

View file

@ -6,7 +6,6 @@ import parseArgs from "minimist";
import * as chokidar from "chokidar"; import * as chokidar from "chokidar";
import * as fs from "node:fs"; import * as fs from "node:fs";
import _ from "lodash"; import _ from "lodash";
import { Cpx } from "cpx";
import { util } from "webpack"; import { util } from "webpack";
import { Translations } from "matrix-web-i18n"; import { Translations } from "matrix-web-i18n";
@ -16,29 +15,6 @@ const INCLUDE_LANGS = [...new Set([...fs.readdirSync(I18N_BASE_PATH), ...fs.read
.filter((fn) => fn.endsWith(".json")) .filter((fn) => fn.endsWith(".json"))
.map((f) => f.slice(0, -5)); .map((f) => f.slice(0, -5));
// cpx includes globbed parts of the filename in the destination, but excludes
// common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and
// "dest/b/...".
const COPY_LIST: [
sourceGlob: string,
outputPath: string,
opts?: {
directwatch?: 1;
},
][] = [
["res/apple-app-site-association", "webapp"],
["res/manifest.json", "webapp"],
["res/sw.js", "webapp"],
["res/welcome.html", "webapp"],
["res/welcome/**", "webapp/welcome"],
["res/themes/**", "webapp/themes"],
["res/vector-icons/**", "webapp/vector-icons"],
["res/decoder-ring/**", "webapp/decoder-ring"],
["node_modules/matrix-react-sdk/res/media/**", "webapp/media"],
["node_modules/@matrix-org/olm/olm_legacy.js", "webapp", { directwatch: 1 }],
["./config.json", "webapp", { directwatch: 1 }],
["contribute.json", "webapp"],
];
const argv = parseArgs(process.argv.slice(2), {}); const argv = parseArgs(process.argv.slice(2), {});
const watch = argv.w; const watch = argv.w;
@ -60,53 +36,13 @@ if (!fs.existsSync("webapp/i18n/")) {
fs.mkdirSync("webapp/i18n/"); fs.mkdirSync("webapp/i18n/");
} }
function next(i: number, err?: Error): void { const logWatch = (path: string) => {
errCheck(err);
if (i >= COPY_LIST.length) {
return;
}
const ent = COPY_LIST[i];
const source = ent[0];
const dest = ent[1];
const opts = ent[2] || {};
const cpx = new Cpx(source, dest);
if (verbose) { if (verbose) {
cpx.on("copy", (event) => { console.log(`Watching: ${path}`);
console.log(`Copied: ${event.srcPath} --> ${event.dstPath}`);
});
cpx.on("remove", (event) => {
console.log(`Removed: ${event.path}`);
});
} }
const cb = (err?: Error): void => {
next(i + 1, err);
}; };
if (watch) { function prepareLangFile(lang: string, dest: string): [filename: string, json: string] {
if (opts.directwatch) {
// cpx -w creates a watcher for the parent of any files specified,
// which in the case of config.json is '.', which inevitably takes
// ages to crawl. So we create our own watcher on the files
// instead.
const copy = (): void => {
cpx.copy(errCheck);
};
chokidar.watch(source).on("add", copy).on("change", copy).on("ready", cb).on("error", errCheck);
} else {
cpx.on("watch-ready", cb);
cpx.on("watch-error", cb);
cpx.watch();
}
} else {
cpx.copy(cb);
}
}
function genLangFile(lang: string, dest: string): string {
const reactSdkFile = REACT_I18N_BASE_PATH + lang + ".json"; const reactSdkFile = REACT_I18N_BASE_PATH + lang + ".json";
const riotWebFile = I18N_BASE_PATH + lang + ".json"; const riotWebFile = I18N_BASE_PATH + lang + ".json";
@ -127,12 +63,14 @@ function genLangFile(lang: string, dest: string): string {
const digest = util.createHash("xxhash64").update(jsonBuffer).digest("hex").slice(0, 7); const digest = util.createHash("xxhash64").update(jsonBuffer).digest("hex").slice(0, 7);
const filename = `${lang}.${digest}.json`; const filename = `${lang}.${digest}.json`;
return [filename, json];
}
function genLangFile(dest: string, filename: string, json: string) {
fs.writeFileSync(dest + filename, json); fs.writeFileSync(dest + filename, json);
if (verbose) { if (verbose) {
console.log("Generated language file: " + filename); console.log("Generated language file: " + filename);
} }
return filename;
} }
function genLangList(langFileMap: Record<string, string>): void { function genLangList(langFileMap: Record<string, string>): void {
@ -175,29 +113,38 @@ function watchLanguage(lang: string, dest: string, langFileMap: Record<string, s
clearTimeout(makeLangDebouncer); clearTimeout(makeLangDebouncer);
} }
makeLangDebouncer = setTimeout(() => { makeLangDebouncer = setTimeout(() => {
const filename = genLangFile(lang, dest); const [filename, json] = prepareLangFile(lang, dest);
genLangFile(dest, filename, json);
langFileMap[lang] = filename; langFileMap[lang] = filename;
genLangList(langFileMap); genLangList(langFileMap);
}, 500); }, 500);
}; };
[reactSdkFile, riotWebFile].forEach(function (f) { [reactSdkFile, riotWebFile].forEach(function (f) {
chokidar.watch(f).on("add", makeLang).on("change", makeLang).on("error", errCheck); chokidar
.watch(f, { ignoreInitial: true })
.on("ready", () => {
logWatch(f);
})
.on("add", makeLang)
.on("change", makeLang)
.on("error", errCheck);
}); });
} }
// language resources // language resources
const I18N_DEST = "webapp/i18n/"; const I18N_DEST = "webapp/i18n/";
const I18N_FILENAME_MAP = INCLUDE_LANGS.reduce<Record<string, string>>((m, l) => { const I18N_FILENAME_MAP = INCLUDE_LANGS.reduce<Record<string, string>>((m, l) => {
const filename = genLangFile(l, I18N_DEST); const [filename, json] = prepareLangFile(l, I18N_DEST);
if (!watch) {
genLangFile(I18N_DEST, filename, json);
}
m[l] = filename; m[l] = filename;
return m; return m;
}, {}); }, {});
genLangList(I18N_FILENAME_MAP);
if (watch) { if (watch) {
INCLUDE_LANGS.forEach((l) => watchLanguage(l, I18N_DEST, I18N_FILENAME_MAP)); INCLUDE_LANGS.forEach((l) => watchLanguage(l, I18N_DEST, I18N_FILENAME_MAP));
} else {
genLangList(I18N_FILENAME_MAP);
} }
// non-language resources
next(0);

43
src/@types/cpx.d.ts vendored
View file

@ -1,43 +0,0 @@
/*
Copyright 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
declare module "cpx" {
export class Cpx {
public constructor(source: string, outDir: string, options?: object);
public on(eventName: "copy", fn: (event: { srcPath: string; dstPath: string }) => void): void;
public on(eventName: "remove", fn: (event: { path: string }) => void): void;
public on(eventName: "watch-ready", fn: () => void): void;
public on(eventName: "watch-error", fn: (error: Error) => void): void;
/**
* Copy all files that matches `this.source` pattern to `this.outDir`.
*
* @param {function} [cb = null] - A callback function.
* @returns {void}
*/
public copy(cb: Function | null): void;
/**
* Copy all files that matches `this.source` pattern to `this.outDir`.
* And watch changes in `this.base`, and copy only the file every time.
*
* @returns {void}
* @throws {Error} This had been watching already.
*/
public watch(): void;
}
}

View file

@ -10,6 +10,7 @@ const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const HtmlWebpackInjectPreload = require("@principalstudio/html-webpack-inject-preload"); const HtmlWebpackInjectPreload = require("@principalstudio/html-webpack-inject-preload");
const { sentryWebpackPlugin } = require("@sentry/webpack-plugin"); const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");
const crypto = require("crypto"); const crypto = require("crypto");
const CopyWebpackPlugin = require("copy-webpack-plugin");
// XXX: mangle Crypto::createHash to replace md4 with sha256, output.hashFunction is insufficient as multiple bits // XXX: mangle Crypto::createHash to replace md4 with sha256, output.hashFunction is insufficient as multiple bits
// of webpack hardcode md4. The proper fix it to upgrade to webpack 5. // of webpack hardcode md4. The proper fix it to upgrade to webpack 5.
@ -707,8 +708,25 @@ module.exports = (env, argv) => {
new webpack.EnvironmentPlugin(["VERSION"]), new webpack.EnvironmentPlugin(["VERSION"]),
new CopyWebpackPlugin({
patterns: [
"res/apple-app-site-association",
"res/manifest.json",
"res/sw.js",
"res/welcome.html",
{ from: "welcome/**", context: path.resolve(__dirname, "res") },
{ from: "themes/**", context: path.resolve(__dirname, "res") },
{ from: "vector-icons/**", context: path.resolve(__dirname, "res") },
{ from: "decoder-ring/**", context: path.resolve(__dirname, "res") },
{ from: "media/**", context: path.resolve(__dirname, "node_modules/matrix-react-sdk/res/") },
"node_modules/@matrix-org/olm/olm_legacy.js",
{ from: "config.json", noErrorOnMissing: true },
"contribute.json",
],
}),
// Automatically load buffer & process modules as we use them without explicitly // Automatically load buffer & process modules as we use them without explicitly
// importing them. // importing them
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
Buffer: ["buffer", "Buffer"], Buffer: ["buffer", "Buffer"],
process: "process/browser", process: "process/browser",

1697
yarn.lock

File diff suppressed because it is too large Load diff