Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:43:24 +08:00
commit e1d41c1e9f
22 changed files with 7231 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
{
"name": "typo3-core-contributions",
"description": "Guide contributions to TYPO3 core following official contribution guidelines. Includes patch creation, Gerrit workflow, coding guidelines, testing requirements, and review processes for contributing to the TYPO3 core.",
"version": "1.4.0-20251114",
"author": {
"name": "Netresearch DTT GmbH",
"email": "info@netresearch.de"
},
"skills": [
"./"
]
}

22
.gitignore vendored Normal file
View File

@@ -0,0 +1,22 @@
# OS files
.DS_Store
Thumbs.db
# Editor files
.vscode/
.idea/
*.swp
*.swo
*~
# Temporary files
*.tmp
*.bak
.*.tmp
# Log files
*.log
# Development files
.env
.env.local

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Netresearch DTT GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# typo3-core-contributions
Guide contributions to TYPO3 core following official contribution guidelines. Includes patch creation, Gerrit workflow, coding guidelines, testing requirements, and review processes for contributing to the TYPO3 core.

1060
SKILL.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
[BUGFIX|TASK|FEATURE|DOCS|SECURITY] Subject line (max 52 chars, imperative)
# Detailed description explaining how and why (not what):
# - Lines wrapped at 72 characters
# - Explain context and reasoning
# - Don't repeat Forge issue content
# - Don't describe reproduction steps
#
# Use bullet points for lists:
# * First item
# * Second item
# * Third item
Resolves: #
Releases: main, 13.4, 12.4
# Change-Id will be added automatically by git hook - DO NOT edit manually!
# ============================================================================
# TYPO3 Commit Message Format Guide
# ============================================================================
#
# SUBJECT LINE
# ------------
# Format: [TYPE] Description
#
# Types:
# [BUGFIX] - Bug fixes
# [FEATURE] - New features (main branch only)
# [TASK] - Refactoring, cleanup, miscellaneous
# [DOCS] - Documentation changes
# [SECURITY] - Security vulnerability fixes
#
# Breaking changes: [!!!][TYPE] Description
#
# Rules:
# - Imperative mood (Fix, Add, Remove - not Fixed, Added, Removed)
# - Start with uppercase letter
# - Max 52 characters (recommended), 72 absolute limit
# - No period at end
# - Describe what now works, not what was broken
#
# DESCRIPTION BODY
# ----------------
# - Explain HOW and WHY, not WHAT (code shows what)
# - Leave blank line after subject
# - Wrap at 72 characters (URLs can be longer)
# - Use asterisks (*) for bullet points
#
# FOOTER TAGS
# -----------
# Resolves: #12345 - Closes issue on merge (features/tasks)
# Related: #12345 - Links issue without closing (bugfixes)
# Releases: main, 13.4 - Target versions (comma-separated)
# Change-Id: I... - Auto-generated, DO NOT modify!
#
# EXAMPLES
# --------
# Good:
# [BUGFIX] Fix null pointer in indexed search
# [FEATURE] Add WebP image format support
# [TASK] Refactor cache manager for better performance
# [!!!][TASK] Drop support for PHP 7.4
#
# Bad:
# [BUGFIX] fixed bug (past tense)
# [FEATURE] Adds webp support (wrong tense)
# [TASK] refactoring cache (lowercase)
# [BUGFIX] Fix null pointer exception. (period at end)
#
# VALIDATION
# ----------
# Run: ./scripts/validate-commit-message.py
#
# MORE INFO
# ---------
# See: references/commit-message-format.md
# Docs: https://docs.typo3.org/m/typo3/guide-contributionworkflow/
# ============================================================================

View File

@@ -0,0 +1,52 @@
# SKILL.md Refactoring Summary
**Date:** 2025-11-14
**Version Change:** 1.3.0 → 1.4.0
**Skill:** typo3-core-contributions
## Changes Applied
### Pattern 1: Removed "## Overview" Section
- **Before:** Lines 21-23 contained brief "## Overview" section
- **After:** Removed entire section
- **Rationale:** Content duplicated by YAML description and "When to Use This Skill" section
### Pattern 2: Converted "## Best Practices" to Imperative Form
- **Before:** "## Best Practices" with numbered list and subsection
- **After:** "## Contribution Workflow Standards" with imperative "When X" format
- **Changes:**
#### When managing commits (5 standards)
- Converted from general practices to specific commit management procedures
- Emphasized proactive skill usage (typo3-conformance-skill, typo3-testing-skill)
#### When maintaining patches (5 standards)
- Extracted patch maintenance guidance into dedicated section
- Action-oriented instructions for rebase, review, feedback
#### When writing code (5 standards)
- Focused on code quality and framework patterns
- Clear integration points with complementary skills
#### When handling CI failures (4 standards)
- Separated CI troubleshooting into distinct workflow
- Emphasized local validation and root cause analysis
## Impact Analysis
**Readability:** Improved - organized by workflow context
**Consistency:** Aligned with skill-creator best practices
**Usability:** Enhanced - clear triggers for when to apply each standard
**Workflow Integration:** Better integration with complementary skills
## Files Modified
- `/SKILL.md` (lines 1-1057)
## Verification
- Version number updated in YAML frontmatter: ✓
- Overview section removed: ✓
- Best Practices converted to Contribution Workflow Standards: ✓
- All 19 standards preserved with improved organization: ✓
- Skill integration guidance maintained: ✓

117
plugin.lock.json Normal file
View File

@@ -0,0 +1,117 @@
{
"$schema": "internal://schemas/plugin.lock.v1.json",
"pluginId": "gh:netresearch/claude-code-marketplace:skills/typo3-core-contributions",
"normalized": {
"repo": null,
"ref": "refs/tags/v20251128.0",
"commit": "c61099775905f80543deaa2bb5c0acde730c30b8",
"treeHash": "ed54abc6f6eb9cd127e0fbd345acb0b190438126ead558e86866cb8dd4517f7a",
"generatedAt": "2025-11-28T10:27:19.600332Z",
"toolVersion": "publish_plugins.py@0.2.0"
},
"origin": {
"remote": "git@github.com:zhongweili/42plugin-data.git",
"branch": "master",
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
},
"manifest": {
"name": "typo3-core-contributions",
"description": "Guide contributions to TYPO3 core following official contribution guidelines. Includes patch creation, Gerrit workflow, coding guidelines, testing requirements, and review processes for contributing to the TYPO3 core.",
"version": "1.4.0-20251114"
},
"content": {
"files": [
{
"path": "LICENSE",
"sha256": "ab373f9ef890455f235a4ccfab7ae7f1157d5edd45e659abae687b3b6255a8d6"
},
{
"path": "README.md",
"sha256": "dbe7246fc0326d7bd94e3d1331333d36644298a5b7efbb0a88cd145c691917fd"
},
{
"path": ".gitignore",
"sha256": "3f62ab1e721fdb95478da9f8f9da4cecdc319027d5bd50875be155096894577b"
},
{
"path": "SKILL.md",
"sha256": "be04cc864305cd81f7c453e438b7561b9d6f55b2d6a08f97dc16de977c01525c"
},
{
"path": "references/commit-message-format.md",
"sha256": "9b2f6e02622990792e3fb3dd9b3517bdf589fdf617177db3e62e8cdb8435ade4"
},
{
"path": "references/ddev-setup-workflow.md",
"sha256": "d4d7ce7295626390c0a7e5d0de001905d8f1eba58c412f6f2fcf2d9756b549b8"
},
{
"path": "references/troubleshooting.md",
"sha256": "5f2fa7356654dc27b7f49c6472ab5548b86927aad8c2452889cc04897fb69ef9"
},
{
"path": "references/forge-api.md",
"sha256": "e7a0fc7dbe169392e851441f9f780de4015040db4bc004a418357ae157359d26"
},
{
"path": "references/gerrit-workflow.md",
"sha256": "4495e847cf2c2865216b54670446060d721d879609a824e6a6b2ce8ec4b93c81"
},
{
"path": "references/commit-msg-hook.md",
"sha256": "1db8b73f5ffcb3c09a23035c7b772b3db5471c07cdd4a9e3a65c2f6420581896"
},
{
"path": "references/account-setup.md",
"sha256": "9dc89d22b729d21cf09efb6aa848237c641faa84a2c9ab234cb5297d07231756"
},
{
"path": "references/gerrit-review-patterns.md",
"sha256": "585195c4184806acdf01e3437dcc9b97de0c7104c86886242067bbf08836de14"
},
{
"path": "claudedocs/refactoring-summary.md",
"sha256": "0feaaf54fc2738956bf5c34829a7093a562ddb7d9f1ab468f0198a40992a347c"
},
{
"path": "scripts/setup-typo3-coredev.sh",
"sha256": "d47c65f4cd00aab4a1c0b46323a8e96ba1c2e1d14992f94d6dce798f8113c7b0"
},
{
"path": "scripts/create-commit-message.py",
"sha256": "c0ea29d591cbeefe21ec7a8375829bd870b6c271ff50d3f7e12717004974c28a"
},
{
"path": "scripts/query-forge-metadata.sh",
"sha256": "aa747ec03f3fc0a8842bd1bff236ae7253ded95f24f70e6c10e7567328a40aec"
},
{
"path": "scripts/verify-prerequisites.sh",
"sha256": "533f0555ec0f2a23088c5d11dce6193175439a68405faf2b6f5eef4251766f19"
},
{
"path": "scripts/create-forge-issue.sh",
"sha256": "60da8c26d4fde62279923281e402ada6a81a61865e9f55b4081188b74d3a97fc"
},
{
"path": "scripts/validate-commit-message.py",
"sha256": "3b75909562f243565927169dccaaf6c9fd5241e6bfd4b571a81aa5bca3b42db9"
},
{
"path": ".claude-plugin/plugin.json",
"sha256": "38ac5fca0f81f268f2714c1b3cc732f8e5512c46b203070ebeea1d9fc82fcc11"
},
{
"path": "assets/commit-template.txt",
"sha256": "9ff82d4769378bd677c2cccf167452040474c219991680a0b674b103fea9d681"
}
],
"dirSha256": "ed54abc6f6eb9cd127e0fbd345acb0b190438126ead558e86866cb8dd4517f7a"
},
"security": {
"scannedAt": null,
"scannerVersion": null,
"flags": []
}
}

275
references/account-setup.md Normal file
View File

@@ -0,0 +1,275 @@
# TYPO3 Core Contribution Account Setup Guide
Complete guide for setting up all required accounts for TYPO3 Core contributions.
## Overview
Three accounts are required for TYPO3 Core contribution:
1. **TYPO3.org Account** - Central authentication for all TYPO3 services
2. **Gerrit Account with SSH** - Code review and patch submission
3. **Slack Access** - Community communication and support
## 1. TYPO3.org Account
### Registration
1. Visit the signup page: https://my.typo3.org/index.php?id=2
2. Fill in the registration form:
- **Username**: Choose alphanumeric identifier (avoid special characters like `@` or `!`)
- **Email Address**: Use email for Forge and Gerrit notifications
- **Full Name**: Use real name (community values genuine identification)
- **Password**: Create strong password (use password manager recommended)
3. Submit the form
4. Check your email for verification message
5. Click verification link to activate account
### What This Account Provides
- Access to Forge issue tracker
- Authentication for Gerrit code review
- Access to my.typo3.org profile management
- Community member identification
### Important Notes
- Username cannot be changed after registration
- Consider using personal email (not corporate) if contributing independently
- This account will be visible in git commits and Gerrit reviews
## 2. Gerrit Account Setup
### Prerequisites
- Active TYPO3.org account
- SSH key pair (will create if needed)
### Step 1: Sign In to Gerrit
1. Visit https://review.typo3.org
2. Click **Sign In** button (top right)
3. Authenticate with your TYPO3.org credentials
4. You'll be redirected back to Gerrit
### Step 2: Generate SSH Key Pair
SSH keys are required for pushing patches to Gerrit.
#### Linux / macOS
```bash
# Generate SSH key pair
ssh-keygen -t ed25519 -C "your-email@example.org"
# Default location: ~/.ssh/id_ed25519
# Press Enter to accept default location
# Optionally set a passphrase for additional security
# View your public key
cat ~/.ssh/id_ed25519.pub
```
#### Windows
**Option A: Git Bash (Recommended)**
```bash
# Same commands as Linux/macOS above
ssh-keygen -t ed25519 -C "your-email@example.org"
```
**Option B: PuTTYgen**
1. Download and install PuTTY: https://www.putty.org/
2. Run PuTTYgen
3. Click "Generate" and move mouse randomly
4. Save private key (*.ppk file)
5. Copy public key from text area
### Step 3: Add Public Key to Gerrit
1. Click your profile icon (top right in Gerrit)
2. Select **Settings** from dropdown
3. Click **SSH Keys** in left sidebar
4. Paste your **public key** content (entire content of `id_ed25519.pub` or `id_rsa.pub`)
5. Click **Add New SSH Key**
**Important**: Only add the PUBLIC key, never the private key!
### Step 4: Test SSH Connection
```bash
# Test connection to Gerrit
ssh -p 29418 <YOUR_USERNAME>@review.typo3.org
# Expected output:
# **** Welcome to Gerrit Code Review ****
# Hi <Your Name>, you have successfully connected over SSH.
```
If you see the welcome message, SSH is configured correctly!
### Multiple Devices
If you work on multiple computers:
**Option 1: Copy Private Key**
- Copy `~/.ssh/id_ed25519` (private key) to other machines
- Set proper permissions: `chmod 600 ~/.ssh/id_ed25519`
- Not recommended for security reasons
**Option 2: Generate Separate Keys (Recommended)**
- Generate new key pair on each device
- Add all public keys to Gerrit settings
- Gerrit supports multiple SSH keys per account
- More secure: compromised device doesn't affect others
### Troubleshooting
**"Permission denied (publickey)"**
- Verify key is added to Gerrit: Settings → SSH Keys
- Check key permissions: `chmod 600 ~/.ssh/id_ed25519`
- Test with verbose: `ssh -vvv -p 29418 <username>@review.typo3.org`
**"Connection refused"**
- Check firewall settings
- Verify port 29418 is accessible
- Try from different network
**"Host key verification failed"**
- Accept host key: `ssh-keyscan -p 29418 review.typo3.org >> ~/.ssh/known_hosts`
## 3. TYPO3 Slack Workspace
### Joining Slack
1. Visit https://typo3.slack.com
2. Click **Create an account** or **Sign in**
3. Use same email as TYPO3.org account (recommended for consistency)
4. Complete Slack registration
5. You'll receive invitation to TYPO3 workspace
### Required Channels
**#typo3-cms-coredev** (Essential)
- Core development discussions
- Patch review requests
- Technical questions
- Get help from core team
### Recommended Channels
**#typo3-cms**
- General TYPO3 CMS discussions
- User questions
- Extension development
**#random**
- Off-topic chat
- Community social
**#announce**
- Official announcements
- Release notifications
### Using Slack Effectively
**Asking for Reviews**:
```
I've submitted a patch for issue #105737 (indexed search crash).
Would appreciate reviews: https://review.typo3.org/c/Packages/TYPO3.CMS/+/12345
```
**Asking Questions**:
```
Working on #105737, need clarification on preg_replace error handling.
Should I use fallback or throw exception? Context: [brief explanation]
```
**Best Practices**:
- Search before asking (knowledge base exists)
- Provide context and Forge/Gerrit links
- Be patient (volunteers respond when available)
- Use threads for discussions
- Thank people who help!
### Slack Etiquette
- **Don't** @here or @channel unless critical
- **Do** use threads to keep discussions organized
- **Don't** DM core team members without asking first
- **Do** share knowledge when you can help others
- **Don't** expect immediate responses (volunteers have lives!)
## Verification Checklist
Before proceeding with development, verify:
- [ ] TYPO3.org account created and email verified
- [ ] Can sign in to https://forge.typo3.org
- [ ] Can sign in to https://review.typo3.org
- [ ] SSH key added to Gerrit
- [ ] SSH connection to Gerrit successful: `ssh -p 29418 <user>@review.typo3.org`
- [ ] Joined TYPO3 Slack workspace
- [ ] Member of #typo3-cms-coredev channel
Run `scripts/verify-prerequisites.sh` to automatically check most of these!
## Security Best Practices
### SSH Key Security
- **Never share private keys** - TYPO3 team will never ask for them
- **Use strong passphrase** - Protects key if device is compromised
- **Rotate keys periodically** - Generate new keys annually
- **Delete old keys** - Remove unused keys from Gerrit settings
### Account Security
- **Use unique strong password** - Use password manager
- **Enable 2FA if available** - Additional security layer
- **Log out on shared devices** - Don't stay signed in
- **Review SSH keys regularly** - Remove keys from old devices
### Privacy Considerations
- Your name and email will be visible in:
- Git commit history
- Gerrit reviews
- Forge issue comments
- Consider using professional email if contributing as individual
- Company contributions may require corporate email
## Next Steps
After completing account setup:
1. Proceed to **Environment Setup** (Phase 2 in main workflow)
2. Configure Git for TYPO3 contributions
3. Clone TYPO3 repository
4. Install Git hooks
5. Start contributing!
## Support Resources
- **Forge Account Issues**: https://forge.typo3.org/projects/typo3cms-core
- **Gerrit SSH Help**: https://review.typo3.org/Documentation/user-upload.html
- **Slack Support**: Ask in #typo3-cms-coredev
- **Documentation**: https://docs.typo3.org/m/typo3/guide-contributionworkflow/
## Quick Reference
| Service | URL | Purpose |
|---------|-----|---------|
| TYPO3.org Registration | https://my.typo3.org/index.php?id=2 | Create account |
| TYPO3.org Profile | https://my.typo3.org | Manage profile |
| Forge | https://forge.typo3.org | Issue tracking |
| Gerrit | https://review.typo3.org | Code review |
| Gerrit SSH Test | `ssh -p 29418 <user>@review.typo3.org` | Verify connection |
| Slack | https://typo3.slack.com | Community chat |
| Documentation | https://docs.typo3.org/m/typo3/guide-contributionworkflow/ | Full guide |

