From 26cb4774b34b1186cb5331402b15f1916a1e20c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BCrk?= Date: Tue, 6 Oct 2026 11:24:11 +0200 Subject: [PATCH] [TASK] Add guidelines for contributors and agents CONTRIBUTING.md describes how a change gets into this branch: the supported versions, the test harness, the code rules, the commit messages and the pull requests. AGENTS.md adds what a coding agent needs on top of it, CLAUDE.md imports AGENTS.md. The three files are marked export-ignore, the agent working directory ".agent/" is ignored by git. --- .gitattributes | 3 + .gitignore | 1 + AGENTS.md | 95 ++++++++++++++++++++++++ CLAUDE.md | 1 + CONTRIBUTING.md | 187 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 287 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 CONTRIBUTING.md diff --git a/.gitattributes b/.gitattributes index d0c1999..23888c2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,6 +8,9 @@ /packages/ export-ignore # Files +AGENTS.md export-ignore +CLAUDE.md export-ignore +CONTRIBUTING.md export-ignore .editorconfig export-ignore .gitattributes export-ignore .gitignore export-ignore diff --git a/.gitignore b/.gitignore index ffc162a..abfeb66 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ vendor tailor-version-artefact/ tailor-version-upload/ /contrib/Libraries/ +/.agent/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..11b2b51 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,95 @@ +# Agent instructions + +Instructions for coding agents working in this repository. `CLAUDE.md` +imports this file. Read [CONTRIBUTING.md](CONTRIBUTING.md) first: its rules +apply to you in full. This file adds what an agent needs on top of it. + +## Know which line you are on + +This file belongs to the branch `main`: deepl-write 2.x, TYPO3 13.4 and +14.3, PHP 8.2 to 8.5. **The branch you work on decides the rules.** For work +on `1` (1.x, TYPO3 12.4 and 13.4), switch to that branch and follow its own +`AGENTS.md` and `CONTRIBUTING.md`, never this one. A backport is written for +the target branch, it is not a copy of the change on `main`. + +Check before you start: + +```bash +git branch --show-current +git status -sb +``` + +## Rules + +- **Never write to a remote** (push, pull request, issue, comment, review, + merge) unless the maintainer asks for exactly that. +- **Never credit a tool or a model** in commits, pull requests, issues, code + comments or documentation. No `Co-authored-by` for it, no "Generated + with" line. The human who submits the change is its author. +- Scratch files, plans, reports and downloads go into `.agent/` (git + ignored), never into the tracked tree and never into `/tmp`. +- Verify by running, not by recalling: the suites below, `git`, `composer`. + Say what you ran and what you did not run. +- An issue reference (`DPL-123`, `#12`) is written only when it is known to + exist. Do not invent one. + +## Running the test harness as an agent + +- **Set `CI=true`.** Without a terminal, `runTests.sh` fails with "the input + device is not a TTY" unless `CI` is `true`: + + ```bash + export CI=true + Build/Scripts/runTests.sh -b docker -t 13 -s composerUpdate + Build/Scripts/runTests.sh -b docker -t 13 -s cgl -n + Build/Scripts/runTests.sh -b docker -t 13 -s phpstan + Build/Scripts/runTests.sh -b docker -t 13 -s unit + Build/Scripts/runTests.sh -b docker -t 13 -s functional + ``` + +- **One TYPO3 version at a time.** `.Build/` holds the installation of the + last `composerUpdate`. Run all suites of v13, then `composerUpdate -t 14` + and the suites of v14. Never run two `runTests.sh` calls of this checkout + in parallel. +- `composerUpdate` rewrites `composer.json` while it runs and restores it + afterwards (`composer.json.orig`). Do not interrupt it, and never commit a + `composer.json` changed by it. +- `-s cgl` changes files, `-s cgl -n` only checks. Run the check before you + commit, the fix only on purpose. +- Pass test filters behind `--`: `-s unit -- --filter VersionTest`. +- The functional tests use a DeepL mock server. Never put a real DeepL key + into a file, a command line or a log. +- Done means: the suites of the changed area green on **both** v13 and v14, + `cgl -n` and `phpstan` green on both, `checkContribComposer` when + `composer.json` or `contrib/` changed, `renderDocumentation` when + `Documentation/` changed. + +## Code you are likely to touch + +- `Classes/` is shared by both TYPO3 versions. A difference between v13 and + v14 goes into `Core13/` and `Core14/`. Never add a new TYPO3 version check + to a class. +- The localization runs through the DataHandler command `deeplwrite` + (`Classes/Hooks/WriteHook.php`): localize the record, then rephrase its + translatable fields with DeepL Write. On v13 the mode comes from the + localization wizard of deepl-base (listeners in `Core13/Event/Listener/`), + on v14 from the TYPO3 localization handler + `Core14/Backend/Localization/DeeplWriteLocalizationHandler.php`. +- deepl-write has its own client and configuration on the DeepL SDK. Do not + add a dependency on `web-vision/deepltranslate-core`. The places that work + with it when it is installed are `Classes/Configuration/Configuration.php` + (API key fallback) and `Configuration/SiteConfiguration/Overrides/sites.php` + (display conditions on core's `deeplTargetLanguage` and `deeplFormality`). + The listener identifiers of deepl-base and deepltranslate-core named in + `after:` must keep matching theirs. +- `org_heigl/hyphenator` has to stay in sync with `contrib/`, see + CONTRIBUTING.md. + +## Commits and pull requests + +- One commit per pull request, following the commit rules in CONTRIBUTING.md. + Amend and force push (`--force-with-lease`) when asked to update a pull + request, do not add fix-up commits. +- Rebase onto `origin/main`, never merge it in. +- When a change also needs a pull request in another DeepL extension, say so, + and name the order in which they have to be merged. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..100875b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,187 @@ +# Contributing to deepl-write + +Thank you for helping. This file explains how a change gets into this +extension: which branch, how to test it, how to write the commit and what a +pull request needs to be merged. + +## Table of contents + +- [Issues and security](#issues-and-security) +- [Branches](#branches) +- [Getting started](#getting-started) +- [Tests and checks](#tests-and-checks) +- [Code rules](#code-rules) +- [The bundled library for classic mode](#the-bundled-library-for-classic-mode) +- [Documentation and changelog](#documentation-and-changelog) +- [Commit messages](#commit-messages) +- [Pull requests](#pull-requests) +- [Other DeepL extensions](#other-deepl-extensions) + +## Issues and security + +- Bugs and feature requests are GitHub issues, with the templates offered + when you open one. Include the TYPO3 version, the version of this extension + and the steps to reproduce. +- **Security issues are never reported publicly.** See + [SECURITY.md](SECURITY.md). +- The maintainers track their work in an internal tracker, project `DPL`. + That is why commits and pull requests refer to `DPL-123`. You do not need + access to it. + +## Branches + +| Branch | Version | TYPO3 | PHP | State | +|--------|---------|--------------|------------|-------------------------------| +| `main` | 2.x | 13.4, 14.3 | 8.2 to 8.5 | development of the next 2.x | +| `1` | 1.x | 12.4, 13.4 | 8.1 to 8.5 | bug fixes and security fixes | + +- Open a pull request against `main`. A fix that is needed in 1.x as well is + a second pull request against `1`, made after the first one, from a branch + with the suffix `-1` (`bugfix/my-fix-main` and `bugfix/my-fix-1`). Both + carry the same title. The maintainers can do that second one for you. +- The branch `1` has its own `CONTRIBUTING.md`. Read that one for a change + there: the supported versions and some code rules differ. + +## Getting started + +You need git, bash and docker or podman. Everything else runs in containers +through `Build/Scripts/runTests.sh`, the same script the CI uses. + +```bash +git clone git@github.com:web-vision/deepl-write.git +cd deepl-write +Build/Scripts/runTests.sh -h # all options and suites +Build/Scripts/runTests.sh -t 13 -s composerUpdate # install for TYPO3 v13 +Build/Scripts/runTests.sh -t 13 -s unit +``` + +- `-t` selects the TYPO3 version (`13`, default, or `14`). The installation + in `.Build/` exists once: run `-s composerUpdate` with the same `-t` before + the suites of that version, and never two versions at the same time. +- `-b docker` or `-b podman` selects the container binary. Without it, + podman is used when it is installed. +- `-p` selects the PHP version (default 8.2). + +## Tests and checks + +A pull request is merged when these are green for TYPO3 v13 and v14. Run them +locally before you push: + +| Check | Command | +|-------------------------------|------------------------------------------------------| +| Coding style (check only) | `Build/Scripts/runTests.sh -t 13 -s cgl -n` | +| Coding style (fix) | `Build/Scripts/runTests.sh -t 13 -s cgl` | +| PHPStan | `Build/Scripts/runTests.sh -t 13 -s phpstan` | +| PHP lint | `Build/Scripts/runTests.sh -t 13 -s lintPhp` | +| TypoScript lint | `Build/Scripts/runTests.sh -t 13 -s lintTypoScript` | +| Unit tests | `Build/Scripts/runTests.sh -t 13 -s unit` | +| Functional tests | `Build/Scripts/runTests.sh -t 13 -s functional` | +| Functional tests, other DBMS | `... -s functional -d mariadb` (also `mysql`, `postgres`) | +| Bundled library in sync | `Build/Scripts/runTests.sh -t 13 -s checkContribComposer` | +| Exception codes unique | `Build/Scripts/runTests.sh -s checkExceptionCodes` | +| Test method names | `Build/Scripts/runTests.sh -s checkTestMethodsPrefix`| +| UTF-8 without BOM | `Build/Scripts/runTests.sh -s checkBom` | +| Documentation renders | `Build/Scripts/runTests.sh -s renderDocumentation` | + +The same with `-t 14` after `-s composerUpdate -t 14`. CI runs +`checkContribComposer` with TYPO3 v13 only. + +- The functional tests talk to a DeepL mock server container, not to DeepL. + They need no API key and cost nothing. +- A bug fix comes with a test that fails without it. A new feature comes + with tests. + +## Code rules + +- `declare(strict_types=1);` in every PHP file, classes `final` unless they + are meant to be extended, dependencies as `readonly` promoted constructor + properties. +- Services are stateless. They carry no data from one call to the next. +- Dependency injection through Symfony attributes (`#[AsEventListener]`, + `#[Autoconfigure]`, ...). `Services.yaml` keeps the defaults and the + resource. `Services.php` only loads the directory of the running TYPO3 + version. +- **No TYPO3 version checks inside classes.** Code that differs between v13 + and v14 lives in `Core13/` and `Core14/` (namespaces `WebVision\DeeplWrite\Core13\` + and `WebVision\DeeplWrite\Core14\`). `Configuration/Services.php` loads only + the directory of the running version. A new difference goes there, not + into a `Typo3Version` check. +- Every exception gets a unique code, the Unix timestamp of the moment you + write it. +- Test methods use the `#[Test]` attribute and do not start with `test`. +- Coding style is PSR-2 with the PHP 7.4 migration rules + (`Build/php-cs-fixer/php-cs-rules.php`). PHPStan runs on level 8 with a + baseline per TYPO3 version in `Build/phpstan/`. A change does not add to + the baselines. + +## The bundled library for classic mode + +The readability score uses `org_heigl/hyphenator`. Composer installations get +it from `composer.json`. For classic mode (TER) installations the release +workflow installs it into `contrib/Libraries/` from `contrib/composer.json` +and `contrib/composer.lock`. `contrib/Libraries/` is not committed. + +- The constraint of `org_heigl/hyphenator` in `composer.json` and + `contrib/composer.json` must be identical. +- `contrib/composer.lock` is resolved with `--prefer-lowest`, so the lowest + supported version is the one shipped. After a change to + `contrib/composer.json`, regenerate it with + `composer update --prefer-lowest -d contrib`. +- `-s checkContribComposer` checks both. + +## Documentation and changelog + +- The documentation is reStructuredText in `Documentation/`, rendered with + `-s renderDocumentation`. The rendered result is not committed. +- A feature, a breaking change, a deprecation or a fix an editor or + integrator notices gets a changelog entry in + `Documentation/Changelog//`, named like the TYPO3 Core + changelog: `Feature-.rst`, `Breaking-...`, `Deprecation-...`, + `Important-...`. It is part of the same commit. + +## Commit messages + +The [TYPO3 Core commit message rules](https://docs.typo3.org/m/typo3/guide-contributionworkflow/main/en-us/Appendix/CommitMessage.html): + +``` +[BUGFIX] DPL-237: Correct the branch alias + +Explain why the change is needed and what it does, not how the diff +looks. Wrap the body at 72 characters. +``` + +- Subject: a tag (`[FEATURE]`, `[BUGFIX]`, `[TASK]`, `[DOCS]`, `[SECURITY]`, + `[!!!]` in front for a breaking change), the internal issue if there is one, + imperative mood, at most 52 characters where possible. +- A GitHub issue goes into the footer (`Resolves: #12`) or at the end of + the subject (`(#12)`). + +## Pull requests + +- **One pull request carries one commit.** The title of the pull request is + the subject of the commit. Review changes are amended into the commit and + force pushed, not added as new commits. +- Rebase onto the current `main` instead of merging it in. The branch is + merged with "rebase and merge", the only method allowed. +- Required: one approving review and the checks `code quality with core v13 + (8.2)`, `all tests with core v13 (8.2)`, `all tests with core v13 (8.5)`, + the same for v14, and `render documentation`. +- Name the branch `/`, for example `bugfix/dpl-237-branch-alias-main` + or `task/security-policy`. + +## Other DeepL extensions + +deepl-write builds on `web-vision/deepl-base` and `web-vision/deeplcom-deepl-php` +(the DeepL PHP SDK). It does not need `web-vision/deepltranslate-core`, but +works together with it when both are installed: + +- Without an API key of its own, deepl-write uses the key of + deepltranslate-core. +- In the site configuration, the DeepL Write language and the target + language and formality of deepltranslate-core exclude each other. +- On TYPO3 v13 its entry in the translation dropdown of the page module is + ordered after the one of deepltranslate-core. + +A change to these places, or to the events of deepl-base it listens to, is +checked with deepltranslate-core installed as well. Say in your pull request +when you know a change affects another DeepL extension.