Initial commit
This commit is contained in:
22
skills/typo3-core-contributions/.gitignore
vendored
Normal file
22
skills/typo3-core-contributions/.gitignore
vendored
Normal 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
skills/typo3-core-contributions/LICENSE
Normal file
21
skills/typo3-core-contributions/LICENSE
Normal 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.
|
||||
273
skills/typo3-core-contributions/README.md
Normal file
273
skills/typo3-core-contributions/README.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# TYPO3 Core Contributions Skill
|
||||
|
||||
An AI skill for guiding contributions to TYPO3 Core through systematic workflows, automated quality checks, and best practices enforcement.
|
||||
|
||||
## Overview
|
||||
|
||||
This skill provides comprehensive guidance for contributing to TYPO3 Core, including:
|
||||
|
||||
- **Gerrit-based code review workflow**
|
||||
- **Automated CI/CD debugging**
|
||||
- **Commit message formatting**
|
||||
- **WIP (Work in Progress) state management**
|
||||
- **Testing and quality assurance**
|
||||
- **Account setup and prerequisites**
|
||||
|
||||
## Features
|
||||
|
||||
### 🔄 Complete Contribution Workflow
|
||||
- Step-by-step guidance from setup to patch submission
|
||||
- Automated detection of common issues
|
||||
- Best practices enforcement at every stage
|
||||
|
||||
### 🤖 CI/CD Integration
|
||||
- Systematic debugging of failed GitLab CI jobs
|
||||
- Pattern recognition for common failures
|
||||
- Automated fix suggestions
|
||||
|
||||
### ✅ Quality Gates
|
||||
- Pre-submission validation
|
||||
- Code style enforcement (CGL)
|
||||
- PHPStan static analysis
|
||||
- Comprehensive test coverage
|
||||
|
||||
### 📝 Documentation
|
||||
- Gerrit workflow reference
|
||||
- Commit message format guidelines
|
||||
- Troubleshooting guide with 60+ scenarios
|
||||
- WIP state management
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Ensure you have:
|
||||
- Git configured with your TYPO3.org email
|
||||
- SSH key uploaded to review.typo3.org
|
||||
- Docker (for DDEV) or native PHP 8.2+ environment
|
||||
|
||||
### Installation
|
||||
|
||||
Use this skill in Claude Code by referencing it from your project's skill configuration.
|
||||
|
||||
### Usage
|
||||
|
||||
The skill activates automatically when working on TYPO3 Core contributions. It guides you through:
|
||||
|
||||
1. **Setup Phase**: Prerequisites verification, environment configuration
|
||||
2. **Development Phase**: Code changes, testing, validation
|
||||
3. **Submission Phase**: Gerrit patch submission, CI monitoring, WIP management
|
||||
4. **Review Phase**: Addressing reviewer feedback, iterating on changes
|
||||
|
||||
## Scope
|
||||
|
||||
**This skill covers**: TYPO3 Core code contributions (PHP, JavaScript, CSS, tests)
|
||||
- Submission via Gerrit (review.typo3.org)
|
||||
- Git commit-msg hooks and validation
|
||||
- Forge issue tracking
|
||||
- GitLab CI/CD pipeline
|
||||
|
||||
**Not covered**: TYPO3 Documentation contributions
|
||||
- For documentation work, use: https://github.com/netresearch/typo3-docs-skill
|
||||
- Documentation uses GitHub Pull Requests, not Gerrit
|
||||
- Different format (reStructuredText) and workflows
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
typo3-core-contributions/
|
||||
├── SKILL.md # Main skill definition
|
||||
├── README.md # This file
|
||||
├── references/
|
||||
│ ├── account-setup.md # Prerequisites and account configuration
|
||||
│ ├── commit-message-format.md # Commit message standards
|
||||
│ ├── ddev-setup-workflow.md # DDEV environment setup
|
||||
│ ├── gerrit-workflow.md # Complete Gerrit submission workflow
|
||||
│ └── troubleshooting.md # 60+ troubleshooting scenarios
|
||||
├── scripts/
|
||||
│ ├── setup-typo3-coredev.sh # Automated environment setup
|
||||
│ └── verify-prerequisites.sh # Prerequisites checker
|
||||
└── assets/
|
||||
└── images/ # Workflow diagrams and screenshots
|
||||
```
|
||||
|
||||
## Key Workflows
|
||||
|
||||
### 1. Initial Setup
|
||||
|
||||
```bash
|
||||
# Verify prerequisites
|
||||
./scripts/verify-prerequisites.sh
|
||||
|
||||
# Setup TYPO3 Core development environment
|
||||
./scripts/setup-typo3-coredev.sh
|
||||
```
|
||||
|
||||
### 2. Create Patch
|
||||
|
||||
```bash
|
||||
# Create feature branch
|
||||
git checkout -b feature/issue-number-description
|
||||
|
||||
# Make changes, commit with proper format
|
||||
git commit -m "[BUGFIX] Fix indexed search null handling
|
||||
|
||||
Resolves: #105737
|
||||
Releases: main"
|
||||
```
|
||||
|
||||
### 3. Submit to Gerrit
|
||||
|
||||
```bash
|
||||
# Submit as WIP (Work in Progress)
|
||||
git push origin HEAD:refs/for/main%wip
|
||||
|
||||
# After CI passes, mark as ready
|
||||
git commit --amend --allow-empty --no-edit
|
||||
git push origin HEAD:refs/for/main%ready
|
||||
```
|
||||
|
||||
### 4. Handle CI Failures
|
||||
|
||||
The skill provides systematic debugging:
|
||||
1. Check ALL failed job logs
|
||||
2. Identify failure patterns (cgl, phpstan, unit tests)
|
||||
3. Fix all issues in ONE patchset
|
||||
4. Re-submit and verify
|
||||
|
||||
## WIP State Management
|
||||
|
||||
### Command-Line Approach (Recommended)
|
||||
|
||||
```bash
|
||||
# Set WIP state
|
||||
git push origin HEAD:refs/for/main%wip
|
||||
|
||||
# Remove WIP state
|
||||
git commit --amend --allow-empty --no-edit
|
||||
git push origin HEAD:refs/for/main%ready
|
||||
```
|
||||
|
||||
### Web UI Alternative
|
||||
|
||||
Open review URL and click "Start Review" button.
|
||||
|
||||
**Note**: SSH `gerrit review` command does NOT support WIP flags.
|
||||
|
||||
## Commit Message Format
|
||||
|
||||
Required structure:
|
||||
|
||||
```
|
||||
[TYPE] Short description (max 52 chars)
|
||||
|
||||
Extended description explaining the why and how.
|
||||
|
||||
Resolves: #12345
|
||||
Releases: main, 12.4
|
||||
```
|
||||
|
||||
**Types**: BUGFIX, FEATURE, TASK, DOCS, CLEANUP, SECURITY
|
||||
|
||||
**Required**: At least one `Resolves:` line
|
||||
|
||||
**Optional**: `Related:` (but cannot be used alone)
|
||||
|
||||
## CI/CD Debugging
|
||||
|
||||
Common failure patterns:
|
||||
|
||||
### CGL (Code Style)
|
||||
```bash
|
||||
Build/Scripts/cglFixMyCommit.sh
|
||||
git commit --amend --no-edit
|
||||
```
|
||||
|
||||
### PHPStan
|
||||
```bash
|
||||
Build/Scripts/runTests.sh -s phpstan
|
||||
# Fix reported issues
|
||||
```
|
||||
|
||||
### Unit Tests
|
||||
```bash
|
||||
Build/Scripts/runTests.sh -s unit path/to/test
|
||||
# Fix test failures
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
The skill includes comprehensive troubleshooting for:
|
||||
|
||||
- **Account Issues**: Email mismatch, SSH authentication, commit-msg hook
|
||||
- **CI Failures**: CGL, PHPStan, unit tests, functional tests
|
||||
- **Gerrit Issues**: WIP state, patch conflicts, rebase requirements
|
||||
- **Testing Issues**: Test failures, coverage gaps, fixture setup
|
||||
- **Code Quality**: Naming conventions, type safety, defensive programming
|
||||
|
||||
See `references/troubleshooting.md` for detailed solutions.
|
||||
|
||||
## Real-World Testing
|
||||
|
||||
This skill was developed and validated through:
|
||||
|
||||
- **Forge Issue #105737**: TypeError in indexed search
|
||||
- **7 patchsets** with iterative CI debugging
|
||||
- **GitHub PR #397**: Documentation improvements
|
||||
- **Live Gerrit testing**: WIP workflow validation
|
||||
|
||||
All workflows have been tested on actual TYPO3 Core submissions.
|
||||
|
||||
## Updates and Enhancements
|
||||
|
||||
Recent additions:
|
||||
|
||||
### v1.1.0 (2025-10-27)
|
||||
- ✅ WIP state management (command-line and web UI)
|
||||
- ✅ CI failure investigation protocol (423 lines)
|
||||
- ✅ Comprehensive troubleshooting guide (60+ scenarios)
|
||||
- ✅ PHPStan error guidance
|
||||
- ✅ Code style enforcement patterns
|
||||
- ✅ Documentation scope clarification
|
||||
|
||||
## Contributing
|
||||
|
||||
To improve this skill:
|
||||
|
||||
1. Test on real TYPO3 Core contributions
|
||||
2. Document edge cases in troubleshooting guide
|
||||
3. Add automation scripts for common tasks
|
||||
4. Validate against official TYPO3 documentation
|
||||
|
||||
## Resources
|
||||
|
||||
### Official TYPO3 Documentation
|
||||
- [Contribution Guide](https://docs.typo3.org/m/typo3/guide-contributionworkflow/main/en-us/)
|
||||
- [Gerrit Documentation](https://gerrit-review.googlesource.com/Documentation/user-upload.html)
|
||||
- [TYPO3 Forge](https://forge.typo3.org/)
|
||||
|
||||
### Related Skills
|
||||
- [TYPO3 Docs Skill](https://github.com/netresearch/typo3-docs-skill) - For documentation contributions
|
||||
|
||||
## License
|
||||
|
||||
MIT License - See LICENSE file for details
|
||||
|
||||
## Author
|
||||
|
||||
Created for use with Claude Code and TYPO3 Core contributions.
|
||||
|
||||
Maintained by: Netresearch DTT GmbH
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- Open an issue in this repository
|
||||
- Reference official TYPO3 documentation
|
||||
- Test workflows on live Gerrit instance
|
||||
|
||||
---
|
||||
|
||||
**Version**: 1.1.0
|
||||
**Last Updated**: 2025-10-27
|
||||
**Status**: Production-ready, validated on live submissions
|
||||
1060
skills/typo3-core-contributions/SKILL.md
Normal file
1060
skills/typo3-core-contributions/SKILL.md
Normal file
File diff suppressed because it is too large
Load Diff
78
skills/typo3-core-contributions/assets/commit-template.txt
Normal file
78
skills/typo3-core-contributions/assets/commit-template.txt
Normal 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/
|
||||
# ============================================================================
|
||||
@@ -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: ✓
|
||||
275
skills/typo3-core-contributions/references/account-setup.md
Normal file
275
skills/typo3-core-contributions/references/account-setup.md
Normal 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 |
|
||||
@@ -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 |
|
||||
460
skills/typo3-core-contributions/references/commit-msg-hook.md
Normal file
460
skills/typo3-core-contributions/references/commit-msg-hook.md
Normal 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
|
||||
@@ -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
skills/typo3-core-contributions/references/forge-api.md
Normal file
436
skills/typo3-core-contributions/references/forge-api.md
Normal 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
|
||||
@@ -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.
|
||||
783
skills/typo3-core-contributions/references/gerrit-workflow.md
Normal file
783
skills/typo3-core-contributions/references/gerrit-workflow.md
Normal 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` |
|
||||
1025
skills/typo3-core-contributions/references/troubleshooting.md
Normal file
1025
skills/typo3-core-contributions/references/troubleshooting.md
Normal file
File diff suppressed because it is too large
Load Diff
186
skills/typo3-core-contributions/scripts/create-commit-message.py
Executable file
186
skills/typo3-core-contributions/scripts/create-commit-message.py
Executable 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
skills/typo3-core-contributions/scripts/create-forge-issue.sh
Executable file
192
skills/typo3-core-contributions/scripts/create-forge-issue.sh
Executable 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
skills/typo3-core-contributions/scripts/query-forge-metadata.sh
Executable file
102
skills/typo3-core-contributions/scripts/query-forge-metadata.sh
Executable 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
skills/typo3-core-contributions/scripts/setup-typo3-coredev.sh
Executable file
433
skills/typo3-core-contributions/scripts/setup-typo3-coredev.sh
Executable 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
|
||||
256
skills/typo3-core-contributions/scripts/validate-commit-message.py
Executable file
256
skills/typo3-core-contributions/scripts/validate-commit-message.py
Executable 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
skills/typo3-core-contributions/scripts/verify-prerequisites.sh
Executable file
181
skills/typo3-core-contributions/scripts/verify-prerequisites.sh
Executable 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
|
||||
Reference in New Issue
Block a user