diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml index 55ea64b90..e3cbf9365 100644 --- a/.github/workflows/backend-tests.yml +++ b/.github/workflows/backend-tests.yml @@ -28,27 +28,28 @@ jobs: fail-fast: false matrix: # PRs: test on latest Node only. Push to develop: full matrix. - node: ${{ github.event_name == 'pull_request' && fromJSON('[">=24.0.0 <25.0.0"]') || fromJSON('[">=20.0.0 <21.0.0", ">=22.0.0 <23.0.0", ">=24.0.0 <25.0.0"]') }} + node: ${{ github.event_name == 'pull_request' && fromJSON('[24]') || fromJSON('[20, 22, 24]') }} steps: - name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.PNPM_HOME }} - ~/.local/share/gnpm - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false + - name: Use Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + cache: pnpm - name: Install libreoffice uses: awalsh128/cache-apt-pkgs-action@v1.6.0 @@ -57,19 +58,19 @@ jobs: version: 1.0 - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm i --frozen-lockfile --runtimeVersion="${{ matrix.node }}" + run: pnpm i --frozen-lockfile - name: Install admin ui working-directory: admin - run: gnpm install --runtimeVersion="${{ matrix.node }}" + run: pnpm install - name: Build admin ui working-directory: admin - run: gnpm build --runtimeVersion="${{ matrix.node }}" + run: pnpm build - name: Run the backend tests - run: gnpm test --runtimeVersion="${{ matrix.node }}" + run: pnpm test - name: Run the new vitest tests working-directory: src - run: gnpm run test:vitest --runtimeVersion="${{ matrix.node }}" + run: pnpm run test:vitest withpluginsLinux: env: @@ -84,27 +85,28 @@ jobs: strategy: fail-fast: false matrix: - node: ${{ github.event_name == 'pull_request' && fromJSON('[">=24.0.0 <25.0.0"]') || fromJSON('[">=20.0.0 <21.0.0", ">=22.0.0 <23.0.0", ">=24.0.0 <25.0.0"]') }} + node: ${{ github.event_name == 'pull_request' && fromJSON('[24]') || fromJSON('[20, 22, 24]') }} steps: - name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup pnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.PNPM_HOME }} - ~/.local/share/gnpm - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false + - name: Use Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + cache: pnpm - name: Install libreoffice uses: awalsh128/cache-apt-pkgs-action@v1.6.0 @@ -113,14 +115,14 @@ jobs: version: 1.0 - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile --runtimeVersion="${{ matrix.node }}" + run: pnpm install --frozen-lockfile - name: Build admin ui working-directory: admin - run: gnpm build --runtimeVersion="${{ matrix.node }}" + run: pnpm build - name: Install Etherpad plugins run: > - gnpm install --workspace-root + pnpm add -w ep_align ep_author_hover ep_cursortrace @@ -134,10 +136,10 @@ jobs: ep_table_of_contents - name: Run the backend tests - run: gnpm test --runtimeVersion="${{ matrix.node }}" + run: pnpm test - name: Run the new vitest tests working-directory: src - run: gnpm run test:vitest --runtimeVersion="${{ matrix.node }}" + run: pnpm run test:vitest # Windows tests only run on push to develop/master, not on PRs withoutpluginsWindows: @@ -148,7 +150,7 @@ jobs: strategy: fail-fast: false matrix: - node: [">=20.0.0 <21.0.0", ">=22.0.0 <23.0.0", ">=24.0.0 <25.0.0"] + node: [20, 22, 24] name: Windows without plugins runs-on: windows-latest steps: @@ -156,26 +158,28 @@ jobs: name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup pnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.PNPM_HOME }} - C:\gnpm\ - C:\Users\runneradmin\AppData\Roaming\gnpm\ - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false + - name: Use Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + cache: pnpm - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile --runtimeVersion="${{ matrix.node }}" + run: pnpm install --frozen-lockfile - name: Build admin ui working-directory: admin - run: gnpm build --runtimeVersion="${{ matrix.node }}" + run: pnpm build - name: Fix up the settings.json run: | @@ -184,10 +188,10 @@ jobs: - name: Run the backend tests working-directory: src - run: gnpm test --runtimeVersion="${{ matrix.node }}" + run: pnpm test - name: Run the new vitest tests working-directory: src - run: gnpm run test:vitest --runtimeVersion="${{ matrix.node }}" + run: pnpm run test:vitest withpluginsWindows: env: @@ -197,7 +201,7 @@ jobs: strategy: fail-fast: false matrix: - node: [">=20.0.0 <21.0.0", ">=22.0.0 <23.0.0", ">=24.0.0 <25.0.0"] + node: [20, 22, 24] name: Windows with Plugins runs-on: windows-latest @@ -206,29 +210,31 @@ jobs: name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup pnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.PNPM_HOME }} - C:\gnpm\ - C:\Users\runneradmin\AppData\Roaming\gnpm\ - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false + - name: Use Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + cache: pnpm - name: Install dependencies - run: gnpm install --runtimeVersion="${{ matrix.node }}" + run: pnpm install - name: Build admin ui working-directory: admin - run: gnpm build --runtimeVersion="${{ matrix.node }}" + run: pnpm build - name: Install Etherpad plugins run: > - gnpm install --workspace-root + pnpm add -w ep_align ep_author_hover ep_cursortrace @@ -251,7 +257,7 @@ jobs: # rules. - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile --runtimeVersion="${{ matrix.node }}" + run: pnpm install --frozen-lockfile - name: Fix up the settings.json run: | @@ -260,7 +266,7 @@ jobs: - name: Run the backend tests working-directory: src - run: gnpm test --runtimeVersion="${{ matrix.node }}" + run: pnpm test - name: Run the new vitest tests working-directory: src - run: gnpm run test:vitest --runtimeVersion="${{ matrix.node }}" + run: pnpm run test:vitest diff --git a/.github/workflows/build-and-deploy-docs.yml b/.github/workflows/build-and-deploy-docs.yml index 6482328bd..84cb1bb00 100644 --- a/.github/workflows/build-and-deploy-docs.yml +++ b/.github/workflows/build-and-deploy-docs.yml @@ -34,28 +34,31 @@ jobs: - name: Checkout uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.STORE_PATH }} - ~/.local/share/gnpm - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ~/.pnpm-store + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: actions/cache@v5 + name: Cache vitepress build with: - version: 0.0.12 + path: doc/.vitepress/cache + key: ${{ runner.os }}-vitepress-${{ hashFiles('doc/**/*.md', 'doc/.vitepress/config.*') }} + restore-keys: | + ${{ runner.os }}-vitepress- + - uses: pnpm/action-setup@v6 + name: Install pnpm + with: + version: 10.33.2 + run_install: false - name: Setup Pages uses: actions/configure-pages@v6 - name: Install dependencies - run: gnpm install + run: pnpm install --frozen-lockfile - name: Build app working-directory: doc - run: gnpm run docs:build + run: pnpm run docs:build env: COMMIT_REF: ${{ github.sha }} - name: Upload artifact diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4c97bcf52..35811cad5 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -43,21 +43,17 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.PNPM_HOME }} - ~/.local/share/gnpm - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false - name: Test working-directory: etherpad @@ -74,7 +70,7 @@ jobs: *) printf %s\\n "unexpected status: ${status}" >&2; exit 1;; esac done - (cd src && gnpm run test-container) + (cd src && pnpm run test-container) git clean -dxf . build-test-db-drivers: diff --git a/.github/workflows/frontend-admin-tests.yml b/.github/workflows/frontend-admin-tests.yml index f31f442f8..dff5fc24d 100644 --- a/.github/workflows/frontend-admin-tests.yml +++ b/.github/workflows/frontend-admin-tests.yml @@ -29,24 +29,25 @@ jobs: name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.PNPM_HOME }} - ~/.local/share/gnpm - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false + - name: Use Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + cache: pnpm - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm i --runtimeVersion="${{ matrix.node }}" + run: pnpm i - name: Cache Playwright browsers uses: actions/cache@v5 id: playwright-cache @@ -71,11 +72,11 @@ jobs: - name: Build admin frontend working-directory: admin run: | - gnpm run build --runtimeVersion="${{ matrix.node }}" + pnpm run build - name: Run the frontend admin tests shell: bash run: | - gnpm run prod --runtimeVersion="${{ matrix.node }}" > /tmp/etherpad-server.log 2>&1 & + pnpm run prod > /tmp/etherpad-server.log 2>&1 & connected=false can_connect() { curl -sSfo /dev/null http://localhost:9001/ || return 1 @@ -87,7 +88,7 @@ jobs: sleep 1 done cd src - gnpm run test-admin --runtimeVersion="${{ matrix.node }}" + pnpm run test-admin - name: Upload server log on failure uses: actions/upload-artifact@v7 if: failure() diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml index da5ce0a3b..c972000b0 100644 --- a/.github/workflows/frontend-tests.yml +++ b/.github/workflows/frontend-tests.yml @@ -22,32 +22,34 @@ jobs: name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.PNPM_HOME }} - ~/.cache/ms-playwright - ~/.local/share/gnpm - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: actions/cache@v5 + name: Cache Playwright browsers with: - version: 0.0.12 + path: ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ hashFiles('src/package.json', 'pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-playwright- + - uses: pnpm/action-setup@v6 + name: Install pnpm + with: + version: 10.33.2 + run_install: false - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Create settings.json run: cp ./src/tests/settings.json settings.json - name: Run the frontend tests shell: bash run: | - gnpm run prod > /tmp/etherpad-server.log 2>&1 & + pnpm run prod > /tmp/etherpad-server.log 2>&1 & connected=false can_connect() { curl -sSfo /dev/null http://localhost:9001/ || return 1 @@ -59,8 +61,8 @@ jobs: sleep 1 done cd src - gnpm exec playwright install chromium --with-deps - gnpm run test-ui --project=chromium + pnpm exec playwright install chromium --with-deps + pnpm run test-ui --project=chromium - name: Upload server log on failure uses: actions/upload-artifact@v7 if: failure() @@ -83,30 +85,32 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.PNPM_HOME }} - ~/.local/share/gnpm - ~/.cache/ms-playwright - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: actions/cache@v5 + name: Cache Playwright browsers with: - version: 0.0.12 + path: ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ hashFiles('src/package.json', 'pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-playwright- + - uses: pnpm/action-setup@v6 + name: Install pnpm + with: + version: 10.33.2 + run_install: false - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Create settings.json run: cp ./src/tests/settings.json settings.json - name: Run the frontend tests shell: bash run: | - gnpm run prod > /tmp/etherpad-server.log 2>&1 & + pnpm run prod > /tmp/etherpad-server.log 2>&1 & connected=false can_connect() { curl -sSfo /dev/null http://localhost:9001/ || return 1 @@ -118,8 +122,8 @@ jobs: sleep 1 done cd src - gnpm exec playwright install firefox --with-deps - gnpm run test-ui --project=firefox + pnpm exec playwright install firefox --with-deps + pnpm run test-ui --project=firefox - name: Upload server log on failure uses: actions/upload-artifact@v7 if: failure() diff --git a/.github/workflows/handleRelease.yml b/.github/workflows/handleRelease.yml index a69d20b6f..3149d2172 100644 --- a/.github/workflows/handleRelease.yml +++ b/.github/workflows/handleRelease.yml @@ -29,30 +29,28 @@ jobs: name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.STORE_PATH }} - ~/.local/share/gnpm - ~/.cache/ms-playwright - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Build etherpad - run: gnpm run build:etherpad - # On release, create release + run: pnpm run build:etherpad + # On release, create release. `--silent` suppresses pnpm's lifecycle + # banner ("> generateChangelog\n> node ...") that would otherwise be + # captured into CHANGELOG.txt and end up at the top of the GitHub + # release notes. - name: Generate Changelog working-directory: bin - run: gnpm run generateChangelog ${{ github.ref }} > ${{ github.workspace }}-CHANGELOG.txt + run: pnpm --silent run generateChangelog ${{ github.ref }} > ${{ github.workspace }}-CHANGELOG.txt - name: Release uses: softprops/action-gh-release@v3 if: ${{startsWith(github.ref, 'refs/tags/v') }} diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml index 46a960aab..06660afdb 100644 --- a/.github/workflows/load-test.yml +++ b/.github/workflows/load-test.yml @@ -26,35 +26,26 @@ jobs: name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.STORE_PATH }} - ~/.local/share/gnpm - ~/.cache/ms-playwright - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Install etherpad-load-test run: sudo npm install -g etherpad-load-test-socket-io - name: Run load test - run: | - gnpm --gnpmEnv - eval "$(gnpm --gnpmEnv)" - echo $PATH - src/tests/frontend/travis/runnerLoadTest.sh 25 50 + run: src/tests/frontend/travis/runnerLoadTest.sh 25 50 withplugins: # run on pushes to any branch @@ -69,31 +60,24 @@ jobs: name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.STORE_PATH }} - ~/.local/share/gnpm - ~/.cache/ms-playwright - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false - name: Install etherpad-load-test run: sudo npm install -g etherpad-load-test-socket-io - name: Install etherpad plugins - # The --legacy-peer-deps flag is required to work around a bug in npm v7: - # https://github.com/npm/cli/issues/2199 run: > - gnpm install --workspace-root + pnpm add -w ep_align ep_author_hover ep_cursortrace @@ -117,12 +101,10 @@ jobs: # rules. - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Run load test - run: | - eval "$(gnpm --gnpmEnv)" - src/tests/frontend/travis/runnerLoadTest.sh 25 50 + run: src/tests/frontend/travis/runnerLoadTest.sh 25 50 long: # run on pushes to any branch @@ -137,32 +119,23 @@ jobs: name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.STORE_PATH }} - ~/.local/share/gnpm - ~/.cache/ms-playwright - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Install etherpad-load-test run: sudo npm install -g etherpad-load-test-socket-io - name: Run load test - run: | - gnpm --gnpmEnv - eval "$(gnpm --gnpmEnv)" - echo $PATH - src/tests/frontend/travis/runnerLoadTest.sh 5000 5 + run: src/tests/frontend/travis/runnerLoadTest.sh 5000 5 diff --git a/.github/workflows/perform-type-check.yml b/.github/workflows/perform-type-check.yml index a2105615e..aacfe279f 100644 --- a/.github/workflows/perform-type-check.yml +++ b/.github/workflows/perform-type-check.yml @@ -26,25 +26,19 @@ jobs: - name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.STORE_PATH }} - ~/.local/share/gnpm - ~/.cache/ms-playwright - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 - - - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile + version: 10.33.2 + run_install: false + - name: Install all dependencies and symlink for ep_etherpad-lite + run: pnpm install --frozen-lockfile - name: Perform type check working-directory: ./src - run: gnpm run ts-check + run: pnpm run ts-check diff --git a/.github/workflows/rate-limit.yml b/.github/workflows/rate-limit.yml index 0a0699c6f..861d576c2 100644 --- a/.github/workflows/rate-limit.yml +++ b/.github/workflows/rate-limit.yml @@ -29,22 +29,17 @@ jobs: name: Checkout repository uses: actions/checkout@v6 - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.STORE_PATH }} - ~/.local/share/gnpm - ~/.cache/ms-playwright - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false - name: docker network @@ -63,7 +58,7 @@ jobs: docker run --rm --network ep_net --ip 172.23.42.3 --name anotherip -dt anotherip - name: install dependencies and create symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: run rate limit test run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d77f94641..e9eb3d373 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,24 +48,19 @@ jobs: path: ether.github.com token: '${{ secrets.ETHER_RELEASE_TOKEN }}' - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.STORE_PATH }} - ~/.local/share/gnpm - ~/.cache/ms-playwright - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false - name: Install dependencies ether.github.com - run: gnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile working-directory: ether.github.com - name: Set git user run: | @@ -82,8 +77,8 @@ jobs: working-directory: etherpad run: | cd bin - gnpm install - gnpm run release ${{ inputs.release_type }} + pnpm install + pnpm run release ${{ inputs.release_type }} - name: Push after release working-directory: etherpad run: | diff --git a/.github/workflows/releaseEtherpad.yml b/.github/workflows/releaseEtherpad.yml index e9575a494..731ae2930 100644 --- a/.github/workflows/releaseEtherpad.yml +++ b/.github/workflows/releaseEtherpad.yml @@ -23,33 +23,25 @@ jobs: registry-url: https://registry.npmjs.org/ - name: Upgrade npm to >=11.5.1 (required for trusted publishing) run: npm install -g npm@latest - - name: Get pnpm store directory - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - uses: actions/cache@v5 - name: Setup pnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.STORE_PATH }} - ~/.local/share/gnpm - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false - name: Install dependencies - run: gnpm install --frozen-lockfile + run: pnpm install --frozen-lockfile - name: Rename etherpad working-directory: ./src run: sed -i 's/ep_etherpad-lite/ep_etherpad/g' package.json - # Use `npm publish` directly (not `gnpm`/`pnpm` wrappers) because OIDC - # trusted publishing requires npm CLI >= 11.5.1 and the wrappers shell + # Use `npm publish` directly (not the `pnpm` wrapper) because OIDC + # trusted publishing requires npm CLI >= 11.5.1 and the wrapper shells # out to npm; calling npm directly avoids any shim ambiguity. The # ep_etherpad package must have a trusted publisher configured on # npmjs.com pointing at this workflow file. See: diff --git a/.github/workflows/update-plugins.yml b/.github/workflows/update-plugins.yml index 4b6a282a8..447ecdcf1 100644 --- a/.github/workflows/update-plugins.yml +++ b/.github/workflows/update-plugins.yml @@ -21,7 +21,7 @@ jobs: - uses: pnpm/action-setup@v6 name: Install pnpm with: - version: 10 + version: 10.33.2 run_install: false - name: Use Node.js diff --git a/.github/workflows/upgrade-from-latest-release.yml b/.github/workflows/upgrade-from-latest-release.yml index c60af163a..e5260d449 100644 --- a/.github/workflows/upgrade-from-latest-release.yml +++ b/.github/workflows/upgrade-from-latest-release.yml @@ -36,22 +36,22 @@ jobs: with: ref: develop #FIXME change to master when doing release - uses: actions/cache@v5 - name: Setup gnpm cache - if: always() + name: Cache pnpm store with: - path: | - ${{ env.STORE_PATH }} - ~/.local/share/gnpm - ~/.cache/ms-playwright - /usr/local/bin/gnpm - /usr/local/bin/gnpm-0.0.12 - key: ${{ runner.os }}-gnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + path: ${{ env.PNPM_HOME }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-gnpm-store- - - name: Setup gnpm - uses: SamTV12345/gnpm-setup@main + ${{ runner.os }}-pnpm-store- + - uses: pnpm/action-setup@v6 + name: Install pnpm with: - version: 0.0.12 + version: 10.33.2 + run_install: false + - name: Use Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ matrix.node }} + cache: pnpm - name: Install libreoffice uses: awalsh128/cache-apt-pkgs-action@v1.6.0 with: @@ -59,14 +59,14 @@ jobs: version: 1.0 - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile --runtimeVersion="${{ matrix.node }}" + run: pnpm install --frozen-lockfile - name: Build admin ui working-directory: admin - run: gnpm build --runtimeVersion="${{ matrix.node }}" + run: pnpm build - name: Install Etherpad plugins run: > - gnpm run install-plugins + pnpm run install-plugins ep_align ep_author_hover ep_cursortrace @@ -78,13 +78,13 @@ jobs: ep_set_title_on_pad ep_spellcheck ep_subscript_and_superscript - ep_table_of_contents --runtimeVersion="${{ matrix.node }}" + ep_table_of_contents - name: Run the backend tests - run: gnpm run test --runtimeVersion="${{ matrix.node }}" + run: pnpm run test - name: Install all dependencies and symlink for ep_etherpad-lite - run: gnpm install --frozen-lockfile --runtimeVersion="${{ matrix.node }}" + run: pnpm install --frozen-lockfile # Because actions/checkout@v6 is called with "ref: master" and without # "fetch-depth: 0", the local clone does not have the ${GITHUB_SHA} # commit. Fetch ${GITHUB_REF} to get the ${GITHUB_SHA} commit. Note that a @@ -101,4 +101,4 @@ jobs: # commit that merges the PR's source branch to its destination branch. run: git checkout "${GITHUB_SHA}" - name: Run the backend tests - run: gnpm run test --runtimeVersion="${{ matrix.node }}" + run: pnpm run test diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c23547eb..64bfa75af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# 2.7.2 + +### Notable enhancements and fixes + +- Accessibility pass: corrected dialog semantics, improved focus management, added missing icon labels, and set the `html lang` attribute correctly. +- Chat: clicking the chat icon works again, disabled toggles render properly, and the username layout no longer overflows. +- `/export/etherpad` now honors the `:rev` URL segment, so revision-specific exports return the requested revision instead of the latest. +- Undo / redo now scrolls the viewport to follow the caret, so reverted edits stay in view. +- Page Down / Page Up now scrolls by viewport height instead of a fixed line count, matching standard editor behavior on tall and short windows alike. +- Editbar: caret is restored to the pad after changing a toolbar select, so typing continues in the document instead of falling through to the toolbar. +- Admin: i18n is restored on `/admin` so the admin UI is translated again. + # 2.7.1 ### Notable enhancements and fixes diff --git a/admin/package.json b/admin/package.json index f55c7f01a..4b83f9e7a 100644 --- a/admin/package.json +++ b/admin/package.json @@ -1,7 +1,7 @@ { "name": "admin", "private": true, - "version": "2.7.1", + "version": "2.7.2", "type": "module", "scripts": { "dev": "vite", @@ -25,9 +25,9 @@ "eslint": "^10.2.1", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.2", - "i18next": "^26.0.6", + "i18next": "^26.0.7", "i18next-browser-languagedetector": "^8.2.1", - "lucide-react": "^1.8.0", + "lucide-react": "^1.11.0", "react": "^19.2.5", "react-dom": "^19.2.5", "react-hook-form": "^7.73.1", @@ -37,7 +37,6 @@ "typescript": "^6.0.3", "vite": "npm:rolldown-vite@7.2.10", "vite-plugin-babel": "^1.6.0", - "vite-plugin-static-copy": "^4.1.0", "zustand": "^5.0.12" }, "overrides": { diff --git a/admin/src/localization/i18n.ts b/admin/src/localization/i18n.ts index 8c97eca75..048601b52 100644 --- a/admin/src/localization/i18n.ts +++ b/admin/src/localization/i18n.ts @@ -1,36 +1,47 @@ import i18n from 'i18next' import {initReactI18next} from "react-i18next"; import LanguageDetector from 'i18next-browser-languagedetector' +import type {BackendModule} from 'i18next'; +// Core translations live in /src/locales (shared with the pad UI). Letting +// Vite resolve them via import.meta.glob means each language ships as its own +// hashed JSON chunk, lazy-loaded on demand — no build-time copy step or +// /admin/locales/* express route. Earlier setups copying files into the build +// output were fragile (see https://github.com/ether/etherpad/issues/7586). +const coreLocales = import.meta.glob<{default: Record}>( + '../../../src/locales/*.json'); -import { BackendModule } from 'i18next'; +const coreLocaleByLang = (language: string) => + coreLocales[`../../../src/locales/${language}.json`]; const LazyImportPlugin: BackendModule = { type: 'backend', init: function () { }, read: async function (language, namespace, callback) { - - let baseURL = import.meta.env.BASE_URL - if(namespace === "translation") { - // If default we load the translation file - baseURL+=`/locales/${language}.json` - } else { - // Else we load the former plugin translation file - baseURL+=`/${namespace}/${language}.json` - } - - const localeJSON = await fetch(baseURL) - let json; - try { - json = JSON.parse(await localeJSON.text()) - } catch(e) { - callback(new Error("Error loading"), null); + if (namespace === 'translation') { + const loader = coreLocaleByLang(language); + if (!loader) { + callback(new Error(`No core locale for "${language}"`), null); + return; + } + const mod = await loader(); + callback(null, mod.default); + return; + } + // Plugin namespaces (e.g. ep_admin_pads) are still served as static + // assets from admin/public//.json. + const baseURL = `${import.meta.env.BASE_URL}/${namespace}/${language}.json`; + const res = await fetch(baseURL); + if (!res.ok) { + callback(new Error(`HTTP ${res.status} loading ${baseURL}`), null); + return; + } + callback(null, await res.json()); + } catch (e) { + callback(e instanceof Error ? e : new Error(String(e)), null); } - - - callback(null, json); }, save: function () { diff --git a/admin/vite.config.ts b/admin/vite.config.ts index ebe4d949d..70ec5182f 100644 --- a/admin/vite.config.ts +++ b/admin/vite.config.ts @@ -1,36 +1,31 @@ import { defineConfig } from 'vite' -import {viteStaticCopy} from "vite-plugin-static-copy"; -import react from '@vitejs/plugin-react'; +import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [viteStaticCopy({ - targets: [ - { - src: '../src/locales', - dest: '' - } - ] - }), react({ - babel: { - plugins: ['babel-plugin-react-compiler'], - }})], - base: '/admin', - build:{ - outDir: '../src/templates/admin', - emptyOutDir: true, - }, - server:{ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], + base: '/admin', + build: { + outDir: '../src/templates/admin', + emptyOutDir: true, + }, + server: { proxy: { '/socket.io/*': { target: 'http://localhost:9001', changeOrigin: true, - rewrite: (path) => path.replace(/^\/api/, '') + rewrite: (path) => path.replace(/^\/api/, ''), }, - '/admin-auth/': { - target: 'http://localhost:9001', - changeOrigin: true, - } - } - } + '/admin-auth/': { + target: 'http://localhost:9001', + changeOrigin: true, + }, + }, + }, }) diff --git a/bin/package.json b/bin/package.json index 483a4a967..eefe42d90 100644 --- a/bin/package.json +++ b/bin/package.json @@ -1,6 +1,6 @@ { "name": "bin", - "version": "2.7.1", + "version": "2.7.2", "description": "", "main": "checkAllPads.js", "directories": { diff --git a/docs/superpowers/plans/2026-04-22-a11y-dialogs-labels-lang.md b/docs/superpowers/plans/2026-04-22-a11y-dialogs-labels-lang.md new file mode 100644 index 000000000..1efc63a0c --- /dev/null +++ b/docs/superpowers/plans/2026-04-22-a11y-dialogs-labels-lang.md @@ -0,0 +1,404 @@ +# Accessibility: Dialog semantics, icon labels, html lang + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add ARIA dialog semantics, focus management, accessible names for icon-only controls, and a `lang` attribute — addressing the highest-impact items from the 2026-04-22 a11y audit. + +**Architecture:** All changes live in templates + a small set of TS files. No new modules. The existing `toggleDropDown` in `pad_editbar.ts` is the single chokepoint for popup show/hide; we extend it with focus management. Icon-only buttons get accessible names via a new `icon.*` locale namespace consumed via `data-l10n-id` (existing l10n machinery applies to `aria-label` automatically through html10n's attribute syntax). + +**Tech Stack:** EJS templates, TypeScript, jQuery (legacy), Playwright tests. + +**Out of scope:** WCAG-AA contrast pass, touch-target sizing (28→44px), full focus-visible CSS pass, modal-by-modal focus-trap library swap. Leaving those for follow-up PRs to keep this one reviewable. + +--- + +### Task 1: Add `lang` attribute to top-level templates + +**Files:** +- Modify: `src/templates/pad.html:7` +- Modify: `src/templates/index.html` (top `` tag) +- Modify: `src/templates/timeslider.html` (top `` tag) + +The pad templates render server-side; `clientVars.userAgent` and `req.headers['accept-language']` aren't directly available here, but the rendered locale is exposed via `settings.defaultLang` in `Settings.ts`. Use that, defaulting to `en` if unset. + +- [ ] **Step 1.1:** Edit `src/templates/pad.html` line 7. Replace + ```html + + ``` + with + ```html + + ``` + +- [ ] **Step 1.2:** Apply the same `lang` attribute to `src/templates/index.html` and `src/templates/timeslider.html` `` tags. (Read each first to get exact current line.) + +- [ ] **Step 1.3:** The client-side language switcher (`html10n`) already updates `documentElement.lang` after page load — verify by grepping `pad_utils.ts` and `vendors/html10n.ts` for `lang =`. No code change needed if html10n already does this; otherwise add one line in `pad.ts` after l10n loads to set `document.documentElement.lang` from the active locale. + +- [ ] **Step 1.4:** Commit: + ```bash + git add src/templates/pad.html src/templates/index.html src/templates/timeslider.html + git commit -m "fix(a11y): add lang attribute to top-level templates" + ``` + +--- + +### Task 2: Dialog semantics on popups + +**Files:** +- Modify: `src/templates/pad.html` — popups at lines 117 (`#settings`), 190 (`#import_export`), 242 (`#connectivity`), 325 (`#embed`), 349 (`#users`), 353 (`#mycolorpicker`), 410 (`#skin-variants`). + +For each popup, add `role="dialog"`, `aria-modal="true"`, `aria-labelledby=""`. Where the popup has an `

` without an id, add an id. Connectivity has multiple `

` (one per state) — give that one `role="dialog" aria-modal="true" aria-label="Connection status"` instead of labelledby. + +- [ ] **Step 2.1:** Settings popup. Add id to its `

`: + ```html +

+ ``` + And: + ```html + -
+
@@ -442,18 +445,18 @@ -
+
+ + 0 +

-
- █   + +
@@ -472,8 +475,8 @@ <% if (settings.skinName == 'colibris') { %> -