View File

@@ -0,0 +1,477 @@
# TYPO3 Commit Message Format Specification
Complete specification for TYPO3 Core contribution commit messages with examples and validation rules.
## Structure Overview
```
[TYPE] Subject line (max 52 chars recommended, 72 absolute limit)
Detailed description explaining how and why the changes were made.
Lines wrapped at 72 characters. Explain the context and reasoning
behind the implementation approach.
Multiple paragraphs are allowed. Use bullet points with asterisks (*)
for lists:
* First item with detailed explanation
* Second item
* Third item
Resolves: #12345
Related: #12346
Releases: main, 13.4, 12.4
Change-Id: I1234567890abcdef1234567890abcdef12345678
```
## Subject Line
### Format
`[TYPE] Description starting with uppercase verb in imperative mood`
### Commit Types
| Type | Purpose | Branch Restrictions |
|------|---------|-------------------|
| `[BUGFIX]` | Bug fixes | All branches |
| `[FEATURE]` | New functionality | main branch only |
| `[TASK]` | Refactoring, cleanup, misc | All branches |
| `[DOCS]` | Documentation changes | All branches |
| `[SECURITY]` | Security vulnerability fixes | All branches |
### Breaking Changes
Use `[!!!]` prefix before type for breaking changes:
```
[!!!][FEATURE] Remove deprecated TypoScript syntax
[!!!][TASK] Drop support for PHP 7.4
```
**Important**: Deprecations must NOT use `[!!!]` prefix!
### Length Limits
- **Recommended**: 52 characters
- **Absolute maximum**: 72 characters
- Breaking changes get 5 extra chars: `[!!!]` is not counted against limit
### Imperative Mood
Subject must use imperative present tense (command form):
**Correct**:
- `Fix memory leak in cache manager`
- `Add support for WebP images`
- `Remove deprecated method calls`
- `Update documentation for hooks`
**Wrong**:
- `Fixed memory leak` (past tense)
- `Fixing memory leak` (present continuous)
- `Fixes memory leak` (present tense)
- `Memory leak fix` (noun phrase)
**Test**: "If applied, this commit will _[your subject]_"
- "If applied, this commit will **fix memory leak**" ✅
- "If applied, this commit will **fixed memory leak**" ❌
### Capitalization
- Start description with uppercase letter after `[TYPE]`
- No period at the end
`[BUGFIX] Fix null pointer exception in indexer`
`[BUGFIX] fix null pointer exception in indexer`
`[BUGFIX] Fix null pointer exception in indexer.`
### What to Describe
Describe **what now works**, not what was broken:
`Allow cancelling file exists modal`
`Cancelling the file exists modal works now`
`Limit element browser to default language pages`
`Element Browser should only render default language pages`
## Description Body
### Purpose
Explain the **how** and **why** of changes, not the **what** (code shows what).
### Guidelines
- Wrap lines at 72 characters (URLs can be longer)
- Leave blank line after subject
- Explain context and reasoning
- **Don't** repeat Forge issue content
- **Don't** describe reproduction steps (belong in Forge)
- **Do** explain non-obvious implementation choices
- **Do** mention side effects or impacts
### Bullet Points
Use asterisks (`*`) with hanging indents:
```
This change improves performance by:
* Caching compiled templates in memory
* Reducing database queries from N+1 to 1
* Pre-loading frequently accessed resources
```
### Long URLs
Lines exceeding 72 chars are acceptable for URLs. Use numbered references:
```
This implements the W3C recommendation [1] for accessible forms.
Additional context can be found in the TYPO3 RFC [2].
[1] https://www.w3.org/WAI/WCAG21/Understanding/labels-or-instructions.html
[2] https://wiki.typo3.org/Category:T3DD12/Sessions/Accessibility
```
## Footer Tags
### Required Format
`Tag: value` (colon followed by space)
### Resolves **(REQUIRED)**
Closes Forge issue when patch is merged:
```
Resolves: #12345
```
Multiple issues (one per line):
```
Resolves: #12345
Resolves: #12346
```
**Critical Rule**: Every commit MUST have at least one `Resolves:` line. The commit-msg hook will reject commits without it.
**When to use**:
- Features: MUST use Resolves
- Tasks: MUST use Resolves
- Bugfixes: MUST use Resolves
- All commit types: ALWAYS use Resolves
**Note**: For features and tasks, `Resolves:` closes the issue on merge. For bugfixes, you can use `Related:` in addition to `Resolves:` if needed, but `Resolves:` is still mandatory.
### Related **(OPTIONAL)**
Links issue without closing it:
```
Related: #12345
```
**Critical Rule**: `Related:` CANNOT be used alone - you MUST have at least one `Resolves:` line in addition to any `Related:` lines. The commit-msg hook will reject commits with only `Related:` tags.
**When to use** (in addition to Resolves):
- Bugfixes: Use Related for issues that should stay open
- Partial fixes: Related for multi-step fixes where issue remains open
- Context: Link related discussions or issues
- Cross-references: Link to related work or documentation
### Releases
Target versions (comma-separated):
```
Releases: main, 13.4, 12.4
```
**Format**:
- `main` - Current development branch
- `13.4` - Patch release version
- `12.4` - LTS version
**Rules**:
- Always include target versions
- List from newest to oldest
- Features go to `main` only
- Bugfixes can target multiple releases
### Change-Id
Auto-generated by git commit-msg hook:
```
Change-Id: I1234567890abcdef1234567890abcdef12345678
```
**Critical Rules**:
- **NEVER** manually add Change-Id
- **NEVER** modify existing Change-Id
- **NEVER** remove Change-Id
- Git hook generates this automatically
- Required for Gerrit to track patch updates
### Depends (Documentation Only)
For documentation patches referencing core changes:
```
Depends: I1234567890abcdef1234567890abcdef12345678
```
Only used in typo3/cms-docs repository.
### Reverts
For reverting patches:
```
[TASK] Revert "[FEATURE] Introduce YAML imports"
This reverts commit abc123def456.
Resolves: #12347
Reverts: I1234567890abcdef1234567890abcdef12345678
```
## Complete Examples
### Example 1: Bugfix
```
[BUGFIX] Prevent null pointer in indexed search
The preg_replace function returns null on PCRE errors like
PREG_BAD_UTF8_ERROR. Passing null to mb_strcut triggers TypeError
in PHP 8.2+.
Add null check with fallback to original content, ensuring type
safety while maintaining graceful degradation for malformed input.
Resolves: #105737
Releases: main, 13.4, 12.4
Change-Id: I1234567890abcdef1234567890abcdef12345678
```
### Example 2: Feature
```
[FEATURE] Add WebP image format support
Implement WebP processing in image manipulation stack:
* Add WebP MIME type detection
* Integrate libwebp encoding/decoding
* Update image quality settings for WebP
* Add configuration options for compression
WebP provides 25-30% better compression than JPEG while maintaining
quality, significantly improving page load times.
Resolves: #98765
Releases: main
Change-Id: Iabcdef1234567890abcdef1234567890abcdef12
```
### Example 3: Task with Breaking Change
```
[!!!][TASK] Drop PHP 7.4 support
PHP 7.4 reached end-of-life in November 2022 and no longer receives
security updates. Remove compatibility code and leverage PHP 8.0+
features:
* Remove PHP 7.4 compatibility polyfills
* Update composer.json to require PHP >= 8.0
* Use union types and match expressions
* Enable strict type declarations globally
Resolves: #99888
Releases: main
Change-Id: I9876543210fedcba9876543210fedcba98765432
```
### Example 4: Documentation
```
[DOCS] Update contribution workflow guide
Clarify git setup instructions and add troubleshooting section
for common SSH key issues reported in #typo3-cms-coredev.
Related: #12345
Releases: main
Change-Id: Iaa11bb22cc33dd44ee55ff66gg77hh88ii99jj00
```
## Validation Rules
### Subject Line
- [ ] Starts with valid commit type: `[BUGFIX]`, `[FEATURE]`, `[TASK]`, `[DOCS]`, or `[SECURITY]`
- [ ] Breaking changes use `[!!!]` prefix correctly
- [ ] Description starts with uppercase letter
- [ ] Uses imperative mood
- [ ] No period at end
- [ ] Length ≤ 52 chars (recommended) or ≤ 72 chars (absolute)
- [ ] No extension names (EXT:) in subject
### Body
- [ ] Blank line after subject (if body exists)
- [ ] Lines wrapped at 72 chars (except URLs)
- [ ] Explains how and why, not what
- [ ] No reproduction steps (belong in Forge)
### Footer
- [ ] `Resolves:` present **(REQUIRED for ALL commits)**
**Critical**: The commit-msg hook WILL REJECT commits without at least one `Resolves:` line
- [ ] `Related:` used only in addition to `Resolves:` (optional, cannot be used alone)
- [ ] `Releases:` present with valid versions
- [ ] `Change-Id:` present (added by hook)
- [ ] Proper format: `Tag: value` (colon + space)
- [ ] Issue references use `#` prefix: `#12345`
## Common Mistakes
### ❌ Wrong: Vague Subject
```
[TASK] Improve extension configuration
```
### ✅ Correct: Specific Subject
```
[TASK] Add validation for extension configuration arrays
```
---
### ❌ Wrong: Past Tense
```
[BUGFIX] Fixed cache invalidation in frontend
```
### ✅ Correct: Imperative Mood
```
[BUGFIX] Fix cache invalidation in frontend
```
---
### ❌ Wrong: No Footer Tags
```
[FEATURE] Add dark mode support
Implements dark mode toggle with user preference storage.
```
### ✅ Correct: Complete Footer
```
[FEATURE] Add dark mode support
Implements dark mode toggle with user preference storage.
Resolves: #12345
Releases: main
Change-Id: I1234567890abcdef1234567890abcdef12345678
```
---
### ❌ Wrong: Comma-Separated Issues
```
Resolves: #12345, #12346, #12347
```
### ✅ Correct: One Per Line
```
Resolves: #12345
Resolves: #12346
Resolves: #12347
```
---
### ❌ Wrong: Missing Space After Colon
```
Releases:main, 13.4
```
### ✅ Correct: Space After Colon
```
Releases: main, 13.4
```
## Tools
### Validation
Use `scripts/validate-commit-message.py`:
```bash
# Validate last commit
./scripts/validate-commit-message.py
# Validate specific file
./scripts/validate-commit-message.py --file commit-msg.txt
# Strict mode (warnings as errors)
./scripts/validate-commit-message.py --strict
```
### Generation
Use `scripts/create-commit-message.py`:
```bash
# Interactive generator
./scripts/create-commit-message.py --issue 105737 --type BUGFIX
# With breaking change
./scripts/create-commit-message.py --issue 98765 --type FEATURE --breaking
```
### Template
Copy `assets/commit-template.txt` to `~/.gitmessage.txt`:
```bash
git config --global commit.template ~/.gitmessage.txt
```
## References
- **Official Guide**: https://docs.typo3.org/m/typo3/guide-contributionworkflow/main/en-us/Appendix/CommitMessage.html
- **Gerrit Documentation**: https://review.typo3.org/Documentation/
- **TYPO3 Forge**: https://forge.typo3.org
## Quick Reference
| Element | Format | Example |
|---------|--------|---------|
| Bugfix | `[BUGFIX] Description` | `[BUGFIX] Fix null pointer in indexer` |
| Feature | `[FEATURE] Description` | `[FEATURE] Add WebP support` |
| Task | `[TASK] Description` | `[TASK] Refactor cache manager` |
| Breaking | `[!!!][TYPE] Description` | `[!!!][TASK] Drop PHP 7.4 support` |
| Resolves | `Resolves: #12345` | Closes issue on merge |
| Related | `Related: #12345` | Links without closing |
| Releases | `Releases: main, 13.4` | Target versions |

View File

@@ -0,0 +1,460 @@
# TYPO3 Commit Message Hook
Deep dive into the `Build/git-hooks/commit-msg` hook: validation rules, error messages, and troubleshooting.
## Overview
The commit-msg hook is a Git client-side hook that validates commit messages before they're created. TYPO3 uses this to enforce commit message standards and automatically add Change-Id for Gerrit tracking.
**Location**: `Build/git-hooks/commit-msg`
**Installed to**: `.git/hooks/commit-msg`
## Installation
### Automated (Recommended)
```bash
composer gerrit:setup
```
This command:
1. Copies hook from `Build/git-hooks/commit-msg` to `.git/hooks/commit-msg`
2. Makes it executable
3. Sets up Gerrit configuration
### Manual
```bash
# Copy hook
cp Build/git-hooks/commit-msg .git/hooks/commit-msg
# Make executable
chmod +x .git/hooks/commit-msg
```
### Verify Installation
```bash
# Check if hook exists and is executable
ls -la .git/hooks/commit-msg
# Expected output:
# -rwxr-xr-x 1 user group 8192 Dec 15 10:00 .git/hooks/commit-msg
```
## Hook Functions
### 1. Change-Id Generation
**Purpose**: Auto-generate unique Change-Id for Gerrit patch tracking
**Function**: `add_ChangeId()`
**Behavior**:
- Generates unique hash based on commit content
- Adds `Change-Id: I<hash>` to commit message footer
- Skips if Change-Id already exists
- Skips for fixup!/squash! commits
- Places Change-Id after Resolves/Releases footer
**Format**:
```
Change-Id: I1234567890abcdef1234567890abcdef12345678
```
**Critical Rules**:
- NEVER manually add Change-Id
- NEVER modify existing Change-Id
- NEVER remove Change-Id
- Same Change-Id = same patch (for updates)
- Different Change-Id = new patch
### 2. Line Length Validation
**Function**: `checkForLineLength()`
**Rules**:
- Maximum line length: 72 characters
- Applies to subject and body
- Excludes comment lines (starting with `#`)
- URLs can exceed limit
**Error Message**:
```
The maximum line length of 72 characters is exceeded.
```
**Location**: Line 200 in hook
### 3. Commit Type Validation
**Function**: `checkForCommitType()`
**Rules**:
- First line must contain commit type in brackets
- Valid types: `[BUGFIX]`, `[FEATURE]`, `[TASK]`, `[DOCS]`, `[SECURITY]`
- Breaking changes: `[!!!][TYPE]`
**Regex**: `/^\[^]]+\] .+$/`
**Error Message**:
```
Your first line has to contain a commit type like '[BUGFIX]'.
```
**Location**: Line 209 in hook
### 4. Resolves Tag Validation
**Function**: `checkForResolves()`
**Rules**:
- Every commit MUST have at least one `Resolves:` or `Fixes:` line
- Format: `Resolves: #<number>` or `Fixes: #<number>`
- Must be on separate line (not inline)
- Issue number must be numeric
**Regex**: `/^(Resolves|Fixes): #[0-9]+$/`
**Error Message** (as of v1.1):
```
You need at least one 'Resolves|Fixes: #<issue number>' line.
```
**Updated Message** (as of v1.2, see Issue #107881):
```
You need at least one 'Resolves: #<issue number>' line.
```
**Location**: Line 218 in hook
**Important Context**:
- The regex accepts both `Resolves:` and `Fixes:` for backward compatibility
- TYPO3 community standard is to use ONLY `Resolves:`
- The error message guides users toward the standard
- This was the source of documentation confusion in Issue #105737
### 5. Releases Tag Validation
**Function**: `checkForReleases()`
**Rules**:
- Every commit MUST have `Releases:` line
- Format: `Releases: main, 13.4, 12.4` (comma-separated)
- Valid values: `main`, version numbers like `13.4`, `12.4`
**Regex**: `/^Releases: (main|[0-9]+\.[0-9])(, *(main|[0-9]+\.[0-9]))*$/`
**Error Message**:
```
You need a 'Releases:' line. For instance: Releases: main, 8.7
```
**Location**: Line 227 in hook
## Complete Validation Flow
```
Commit attempted
1. Check line length (≤ 72 chars)
2. Check commit type ([BUGFIX], etc.)
3. Check Resolves/Fixes tag exists
4. Check Releases tag exists
All pass? → Add Change-Id → Commit succeeds
Any fail? → Show errors → Commit rejected
```
## Error Messages
### Full Error Output
When validation fails:
```
------------------------------------------------------------------
>> ERROR in your commit message:
- The maximum line length of 72 characters is exceeded.
- You need at least one 'Resolves: #<issue number>' line.
- You need a 'Releases:' line. For instance: Releases: main, 8.7
Please refer to [1] for details on the commit requirements.
You should fix this and then do commit --amend etc.
[1] https://docs.typo3.org/typo3cms/ContributionWorkflowGuide/latest/singlehtml/Index.html#commit-message-rules-for-typo3-cms
------------------------------------------------------------------
```
### Individual Errors
| Check | Error Message |
|-------|---------------|
| Line length | `The maximum line length of 72 characters is exceeded.` |
| Commit type | `Your first line has to contain a commit type like '[BUGFIX]'.` |
| Resolves tag | `You need at least one 'Resolves: #<issue number>' line.` |
| Releases tag | `You need a 'Releases:' line. For instance: Releases: main, 8.7` |
## Troubleshooting
### Hook Not Running
**Symptom**: Commits succeed without validation
**Causes**:
1. Hook not installed
2. Hook not executable
3. Git hooks disabled
**Solutions**:
```bash
# Check if hook exists
ls -la .git/hooks/commit-msg
# Reinstall hook
composer gerrit:setup
# Verify permissions
chmod +x .git/hooks/commit-msg
# Check Git config (hooks disabled?)
git config --get core.hooksPath
```
### Hook Rejecting Valid Commit
**Symptom**: Valid commit message rejected
**Debug**:
```bash
# Test commit message manually
bash .git/hooks/commit-msg .git/COMMIT_EDITMSG
# Check for hidden characters
cat -A .git/COMMIT_EDITMSG
# Verify line endings (should be LF, not CRLF)
file .git/COMMIT_EDITMSG
```
**Common issues**:
- Windows line endings (CRLF) instead of Unix (LF)
- Trailing whitespace
- Non-ASCII characters in unexpected places
- Tabs vs spaces
### Change-Id Not Generated
**Symptom**: Commit succeeds but no Change-Id added
**Causes**:
1. Change-Id already exists (manual addition)
2. Config disables it: `git config --get gerrit.createChangeId` returns `false`
3. fixup!/squash! commit (intentionally skipped)
**Solutions**:
```bash
# Enable Change-Id generation
git config gerrit.createChangeId true
# Re-commit to generate
git commit --amend --no-edit
# Verify Change-Id added
git log -1
```
### Multiple Change-Ids
**Symptom**: Commit has multiple Change-Id lines
**Impact**: Gerrit will reject or behave unexpectedly
**Fix**:
```bash
# Edit commit message
git commit --amend
# Remove duplicate Change-Id lines (keep only one)
# Save and exit
```
## Hook Customization
### When to Customize
**Valid reasons**:
- Project-specific validation rules
- Additional required tags
- Custom commit message format
**Invalid reasons**:
- Bypassing validation (use `--no-verify` temporarily instead)
- Making validation more lenient (breaks standardization)
### Safe Customization Pattern
```bash
# 1. Fork the hook
cp .git/hooks/commit-msg .git/hooks/commit-msg.custom
# 2. Add custom validation
# Edit .git/hooks/commit-msg.custom
# 3. Call from main hook
# In .git/hooks/commit-msg, add:
# .git/hooks/commit-msg.custom "$1"
# 4. Document customization
echo "Custom validation: <description>" >> .git/hooks/commit-msg.custom
```
### Example: Additional Tag
Add optional `Sponsored-by:` tag:
```bash
# Add to checkForResolves() section
checkForSponsor() {
if grep -q -E '^Sponsored-by: ' "$MSG"; then
# Valid sponsor tag found
return 0
fi
}
# Call in validation sequence
checkForLineLength
checkForCommitType
checkForResolves
checkForReleases
checkForSponsor # Custom check
```
## Bypassing Hook
### When to Bypass
**Valid cases**:
- Emergency hotfixes
- Rebasing with preserved commits
- Importing historical commits
- Temporary testing
**Invalid cases**:
- Avoiding fixing commit message
- Regular development workflow
### How to Bypass
```bash
# Single commit
git commit --no-verify
# Amend without hook
git commit --amend --no-verify
# Rebase without hook
GIT_EDITOR=true git rebase -i HEAD~5 --no-verify
```
**Warning**: Gerrit will still reject invalid commits! Bypassing hook locally doesn't bypass Gerrit validation.
## Hook History
### Version 1.1 (Current)
**From**: TYPO3 CI Review 1.1
**Based on**: Gerrit Code Review 2.14.6
**Changes from Gerrit original**:
- Added line length check (72 chars)
- Added commit type check ([BUGFIX], etc.)
- Added Resolves/Fixes check
- Added Releases check
- Modified Change-Id placement (after footer)
### Proposed Version 1.2 (Issue #107881)
**Change**: Update error message for Resolves check
- **Old**: `'Resolves|Fixes: #<issue number>'`
- **New**: `'Resolves: #<issue number>'`
**Rationale**:
- TYPO3 standard is `Resolves:` only
- `Fixes:` accepted for backward compatibility only
- Error message should guide toward standard practice
**Validation regex unchanged**: Still accepts both for compatibility
## Hook Source Code Structure
```bash
Build/git-hooks/commit-msg
├── License header (Apache 2.0)
├── TYPO3 changes documentation
├── add_ChangeId() function
│ ├── clean_message preprocessing
│ ├── Skip conditions (fixup, squash, existing)
│ ├── ID generation
│ └── AWK script for placement
├── _gen_ChangeId() helper
├── _gen_ChangeIdInput() helper
├── Validation functions:
│ ├── checkForLineLength()
│ ├── checkForCommitType()
│ ├── checkForResolves()
│ └── checkForReleases()
├── Validation execution
└── add_ChangeId() call
```
## Best Practices
### For Contributors
1. **Install hook early**: First thing after cloning
2. **Never bypass**: Fix messages instead of bypassing
3. **Don't fight the hook**: Learn requirements, follow them
4. **Use templates**: `git config commit.template ~/.gitmessage.txt`
5. **Test locally**: Use `scripts/validate-commit-message.py`
### For Maintainers
1. **Document changes**: Keep this reference updated
2. **Test thoroughly**: Validate changes don't break existing commits
3. **Backward compatible**: Keep regex accepting old patterns
4. **Clear errors**: Make error messages actionable
5. **Version carefully**: Changes affect all contributors
## Related Files
- `Build/git-hooks/commit-msg` - The hook itself
- `Build/git-hooks/pre-commit` - Code quality checks
- `assets/commit-template.txt` - Commit message template
- `scripts/validate-commit-message.py` - Offline validator
- `references/commit-message-format.md` - Commit message specification
## References
- **Hook Source**: https://github.com/TYPO3/typo3/blob/main/Build/git-hooks/commit-msg
- **Git Hooks Docs**: https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
- **Gerrit Hooks**: https://gerrit-review.googlesource.com/Documentation/cmd-hook-commit-msg.html
- **Issue #107881**: Standardize error message to mention only Resolves
## Quick Reference
| Validation | Required Format | Error if Missing |
|------------|----------------|------------------|
| Commit type | `[TYPE]` in first line | Yes |
| Line length | ≤ 72 characters | Yes |
| Resolves | `Resolves: #123` | Yes |
| Releases | `Releases: main` | Yes |
| Change-Id | Auto-generated | N/A (added by hook) |
## See Also
- `scripts/validate-commit-message.py` - Test messages offline
- `scripts/create-commit-message.py` - Generate compliant messages
- `assets/commit-template.txt` - Pre-filled template

View File

@@ -0,0 +1,674 @@
# TYPO3 Core Development - Complete DDEV Setup Workflow
Production-tested workflow for setting up a complete TYPO3 Core development environment with DDEV.
## Overview
This workflow creates a fully functional TYPO3 Core development environment with:
- TYPO3 Core v14 (main branch)
- PHP 8.4 on Apache with FPM
- MariaDB 10.6
- Test data and styleguide extensions
- Git configured for Gerrit submissions
- Ready for Core development and testing
## Prerequisites
**Required**:
- Git installed and configured
- DDEV installed (https://ddev.readthedocs.io/)
- SSH keys configured for GitHub and Gerrit
**Verify DDEV**:
```bash
ddev version
# Should show DDEV version >= 1.21
```
## Complete Setup Workflow
### Step 1: Create Project Directory
```bash
# Option A: Using 'take' (zsh/oh-my-zsh)
take t3coredev-14-php8-4
# Option B: Standard bash
mkdir -p t3coredev-14-php8-4 && cd t3coredev-14-php8-4
```
**Note**: Use descriptive directory names indicating TYPO3 version and PHP version.
### Step 2: Clone TYPO3 Core Repository
```bash
# Clone from GitHub (faster than Gerrit for initial clone)
git clone git@github.com:typo3/typo3 .
# Note: The dot (.) clones into current directory
```
### Step 3: Configure Git for TYPO3 Contributions
```bash
# Set your identity
git config user.name "YOUR NAME"
git config user.email "YOUR@EMAIL"
# Enable automatic rebase (required for TYPO3)
git config branch.autosetuprebase remote
```
### Step 4: Install Git Hooks
```bash
# Copy commit-msg hook (adds Change-Id)
cp Build/git-hooks/commit-msg .git/hooks/commit-msg
# Alternative: Use composer command
# composer gerrit:setup
```
### Step 5: Configure Gerrit Remote
```bash
# Set Gerrit as push destination
git config remote.origin.pushurl ssh://YOURT3OUSERNAME@review.typo3.org:29418/Packages/TYPO3.CMS.git
# Configure push refspec for Gerrit review
git config remote.origin.push +refs/heads/main:refs/for/main
```
**Important**: Replace `YOURT3OUSERNAME` with your actual Gerrit username!
### Step 6: Configure DDEV Project
```bash
# Set project type to TYPO3
ddev config --project-type typo3 -y
# Configure timezone (adjust to your location)
ddev config --timezone "Europe/Vienna"
# Set PHP version for v14 development
ddev config --php-version=8.4
# Use Apache with FPM (recommended for Core dev)
ddev config --webserver-type=apache-fpm
# Set MariaDB version
ddev config --database=mariadb:10.6
```
**PHP Version Notes**:
- TYPO3 v14: PHP 8.2, 8.3, 8.4
- TYPO3 v13: PHP 8.1, 8.2, 8.3
- Check `composer.json` for exact requirements
### Step 7: Configure DDEV Environment Variables
```bash
# Set TYPO3 context to Development/Ddev
ddev config --web-environment-add="TYPO3_CONTEXT=Development/Ddev"
# Set Composer root version for dev branch
ddev config --web-environment-add="COMPOSER_ROOT_VERSION=14.0.x-dev"
```
**Context Meanings**:
- `Development/Ddev`: Enables debugging, disables caching
- `Production`: Live site configuration
- `Testing`: For automated test environments
### Step 8: Start DDEV
```bash
ddev start
```
**What happens**:
1. Creates Docker containers (web, db, phpmyadmin)
2. Configures networking
3. Sets up SSL certificates
4. Mounts project directory
**Expected output**:
```
Starting t3coredev-14-php8-4...
Successfully started t3coredev-14-php8-4
Project can be reached at https://t3coredev-14-php8-4.ddev.site
```
### Step 9: Install Dependencies
```bash
# Use TYPO3's runTests.sh script (preferred for Core dev)
./Build/Scripts/runTests.sh -s composerInstall
# Alternative: Direct composer command
# ddev composer install
```
**Why runTests.sh?**
- Ensures correct Composer flags
- Consistent with CI environment
- Handles Core-specific requirements
### Step 10: Prepare TYPO3 Installation
```bash
# Create installation trigger file
ddev exec 'touch /var/www/html/FIRST_INSTALL'
# Enable Install Tool
ddev exec 'touch /var/www/html/typo3conf/ENABLE_INSTALL_TOOL'
ddev exec 'echo "KEEP_FILE" > /var/www/html/typo3conf/ENABLE_INSTALL_TOOL'
```
**File purposes**:
- `FIRST_INSTALL`: Triggers installation wizard
- `ENABLE_INSTALL_TOOL`: Enables Install Tool access (with KEEP_FILE prevents auto-deletion)
### Step 11: Run TYPO3 Setup
```bash
ddev typo3 setup \
--driver=mysqli \
--host=db \
--port=3306 \
--dbname=db \
--username=db \
--password=db \
--admin-username=backenduser \
--admin-user-password='YOUR_SECURE_PASSWORD' \
--admin-email='YOUR@EMAIL' \
--project-name='TYPO3 Core Dev v14 PHP 8.4' \
--no-interaction \
--server-type=apache \
--force
```
**Important**:
- Replace `YOUR_SECURE_PASSWORD` with your preferred admin password
- Replace `YOUR@EMAIL` with your email
- Database credentials (db/db/db) are DDEV defaults
**What this creates**:
- Database tables and schema
- Backend admin user account
- Basic TYPO3 configuration
- AdditionalConfiguration.php
### Step 12: Activate Core Extensions
```bash
# Set up extensions first
ddev typo3 extension:setup
# Activate indexed_search (relevant for testing search functionality)
ddev typo3 extension:activate indexed_search
# Activate styleguide (provides test data and UI components)
ddev typo3 extension:activate styleguide
# Activate scheduler (for scheduled tasks)
ddev typo3 extension:activate scheduler
```
**Extension purposes**:
- `indexed_search`: Full-text search (relevant to bug #105737!)
- `styleguide`: Test data generator, UI component showcase
- `scheduler`: Cron-like task scheduling
### Step 13: Configure Backend User Groups
```bash
ddev typo3 setup:begroups:default --groups=Both
```
**Creates**:
- Editor group (content management)
- Advanced Editor group (extended permissions)
- Assigns both groups to admin user
### Step 14: Generate Test Data
```bash
# Generate TCA (Table Configuration Array) examples
ddev typo3 styleguide:generate --create -- tca
# Generate frontend system template
ddev typo3 styleguide:generate --create -- frontend-systemplate
```
**Test data includes**:
- All TCA field types with examples
- Content elements with various configurations
- Pages with different properties
- Frontend templates and TypoScript
### Step 15: Launch TYPO3 Backend
```bash
ddev launch /typo3
```
Opens TYPO3 backend in your default browser.
**Login credentials**:
- Username: `backenduser`
- Password: Whatever you set in Step 11
## Post-Setup Verification
### Verify Installation
**Check TYPO3 is running**:
```bash
ddev launch
```
**Access Install Tool**:
```bash
ddev launch /typo3/install.php
```
**View site info**:
```bash
ddev describe
```
### Verify Git Configuration
```bash
# Check user config
git config user.name
git config user.email
# Check Gerrit config
git config remote.origin.pushurl
git config remote.origin.push
# Verify hooks
ls -la .git/hooks/commit-msg
```
### Verify DDEV Configuration
```bash
# View DDEV config
cat .ddev/config.yaml
# Should show:
# - project_type: typo3
# - php_version: "8.4"
# - webserver_type: apache-fpm
# - database: mariadb:10.6
# - web_environment:
# - TYPO3_CONTEXT=Development/Ddev
# - COMPOSER_ROOT_VERSION=14.0.x-dev
```
### Test Core Functionality
**Access frontend**:
```bash
ddev launch
```
**Run tests**:
```bash
# Unit tests
./Build/Scripts/runTests.sh -s unit
# Functional tests
./Build/Scripts/runTests.sh -s functional
# Check available test suites
./Build/Scripts/runTests.sh -h
```
## Development Workflow
### Creating a Feature Branch
```bash
# Ensure main is up-to-date
git checkout main
git pull origin main
# Create feature branch
git checkout -b feature/105737-fix-indexed-search-crash
```
### Making Changes
```bash
# Make code changes
vim typo3/sysext/indexed_search/Classes/Indexer.php
# Stage changes
git add .
# Commit with proper message
git commit
# (Use commit message template)
```
### Testing Changes
```bash
# Run relevant tests
./Build/Scripts/runTests.sh -s unit -- \
typo3/sysext/indexed_search/Tests/Unit/
# Check code style
./Build/Scripts/runTests.sh -s cgl -n
```
### Submitting to Gerrit
```bash
# Push to Gerrit for review
git push origin HEAD:refs/for/main
```
## Useful DDEV Commands
### Project Management
```bash
# Start project
ddev start
# Stop project
ddev stop
# Restart project
ddev restart
# Delete project (keeps files)
ddev delete
# Power off all DDEV projects
ddev poweroff
```
### Database Management
```bash
# Export database
ddev export-db --file=backup.sql.gz
# Import database
ddev import-db --file=backup.sql.gz
# Access database CLI
ddev mysql
# Launch phpMyAdmin
ddev launch -p
```
### TYPO3 Commands
```bash
# Clear all caches
ddev typo3 cache:flush
# Clear specific cache
ddev typo3 cache:flush --group=system
# Run scheduler tasks
ddev typo3 scheduler:run
# List available commands
ddev typo3 list
```
### Debugging
```bash
# View logs
ddev logs
# Follow logs (like tail -f)
ddev logs -f
# SSH into container
ddev ssh
# Execute command in container
ddev exec 'command'
```
### Performance
```bash
# View resource usage
docker stats
# Restart services if slow
ddev restart
```
## Customization Options
### Different PHP Versions
```bash
# Switch to PHP 8.2
ddev config --php-version=8.2
ddev restart
```
### Different Database Versions
```bash
# Use MySQL instead of MariaDB
ddev config --database=mysql:8.0
ddev restart
```
### Additional Services
```bash
# Add Redis
ddev get ddev/ddev-redis
# Add Elasticsearch
ddev get ddev/ddev-elasticsearch
# Add Mailhog (email testing)
ddev config --mailhog-port=8026
```
### Custom Domain
```bash
# Add additional hostname
ddev config --additional-hostnames=t3dev.local
ddev restart
```
## Troubleshooting
### "Port already allocated"
**Problem**: DDEV can't start because ports are in use
**Solution**:
```bash
# Stop other DDEV projects
ddev poweroff
# Or change port
ddev config --router-http-port=8080 --router-https-port=8443
```
### "Composer timeout"
**Problem**: Composer operations timeout
**Solution**:
```bash
# Increase timeout
ddev composer config --global process-timeout 2000
# Or use runTests.sh
./Build/Scripts/runTests.sh -s composerInstall
```
### "Cannot write to directory"
**Problem**: Permission issues in container
**Solution**:
```bash
# Fix permissions
ddev exec 'chmod -R 777 var/ typo3temp/ typo3conf/'
# Or restart DDEV
ddev restart
```
### "Database connection failed"
**Problem**: TYPO3 can't connect to database
**Solution**:
```bash
# Check database is running
ddev describe
# Verify credentials in LocalConfiguration.php
ddev exec 'cat typo3conf/LocalConfiguration.php | grep -A5 DB'
# Should show: host=db, username=db, password=db, database=db
```
## Best Practices
### Directory Naming
Use descriptive names indicating:
- TYPO3 version: `t3coredev-14`
- PHP version: `php8-4`
- Purpose: `coredev`, `testing`, `feature-name`
Examples:
- `t3coredev-14-php8-4`
- `t3-bugfix-105737`
- `t3-testing-indexed-search`
### Git Workflow
1. **Always start from main**:
```bash
git checkout main
git pull origin main
```
2. **Use feature branches**:
```bash
git checkout -b feature/issue-description
```
3. **Keep single commit per patch**:
```bash
git commit --amend # Update existing commit
```
4. **Rebase regularly**:
```bash
git fetch origin
git rebase origin/main
```
### DDEV Management
1. **Stop unused projects**:
```bash
ddev list
ddev stop <project>
```
2. **Clean up old projects**:
```bash
ddev delete <project>
# Then manually delete directory
```
3. **Monitor resources**:
```bash
docker stats
```
### Testing Workflow
1. **Test before committing**:
```bash
./Build/Scripts/runTests.sh -s unit
./Build/Scripts/runTests.sh -s functional
```
2. **Check code style**:
```bash
./Build/Scripts/runTests.sh -s cgl -n
```
3. **Fix code style automatically**:
```bash
./Build/Scripts/runTests.sh -s cgl
```
## Quick Reference
### Essential Commands
| Task | Command |
|------|---------|
| Start DDEV | `ddev start` |
| Stop DDEV | `ddev stop` |
| Open backend | `ddev launch /typo3` |
| Clear cache | `ddev typo3 cache:flush` |
| Run unit tests | `./Build/Scripts/runTests.sh -s unit` |
| Install composer | `./Build/Scripts/runTests.sh -s composerInstall` |
| View logs | `ddev logs -f` |
| SSH into container | `ddev ssh` |
| Export database | `ddev export-db --file=backup.sql.gz` |
| Git push to Gerrit | `git push origin HEAD:refs/for/main` |
### TYPO3 Versions & PHP Compatibility
| TYPO3 Version | PHP Versions | Branch | Status |
|---------------|--------------|--------|--------|
| v14 (main) | 8.2, 8.3, 8.4 | main | Development |
| v13 (LTS) | 8.1, 8.2, 8.3 | 13.4 | Active |
| v12 (ELTS) | 8.1, 8.2 | 12.4 | Security only |
### Default Credentials
| Service | URL | Username | Password |
|---------|-----|----------|----------|
| Backend | `https://[project].ddev.site/typo3` | backenduser | (your choice) |
| Database | `db:3306` | db | db |
| phpMyAdmin | `https://[project].ddev.site:8037` | db | db |
## Integration with typo3-ddev-skill
This workflow complements the `typo3-ddev-skill`:
- Use `typo3-ddev-skill` for quick setup automation
- Use this workflow for manual step-by-step understanding
- Both produce equivalent development environments
## Additional Resources
- **DDEV Documentation**: https://ddev.readthedocs.io/
- **TYPO3 Development**: https://docs.typo3.org/m/typo3/reference-coreapi/
- **runTests.sh Guide**: https://docs.typo3.org/m/typo3/guide-contributionworkflow/main/en-us/Testing/
- **TYPO3 Slack**: https://typo3.slack.com (#typo3-cms-coredev)
---
**Note**: This workflow is based on proven production usage and is continuously updated for current TYPO3 versions. Always check official documentation for the latest recommendations.

436
references/forge-api.md Normal file
View File

@@ -0,0 +1,436 @@
# Forge REST API Documentation
Complete guide to using the TYPO3 Forge (Redmine) REST API for programmatic issue management.
## Overview
TYPO3 Forge (https://forge.typo3.org) is built on Redmine and exposes a REST API for:
- Creating issues
- Updating issues
- Querying project metadata
- Managing issue relationships
## Authentication
### Get API Key
1. Log in to https://forge.typo3.org
2. Go to https://forge.typo3.org/my/account
3. Find "API access key" on the right side
4. Click "Show" to reveal your key
5. Store securely (treat like a password!)
### Using API Key
Pass via HTTP header:
```bash
-H "X-Redmine-API-Key: your-api-key-here"
```
**Security**: Never commit API keys to repositories. Use environment variables:
```bash
export FORGE_API_KEY="your-api-key-here"
```
## Base URL
All API endpoints use:
```
https://forge.typo3.org
```
## Common Endpoints
### Create Issue
**Endpoint**: `POST /issues.json`
**Request**:
```bash
curl -X POST \
-H "Content-Type: application/json" \
-H "X-Redmine-API-Key: $FORGE_API_KEY" \
-d '{
"issue": {
"project_id": "typo3cms-core",
"subject": "Issue title here",
"description": "Detailed description",
"tracker_id": 1,
"category_id": 975,
"priority_id": 4,
"custom_fields": [
{"id": 4, "value": "13"}
]
}
}' \
https://forge.typo3.org/issues.json
```
**Response**:
```json
{
"issue": {
"id": 107881,
"project": {"id": 27, "name": "TYPO3 Core"},
"tracker": {"id": 1, "name": "Bug"},
"status": {"id": 1, "name": "New"},
"priority": {"id": 4, "name": "Should have"},
"subject": "Issue title here",
"description": "Detailed description",
"created_on": "2024-12-15T10:30:00Z",
"updated_on": "2024-12-15T10:30:00Z"
}
}
```
**Extract Issue Number**:
```bash
# Parse with jq
curl ... | jq -r '.issue.id'
# Parse with grep
curl ... | grep -oP '"id":\K[0-9]+' | head -1
```
### Get Project Metadata
**Endpoint**: `GET /projects/typo3cms-core.json`
**Request**:
```bash
curl -H "X-Redmine-API-Key: $FORGE_API_KEY" \
https://forge.typo3.org/projects/typo3cms-core.json
```
**Response includes**:
- Available trackers (Bug, Feature, Task, etc.)
- Issue categories (Backend, Frontend, etc.)
- Custom field definitions
### Get Issue Details
**Endpoint**: `GET /issues/{id}.json`
**Request**:
```bash
curl -H "X-Redmine-API-Key: $FORGE_API_KEY" \
https://forge.typo3.org/issues/105737.json
```
**Response includes**:
- Full issue details
- Custom fields
- Status and assignments
- Related issues
## Field IDs
### Trackers
| ID | Name |
|----|------|
| 1 | Bug |
| 2 | Feature |
| 4 | Task |
| 6 | Story |
| 10 | Epic |
### Priorities
| ID | Name |
|----|------|
| 2 | Nice to have |
| 3 | Must have |
| 4 | Should have |
| 5 | Could have |
### Common Categories
| ID | Name |
|------|------|
| 971 | Backend API |
| 972 | Backend User Interface |
| 973 | Caching |
| 974 | Database API (Doctrine DBAL) |
| 975 | Miscellaneous |
| 976 | Extension Manager |
| 977 | Frontend |
| 1000 | Indexed Search |
| 1003 | Content Rendering |
| 1004 | Documentation |
**Get full list**: Use `scripts/query-forge-metadata.sh`
### Custom Fields
| ID | Name | Purpose |
|----|------|---------|
| 3 | Tags | Comma-separated keywords |
| 4 | TYPO3 Version | Version affected (e.g., "13", "12") |
| 5 | PHP Version | PHP version (e.g., "8.2", "8.3") |
| 8 | Complexity | Complexity estimate |
| 15 | Is Regression | Whether it's a regression |
| 18 | Sprint Focus | Sprint assignment |
## Complete Examples
### Example 1: Create Bug Report
```bash
export FORGE_API_KEY="your-api-key-here"
curl -X POST \
-H "Content-Type: application/json" \
-H "X-Redmine-API-Key: $FORGE_API_KEY" \
-d '{
"issue": {
"project_id": "typo3cms-core",
"subject": "Indexed search causes crash on malformed UTF-8",
"description": "When processing content with malformed UTF-8, the indexed search indexer crashes with TypeError in PHP 8.2+.\n\nSteps to reproduce:\n1. Create page with malformed UTF-8 content\n2. Run indexer\n3. Observe crash\n\nExpected: Graceful handling\nActual: TypeError exception",
"tracker_id": 1,
"category_id": 1000,
"priority_id": 4,
"custom_fields": [
{"id": 4, "value": "13"},
{"id": 5, "value": "8.2"},
{"id": 3, "value": "indexed search, UTF-8, crash"}
]
}
}' \
https://forge.typo3.org/issues.json
```
### Example 2: Create Feature Request
```bash
curl -X POST \
-H "Content-Type: application/json" \
-H "X-Redmine-API-Key: $FORGE_API_KEY" \
-d '{
"issue": {
"project_id": "typo3cms-core",
"subject": "Add WebP image format support",
"description": "Add native WebP support to TYPO3 image processing:\n\n- WebP MIME type detection\n- Image manipulation support\n- Configuration options\n\nBenefit: 25-30% better compression than JPEG",
"tracker_id": 2,
"category_id": 977,
"priority_id": 5,
"custom_fields": [
{"id": 4, "value": "14"},
{"id": 3, "value": "WebP, images, performance"}
]
}
}' \
https://forge.typo3.org/issues.json
```
### Example 3: Create Task
```bash
curl -X POST \
-H "Content-Type: application/json" \
-H "X-Redmine-API-Key: $FORGE_API_KEY" \
-d '{
"issue": {
"project_id": "typo3cms-core",
"subject": "Standardize commit-msg hook error message",
"description": "Update Build/git-hooks/commit-msg error message to mention only '\''Resolves:'\'' tag instead of '\''Resolves|Fixes:'\'' to align with TYPO3 community standard.\n\nWhile validation regex accepts both for backward compatibility, error message should guide toward single standard keyword.",
"tracker_id": 4,
"category_id": 975,
"priority_id": 4,
"custom_fields": [
{"id": 4, "value": "14"}
]
}
}' \
https://forge.typo3.org/issues.json
```
## Error Handling
### Common Errors
**422 Unprocessable Entity**:
```json
{
"errors": ["Category is not included in the list"]
}
```
**Solution**: Check field IDs are valid for the project
**422 - Required Field Missing**:
```json
{
"errors": ["Typo3 version cannot be blank"]
}
```
**Solution**: Add required custom field (id: 4 for TYPO3 version)
**401 Unauthorized**:
```
{"errors": ["You are not authorized to access this page."]}
```
**Solution**: Check API key is correct and has permissions
### Validation
Before creating issue, validate:
- [ ] API key is set and valid
- [ ] project_id is "typo3cms-core"
- [ ] subject is descriptive (not too generic)
- [ ] tracker_id is valid (1, 2, or 4 most common)
- [ ] category_id matches project categories
- [ ] TYPO3 version custom field included (id: 4)
## Best Practices
### Subject Lines
**Good**:
- "Indexed search crashes on malformed UTF-8"
- "Add WebP image format support"
- "Standardize commit-msg hook error message"
**Bad**:
- "Fix bug"
- "Improvement needed"
- "Question about feature"
### Descriptions
**Structure**:
1. Brief summary (what is the issue)
2. Steps to reproduce (for bugs)
3. Expected behavior
4. Actual behavior
5. Additional context
**Include**:
- Error messages
- Stack traces
- Version information
- Configuration details
**Avoid**:
- Asking questions (use Slack instead)
- Multiple unrelated issues in one ticket
- Vague descriptions without details
### Categories
Choose most specific category:
- Not "Miscellaneous" if more specific exists
- "Backend API" for backend PHP code
- "Backend User Interface" for backend UI/UX
- "Frontend" for frontend rendering
- Component-specific for extensions (e.g., "Indexed Search")
### Priority
**Guidelines**:
- **Must have (3)**: Blocking issues, critical bugs, security
- **Should have (4)**: Normal bugs, important features (most common)
- **Could have (5)**: Nice-to-have features, minor improvements
- **Nice to have (2)**: Low priority, future considerations
## Automation Tips
### Store Issue Template
```bash
cat > /tmp/issue-template.json <<'EOF'
{
"issue": {
"project_id": "typo3cms-core",
"subject": "",
"description": "",
"tracker_id": 1,
"category_id": 975,
"priority_id": 4,
"custom_fields": [
{"id": 4, "value": "13"}
]
}
}
EOF
```
### Parse Response
```bash
# Extract issue number
ISSUE_ID=$(curl ... | jq -r '.issue.id')
# Build URL
ISSUE_URL="https://forge.typo3.org/issues/${ISSUE_ID}"
# Use in commit message
echo "Resolves: #${ISSUE_ID}"
```
### Batch Operations
Query multiple issues:
```bash
for id in 105737 107881 108000; do
curl -H "X-Redmine-API-Key: $FORGE_API_KEY" \
"https://forge.typo3.org/issues/${id}.json"
done
```
## Integration with Git
### Create Issue and Commit
```bash
#!/bin/bash
# Create issue
RESPONSE=$(curl -s -X POST \
-H "Content-Type: application/json" \
-H "X-Redmine-API-Key: $FORGE_API_KEY" \
-d @issue.json \
https://forge.typo3.org/issues.json)
# Extract issue number
ISSUE_ID=$(echo "$RESPONSE" | jq -r '.issue.id')
# Use in commit
git commit -m "[BUGFIX] Fix the problem
Resolves: #${ISSUE_ID}
Releases: main"
```
### Link Gerrit Patch to Issue
After submitting to Gerrit:
```bash
GERRIT_URL="https://review.typo3.org/c/Packages/TYPO3.CMS/+/91302"
# Add comment to Forge issue with patch link
# (requires additional API call - see Redmine API docs)
```
## Resources
- **Redmine API Docs**: https://www.redmine.org/projects/redmine/wiki/Rest_api
- **TYPO3 Forge**: https://forge.typo3.org
- **API Access Key**: https://forge.typo3.org/my/account
- **Project Info**: https://forge.typo3.org/projects/typo3cms-core
## Quick Reference
| Task | Endpoint | Method |
|------|----------|--------|
| Create issue | `/issues.json` | POST |
| Get issue | `/issues/{id}.json` | GET |
| Update issue | `/issues/{id}.json` | PUT |
| Get project | `/projects/{id}.json` | GET |
| List issues | `/issues.json?project_id=typo3cms-core` | GET |
## See Also
- `scripts/create-forge-issue.sh` - Interactive issue creation
- `scripts/query-forge-metadata.sh` - Query project metadata
- `references/commit-message-format.md` - For using issue numbers in commits

View File

@@ -0,0 +1,386 @@
# TYPO3 Gerrit Review Patterns - Real-World Insights
Based on analysis of actual merged patches from review.typo3.org, this document captures common review patterns, expectations, and best practices.
## Understanding Revision Counts
**Key Insight**: High revision counts (7-25 patch sets) are NORMAL and expected, not a sign of failure.
**Real Examples**:
- Change #90226: 24 patch sets (functional tests for Extbase FileUpload)
- Change #88519: 14 patch sets (breaking change - Record API)
- Change #91161: 9 patch sets (DI refactoring)
- Change #91284: 7 patch sets (pagetree performance)
**What causes multiple revisions**:
1. CI failures requiring fixes
2. Rebases due to base branch updates
3. Code quality refinements based on reviewer feedback
4. Architectural improvements suggested by core team
5. Edge case handling
6. Scope adjustments (e.g., backport constraints)
**Mindset**: Each revision makes the patch better. Multiple revisions show:
- Responsiveness to feedback
- Iterative improvement
- Collaboration with core team
- Thorough vetting process
## Common Reviewer Feedback Themes
### 1. Architectural Alignment
**Pattern**: Leverage framework patterns over custom solutions
**Example from #91161**:
```
Reviewer: "Just make this method no-op with only the trigger_error() and
remove $this->instances since the service locator will catch classes that
implements the interface automatically."
```
**Expectation**:
- Use dependency injection (DI) over manual instance management
- Leverage service locators for interface-based registration
- Follow TYPO3 framework patterns
- Avoid reinventing framework capabilities
**Best Practice**: Before implementing, check if TYPO3 framework already provides the pattern.
### 2. Configuration Best Practices
**Pattern**: Services.yaml configuration matters
**Example from #90226**:
```
Reviewer: "Why is Domain/Validator/ excluded here? This would prevent
validators from receiving dependency injection."
```
**Expectation**:
- Understand Services.yaml exclusion patterns
- Don't copy boilerplate without understanding
- Enable DI for all appropriate classes
- Reference official documentation for patterns
**Best Practice**: Review Services.yaml carefully, don't blindly copy from examples.
### 3. Performance Validation
**Pattern**: Performance claims require empirical evidence
**Example from #91284**:
```
Reviewer: "It performs much better. If a large number of pages are open,
there is still a very slight delay (milliseconds), but this should not
cause any problems."
Reviewer: "Nice one here, removing the expensive calls to this.nodes.find()
- reduced from O(n^(m²)) [30ms] to O(n) [2-3ms]"
```
**Expectation**:
- Test performance fixes in production-like environments
- Provide computational complexity analysis
- Measure actual performance improvements
- Document before/after metrics
- Multiple reviewers test independently
**Best Practice**: Include performance measurements in commit message or comments.
### 4. Breaking Changes Documentation
**Pattern**: Breaking changes need explicit communication
**Example from #88519**:
```
Reviewer: "The info that the item.record is now a record object, is
important to know for externals."
Reviewer: "That's breaking IMHO" (regarding API change)
```
**Expectation**:
- Document API changes affecting extension developers
- Use `[!!!]` prefix for breaking changes
- Add deprecations with `trigger_error()` for BC breaks
- Consider backport constraints (may limit to main branch)
- Provide migration examples
**Best Practice**: Always think about extension developers when changing public APIs.
### 5. Code Quality Standards
**Pattern**: Modern PHP practices and clean code
**Recurring feedback themes**:
- Use named arguments in function calls
- Separate concerns (split large functions into classes)
- Improve readability through refactoring
- Handle edge cases explicitly
- Remove unused code
**Best Practice**: Follow PSR-12 and modern PHP 8+ features.
### 6. Test Stability Focus
**Pattern**: Tests serve as API stability monitors
**Example from #90226**:
```
Reviewer: "These tests could serve as an important whistleblower with
extbase to monitor API stability and how frequently changes are needed."
```
**Expectation**:
- Tests should catch unintended API changes
- Test scope should be "as simple as possible and as complex as needed"
- Functional tests preferred over unit tests for integration points
- Tests validate real-world usage patterns
**Best Practice**: Write tests that detect breaking changes, not just code coverage.
### 7. Iterative Refinement Philosophy
**Pattern**: Patches improve through collaboration, not rejection
**Observed patterns**:
- Positive language: "I like! 🙌", "Awesome job!", "Nice one here"
- Constructive suggestions: "You could...", "Consider...", "What about..."
- Collaborative problem-solving: Multiple reviewers contribute ideas
- Incremental improvements: Each revision refines the approach
**Expectation**:
- Be responsive to feedback
- Implement suggested improvements
- Ask clarifying questions when needed
- Iterate toward excellence
**Best Practice**: View reviews as mentoring, not gatekeeping.
## Common Revision Patterns
### Pattern 1: CI Failure Cycle
**Typical flow**:
1. Initial submission
2. CI rejects (CGL, PHPStan, tests)
3. Fix CI issues
4. Resubmit
5. New CI issues found
6. Repeat until green
**Prevention**: Use typo3-conformance-skill and typo3-testing-skill BEFORE first submission.
### Pattern 2: Rebase Cycle
**Typical flow**:
1. Patch submitted
2. Base branch updated with other changes
3. Gerrit shows "needs rebase"
4. Rebase on latest main
5. Resolve conflicts
6. CI runs again (may reveal new issues)
7. Repeat as needed
**Prevention**: Rebase regularly during development, not just at submission.
### Pattern 3: Scope Adjustment
**Typical flow**:
1. Patch targets main + version branches
2. Review reveals backport complexity
3. Dependencies on other changes discovered
4. Scope changed to "main only"
5. Commit message updated
**Prevention**: Check dependencies before claiming backport compatibility.
### Pattern 4: Architecture Refinement
**Typical flow**:
1. Working implementation submitted
2. Reviewer suggests better framework pattern
3. Refactor to use framework capabilities
4. Simplify code by removing custom logic
5. May take 3-5 revisions to align
**Prevention**: Study framework patterns before implementing custom solutions.
## Review Timeline Expectations
Based on analyzed patches:
**Simple changes** (1-3 files, no breaking changes):
- Review starts: Within 1-2 days
- First feedback: 2-3 days
- Typical revisions: 2-5 patch sets
- Merge time: 1-2 weeks
**Complex changes** (multiple files, new features):
- Review starts: Within 3-5 days
- First feedback: 3-7 days
- Typical revisions: 7-15 patch sets
- Merge time: 2-4 weeks
**Breaking changes** (API changes, [!!!]):
- Review starts: Within 1-2 days
- First feedback: 1-3 days (architectural concerns raised early)
- Typical revisions: 10-20 patch sets
- Merge time: 3-6 weeks (due to documentation, deprecation)
**Performance fixes**:
- Review starts: Within 1-2 days
- Testing phase: 1-2 weeks (reviewers test in production)
- Typical revisions: 5-10 patch sets
- Merge time: 2-3 weeks
## Key Reviewers and Their Focus Areas
Based on observed patterns:
**Christian Kuhn (lolli)**:
- Architectural alignment
- Framework pattern usage
- Test quality and coverage
- Long-term maintainability
**Benni Mack**:
- Breaking change implications
- Extension developer impact
- API design
- Documentation completeness
**Stefan Bürk**:
- Configuration best practices
- Services.yaml patterns
- Dependency injection
- Code quality standards
**Pattern**: Different reviewers have different expertise areas. Address each reviewer's specific concerns.
## Best Practices from Real Reviews
### Do's
**Respond to every comment**: Even if just "Done" or "Fixed in PS X"
**Test in production-like environments**: Especially for performance fixes
**Use framework patterns**: DI, service locators, event dispatchers
**Document breaking changes**: Think about extension developers
**Iterate based on feedback**: Don't defend, improve
**Keep scope focused**: Don't expand scope during review
**Update commit messages**: Reflect scope or approach changes
**Add deprecations properly**: Use trigger_error() for BC breaks
### Don'ts
**Don't take high revision counts personally**: They're normal and expected
**Don't copy boilerplate blindly**: Understand configuration patterns
**Don't skip testing**: CI will catch it anyway
**Don't ignore architectural feedback**: Core team guides for good reasons
**Don't rush rebases**: Test after rebasing
**Don't claim performance without metrics**: Provide evidence
**Don't break APIs without [!!!]**: Use proper prefixes
**Don't argue with multiple reviewers**: If 2+ reviewers agree, they're probably right
## Handling Common Situations
### Situation 1: "My patch has 10 revisions already"
**Response**: This is normal! Changes #90226 had 24, #88519 had 14. Keep iterating.
**Action**:
1. Review all outstanding comments
2. Address each systematically
3. Test thoroughly after each change
4. Mark comments as resolved with explanation
5. Keep positive attitude
### Situation 2: "Reviewer suggested complete refactoring"
**Response**: Core team is guiding toward better patterns. This is mentoring.
**Action**:
1. Ask clarifying questions if needed
2. Study the suggested pattern
3. Implement as suggested
4. Don't defend original approach
5. Learn framework patterns for future
### Situation 3: "CI keeps failing after fixes"
**Response**: Each rebase can reveal new issues. This is expected.
**Action**:
1. Use typo3-conformance-skill locally
2. Use typo3-testing-skill for test failures
3. Validate BEFORE pushing
4. Consider environment differences
5. Ask for help if stuck
### Situation 4: "Scope changed from 'main + 13.4' to 'main only'"
**Response**: Backport complexity discovered during review. Common pattern.
**Action**:
1. Update commit message (Releases: main)
2. Update Forge issue target version
3. Don't argue - backporting is complex
4. Focus on getting main merged first
5. Backport can be separate patch later
## Learning from Reviews
### What to Extract from Reviews
When reading other reviews:
1. **Architectural patterns**: How do they structure code?
2. **Framework usage**: What TYPO3 APIs do they leverage?
3. **Testing approaches**: How do they test complex scenarios?
4. **Documentation style**: How do they explain breaking changes?
5. **Reviewer priorities**: What concerns get raised most?
### How to Improve
Based on review patterns:
1. **Study merged patches**: See what passes review
2. **Read reviewer comments**: Learn what matters to core team
3. **Use framework patterns**: Follow existing approaches
4. **Test thoroughly**: Validate locally before submission
5. **Be responsive**: Quick turnaround on feedback
6. **Stay positive**: Reviews are mentoring, not rejection
## Summary: Review Success Pattern
**Before submission**:
- ✅ Use typo3-conformance-skill
- ✅ Use typo3-testing-skill
- ✅ Study framework patterns
- ✅ Check Services.yaml configuration
- ✅ Test in realistic environment
**During review**:
- ✅ Respond to all comments promptly
- ✅ Implement suggestions positively
- ✅ Test after each revision
- ✅ Update commit message as needed
- ✅ Ask questions when unclear
**Mindset**:
- ✅ Multiple revisions are normal and healthy
- ✅ Reviews improve your code
- ✅ Core team is mentoring you
- ✅ Each iteration makes TYPO3 better
- ✅ You're learning framework patterns
## References
**Analyzed patches**:
- #90226: Extbase FileUpload functional tests (24 PS)
- #91161: DI in ExtractorService (9 PS)
- #91284: Pagetree performance (7 PS)
- #88519: Record API breaking change (14 PS)
**Review platform**: https://review.typo3.org
**Remember**: The best contributors don't have the fewest revisions - they have the most responsive and collaborative review interactions.

View File

@@ -0,0 +1,783 @@
# TYPO3 Gerrit Workflow Guide
Comprehensive guide for working with Gerrit code review system in TYPO3 Core contributions.
## What is Gerrit?
Gerrit is a web-based code review tool that TYPO3 uses for managing patch submissions. Every code change must go through Gerrit review before being merged into TYPO3 Core.
**Key Concepts**:
- **Patch/Change**: Single commit representing your contribution
- **Patchset**: Version of a patch (same Change-Id, updated code)
- **Review**: Process of evaluating code quality and correctness
- **Merge**: Final acceptance of patch into TYPO3 Core
## Accessing Gerrit
**URL**: https://review.typo3.org
**Authentication**: Use TYPO3.org account credentials
**Search Tool**: https://forger.typo3.com (easier searching)
## Submitting Your First Patch
### Prerequisites
- Git configured for TYPO3 (see Environment Setup)
- SSH keys added to Gerrit
- Commit ready with proper message format
- All changes in single commit
### Push to Gerrit
```bash
# From your feature branch
git push origin HEAD:refs/for/main
```
**What happens**:
1. Git pushes to special Gerrit ref: `refs/for/main`
2. Gerrit creates new review
3. You receive SUCCESS message with review URL
**Expected Output**:
```
remote: Processing changes: new: 1, done
remote:
remote: SUCCESS
remote:
remote: https://review.typo3.org/c/Packages/TYPO3.CMS/+/12345 [NEW]
remote:
To ssh://review.typo3.org:29418/Packages/TYPO3.CMS.git
* [new branch] HEAD -> refs/for/main
```
**Save the review URL!** You'll need it to monitor progress.
### Alternative Push Methods
If you've configured default push settings:
```bash
# Simple push (if remote.origin.push configured)
git push
```
## Continuous Integration
After submission, Gerrit automatically runs tests:
1. **GitLab CI** triggers test pipeline
2. Tests run across multiple PHP versions, code style checks, static analysis (PHPStan), and unit/functional tests
3. Results appear on Gerrit review page
4. Usually completes in 10-20 minutes
**Status Indicators**:
- ✅ Green checkmark: All tests passed
- ❌ Red X: Tests failed
- ⏳ Clock: Tests running
### IMPORTANT: New Patches Start in "Work in Progress" State
**By default, newly submitted patches are marked as WIP (Work in Progress)**. This means:
1. ⚠️ **Not visible to reviewers** - Core team won't see your patch for review
2.**CI tests still run** - You get test feedback immediately
3. 🔍 **You must verify yourself first** - Check all CI jobs before requesting review
4.**You must manually mark as ready** - Change state to "Ready for Review" when done
**Workflow for New Submissions**:
```bash
# 1. Push your patch
git push origin HEAD:refs/for/main
# 2. Note the review URL from output
# https://review.typo3.org/c/Packages/TYPO3.CMS/+/12345 [WIP]
# 3. Wait for CI to complete (10-20 minutes)
# 4. CHECK ALL FAILING JOBS (critical step!)
# - Open the review URL
# - Look for any CI failures (red X marks)
# - For each failure, find the GitLab job URL
# - Read the ACTUAL ERROR LOGS (don't guess!)
# - Fix ALL issues before marking ready
# 5. Once all tests pass, mark as ready for review
#
# Option A: Remove WIP via command line (empty push)
git commit --amend --allow-empty --no-edit
git push origin HEAD:refs/for/main%ready
# Option B: Remove WIP via web UI
# a. Open review URL: https://review.typo3.org/c/Packages/TYPO3.CMS/+/XXXXX
# b. Click "Start Review" button (top right area, near your avatar)
#
# Notes:
# - %ready flag removes WIP state (even with empty pushes)
# - %wip flag sets WIP state: git push origin HEAD:refs/for/main%wip
# - SSH 'gerrit review' command does NOT support WIP flags (use git push flags instead)
```
### Investigating CI Failures (CRITICAL!)
**NEVER assume what failed - ALWAYS check the actual job logs!**
#### Step 1: Find All Failing Jobs
On your Gerrit review page:
1. Scroll to the CI results section
2. Look for red ❌ marks next to job names
3. Note ALL failing job names (there might be multiple!)
Common failing jobs:
- `cgl pre-merge` - Code style violations (PHP CS Fixer)
- `phpstan php X.X pre-merge` - Static analysis errors
- `unit php X.X pre-merge` - Unit test failures
- `functional php X.X pre-merge` - Functional test failures
#### Step 2: Access GitLab Job Logs
For each failing job:
1. Click on the failing job name in Gerrit
2. You'll be redirected to GitLab CI (https://git.typo3.org/typo3/CI/cms/-/jobs/XXXXXX)
3. Click the job log or raw log to see the actual error
**Example**: If job #4896429 failed:
- URL: `https://git.typo3.org/typo3/CI/cms/-/jobs/4896429`
- Raw log: `https://git.typo3.org/typo3/CI/cms/-/jobs/4896429/raw`
#### Step 3: Read and Understand ACTUAL Errors
**DO NOT GUESS!** Read the actual error messages:
**Code Style (cgl) Example**:
```
Fixed 1 of 1 files in ... seconds.
Checked 1 of 1 files in ... seconds.
1) typo3/sysext/indexed_search/Tests/Unit/IndexerTest.php (single_quote)
---------- begin diff ----------
- body: "This content should not appear"
+ body: 'This content should not appear'
----------- end diff -----------
```
**Fix**: Change double quotes to single quotes in test file.
**PHPStan Example**:
```
------ -------------------------------------------------------------------------
Line indexed_search/Tests/Unit/IndexerTest.php
------ -------------------------------------------------------------------------
236 Call to static method PHPUnit\Framework\Assert::assertNotNull()
with string will always evaluate to true.
------ -------------------------------------------------------------------------
```
**Fix**: Remove `assertNotNull()` call - it's redundant for string return types.
**Unit Test Failure Example**:
```
FAILURES!
Tests: 11683, Assertions: 20300, Failures: 1.
There was 1 failure:
1) TYPO3\CMS\IndexedSearch\Tests\Unit\IndexerTest::bodyDescriptionReturnsEmptyStringWhenMaxLengthIsZero
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-''
+'This content should not appear in description'
```
**Fix**: Test logic is wrong - review the test expectations.
#### Step 4: Fix ALL Issues
⚠️ **CRITICAL**: A CI pipeline may have multiple failing jobs. Fix ALL of them:
```bash
# Example: 5 jobs failed (cgl, phpstan, 3x unit tests)
# You must fix:
# 1. Code style issues (single quotes)
# 2. PHPStan warnings (remove redundant assertions)
# 3. Unit test failures (fix test logic)
# Make all fixes
vim typo3/sysext/indexed_search/Tests/Unit/IndexerTest.php
# Stage changes
git add typo3/sysext/indexed_search/Tests/Unit/IndexerTest.php
# Amend commit
git commit --amend --no-edit
# Push updated patchset
git push origin HEAD:refs/for/main
```
#### Step 5: Wait for Re-verification
After pushing fixes:
1. CI automatically runs again
2. Old failed votes (Verified-1) are removed
3. Wait for all jobs to complete
4. Verify ALL jobs are now passing (green ✅)
#### Step 6: Mark as Ready for Review
Once ALL CI jobs pass:
1. Open your review on Gerrit
2. Click **"More"** → **"Start Review"**
3. Optionally add a comment: "Ready for review. All CI checks passing."
4. Your patch is now visible to core team reviewers
### Common CI Failure Patterns
| Job Type | Common Issues | Where to Look |
|----------|---------------|---------------|
| cgl (Code Style) | Double quotes, spacing, indentation | PHP CS Fixer diff in log |
| phpstan | Type errors, redundant code, undefined vars | Line numbers + error descriptions |
| unit tests | Test failures, assertion mismatches | Test name + expected vs actual |
| functional tests | Database issues, integration problems | Full stack trace in log |
**If tests fail**:
1. ⚠️ **DO NOT GUESS** - Always read actual job logs
2. Check ALL failing jobs, not just the first one
3. Access GitLab CI job logs via links on Gerrit
4. Fix all issues in one patchset
5. Push updated patchset (next section)
6. Wait for re-verification
7. Mark as ready only when ALL jobs pass
## Updating Your Patch
When reviewers request changes or tests fail:
### Step 1: Make Changes Locally
```bash
# Make code changes
vim path/to/file.php
# Stage changes
git add path/to/file.php
```
### Step 2: Amend Commit
```bash
# Amend existing commit (DO NOT create new commit!)
git commit --amend
# CRITICAL: Keep the Change-Id line unchanged!
```
### Step 3: Push Updated Patchset
```bash
# Push to same Gerrit change
git push origin HEAD:refs/for/main
```
**What happens**:
- Gerrit matches Change-Id
- Creates new patchset (Patch Set 2, 3, etc.)
- Previous patchsets remain for comparison
- CI tests run again
**Patchset Versioning**:
- Patch Set 1: Initial submission
- Patch Set 2: First update
- Patch Set 3: Second update
- etc.
## Rebasing Your Patch
### Why Rebase?
While you're working, other contributors' patches get merged. Your patch becomes based on outdated code. Rebasing updates your patch to build on the latest codebase.
### When to Rebase
- Merge conflict indicator appears on Gerrit
- Regularly during development (best practice)
- Before running tests
- When requested by reviewers
### Method 1: Browser-Based Rebase (Easiest)
**Requirements**: No merge conflicts
**Steps**:
1. Open your patch on Gerrit
2. Click **Rebase** button (top right)
3. Select "Rebase on top of the main branch"
4. Click **Rebase**
Gerrit automatically:
- Rebases your change
- Creates new patchset
- Runs CI tests
### Method 2: Command-Line Rebase
**When to use**: Merge conflicts exist, or prefer manual control
**Steps**:
```bash
# Ensure on your feature branch
git checkout feature/105737-fix-indexed-search
# Fetch latest changes
git fetch origin
# Rebase onto main
git rebase origin/main
```
**If no conflicts**:
```bash
# Push rebased patch
git push origin HEAD:refs/for/main
```
**If conflicts occur**: See Resolving Merge Conflicts section below.
### Alternative Rebase Methods
**Option A: Pull with Rebase**
```bash
git pull --rebase origin main
```
**Option B: Interactive Rebase** (advanced)
```bash
git rebase -i origin/main
```
## Resolving Merge Conflicts
### What Are Conflicts?
Conflicts occur when:
- You modified file X
- Someone else modified same lines in file X
- Their patch merged first
- Git can't auto-merge
### Conflict Resolution Process
#### Step 1: Start Rebase
```bash
git rebase origin/main
```
**Output with conflicts**:
```
CONFLICT (content): Merge conflict in path/to/file.php
error: could not apply abc123... Your commit message
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
```
#### Step 2: Identify Conflicted Files
```bash
git status
```
**Output**:
```
On branch feature/105737-fix-indexed-search
You are currently rebasing branch 'feature/105737-fix-indexed-search' on 'abc123'.
(fix conflicts and then run "git rebase --continue")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: path/to/file.php
```
#### Step 3: Resolve Conflicts
Open conflicted file in editor:
```php
<<<<<<< HEAD
// Code from main branch (their changes)
$result = newFunction($data);
=======
// Your changes
$result = oldFunction($data);
>>>>>>> Your commit message
```
**Choose resolution**:
**Option A: Keep their changes**
```php
$result = newFunction($data);
```
**Option B: Keep your changes**
```php
$result = oldFunction($data);
```
**Option C: Merge both** (most common)
```php
// Updated to use new function while preserving your logic
$result = newFunction($processedData);
```
Remove conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`).
#### Step 4: Mark as Resolved
```bash
# Stage resolved files
git add path/to/file.php
# Check all conflicts resolved
git status
```
#### Step 5: Continue Rebase
```bash
git rebase --continue
```
If more conflicts exist, repeat steps 3-5.
#### Step 6: Push Rebased Patch
```bash
git push origin HEAD:refs/for/main
```
### Conflict Resolution Tips
**Understand Context**:
- Review their changes: `git show HEAD:path/to/file.php`
- Review your changes: `git show feature/105737-fix-indexed-search:path/to/file.php`
- Check file history: `git log -- path/to/file.php`
**Test After Resolution**:
```bash
# Run tests locally
composer test:unit
composer test:functional
# Check syntax
php -l path/to/file.php
```
**Ask for Help**:
- Post in #typo3-cms-coredev Slack
- Comment on Gerrit review
- Reference conflicting patch if known
### Aborting Rebase
If rebase goes wrong:
```bash
git rebase --abort
```
Returns to pre-rebase state. You can try again.
## Review Process
### Voting System
**Code Review** (CR):
- **+2**: Looks good, approved
- **+1**: Looks mostly good
- **0**: Neutral (default)
- **-1**: Needs improvement
- **-2**: Do not merge (veto)
**Verified** (V):
- **+1**: Tests passed
- **0**: Not yet tested
- **-1**: Tests failed
**Merge Requirements**:
- At least **+2 Code Review** from core team member
- At least **+1 Verified** (CI tests passed)
- No unresolved **-2** votes
- At least 2 reviewers involved (one must be core team)
### Typical Review Timeline
**Simple Bugfixes**: 1-3 days
**Medium Features**: 3-7 days
**Complex Features**: 1-2 weeks
**Breaking Changes**: 2-4 weeks (more scrutiny)
**Factors affecting timeline**:
- Code quality and completeness
- Test coverage
- Documentation
- Reviewer availability (volunteers!)
- Complexity and impact
### Responding to Review Comments
#### Step 1: Read Feedback Carefully
- Understand what's being requested
- Ask questions if unclear
- Check if feedback applies to multiple locations
#### Step 2: Implement Changes
```bash
# Make requested changes
vim path/to/file.php
# Stage and amend
git add path/to/file.php
git commit --amend
# Push update
git push origin HEAD:refs/for/main
```
#### Step 3: Respond on Gerrit
- Click **Reply** button
- Address each comment:
- "Done" - Simple confirmation
- "Fixed in PS3" - Reference patchset number
- Explain your approach if different from suggestion
- Thank reviewers
- Click **Send**
#### Example Response
```
Thanks for the review!
> Line 45: Consider using dependency injection
Good point! I've refactored to use DI in PS3.
> Line 120: Add type hint
Added in PS3. Also added return type hints throughout.
> Missing tests for edge case
Added test case for empty string input in Tests/Unit/IndexerTest.php
```
### Getting More Reviews
**If no reviews after 3-4 days**:
1. **Advertise on Slack** (#typo3-cms-coredev):
```
I've submitted a patch for #105737 (indexed search crash).
Would appreciate reviews when you have time: https://review.typo3.org/c/Packages/TYPO3.CMS/+/12345
```
2. **Check patch quality**:
- Tests passing?
- Documentation complete?
- Follows coding standards?
- Clear commit message?
3. **Ask specific reviewers** (if appropriate):
- Maintainers of affected area
- Previous contributors to same files
- Don't spam or DM randomly!
## Gerrit Interface Guide
### Review Page Sections
**Header**:
- Status (Active, Merged, Abandoned)
- Subject and description
- Owner and reviewers
- CI test results
**Files**:
- List of changed files
- Click file to see diff
- Add inline comments
**History**:
- Patchset versions
- Comments and votes
- CI results per patchset
**Related Changes**:
- Depends on / Needed by
- Related topics
- Conflicts with
### Useful Gerrit Features
**Diff Views**:
- **Side-by-side**: Compare old/new code
- **Unified**: Traditional diff format
- **Between patchsets**: Compare PS1 vs PS2
**Search**:
- Find your changes: `owner:self status:open`
- Find by issue: `bug:105737`
- Find by topic: `topic:indexed-search`
**Keyboard Shortcuts**:
- `?`: Show all shortcuts
- `u`: Go up to dashboard
- `a`: Expand all inline comments
- `c`: Compose review comment
- `n/p`: Next/previous file
## Advanced Topics
### Cherry-Picking Patches
Apply someone else's patch locally:
```bash
# From Gerrit download dropdown, copy cherry-pick command
git fetch origin refs/changes/45/12345/3 && git cherry-pick FETCH_HEAD
```
### Topics
Group related changes:
```bash
git push origin HEAD:refs/for/main%topic=indexed-search-improvements
```
### Work In Progress (WIP)
Mark patch as work-in-progress:
```bash
git push origin HEAD:refs/for/main%wip
```
Or on Gerrit web UI: **More** → **Mark as Work In Progress**
**Use WIP when**:
- Patch incomplete, not ready for review
- Want CI test results before review
- Demonstrating proof of concept
**Remove WIP**: **More** → **Start Review**
### Private Changes
Keep change private (visible only to you and explicit reviewers):
```bash
git push origin HEAD:refs/for/main%private
```
### Draft Comments
Save review comments without publishing:
1. Add comments on files
2. Click **Save** instead of **Send**
3. Edit later
4. Publish when ready
## Troubleshooting
### "Change-Id not found"
**Problem**: Missing or modified Change-Id
**Solution**:
```bash
# Ensure commit-msg hook installed
ls -la .git/hooks/commit-msg
# If missing, install
composer gerrit:setup
# Amend commit to generate Change-Id
git commit --amend --no-edit
```
### "Prohibited by Gerrit"
**Problem**: Pushing to wrong branch or permissions issue
**Solution**:
```bash
# Verify push URL
git config remote.origin.pushurl
# Should be: ssh://<username>@review.typo3.org:29418/Packages/TYPO3.CMS.git
# Push to refs/for/main, not main directly
git push origin HEAD:refs/for/main
```
### "No New Changes"
**Problem**: Pushing identical commit
**Solution**:
- Make actual code changes
- Or amend commit message
- Then push again
### Multiple Commits on Branch
**Problem**: Accidentally created multiple commits
**Solution**: Squash into one commit
```bash
# Interactive rebase
git rebase -i origin/main
# In editor, change all but first "pick" to "squash"
# Save and exit
# Edit combined commit message
# Push
```
## Best Practices
1. **One commit per patch**: Squash multiple commits into one
2. **Rebase regularly**: Stay up-to-date with main branch
3. **Preserve Change-Id**: Never modify when amending
4. **Respond promptly**: Reply to reviews within 2-3 days
5. **Test locally first**: Run tests before pushing
6. **Clear communication**: Explain changes in Gerrit comments
7. **Be patient**: Reviewers are volunteers
8. **Learn from feedback**: Apply lessons to future patches
## Resources
- **Gerrit**: https://review.typo3.org
- **Forger Search**: https://forger.typo3.com
- **Gerrit Documentation**: https://review.typo3.org/Documentation/
- **Slack**: #typo3-cms-coredev
## Quick Command Reference
| Action | Command |
|--------|---------|
| Push new patch | `git push origin HEAD:refs/for/main` |
| Update patch | `git commit --amend && git push origin HEAD:refs/for/main` |
| Rebase on main | `git fetch origin && git rebase origin/main` |
| Abort rebase | `git rebase --abort` |
| Continue rebase | `git rebase --continue` |
| Cherry-pick | `git fetch origin refs/changes/XX/XXXX/X && git cherry-pick FETCH_HEAD` |
| Push as WIP | `git push origin HEAD:refs/for/main%wip` |
| Test SSH | `ssh -p 29418 <user>@review.typo3.org` |

File diff suppressed because it is too large Load Diff

186
scripts/create-commit-message.py Executable file
View File

@@ -0,0 +1,186 @@
#!/usr/bin/env python3
"""
TYPO3 Core Contribution Commit Message Generator
Creates properly formatted commit messages following TYPO3 standards
"""
import argparse
import sys
import re
from typing import Optional
COMMIT_TYPES = {
'BUGFIX': 'Bug fixes',
'FEATURE': 'New features (main branch only)',
'TASK': 'Refactoring, cleanup, miscellaneous',
'DOCS': 'Documentation changes',
'SECURITY': 'Security vulnerability fixes'
}
BREAKING_CHANGE_PREFIX = '[!!!]'
def validate_subject(subject: str, has_breaking: bool) -> tuple[bool, Optional[str]]:
"""Validate subject line against TYPO3 rules"""
max_length = 52 if not has_breaking else 47 # Account for [!!!] prefix
if len(subject) > 72:
return False, "Subject line exceeds 72 characters (absolute limit)"
if len(subject) > max_length:
return False, f"Subject line exceeds {max_length} characters (recommended limit)"
if not subject[0].isupper():
return False, "Subject must start with uppercase letter"
if subject.endswith('.'):
return False, "Subject should not end with a period"
# Check for imperative mood (simple heuristic)
past_tense_endings = ['ed', 'ing']
first_word = subject.split()[0].lower()
if any(first_word.endswith(end) for end in past_tense_endings):
return False, f"Use imperative mood ('{first_word}' appears to be past/present continuous tense)"
return True, None
def wrap_text(text: str, width: int = 72) -> str:
"""Wrap text at specified width"""
words = text.split()
lines = []
current_line = []
current_length = 0
for word in words:
word_length = len(word)
if current_length + word_length + len(current_line) > width:
if current_line:
lines.append(' '.join(current_line))
current_line = [word]
current_length = word_length
else:
current_line.append(word)
current_length += word_length
if current_line:
lines.append(' '.join(current_line))
return '\n'.join(lines)
def parse_releases(releases_str: str) -> list[str]:
"""Parse comma-separated release versions"""
releases = [r.strip() for r in releases_str.split(',')]
# Validate format
valid_releases = []
for release in releases:
if release == 'main' or re.match(r'^\d+\.\d+$', release):
valid_releases.append(release)
else:
print(f"Warning: Invalid release format '{release}', skipping")
return valid_releases
def main():
parser = argparse.ArgumentParser(
description='Generate TYPO3-compliant commit messages',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
Examples:
%(prog)s --issue 105737 --type BUGFIX
%(prog)s --issue 105737 --type FEATURE --breaking
%(prog)s --type TASK --related 12345,12346
'''
)
parser.add_argument('--issue', type=int, help='Forge issue number')
parser.add_argument('--related', help='Related issue numbers (comma-separated)')
parser.add_argument('--type', choices=COMMIT_TYPES.keys(), required=True,
help='Commit type')
parser.add_argument('--breaking', action='store_true',
help='Mark as breaking change (adds [!!!] prefix)')
parser.add_argument('--releases', default='main',
help='Target releases (comma-separated, e.g., "main, 13.4, 12.4")')
parser.add_argument('--output', help='Output file (default: print to stdout)')
args = parser.parse_args()
# Interactive mode
print("=== TYPO3 Commit Message Generator ===\n")
# Get subject line
print(f"Commit Type: [{args.type}]")
if args.breaking:
print(f"Breaking Change: Yes (will add {BREAKING_CHANGE_PREFIX} prefix)")
print()
subject = input("Enter subject line (max 52 chars, imperative mood): ").strip()
# Validate subject
valid, error = validate_subject(subject, args.breaking)
if not valid:
print(f"\n❌ Error: {error}")
sys.exit(1)
# Get description
print("\nEnter description (explain how and why, not what).")
print("Press Ctrl+D (Linux/Mac) or Ctrl+Z (Windows) when done:")
description_lines = []
try:
while True:
line = input()
description_lines.append(line)
except EOFError:
pass
description = '\n'.join(description_lines).strip()
if description:
description = wrap_text(description)
# Build commit message
type_prefix = f"{BREAKING_CHANGE_PREFIX}{args.type}" if args.breaking else args.type
message = f"[{type_prefix}] {subject}\n\n"
if description:
message += f"{description}\n\n"
# Add footer
if args.issue:
message += f"Resolves: #{args.issue}\n"
if args.related:
related_issues = [f"#{num.strip()}" for num in args.related.split(',')]
for issue in related_issues:
message += f"Related: {issue}\n"
releases = parse_releases(args.releases)
if releases:
message += f"Releases: {', '.join(releases)}\n"
# Output
print("\n" + "="*60)
print("Generated Commit Message:")
print("="*60)
print(message)
print("="*60)
print("\nNote: Change-Id will be added automatically by git hook")
print("="*60)
if args.output:
with open(args.output, 'w') as f:
f.write(message)
print(f"\n✓ Commit message saved to: {args.output}")
print(f" Use: git commit -F {args.output}")
else:
print("\nTo use this message:")
print(" 1. Copy the message above")
print(" 2. Run: git commit")
print(" 3. Paste into your editor")
return 0
if __name__ == '__main__':
sys.exit(main())

192
scripts/create-forge-issue.sh Executable file
View File

@@ -0,0 +1,192 @@
#!/bin/bash
# Create TYPO3 Forge issue via Redmine REST API
#
# Usage:
# 1. Get your API key from https://forge.typo3.org/my/account
# 2. Set environment variable: export FORGE_API_KEY="your-key-here"
# 3. Run: ./scripts/create-forge-issue.sh
set -e
# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Check for API key
if [ -z "$FORGE_API_KEY" ]; then
echo -e "${RED}Error: FORGE_API_KEY environment variable not set${NC}"
echo ""
echo "Get your API key from: https://forge.typo3.org/my/account"
echo "Then set it: export FORGE_API_KEY=\"your-key-here\""
exit 1
fi
# Check for required tools
for tool in curl jq; do
if ! command -v $tool &> /dev/null; then
echo -e "${RED}Error: $tool is required but not installed${NC}"
exit 1
fi
done
echo -e "${GREEN}TYPO3 Forge Issue Creator${NC}"
echo ""
# Interactive prompts
read -p "Issue subject (title): " SUBJECT
if [ -z "$SUBJECT" ]; then
echo -e "${RED}Error: Subject is required${NC}"
exit 1
fi
echo ""
echo "Issue description (multi-line, press Ctrl+D when done):"
DESCRIPTION=$(cat)
if [ -z "$DESCRIPTION" ]; then
echo -e "${RED}Error: Description is required${NC}"
exit 1
fi
echo ""
echo "Select tracker type:"
echo " 1) Bug"
echo " 2) Feature"
echo " 3) Task"
read -p "Choice [1]: " TRACKER_CHOICE
TRACKER_CHOICE=${TRACKER_CHOICE:-1}
case $TRACKER_CHOICE in
1) TRACKER_ID=1; TRACKER_NAME="Bug" ;;
2) TRACKER_ID=2; TRACKER_NAME="Feature" ;;
3) TRACKER_ID=4; TRACKER_NAME="Task" ;;
*) echo -e "${RED}Invalid choice${NC}"; exit 1 ;;
esac
echo ""
echo "Select priority:"
echo " 1) Must have"
echo " 2) Should have (recommended)"
echo " 3) Could have"
read -p "Choice [2]: " PRIORITY_CHOICE
PRIORITY_CHOICE=${PRIORITY_CHOICE:-2}
case $PRIORITY_CHOICE in
1) PRIORITY_ID=3; PRIORITY_NAME="Must have" ;;
2) PRIORITY_ID=4; PRIORITY_NAME="Should have" ;;
3) PRIORITY_ID=5; PRIORITY_NAME="Could have" ;;
*) echo -e "${RED}Invalid choice${NC}"; exit 1 ;;
esac
echo ""
read -p "TYPO3 version affected (e.g., 13, 14) [13]: " TYPO3_VERSION
TYPO3_VERSION=${TYPO3_VERSION:-13}
echo ""
echo "Select category (common ones, or enter ID manually):"
echo " 1) Miscellaneous (975)"
echo " 2) Backend API (971)"
echo " 3) Backend User Interface (972)"
echo " 4) Frontend (977)"
echo " 5) Database API (974)"
echo " 6) Indexed Search (1000)"
echo " 7) Extension Manager (976)"
echo " 8) Documentation (1004)"
echo " 9) Enter category ID manually"
read -p "Choice [1]: " CATEGORY_CHOICE
CATEGORY_CHOICE=${CATEGORY_CHOICE:-1}
case $CATEGORY_CHOICE in
1) CATEGORY_ID=975; CATEGORY_NAME="Miscellaneous" ;;
2) CATEGORY_ID=971; CATEGORY_NAME="Backend API" ;;
3) CATEGORY_ID=972; CATEGORY_NAME="Backend User Interface" ;;
4) CATEGORY_ID=977; CATEGORY_NAME="Frontend" ;;
5) CATEGORY_ID=974; CATEGORY_NAME="Database API" ;;
6) CATEGORY_ID=1000; CATEGORY_NAME="Indexed Search" ;;
7) CATEGORY_ID=976; CATEGORY_NAME="Extension Manager" ;;
8) CATEGORY_ID=1004; CATEGORY_NAME="Documentation" ;;
9)
read -p "Enter category ID: " CATEGORY_ID
CATEGORY_NAME="Custom ($CATEGORY_ID)"
;;
*) echo -e "${RED}Invalid choice${NC}"; exit 1 ;;
esac
# Optional tags
echo ""
read -p "Tags (comma-separated, optional): " TAGS
# Summary
echo ""
echo -e "${YELLOW}Summary:${NC}"
echo " Tracker: $TRACKER_NAME"
echo " Subject: $SUBJECT"
echo " Priority: $PRIORITY_NAME"
echo " Category: $CATEGORY_NAME"
echo " TYPO3 Version: $TYPO3_VERSION"
[ -n "$TAGS" ] && echo " Tags: $TAGS"
echo ""
read -p "Create this issue? [Y/n]: " CONFIRM
CONFIRM=${CONFIRM:-Y}
if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
echo "Cancelled."
exit 0
fi
# Build JSON payload
JSON_PAYLOAD=$(jq -n \
--arg subject "$SUBJECT" \
--arg description "$DESCRIPTION" \
--argjson tracker "$TRACKER_ID" \
--argjson category "$CATEGORY_ID" \
--argjson priority "$PRIORITY_ID" \
--arg typo3_version "$TYPO3_VERSION" \
--arg tags "$TAGS" \
'{
issue: {
project_id: "typo3cms-core",
subject: $subject,
description: $description,
tracker_id: $tracker,
category_id: $category,
priority_id: $priority,
custom_fields: [
{id: 4, value: $typo3_version}
] + (if $tags != "" then [{id: 3, value: $tags}] else [] end)
}
}')
# Create issue
echo ""
echo -e "${YELLOW}Creating issue...${NC}"
RESPONSE=$(curl -s -X POST \
-H "Content-Type: application/json" \
-H "X-Redmine-API-Key: $FORGE_API_KEY" \
-d "$JSON_PAYLOAD" \
https://forge.typo3.org/issues.json)
# Check for errors
if echo "$RESPONSE" | jq -e '.errors' > /dev/null 2>&1; then
echo -e "${RED}Error creating issue:${NC}"
echo "$RESPONSE" | jq -r '.errors[]'
exit 1
fi
# Extract issue details
ISSUE_ID=$(echo "$RESPONSE" | jq -r '.issue.id')
ISSUE_URL="https://forge.typo3.org/issues/${ISSUE_ID}"
echo ""
echo -e "${GREEN}Success! Issue created:${NC}"
echo ""
echo " Issue #: $ISSUE_ID"
echo " URL: $ISSUE_URL"
echo ""
echo -e "${YELLOW}Next steps:${NC}"
echo " 1. Use in commit message: ${GREEN}Resolves: #${ISSUE_ID}${NC}"
echo " 2. Create feature branch: ${GREEN}git checkout -b feature/${ISSUE_ID}-description${NC}"
echo ""

102
scripts/query-forge-metadata.sh Executable file
View File

@@ -0,0 +1,102 @@
#!/bin/bash
# Query TYPO3 Forge project metadata via Redmine REST API
#
# Usage:
# 1. Get your API key from https://forge.typo3.org/my/account
# 2. Set environment variable: export FORGE_API_KEY="your-key-here"
# 3. Run: ./scripts/query-forge-metadata.sh [categories|trackers|all]
set -e
# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Check for API key
if [ -z "$FORGE_API_KEY" ]; then
echo -e "${RED}Error: FORGE_API_KEY environment variable not set${NC}"
echo ""
echo "Get your API key from: https://forge.typo3.org/my/account"
echo "Then set it: export FORGE_API_KEY=\"your-key-here\""
exit 1
fi
# Check for required tools
for tool in curl jq; do
if ! command -v $tool &> /dev/null; then
echo -e "${RED}Error: $tool is required but not installed${NC}"
exit 1
fi
done
# Parse arguments
QUERY_TYPE=${1:-all}
# Fetch project metadata
echo -e "${YELLOW}Fetching TYPO3 Core project metadata...${NC}"
echo ""
RESPONSE=$(curl -s \
-H "X-Redmine-API-Key: $FORGE_API_KEY" \
https://forge.typo3.org/projects/typo3cms-core.json)
# Check for errors
if echo "$RESPONSE" | jq -e '.errors' > /dev/null 2>&1; then
echo -e "${RED}Error querying Forge:${NC}"
echo "$RESPONSE" | jq -r '.errors[]'
exit 1
fi
# Display trackers
if [[ "$QUERY_TYPE" == "trackers" || "$QUERY_TYPE" == "all" ]]; then
echo -e "${GREEN}=== Trackers ===${NC}"
echo ""
echo "$RESPONSE" | jq -r '.project.trackers[] | "\(.id)\t\(.name)"' | \
awk -F'\t' '{printf " %-4s %s\n", $1, $2}'
echo ""
fi
# Display categories
if [[ "$QUERY_TYPE" == "categories" || "$QUERY_TYPE" == "all" ]]; then
echo -e "${GREEN}=== Issue Categories ===${NC}"
echo ""
echo "$RESPONSE" | jq -r '.project.issue_categories[] | "\(.id)\t\(.name)"' | \
awk -F'\t' '{printf " %-6s %s\n", $1, $2}'
echo ""
fi
# Display usage examples
if [[ "$QUERY_TYPE" == "all" ]]; then
echo -e "${BLUE}=== Usage Examples ===${NC}"
echo ""
echo "Create bug in Backend API category:"
echo ' curl -X POST \'
echo ' -H "Content-Type: application/json" \'
echo ' -H "X-Redmine-API-Key: $FORGE_API_KEY" \'
echo ' -d '"'"'{'
echo ' "issue": {'
echo ' "project_id": "typo3cms-core",'
echo ' "subject": "Issue title",'
echo ' "description": "Description",'
echo ' "tracker_id": 1,'
echo ' "category_id": 971,'
echo ' "priority_id": 4,'
echo ' "custom_fields": [{"id": 4, "value": "13"}]'
echo ' }'
echo ' }'"'"' \'
echo ' https://forge.typo3.org/issues.json'
echo ""
echo "Or use the interactive script:"
echo " ./scripts/create-forge-issue.sh"
echo ""
fi
# Save to file if requested
if [[ "$2" == "--save" ]]; then
OUTPUT_FILE="forge-metadata-$(date +%Y%m%d).json"
echo "$RESPONSE" > "$OUTPUT_FILE"
echo -e "${GREEN}Metadata saved to: $OUTPUT_FILE${NC}"
fi

433
scripts/setup-typo3-coredev.sh Executable file
View File

@@ -0,0 +1,433 @@
#!/bin/bash
# TYPO3 Core Development Environment Setup Script
# Based on proven production workflow
# Creates complete DDEV-based TYPO3 Core development environment
set -e
# Colors
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Print functions
print_header() {
echo -e "\n${BLUE}===================================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}===================================================${NC}\n"
}
print_step() {
echo -e "${GREEN}${NC} $1"
}
print_info() {
echo -e "${YELLOW}${NC} $1"
}
print_error() {
echo -e "${RED}${NC} $1"
}
print_success() {
echo -e "${GREEN}${NC} $1"
}
# Check prerequisites
check_prerequisites() {
print_header "Checking Prerequisites"
local missing_prereqs=false
# Check Git
if command -v git &> /dev/null; then
print_success "Git: $(git --version)"
else
print_error "Git not found. Please install Git first."
missing_prereqs=true
fi
# Check DDEV
if command -v ddev &> /dev/null; then
print_success "DDEV: $(ddev version | head -n1)"
else
print_error "DDEV not found. Please install DDEV first: https://ddev.readthedocs.io/"
missing_prereqs=true
fi
# Check Docker
if command -v docker &> /dev/null; then
if docker ps &> /dev/null; then
print_success "Docker: Running"
else
print_error "Docker not running. Please start Docker."
missing_prereqs=true
fi
else
print_error "Docker not found. DDEV requires Docker."
missing_prereqs=true
fi
if [ "$missing_prereqs" = true ]; then
print_error "Missing prerequisites. Please install required tools and try again."
exit 1
fi
}
# Gather user input
gather_input() {
print_header "Configuration"
# Project name
read -p "Project name (e.g., t3coredev-14-php8-4): " PROJECT_NAME
if [ -z "$PROJECT_NAME" ]; then
PROJECT_NAME="t3coredev-14-php8-4"
print_info "Using default: $PROJECT_NAME"
fi
# Git user name
read -p "Your name for Git commits: " GIT_NAME
while [ -z "$GIT_NAME" ]; do
print_error "Name is required"
read -p "Your name for Git commits: " GIT_NAME
done
# Git email
read -p "Your email for Git commits: " GIT_EMAIL
while [ -z "$GIT_EMAIL" ]; do
print_error "Email is required"
read -p "Your email for Git commits: " GIT_EMAIL
done
# Gerrit username
read -p "Your Gerrit username (review.typo3.org): " GERRIT_USER
while [ -z "$GERRIT_USER" ]; do
print_error "Gerrit username is required"
read -p "Your Gerrit username: " GERRIT_USER
done
# PHP version
read -p "PHP version (8.2, 8.3, 8.4) [default: 8.4]: " PHP_VERSION
if [ -z "$PHP_VERSION" ]; then
PHP_VERSION="8.4"
fi
# Timezone
read -p "Timezone [default: Europe/Vienna]: " TIMEZONE
if [ -z "$TIMEZONE" ]; then
TIMEZONE="Europe/Vienna"
fi
# Admin password
read -sp "TYPO3 admin password: " ADMIN_PASSWORD
echo
while [ -z "$ADMIN_PASSWORD" ]; do
print_error "Admin password is required"
read -sp "TYPO3 admin password: " ADMIN_PASSWORD
echo
done
# Confirm
echo -e "\n${YELLOW}Configuration Summary:${NC}"
echo " Project: $PROJECT_NAME"
echo " Git Name: $GIT_NAME"
echo " Git Email: $GIT_EMAIL"
echo " Gerrit User: $GERRIT_USER"
echo " PHP Version: $PHP_VERSION"
echo " Timezone: $TIMEZONE"
echo
read -p "Proceed with setup? (y/n): " CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
print_info "Setup cancelled."
exit 0
fi
}
# Create project directory
create_project_dir() {
print_header "Creating Project Directory"
if [ -d "$PROJECT_NAME" ]; then
print_error "Directory $PROJECT_NAME already exists!"
read -p "Delete and recreate? (y/n): " DELETE_CONFIRM
if [[ "$DELETE_CONFIRM" =~ ^[Yy]$ ]]; then
rm -rf "$PROJECT_NAME"
print_success "Deleted existing directory"
else
print_error "Cannot proceed with existing directory"
exit 1
fi
fi
mkdir -p "$PROJECT_NAME"
cd "$PROJECT_NAME"
print_success "Created and entered directory: $PROJECT_NAME"
}
# Clone TYPO3 repository
clone_repository() {
print_header "Cloning TYPO3 Repository"
print_step "Cloning from GitHub..."
if git clone git@github.com:typo3/typo3 . 2>&1 | grep -q "Permission denied\|Could not"; then
print_error "Failed to clone via SSH. Trying HTTPS..."
rm -rf .git
if ! git clone https://github.com/typo3/typo3.git . ; then
print_error "Failed to clone repository"
exit 1
fi
fi
print_success "Repository cloned successfully"
}
# Configure Git
configure_git() {
print_header "Configuring Git"
print_step "Setting user identity..."
git config user.name "$GIT_NAME"
git config user.email "$GIT_EMAIL"
print_success "User identity configured"
print_step "Enabling automatic rebase..."
git config branch.autosetuprebase remote
print_success "Automatic rebase enabled"
print_step "Installing git hooks..."
if [ -f "Build/git-hooks/commit-msg" ]; then
cp Build/git-hooks/commit-msg .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg
print_success "Commit-msg hook installed"
else
print_error "Commit-msg hook not found in Build/git-hooks/"
fi
print_step "Configuring Gerrit remote..."
git config remote.origin.pushurl "ssh://${GERRIT_USER}@review.typo3.org:29418/Packages/TYPO3.CMS.git"
git config remote.origin.push "+refs/heads/main:refs/for/main"
print_success "Gerrit remote configured"
# Test Gerrit connection
print_step "Testing Gerrit SSH connection..."
if timeout 5 ssh -p 29418 -o StrictHostKeyChecking=no -o BatchMode=yes "${GERRIT_USER}@review.typo3.org" gerrit version &>/dev/null; then
print_success "Gerrit connection successful"
else
print_error "Cannot connect to Gerrit. Please verify your SSH keys are configured."
print_info "Continue anyway? SSH key might need configuration."
read -p "Continue? (y/n): " CONTINUE
if [[ ! "$CONTINUE" =~ ^[Yy]$ ]]; then
exit 1
fi
fi
}
# Configure DDEV
configure_ddev() {
print_header "Configuring DDEV"
print_step "Setting project type..."
ddev config --project-type typo3 -y
print_step "Configuring timezone..."
ddev config --timezone "$TIMEZONE"
print_step "Setting PHP version..."
ddev config --php-version="$PHP_VERSION"
print_step "Configuring webserver..."
ddev config --webserver-type=apache-fpm
print_step "Setting database version..."
ddev config --database=mariadb:10.6
print_step "Adding environment variables..."
ddev config --web-environment-add="TYPO3_CONTEXT=Development/Ddev"
ddev config --web-environment-add="COMPOSER_ROOT_VERSION=14.0.x-dev"
print_success "DDEV configured successfully"
}
# Start DDEV
start_ddev() {
print_header "Starting DDEV"
print_step "Starting containers..."
if ddev start; then
print_success "DDEV started successfully"
ddev describe
else
print_error "Failed to start DDEV"
exit 1
fi
}
# Install dependencies
install_dependencies() {
print_header "Installing Dependencies"
print_step "Running Composer install via runTests.sh..."
if ./Build/Scripts/runTests.sh -s composerInstall; then
print_success "Dependencies installed"
else
print_error "Failed to install dependencies"
print_info "Trying alternative method..."
if ddev composer install; then
print_success "Dependencies installed via ddev composer"
else
print_error "Failed to install dependencies"
exit 1
fi
fi
}
# Setup TYPO3
setup_typo3() {
print_header "Setting Up TYPO3"
print_step "Creating installation trigger files..."
ddev exec 'touch /var/www/html/FIRST_INSTALL'
ddev exec 'touch /var/www/html/typo3conf/ENABLE_INSTALL_TOOL'
ddev exec 'echo "KEEP_FILE" > /var/www/html/typo3conf/ENABLE_INSTALL_TOOL'
print_success "Trigger files created"
print_step "Running TYPO3 setup..."
if ddev typo3 setup \
--driver=mysqli \
--host=db \
--port=3306 \
--dbname=db \
--username=db \
--password=db \
--admin-username=backenduser \
--admin-user-password="$ADMIN_PASSWORD" \
--admin-email="$GIT_EMAIL" \
--project-name="TYPO3 Core Dev v14 PHP ${PHP_VERSION}" \
--no-interaction \
--server-type=apache \
--force; then
print_success "TYPO3 setup completed"
else
print_error "TYPO3 setup failed"
exit 1
fi
}
# Activate extensions
activate_extensions() {
print_header "Activating Extensions"
print_step "Setting up extensions..."
ddev typo3 extension:setup
print_step "Activating indexed_search..."
ddev typo3 extension:activate indexed_search
print_step "Activating styleguide..."
ddev typo3 extension:activate styleguide
print_step "Activating scheduler..."
ddev typo3 extension:activate scheduler
print_success "Extensions activated"
}
# Setup backend groups
setup_backend_groups() {
print_header "Setting Up Backend User Groups"
print_step "Creating default backend groups..."
if ddev typo3 setup:begroups:default --groups=Both; then
print_success "Backend groups configured"
else
print_error "Failed to setup backend groups"
fi
}
# Generate test data
generate_test_data() {
print_header "Generating Test Data"
read -p "Generate styleguide test data? (y/n): " GENERATE_DATA
if [[ "$GENERATE_DATA" =~ ^[Yy]$ ]]; then
print_step "Generating TCA examples..."
ddev typo3 styleguide:generate --create -- tca
print_step "Generating frontend system template..."
ddev typo3 styleguide:generate --create -- frontend-systemplate
print_success "Test data generated"
else
print_info "Skipping test data generation"
fi
}
# Final steps
finalize() {
print_header "Setup Complete!"
print_success "TYPO3 Core development environment is ready!"
echo
echo -e "${GREEN}Project Details:${NC}"
echo " Name: $PROJECT_NAME"
echo " URL: https://${PROJECT_NAME}.ddev.site"
echo " Backend: https://${PROJECT_NAME}.ddev.site/typo3"
echo " Admin User: backenduser"
echo " Admin Password: [the password you entered]"
echo
echo -e "${GREEN}Next Steps:${NC}"
echo " 1. Open backend: ddev launch /typo3"
echo " 2. Run tests: ./Build/Scripts/runTests.sh -s unit"
echo " 3. Create branch: git checkout -b feature/your-feature"
echo " 4. Make changes and commit with proper message"
echo " 5. Push to Gerrit: git push origin HEAD:refs/for/main"
echo
echo -e "${GREEN}Useful Commands:${NC}"
echo " ddev start - Start project"
echo " ddev stop - Stop project"
echo " ddev restart - Restart project"
echo " ddev ssh - SSH into container"
echo " ddev typo3 cache:flush - Clear TYPO3 caches"
echo " ddev logs -f - Follow logs"
echo
read -p "Open TYPO3 backend now? (y/n): " OPEN_BACKEND
if [[ "$OPEN_BACKEND" =~ ^[Yy]$ ]]; then
ddev launch /typo3
fi
}
# Main execution
main() {
clear
print_header "TYPO3 Core Development Setup"
echo "This script will set up a complete TYPO3 Core development environment."
echo "It will:"
echo " - Clone TYPO3 Core repository"
echo " - Configure Git for Gerrit submissions"
echo " - Set up DDEV with optimal settings"
echo " - Install TYPO3 with test data"
echo " - Activate development extensions"
echo
check_prerequisites
gather_input
create_project_dir
clone_repository
configure_git
configure_ddev
start_ddev
install_dependencies
setup_typo3
activate_extensions
setup_backend_groups
generate_test_data
finalize
}
# Run main function
main

View File

@@ -0,0 +1,256 @@
#!/usr/bin/env python3
"""
TYPO3 Commit Message Validator
Validates commit messages against TYPO3 contribution standards
"""
import sys
import re
import argparse
from typing import List, Tuple
VALID_TYPES = ['BUGFIX', 'FEATURE', 'TASK', 'DOCS', 'SECURITY']
BREAKING_PREFIX = '[!!!]'
class CommitMessageValidator:
def __init__(self, message: str):
self.message = message
self.lines = message.split('\n')
self.errors = []
self.warnings = []
def validate(self) -> Tuple[bool, List[str], List[str]]:
"""Run all validation checks"""
self.check_subject_line()
self.check_blank_line()
self.check_footer()
self.check_change_id()
return len(self.errors) == 0, self.errors, self.warnings
def check_subject_line(self):
"""Validate the subject line"""
if not self.lines:
self.errors.append("Commit message is empty")
return
subject = self.lines[0]
# Check for commit type
type_pattern = r'^\[(?:\[!!!\])?(BUGFIX|FEATURE|TASK|DOCS|SECURITY)\]'
match = re.match(type_pattern, subject)
if not match:
self.errors.append(
f"Subject must start with commit type: {', '.join(f'[{t}]' for t in VALID_TYPES)}"
)
return
commit_type = match.group(1)
# Check for breaking change prefix
if subject.startswith('[!!!]'):
if commit_type == 'BUGFIX':
self.warnings.append(
"Breaking changes are unusual for BUGFIX. Consider using FEATURE or TASK"
)
# Extract subject without type prefix
subject_without_type = re.sub(type_pattern, '', subject).strip()
# Check length
if len(subject) > 72:
self.errors.append(
f"Subject line is {len(subject)} characters (max 72). Current: {len(subject)}"
)
elif len(subject) > 52:
self.warnings.append(
f"Subject line is {len(subject)} characters (recommended max 52)"
)
# Check capitalization
if subject_without_type and not subject_without_type[0].isupper():
self.errors.append("Subject description must start with uppercase letter")
# Check for period at end
if subject.endswith('.'):
self.errors.append("Subject line should not end with a period")
# Check for imperative mood (heuristic)
if subject_without_type:
first_word = subject_without_type.split()[0].lower()
if first_word.endswith('ed') or first_word.endswith('ing'):
self.warnings.append(
f"Use imperative mood: '{first_word}' may not be imperative. "
"Use 'Fix' not 'Fixed' or 'Fixing'"
)
def check_blank_line(self):
"""Check for blank line after subject"""
if len(self.lines) < 2:
return # Only subject line, no body
if len(self.lines) >= 2 and self.lines[1] != '':
self.errors.append("Second line must be blank (separate subject from body)")
def check_footer(self):
"""Check footer tags"""
footer_pattern = r'^(Resolves|Related|Releases|Depends|Reverts):\s*'
has_resolves = False
has_releases = False
has_change_id = False
for i, line in enumerate(self.lines):
if re.match(footer_pattern, line):
# Check format: should have colon followed by space
if not re.match(r'^[A-Z][a-z]+:\s+', line):
self.errors.append(
f"Line {i+1}: Footer tag must have colon followed by space: '{line}'"
)
# Check specific tags
if line.startswith('Resolves:'):
has_resolves = True
# Validate issue number format
if not re.match(r'^Resolves:\s+#\d+', line):
self.errors.append(
f"Line {i+1}: Resolves must reference issue number: 'Resolves: #12345'"
)
elif line.startswith('Related:'):
if not re.match(r'^Related:\s+#\d+', line):
self.errors.append(
f"Line {i+1}: Related must reference issue number: 'Related: #12345'"
)
elif line.startswith('Releases:'):
has_releases = True
# Validate releases format
releases_value = line.split(':', 1)[1].strip()
releases = [r.strip() for r in releases_value.split(',')]
for release in releases:
if release != 'main' and not re.match(r'^\d+\.\d+$', release):
self.errors.append(
f"Line {i+1}: Invalid release format '{release}'. "
"Use 'main' or version like '13.4'"
)
elif line.startswith('Change-Id:'):
has_change_id = True
# Warnings for missing tags
if not has_resolves:
self.warnings.append(
"No 'Resolves: #<issue>' tag found. Required for features and tasks."
)
if not has_releases:
self.warnings.append(
"No 'Releases:' tag found. Required to specify target versions."
)
def check_change_id(self):
"""Check for Change-Id"""
change_id_pattern = r'^Change-Id:\s+I[a-f0-9]{40}$'
has_change_id = any(re.match(change_id_pattern, line) for line in self.lines)
if not has_change_id:
self.warnings.append(
"No Change-Id found. It will be added automatically by git commit-msg hook."
)
def check_line_length(self):
"""Check body line lengths"""
for i, line in enumerate(self.lines[2:], start=3): # Skip subject and blank line
if line.startswith(('Resolves:', 'Related:', 'Releases:', 'Change-Id:', 'Depends:', 'Reverts:')):
continue # Skip footer
if len(line) > 72:
# Allow URLs to be longer
if not re.search(r'https?://', line):
self.warnings.append(
f"Line {i}: Length {len(line)} exceeds 72 characters"
)
def main():
parser = argparse.ArgumentParser(
description='Validate TYPO3 commit messages',
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument('--file', '-f', help='File containing commit message')
parser.add_argument('--message', '-m', help='Commit message string')
parser.add_argument('--strict', action='store_true',
help='Treat warnings as errors')
args = parser.parse_args()
# Get message
if args.file:
try:
with open(args.file, 'r') as f:
message = f.read()
except FileNotFoundError:
print(f"Error: File not found: {args.file}")
return 1
elif args.message:
message = args.message
else:
# Read from last commit
try:
import subprocess
result = subprocess.run(
['git', 'log', '-1', '--pretty=%B'],
capture_output=True,
text=True,
check=True
)
message = result.stdout
except subprocess.CalledProcessError:
print("Error: Could not read last commit message")
print("Usage: Provide --file or --message, or run in a git repository")
return 1
# Validate
validator = CommitMessageValidator(message)
is_valid, errors, warnings = validator.validate()
# Print results
print("=" * 60)
print("TYPO3 Commit Message Validation")
print("=" * 60)
print()
if errors:
print("❌ ERRORS:")
for error in errors:
print(f"{error}")
print()
if warnings:
print("⚠️ WARNINGS:")
for warning in warnings:
print(f"{warning}")
print()
if not errors and not warnings:
print("✅ Commit message is valid!")
elif not errors:
print("✅ No errors found (warnings can be ignored)")
else:
print("❌ Validation failed. Please fix errors above.")
print("=" * 60)
# Exit code
if errors or (args.strict and warnings):
return 1
return 0
if __name__ == '__main__':
sys.exit(main())

181
scripts/verify-prerequisites.sh Executable file
View File

@@ -0,0 +1,181 @@
#!/bin/bash
# TYPO3 Core Contribution Prerequisites Checker
# Verifies accounts, git configuration, and development environment setup
set -e
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo "================================================"
echo "TYPO3 Core Contribution Prerequisites Check"
echo "================================================"
echo
# Track overall status
ALL_CHECKS_PASSED=true
# Function to print status
print_status() {
if [ "$1" = "pass" ]; then
echo -e "${GREEN}${NC} $2"
elif [ "$1" = "fail" ]; then
echo -e "${RED}${NC} $2"
ALL_CHECKS_PASSED=false
elif [ "$1" = "warn" ]; then
echo -e "${YELLOW}${NC} $2"
fi
}
# 1. Check Git installation
echo "1. Checking Git installation..."
if command -v git &> /dev/null; then
GIT_VERSION=$(git --version)
print_status "pass" "Git installed: $GIT_VERSION"
else
print_status "fail" "Git not installed"
fi
echo
# 2. Check Git user configuration
echo "2. Checking Git user configuration..."
GIT_USER_NAME=$(git config --global user.name 2>/dev/null || echo "")
GIT_USER_EMAIL=$(git config --global user.email 2>/dev/null || echo "")
if [ -n "$GIT_USER_NAME" ] && [ -n "$GIT_USER_EMAIL" ]; then
print_status "pass" "Git user configured: $GIT_USER_NAME <$GIT_USER_EMAIL>"
else
print_status "fail" "Git user not configured. Run:"
echo " git config --global user.name \"Your Name\""
echo " git config --global user.email \"your-email@example.org\""
fi
echo
# 2a. Verify Git email matches Gerrit account
echo "2a. Verifying Git email against Gerrit..."
if [ -n "$GIT_USER_EMAIL" ]; then
echo " Your Git email: $GIT_USER_EMAIL"
print_status "warn" " IMPORTANT: Verify this email is registered at:"
echo " https://review.typo3.org/settings#EmailAddresses"
echo " Gerrit will reject pushes if email doesn't match!"
fi
echo
# 3. Check if in TYPO3 repository
echo "3. Checking TYPO3 repository..."
if [ -d ".git" ]; then
REPO_URL=$(git config --get remote.origin.url 2>/dev/null || echo "")
if [[ "$REPO_URL" == *"typo3"* ]]; then
print_status "pass" "In TYPO3 repository"
# Check TYPO3-specific git config
echo " Checking TYPO3-specific configuration..."
# Check auto-rebase
AUTO_REBASE=$(git config --get branch.autosetuprebase 2>/dev/null || echo "")
if [ "$AUTO_REBASE" = "remote" ]; then
print_status "pass" " Auto-rebase configured"
else
print_status "fail" " Auto-rebase not configured. Run: git config branch.autosetuprebase remote"
fi
# Check Gerrit push URL
PUSH_URL=$(git config --get remote.origin.pushurl 2>/dev/null || echo "")
if [[ "$PUSH_URL" == *"review.typo3.org"* ]]; then
print_status "pass" " Gerrit push URL configured"
else
print_status "fail" " Gerrit push URL not configured. Run:"
echo " git config remote.origin.pushurl ssh://<USERNAME>@review.typo3.org:29418/Packages/TYPO3.CMS.git"
fi
# Check push refspec
PUSH_REFSPEC=$(git config --get remote.origin.push 2>/dev/null || echo "")
if [[ "$PUSH_REFSPEC" == *"refs/for/main"* ]]; then
print_status "pass" " Push refspec configured for Gerrit"
else
print_status "fail" " Push refspec not configured. Run:"
echo " git config remote.origin.push +refs/heads/main:refs/for/main"
fi
else
print_status "warn" "In git repository but not TYPO3. URL: $REPO_URL"
fi
else
print_status "warn" "Not in a git repository (run from TYPO3 repo root)"
fi
echo
# 4. Check Git hooks
echo "4. Checking Git hooks..."
if [ -f ".git/hooks/commit-msg" ]; then
print_status "pass" "commit-msg hook installed"
else
print_status "fail" "commit-msg hook not installed. Run: composer gerrit:setup"
fi
if [ -f ".git/hooks/pre-commit" ]; then
print_status "pass" "pre-commit hook installed"
else
print_status "warn" "pre-commit hook not installed (optional but recommended)"
fi
echo
# 5. Check SSH connection to Gerrit
echo "5. Checking Gerrit SSH connection..."
if timeout 5 ssh -p 29418 -o StrictHostKeyChecking=no -o BatchMode=yes review.typo3.org gerrit version &>/dev/null; then
print_status "pass" "Gerrit SSH connection successful"
else
print_status "fail" "Cannot connect to Gerrit via SSH. Check your SSH keys and Gerrit setup"
fi
echo
# 6. Check Composer
echo "6. Checking Composer installation..."
if command -v composer &> /dev/null; then
COMPOSER_VERSION=$(composer --version 2>/dev/null | head -n1)
print_status "pass" "Composer installed: $COMPOSER_VERSION"
else
print_status "warn" "Composer not found (needed for running tests and gerrit:setup)"
fi
echo
# 7. Check PHP
echo "7. Checking PHP installation..."
if command -v php &> /dev/null; then
PHP_VERSION=$(php -v | head -n1)
print_status "pass" "PHP installed: $PHP_VERSION"
else
print_status "warn" "PHP not found (needed for development and testing)"
fi
echo
# 8. Check DDEV (optional)
echo "8. Checking DDEV installation (optional)..."
if command -v ddev &> /dev/null; then
DDEV_VERSION=$(ddev version | head -n1)
print_status "pass" "DDEV installed: $DDEV_VERSION"
else
print_status "warn" "DDEV not found (recommended for development environment)"
fi
echo
# Final Summary
echo "================================================"
if [ "$ALL_CHECKS_PASSED" = true ]; then
echo -e "${GREEN}✓ All critical checks passed!${NC}"
echo "You're ready to contribute to TYPO3 Core."
else
echo -e "${RED}✗ Some checks failed.${NC}"
echo "Please address the issues above before contributing."
fi
echo "================================================"
# Exit with appropriate code
if [ "$ALL_CHECKS_PASSED" = true ]; then
exit 0
else
exit 1
fi