Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ vendor
tailor-version-artefact/
tailor-version-upload/
/contrib/Libraries/
/.agent/
95 changes: 95 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
187 changes: 187 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -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/<major.minor>/`, named like the TYPO3 Core
changelog: `Feature-<Topic>.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 `<type>/<topic>`, 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.