Follow the setup instructions for Gerrit backend developers where applicable. The most important command is:
git clone --recurse-submodules https://gerrit.googlesource.com/gerrit
The --recurse-submodules option is needed on git clone to ensure that the core plugins, which are included as git submodules, are also cloned.
Then make sure to install the commit hook that will set up the Change-Id for each push to Gerrit:
cd gerrit && ( cd .git/hooks ln -s ../../resources/com/google/gerrit/server/tools/root/hooks/commit-msg )
Follow the instructions here to get and install Bazel. Using Bazelisk is usually the easiest option.
Use a recent Node.js version that is supported by the repository. If in doubt, use the version that is used in CI or documented in the root package.json.
Examples:
# Debian / Ubuntu sudo apt-get install nodejs npm # macOS with Homebrew brew install node
All other platforms: download from nodejs.org,
or use nvm - Node Version Manager.
Install Yarn:
npm install -g yarn
Install pnpm:
npm install -g pnpm
pnpm importFirst run may fail with:
pnpm-lock.yaml file updated. Please run your build again.
Rerun the same command.
The tsc used by the Bazel build is selected by rules_ts in polygerrit-ui/polygerrit.MODULE.bazel:
rules_ts_ext.deps(
version_from = "@npm//:typescript/resolved.json",
)
resolved.json is generated by npm_translate_lock from the lockfile, so the Bazel compiler tracks the version and integrity that yarn actually resolved — the same flow as the dependency management above. The exact pin still lives in the typescript entry of the root package.json (and tools/node_tools/ package.json); resolved.json just reports whatever that pin resolved to, and supplies the integrity from the lockfile rather than from an rules_ts mirror table. To change the compiler version, edit the package.json pin and rerun the yarn → pnpm workflow above.
yarn to pnpmpnpm install
It creates a different dependency graph.
Eventually:
Frontend plugins import the TypeScript plugin API by package name, @gerritcodereview/typescript-api. For standalone plugins (built outside the Gerrit tree) that name resolves to the npm release (link:https://www.npmjs.com/package/@gerritcodereview/typescript-api[@gerritcodereview/typescript-api]), which lags behind master.
Plugins built inside the Gerrit tree (the core plugin submodules, and any plugin symlinked under plugins/ by CI) instead build against the API of the branch they are built with, polygerrit-ui/app/api — so they can use APIs that this branch adds but that are not published to npm yet. Nothing in the plugin has to opt in: a plugin just imports @gerritcodereview/typescript-api and depends on //plugins:node_modules, exactly like plugins/codemirror-editor.
This works via npm_replace_package in polygerrit-ui/polygerrit.MODULE.bazel: plugins/package.json still pins the published version, but the plugins_npm lock substitutes the in-tree //polygerrit-ui/app:plugin_api_npm_package (the branch API, packaged like the npm release) for it at link time. So:
# Builds against the branch API, no npm publish and no packed tarball needed: bazelisk build plugins/<plugin>/...
Do not reintroduce a packed-tarball workflow (publish.sh --pack plus a file:/../*.tgz dependency) for this: a relative tarball path cannot be resolved by npm_translate_lock, which runs pnpm in a sandboxed external repository, not in the source tree.
Modern IDEs should automatically handle TypeScript settings from polygerrit-ui/app/tsconfig.json. The tsc compiler places compiled files in the .ts-out/pg directory at the root of the Gerrit workspace, and you can configure the IDE to exclude the whole .ts-out directory. In IntelliJ IDEA, right-click the directory and select Mark Directory As > Excluded.
If your IDE still reports errors, then you can try configuring TypeScript manually. For example, if IntelliJ IDEA shows Cannot find parent 'tsconfig.json', then set the TypeScript options to:
--project polygerrit-ui/app/tsconfig.json
The frontend is type-checked two ways, and CI runs both. Keep both green.
Type-check with Bazel (production and tests):
bazelisk build //polygerrit-ui/app:compile_pg_with_tests
Type-check without Bazel (this is CI's “run type checker” step):
yarn compile # runs: tsc --project ./polygerrit-ui/app/tsconfig.json
Type-aware lint with Bazel:
bazelisk test //polygerrit-ui/app:lint_test
The two type-check paths use different tsconfigs. Bazel splits production (tsconfig_bazel.json) from tests (tsconfig_bazel_test.json, which sets types: ["mocha"]). The non-Bazel tsc uses the base tsconfig.json, which also type-checks tests and therefore sets types: ["mocha"]; production overrides it with types: [] in tsconfig_bazel.json.
The preferred method for development is to serve the web files locally using the Web Dev Server and then view a running Gerrit instance (local or otherwise) and replace its web client with the local one using the Gerrit FE Dev Helper extension.
The Web Dev Server serves the compiled web files and dependencies unbundled over localhost. Start it with:
pnpm start
To inject plugins or other files, we use the Gerrit FE Dev Helper Chrome extension.
If you run into problems, refer to the troubleshooting section below or contact the team.
To help frontend development, including bypassing auth in local dev workflows, we created this Chrome extension: Gerrit FE Dev Helper.
It basically works as a proxy that blocks or redirects requests from the current site to a configured URL according to rules.
The source code is in Gerrit - gerrit-fe-dev-helper, and contributions are welcome.
To use this extension, follow its README.
Set up a local test site once:
For running a locally built Gerrit war against your test instance use this command.
If you want to serve the Lit frontend directly from the sources in polygerrit-ui/app/ instead of from the war:
--dev-cdn option:$(bazel info output_base)/external/local_jdk/bin/java \ -DsourceRoot=$(bazel info workspace) \ -jar bazel-bin/gerrit.war daemon \ -d $GERRIT_SITE \ --console-log \ --dev-cdn http://localhost:8081
The Web Dev Server currently does not serve fonts or some other static assets. Follow Issue 40015119 for updates.
Note: You can also use another CDN here, for example: https://cdn.googlesource.com/polygerrit_ui/678.0
For daily development you typically only want to run and debug individual tests. Our tests run using the Web Test Runner.
Common commands:
pnpm test
pnpm test:watch
./polygerrit-ui/app/run_test.sh
pnpm test:single "**/gr-comment_test.ts"
We use screenshot tests to prevent unintended visual regressions.
To run the screenshot tests:
pnpm test:screenshot
Or via Bazel, which matches what CI runs and uses the Bazel-managed dependency tree:
bazelisk test //polygerrit-ui:web_test_runner_screenshots
The //polygerrit-ui:web_test_runner_all target runs both the unit and screenshot buckets in a single invocation. Both screenshot targets are tagged manual, so they are never picked up by a bare bazel test //... and must be named explicitly.
If a test fails, then the component's appearance has changed. New screenshots are generated in the polygerrit-ui/screenshots/Chromium/failed/ directory. If an existing baseline differs, then a diff image is also created there.
If the change is intended, then approve the new screenshots as the baseline by moving the new screenshot files from failed to baseline, overwriting the old ones. The diff images in failed can be deleted.
mv polygerrit-ui/screenshots/Chromium/failed/*.png \ polygerrit-ui/screenshots/Chromium/baseline/
After moving the file(s), run pnpm test:screenshot again to confirm they pass.
# Compile frontend once to check for type errors pnpm compile # Watch mode pnpm compile:watch
We follow the Google JavaScript Style Guide with a few exceptions. When in doubt, remain consistent with the surrounding code.
In addition, we encourage the use of ESLint. It is available as a command-line utility as well as a plugin for most editors and IDEs.
We have an ESLint flat config in polygerrit-ui/app/eslint-bazel.config.js configured to enforce the preferred style of the PolyGerrit project.
Some useful commands:
pnpm eslint
pnpm eslintfix
pnpm exec eslint --config polygerrit-ui/app/eslint-bazel.config.js \ --ext .html,.js,.ts polygerrit-ui/app/$YOUR_DIR_HERE
git diff --name-only HEAD | xargs pnpm exec eslint \ --config polygerrit-ui/app/eslint-bazel.config.js \ --ext .html,.js,.ts
When running ESLint manually, invoke it from the repository root so that repo-root-relative paths in the flat config resolve correctly.
Our users report bugs and feature requests related to the UI through the Gerrit Tracker in the WebFrontend component.
If you want to help, feel free to pick one of the New issues without assignees and send us a change.
If you don't know who to assign as reviewer for your change, then you can use this special account:
gerrit-fe-reviewers@api-project-164060093628.iam.gserviceaccount.com
Assigning that account automatically picks two volunteers from the frontend reviewer queue.
If you are willing to join that queue and help review community changes, then create an issue through Gerrit issue tracker and ask to join.