# Contributing **AI coding agents:** see [AGENTS.md](AGENTS.md) at the repository root for project-specific guidance (development setup, tests, conventions, and workflow). ## Write Code You might find this project helpful for setting up a development environment for tine Groupware: https://github.com/tine-groupware/tine-dev * Please make sure that there aren’t existing pull requests attempting to address the issue mentioned * Check for related issues on the issue tracker * Non-trivial changes should be discussed on an issue first * Let us know you’re working on the issue (by using the [Kanban board](https://github.com/orgs/tine-groupware/projects/1)) * Develop in a topic branch, not main * Provide useful pull request description * Write a good description of your PR * Link to the Github issue in the description * See below for avoiding merge conflicts in the first place The default workflow for Github Pull Requests applies for tine Groupware, too. see https://help.github.com/articles/about-pull-requests/ ### Sign the CLA This can be done directly in the Pull Request, thanks to https://cla-assistant.io/ ### Writing Tests For PHP code, write [phpunit](https://phpunit.de/) tests (see https://github.com/tine-groupware/tine/tree/main/tests/tine20) For JavaScript unit tests, write [Jest](https://jestjs.io/) tests (see https://github.com/tine-groupware/tine/tree/main/tests/js) For end-to-end tests, write [Jest + Puppeteer](https://github.com/tine-groupware/tine/tree/main/tests/e2etests) tests ### Commit Message Guidelines tine Groupware uses [Conventional Commits](https://conventionalcommits.org/) style commit messages: (): MESSAGE [optional body] [optional footer] Example: feature(Addressbook): adds type-ahead to some contact fields * company * unit * address data closes #289 Another: fix(Phone): improve handling of empty phone numbers ... when looking for the matching contact See also the [AngularJS commit guidelines](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines). \ can be one of the following: - tweak - hack - fix - feature - build - docs - perf - refactor - style - test - config - script - text Some example \s: - APPNAME like Addressbook, Calendar, Tasks - Tests / Unittests - Cli - Import, Export - Setup You should reference a GitHub issue (if exists) like this: See #1234 If the commit closes an issue, it should be done like this: Closes #1234 (or any other "closing" keyword - see https://help.github.com/articles/closing-issues-using-keywords/ for reference) If the commit reverts a previous commit, it should begin with revert:, followed by the header of the reverted commit. In the body it should say: "This reverts commit ", where the hash is the SHA of the commit being reverted. We also use some annotations to mark commits for documentation follow-ups: - @usermanual (User manual needs to be updated because of this commit) - @releasenotes (RELEASENOTES need to be updated because of this commit) If you use ai coding agents, please add the following annotation: - @ai supported by qwen 3.6 ## Merge Conflicts A merge conflict occurs when two branches modify the same lines of a file and git cannot merge them automatically. You must resolve the conflict by hand, keeping the parts you want and removing the conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`). ### Ground rules * Never commit directly to `main` or any release branch. Always work on a topic branch and open a pull request. * For new features and general development: create the topic branch from `main` and open the PR targeting `main`. * For bug fixes and work on older release branches (e.g. `2025.11`): create the topic branch from that release branch and open the PR targeting it. ### Preventing conflicts Before opening a PR (and before pushing updates to an existing one), sync your topic branch with the branch it targets: ```sh git fetch origin git checkout main git pull --rebase git checkout my-topic-branch git rebase main ``` Resolve any conflicts that appear, then push. Rebase early and often — the longer a topic branch stays out of sync, the bigger the conflicts get. (Optional convenience: `git config pull.rebase true` makes `git pull` rebase instead of creating merge commits.) ### Case 1: topic branch from `main`, PR targeting `main` This is the most common case. If the PR reports merge conflicts, rebase your topic branch onto the current `main`: ```sh git fetch origin git checkout my-topic-branch git rebase main # resolve conflicts, then: git add git rebase --continue git push --force-with-lease origin my-topic-branch ``` * `--force-with-lease` is the safe variant of force-push: it refuses to overwrite the remote branch if it has changed in the meantime. Only force-push your own topic branch — never `main` or release branches. * If the rebase gets messy, `git rebase --abort` restores the state from before the rebase. * Alternative: `git merge main` into the topic branch instead of rebasing. This avoids force-push but adds a merge commit. Rebase is the preferred approach here. ### Case 2: work on a release branch (e.g. `2025.11`) 1. Checkout the release branch, create a topic branch from it, push, and open a PR targeting the release branch. 2. After the PR is merged, the CI pipeline automatically merges the change forward through each intermediate branch until it reaches `main`. This forward-merge can produce conflicts even if the topic branch itself had none, because the same files have diverged between the release branch and `main` independently of your change. This is especially common for the e2etests: `main` has moved on (new node packages, new helpers in the e2etest libs, switch to ES modules, ...), so the test files on both branches are only partly compatible. **Rules for e2etests in this situation:** * Do not change the e2etests on `main` unless the changes in the topic branch also fix the e2etests on `main`. * When resolving conflicts in test files, keep as much of the `main` version as possible (ES module syntax, new helpers, current package versions) and only port the functional test changes from the release branch. **Resolving the forward-merge conflict** (do not revive the deleted topic branch): 1. Look at the failing pipeline job and note the two branches involved (e.g. `2025.11` and `main`). 2. Fetch both branches. 3. Create a new branch from the target branch (`main`) with a name that includes `merge` and the PR id, e.g. `merge-1234-2025.11-into-main`. 4. Merge the originating branch (`2025.11`) into it. 5. Resolve the conflicts (see the e2etest rules above). 6. Push the branch and open a PR targeting `main`. 7. Do not squash the commits and do not rebase the new branch when merging the PR. In case the PR pipeline fails and only the job "prevent_dot_agents_changes" did not succeed: Simply add a label "allow-failure-prevent-dot-agents-changes" to the PR and ignore the failed job. ### After resolving conflicts (all cases) * Re-run the tests that cover the code you touched (PHPUnit via the tine-dev console, Jest, ...). * In particular, verify that the e2etests pass locally. They are the most likely to fail in CI after a conflict resolution. ### Other cases and tips * **Two open PRs touching the same files:** coordinate with the other author. Merge the first PR, then rebase the second one onto the updated `main`. * **Lock files** (`package-lock.json`, `composer.lock`): do not merge them by hand. Resolve the conflicts in `package.json` / `composer.json` first, then run `npm install` / `composer update` to regenerate the lock file. * **Generated files** (build output, language files): pick one side and regenerate. Never hand-edit `.po` translation files — they are managed via Transifex. * **Take one side wholesale:** `git checkout --ours ` / `git checkout --theirs `. Watch out: during a *rebase*, "ours" is the branch you rebase onto (`main`) and "theirs" is your topic branch — the opposite of what most people expect. During a *merge*, "ours" is the branch you are currently on. ## Reporting Bugs Before submitting an issue please check that you’ve completed the following steps: * Made sure you’re on the latest version * Used the search feature to ensure that the bug hasn’t been reported before Bug reports should contain the following information: * Summary: A brief description * Steps to reproduce: How did you encounter the bug? Instructions to reproduce it * Expected behavior: How did you expect it to behave? * Actual behavior: How did it actually behave? * References: Links to any related tickets or information sources. * If possible, add log file snippets (tine Groupware bog, webserver logs, browser console logs, ...) * If possible, attach visual documentation of the bug. Screenshots, video and/or animated gifs. ## Translations tine Groupware manages translations at [Transifex](https://app.transifex.com/tine/groupware/dashboard/), a free Web-Service for open source projects. ## Write Documentation _TODO add more_ ### Coding Standards For PHP Code, we use the [PSR-1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) and [PSR-2](https://www.php-fig.org/psr/psr-2/) Coding Standards. ## Asking and Answering Questions If you have a question, please open an issue or a [discussion](https://github.com/orgs/tine-groupware/discussions). We will put the label "Question" on it. Feel free to answer questions of other users. Questions on GitHub can be asked in german or english. ## Additional Resources * [Guidelines for CONTRIBUTING](https://help.github.com/articles/setting-guidelines-for-repository-contributors/) * [AngularJS Commit Message Guidelines](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines)