# Contributing --- [简体中文](docs/CONTRIBUTING.zh-CN.md) Contributions to themes, tools, documentation and translations are welcome. This guide covers the development environment, command-line tools and contribution workflow. For template installation and release selection, see the [README](README.md#installation) and [compatibility matrix](COMPATIBILITY.md#compatibility-matrix). ## Local Development Use **Go 1.24 or later**. From the repository root, prepare the dependencies and locked official files, run the tests and generate the preview: ```bash cd tools go mod download go run . upstream prepare go test ./... go run . preview all ``` Then open [preview/index.html](preview/index.html) in a browser, or run `go run . dev` for live preview. The validation and packaging workflows use Python 3.11. The project is organized into a shared framework, theme styles and build tools. Official templates provide notification content, conditions, subjects and links. The shared framework handles presentation, while theme metadata and CSS select layouts and define styles. See the [README](README.md#project-directory-structure) for the directory layout. > [!NOTE] > Downloaded official files, generated templates and preview data are not tracked in version control. Submit the relevant source files, tests and documentation; do not include `build/`, `dist/` or generated preview data. ## Development Tools The CLI prepares official files, manages themes, builds templates and generates previews. > [!TIP] > Run all commands below from `tools/`. Place options before positional arguments. In the examples, `my-theme` is a theme name; quote paths containing spaces. | Command | Purpose | |---|---| | `upstream` | Prepare, synchronize or verify locked official build inputs | | `build` | Generate installable themes from official inputs and shared controls | | `list` | List available themes and their metadata | | `create` | Create theme CSS and metadata for the shared framework | | `delete` | Delete one or more theme source directories | | `preview` | Pre-render mail templates to generate preview and test data | | `dev` | Start a live-reload development server with SSE browser refresh | | `help`, `h` | Show the command list or help for a specific command | ### upstream `upstream` manages the official files pinned by `gitea.lock.json`, including mail templates, locale files, the icon, license and reviewed adapter reference sources. Downloaded files are stored in `build/upstream/`. | Subcommand | Behavior | |---|---| | `prepare` | Read the root lock file. Download and verify inputs if the cache is absent, or verify an existing cache before use. Does not modify the root lock file. | | `sync --tag ` | Download the specified stable version's official files, verify them, then replace the cache and update the root lock file. | | `verify` | Verify the existing cache against the root lock file, offline and read-only. | To prepare inputs for the first time or check them independently, run: ```bash go run . upstream prepare go run . upstream verify ``` All three subcommands support `--root`, which defaults to `..` relative to the current working directory. For example: ```powershell go run . upstream verify --root "C:\Projects\GiteaMailTemplates" ``` The root lock file records the Gitea tag, its commit and file SHA-256 hashes. `verify` checks file hashes, reviewed adapter reference sources and English translation keys referenced by official templates. Missing keys in other languages produce warnings and fall back to English in the preview. Building and rendering also check framework translation keys and action-link anchors; cache verification does not replace those checks. #### Updating the Official Version Use `sync` only when reviewing a new official version. For example, to explicitly synchronize to `v28.1.0`: ```bash go run . upstream sync --tag v28.1.0 go run . upstream verify go test ./... go run . preview all ``` Tags must use the `vX.Y.Z` format and identify a stable release of Gitea 28 or later. `latest`, prerelease tags and older version tags are not supported. `sync` resolves tags through `api.github.com` and downloads files from `raw.githubusercontent.com`; it does not accept a local Gitea clone or an authentication token option. After synchronization, review the lock file diff, adjust adapter logic and preview data as needed, and update compatibility records after validation. Synchronization does not automatically update documentation, release tags or compatibility conclusions. > [!IMPORTANT] > When adapter reference sources change, review the affected behavior before updating their hashes. Do not change hashes simply to bypass the checks. Network or validation errors before cache replacement leave existing files unchanged. Cache replacement and root lock file writing are separate operations; if a filesystem error interrupts the process, check that both agree before retrying. Stop `dev` before updating inputs to avoid concurrent processes writing to the cache. ### build `build` generates installable mail templates from locked official files, the shared framework and theme sources. Specify one or more themes, or use `all` to build every theme: ```bash go run . build aurora go run . build aurora bloom go run . build all ``` | Option | Default | Description | |---|---|---| | `--folder` | `../themes` | Theme source directory; its parent is used as the project root | When using another project path, that project's root must also provide the lock file and shared framework: ```powershell go run . build --folder "C:\Projects\GiteaMailTemplates\themes" aurora ``` Output is written to `build/themes//mail/`, with build provenance and generated file hashes recorded in the adjacent `build.json`. Rebuilding updates the selected themes and removes their obsolete templates; it does not clean unselected themes. Building does not deploy templates. See the [README](README.md#install-a-theme) for installation. > [!TIP] > To change templates, edit theme sources, the shared framework or build adapter logic. Direct edits to generated `.tmpl` files are overwritten by subsequent builds and cause packaging provenance checks to fail. ### list `list` displays theme names, modes and short descriptions, sorted by name: ```bash go run . list ``` Use `--folder` to select a theme directory; the default is `../themes`. The command validates theme metadata and styles without downloading official files or generating templates. Fix any reported theme-format errors first. ### create `create` creates `theme.json` and `theme.css` for a new theme and supports creating multiple themes at once: ```bash go run . create my-theme go run . create first-theme second-theme ``` Use `--folder` to select the theme source directory; the default is `../themes`. The command does not overwrite existing directories. Theme names start with a lowercase letter and contain only lowercase letters, digits and hyphens. Avoid `all`, because build and preview commands treat it as the selector for every theme. Edit the generated metadata and CSS to describe and style the theme. For example: ```json { "name": "my-theme", "description": "A short description of the theme", "mode": "framed", "layout": "standard" } ``` `name` must match the directory name. Theme directories contain only these two source files, without copies of official mail templates or translations. | Mode | Presentation structure | |---|---| | `framed` | Shared controls and a layout, styled with theme CSS. New themes default to this mode and the `standard` layout. | | `shared` | CSS is added to the official head partial, and the official footer partial is retained. No framework controls or per-mail template overrides are added. | A `framed` theme can use `layout` to select a preset from `framework/layouts/`. Headers, action buttons, fallback links, sidebars and footers live in `framework/mail/base/`. Structural changes shared by multiple themes belong in the framework; adaptation between official content and controls is handled in `tools/builder/framework.go`. Theme CSS uses existing classes such as `email-heading`, `email-text` and `email-subtext` to distinguish headings, body text and supporting text. Preserve official notification wording, translation keys, variables and functional links. Do not generate wording or hide notification content through CSS. The style validator rejects template expressions, external resource references and unsupported hiding rules. After completing the theme, run the tests and generate a preview: ```bash go test ./... go run . preview my-theme ``` ### delete `delete` removes the source directories of one or more named themes: ```bash go run . delete my-theme go run . delete first-theme second-theme ``` Use `--folder` to select the theme directory; the default is `../themes`. > [!WARNING] > After validation, the command deletes directories directly, without a confirmation prompt or recovery through the recycle bin. Check the names and preserve any changes you need before running it. Missing themes produce warnings; invalid themes and symlink directories are rejected. Themes are processed sequentially, so a later failure does not restore directories already deleted. `all` does not mean deleting every theme. Deleting sources does not remove previously generated builds, preview data or deployed templates. Run `preview all` again to update the preview manifest. Remove deployed templates separately at their actual installation location. ### preview `preview` builds the selected themes and renders all locked official languages using sample data. Specify one or more themes, or use `all`: ```bash go run . preview aurora go run . preview aurora bloom go run . preview all ``` | Option | Default | Description | |---|---|---| | `--folder` | `../themes` | Theme source directory; its parent is used as the project root | | `--config` | `./data/templates_config.json` | Mail type descriptions and preview sample data | | `--output` | `preview/rendered.js` under the project root | Preview manifest path | Default output includes `preview/rendered.js` and `preview/rendered/.js`. Open [preview/index.html](preview/index.html) in a browser; no server is required. See the [README](README.md#controls-and-keyboard-shortcuts) for controls and shortcuts. > [!IMPORTANT] > Each run overwrites the preview manifest at the output location instead of merging with previously selected themes. For example, after `preview aurora`, the manifest contains only Aurora. Run `preview all` to restore every theme. To use a custom output path: ```bash go run . preview --config ./data/templates_config.json --output ../build/preview-review/rendered.js all ``` > [!NOTE] > Language data is written to a `rendered/` directory next to the output file. The command does not copy the preview interface or change its script references; the existing `preview/index.html` still reads data from the default location. When adding mail types or rendering branches, extend the descriptions and sample contexts in `tools/data/templates_config.json`. Keep integer values, such as counts and sizes, as integers in JSON. Use controlled test content for HTML fields such as body text, release notes and review content; do not include personal information or real credentials. > [!NOTE] > The preview checks template structure and presentation using sample contexts. It does not replace parameter compatibility review for the target Gitea version. Browsers and mail clients also differ in their CSS support. ### dev `dev` starts a local development server, building every theme and preparing preview data on startup: ```bash go run . dev ``` Open [http://127.0.0.1:3456](http://127.0.0.1:3456). The default port is `3456`; use `--port` to change it: ```bash go run . dev --port 3457 ``` The server listens only on `127.0.0.1`. Press `Ctrl + C` in the terminal to stop it. The command locates the project relative to the current `tools/` working directory and does not provide `--folder`, `--config` or `--root` options. The server watches theme sources, the shared framework, the root lock file, official cache and preview data in `tools/data/`. Changes trigger a rebuild and refresh the preview through server-sent events (SSE). If a build fails, resolve the terminal error and save the file again. > [!TIP] > Refresh the page manually after editing `preview/index.html`. Stop and restart the server after editing Go tool code. These files are outside the current automatic rebuild watch scope. ### help, h View all commands or help for a specific command: ```bash go run . help go run . h go run . help build go run . preview --help ``` For `upstream` subcommand options, place `--help` after the subcommand: ```bash go run . upstream prepare --help go run . upstream sync --help go run . upstream verify --help ``` Tool diagnostics use the `[LEVEL] [NAME] Message` format. `[I]`, `[W]`, `[E]` and `[F]` mean information, warning, error and fatal error, respectively. Level markers use different colors in supported terminals; set `NO_COLOR` to disable colors. Failed commands return a nonzero exit code. Preserve the complete output when troubleshooting. ## Frequently Asked Questions ### What if the lock file or official cache is missing? If an existing clone lacks `gitea.lock.json`, restore the tracked root lock file. The copy at `build/upstream/lock.json` cannot replace it. If only the cache is missing, run `upstream prepare` rather than synchronizing to another version to recover it. `build`, `preview` and `dev` prepare official inputs automatically. They can run offline once the cache, Go toolchain and dependencies are available; `upstream verify` always checks local files only. For network errors or GitHub API rate limits during the initial download, resolve the network issue and retry. ### What if the cache is corrupt or does not match the lock file? `prepare` does not repair corrupt caches automatically, and `sync` refuses to replace a non-empty invalid snapshot. Stop the development server, preserve the root lock file and move the cache to a backup location before preparing it again. For example, in PowerShell **from the repository root**, use a backup name that does not already exist: ```powershell Move-Item -LiteralPath .\build\upstream -Destination .\build\upstream.backup Set-Location tools go run . upstream prepare go run . upstream verify ``` > [!WARNING] > Do not edit official cached files directly or delete the rest of `build/`. To revert the official version, restore the previously reviewed root lock file and rebuild the cache in the same way. ### Why does synchronizing a new version report changed adapter sources? The project pins reviewed mail-rendering and translation reference sources. When upstream changes these implementations, the tool requires another review to avoid using incompatible preview functions or variable structures. Examine the official changes, adjust adapter logic and relevant tests, then update the reference hashes. New mail types, translation keys, functions or variable paths may also require changes. Update [compatibility records](COMPATIBILITY.md) after validation; a successful download does not establish compatibility. ### Why do some languages use English or produce formatting warnings? Official English must contain all referenced translation keys. Missing keys in other languages fall back to English and produce warnings. Preserve official locale files without adding translations to the cache. For example, Gitea v28.0.0 has a known placeholder defect in the Polish `mail.team_invite.text_1`. The preview preserves official output for the exact reviewed source text and reports a warning. This exception does not apply to other formatting errors. Include the version, translation key and reproduction details when reporting new issues for review and upstream feedback. ### Why does the preview not show a new theme or recent changes? The static preview does not build automatically. Run `preview all` again and refresh the page, then confirm that the manifest contains the required themes. With a custom output path, check where the preview interface actually reads its data. With `dev`, first check the terminal for rebuild errors. Go code changes require a server restart; preview interface changes require a manual refresh. If the default port is occupied, select another port with `--port`. ### Does a successful build mean all Gitea versions are supported? Builds target the official inputs specified in the root lock file. Other versions may change template directories, functions or variable structures, so a successful build or preview alone cannot establish backward compatibility. Select release archives using the [compatibility matrix](COMPATIBILITY.md#compatibility-matrix), rather than installing new-version templates directly on older instances. ### Why does the packaging script reject the current output? Run `preview all` before packaging to ensure that every theme and language bundle is present and generated files match the current sources. The version argument must match the tag in the root lock file. Rebuild and regenerate previews after source or generated file changes. The script does not overwrite existing release archives. Use a new output directory when repackaging and retain old artifacts needed for comparison. ## Other Contribution Information ### Themes and the Shared Framework Use CSS suitable for mail clients. When editing an existing theme, preserve its palette, fonts, borders and layout, keep headings, body text and supporting text distinct, and account for long text, long URLs and mobile widths. Layout fragments use presentation markup and support `table`, `tbody`, `tr`, `td`, `div`, `span` and attributes allowed by the validator. Combined markup must have balanced tags. `__HEADER__` inserts the shared header, `__MAIL_TYPE__` expands to the mail ID, and `__SIDEBAR__` inserts the shared sidebar in footer fragments. Review changes to notification variables and conditions in the build adapter logic, not in theme CSS or layout presets. For new themes, update the galleries in both English and Chinese READMEs. Use PNG images of at most 50 KiB each; 10–20 KiB is preferred. Follow the [capture guide](docs/images/README.md) for consistent themes, mail types, languages and cropping. ### Commits and Pull Requests Keep changes focused on a specific problem and avoid unrelated formatting changes. Describe the reason, scope and validation results in the pull request. For visual changes, you can include comparison images generated with sample data. When changing themes, the shared framework or Go tools, run from `tools/`: ```bash go test ./... go run . preview all ``` For changes to mail content, links, variables or function adaptation, add regression tests covering affected conditional branches. Existing tests check generated output, translation keys, notification subjects, text and links across every theme and language, including push, review, reply, workflow and attachment branches. When changing packaging scripts, run from the repository root: ```bash python -B -m unittest discover -s .github/scripts -p 'test_*.py' ``` For documentation-only changes, check wording, command examples and links. Keep Chinese and English documentation aligned; preserve commands, paths, variables and version information without changing their meaning in translation. Use concise commit messages. The following prefixes are available as a reference: | Prefix | Scope | |---|---| | `style():` | Theme presentation styles | | `preview:` | Preview tools | | `tools:` | CLI, build and snapshot tools | | `docs:` | Documentation and translations | | `fix:` | Bug fixes | | `project:` | Repository configuration and project structure | | `refactor:` | Code restructuring | | `chore:` | Routine maintenance | ### Version and Release Maintenance Release tags must match the locked Gitea tag. Version labels, badges and compatibility records are maintained manually; changing official inputs does not trigger automatic version maintenance. Retain historical release assets and check documentation and compatibility records before tagging. After validation and generation of all previews, you can package manually from the repository root: ```bash python .github/scripts/package_release.py --version v28.1.0 --output build/release-review ``` Replace the example version with the tag in the root lock file and use an output directory without release archives of the same name. The script checks source and artifact hashes, packages themes, previews, documentation, the official license and provenance, and excludes stale theme builds. `.github/workflows/validate.yml` handles checks for ordinary pushes and pull requests and is also called by the Release workflow. After validation, Release packages the archives and uploads them through the release action. It uses the tag as the title and creates new releases with an empty body, without requiring a release notes file. Republishing an existing tag preserves its existing body and replaces same-name attachments. Check the release and attachment state before retrying a failed publication. Workflows use the `linux-amd64-docker-small` runner label, with setup steps preparing Go, Python and Node.js for publication. Actions use `actions/...@version` references, resolved through the runner's action source configuration; consider the current `github_mirror` setting when maintaining them. Publication uses the built-in `GITEA_TOKEN`, and the repository must permit release writes. ### Reporting Problems Include the Gitea version, template release or source commit, theme, mail type, language and steps to reproduce. For build or preview issues, also include the tag in the root lock file, relevant commands and complete error output. For display issues, specify the mail client and attach screenshots with personal information removed. For improvement suggestions, explain the use case, expected result and affected themes or tools. For official template or translation defects, preserve the original inputs and provide a minimal example that reproduces the issue. ### License This project uses the [MIT License](LICENSE). Contribute code, styles and images that can be legally redistributed. When generating or distributing derived templates, retain Gitea copyright, the official license and snapshot provenance; release archives already include these files.