feat: implement fork-friendly CI/CD with opt-in mechanism (#476)
- CI/CD disabled by default in forks to conserve resources - Users can enable via ENABLE_CI_IN_FORK repository variable - Added comprehensive Fork Guide documentation - Updated README with Contributing section - Created automation script for future implementations Benefits: - Saves GitHub Actions minutes across 1,600+ forks - Cleaner fork experience for contributors - Full control for fork owners - PR validation still runs automatically BREAKING CHANGE: CI/CD no longer runs automatically in forks. Fork owners must set ENABLE_CI_IN_FORK=true to enable workflows. Co-authored-by: Brian <bmadcode@gmail.com> Co-authored-by: PinkyD <paulbeanjr@gmail.com>
This commit is contained in:
104
.github/FORK_GUIDE.md
vendored
Normal file
104
.github/FORK_GUIDE.md
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
# Fork Guide - CI/CD Configuration
|
||||
|
||||
## CI/CD in Forks
|
||||
|
||||
By default, CI/CD workflows are **disabled in forks** to conserve GitHub Actions resources and provide a cleaner fork experience.
|
||||
|
||||
### Why This Approach?
|
||||
|
||||
- **Resource efficiency**: Prevents unnecessary GitHub Actions usage across 1,600+ forks
|
||||
- **Clean fork experience**: No failed workflow notifications in your fork
|
||||
- **Full control**: Enable CI/CD only when you actually need it
|
||||
- **PR validation**: Your changes are still fully tested when submitting PRs to the main repository
|
||||
|
||||
## Enabling CI/CD in Your Fork
|
||||
|
||||
If you need to run CI/CD workflows in your fork, follow these steps:
|
||||
|
||||
1. Navigate to your fork's **Settings** tab
|
||||
2. Go to **Secrets and variables** → **Actions** → **Variables**
|
||||
3. Click **New repository variable**
|
||||
4. Create a new variable:
|
||||
- **Name**: `ENABLE_CI_IN_FORK`
|
||||
- **Value**: `true`
|
||||
5. Click **Add variable**
|
||||
|
||||
That's it! CI/CD workflows will now run in your fork.
|
||||
|
||||
## Disabling CI/CD Again
|
||||
|
||||
To disable CI/CD workflows in your fork, you can either:
|
||||
|
||||
- **Delete the variable**: Remove the `ENABLE_CI_IN_FORK` variable entirely, or
|
||||
- **Set to false**: Change the `ENABLE_CI_IN_FORK` value to `false`
|
||||
|
||||
## Alternative Testing Options
|
||||
|
||||
You don't always need to enable CI/CD in your fork. Here are alternatives:
|
||||
|
||||
### Local Testing
|
||||
|
||||
Run tests locally before pushing:
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm ci
|
||||
|
||||
# Run linting
|
||||
npm run lint
|
||||
|
||||
# Run format check
|
||||
npm run format:check
|
||||
|
||||
# Run validation
|
||||
npm run validate
|
||||
|
||||
# Build the project
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Pull Request CI
|
||||
|
||||
When you open a Pull Request to the main repository:
|
||||
- All CI/CD workflows automatically run
|
||||
- You get full validation of your changes
|
||||
- No configuration needed
|
||||
|
||||
### GitHub Codespaces
|
||||
|
||||
Use GitHub Codespaces for a full development environment:
|
||||
- All tools pre-configured
|
||||
- Same environment as CI/CD
|
||||
- No local setup required
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
### Q: Will my PR be tested even if CI is disabled in my fork?
|
||||
|
||||
**A:** Yes! When you open a PR to the main repository, all CI/CD workflows run automatically, regardless of your fork's settings.
|
||||
|
||||
### Q: Can I selectively enable specific workflows?
|
||||
|
||||
**A:** The `ENABLE_CI_IN_FORK` variable enables all workflows. For selective control, you'd need to modify individual workflow files.
|
||||
|
||||
### Q: Do I need to enable CI in my fork to contribute?
|
||||
|
||||
**A:** No! Most contributors never need to enable CI in their forks. Local testing and PR validation are sufficient for most contributions.
|
||||
|
||||
### Q: Will disabling CI affect my ability to merge PRs?
|
||||
|
||||
**A:** No! PR merge requirements are based on CI runs in the main repository, not your fork.
|
||||
|
||||
### Q: Why was this implemented?
|
||||
|
||||
**A:** With over 1,600 forks of BMAD-METHOD, this saves thousands of GitHub Actions minutes monthly while maintaining code quality standards.
|
||||
|
||||
## Need Help?
|
||||
|
||||
- Join our [Discord Community](https://discord.gg/gk8jAdXWmj) for support
|
||||
- Check the [Contributing Guide](../README.md#contributing) for more information
|
||||
- Open an issue if you encounter any problems
|
||||
|
||||
---
|
||||
|
||||
> 💡 **Pro Tip**: This fork-friendly approach is particularly valuable for projects using AI/LLM tools that create many experimental commits, as it prevents unnecessary CI runs while maintaining code quality standards.
|
||||
1
.github/workflows/discord.yaml
vendored
1
.github/workflows/discord.yaml
vendored
@@ -14,6 +14,7 @@ name: Discord Notification
|
||||
jobs:
|
||||
notify:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == 'true'
|
||||
steps:
|
||||
- name: Notify Discord
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
|
||||
2
.github/workflows/format-check.yaml
vendored
2
.github/workflows/format-check.yaml
vendored
@@ -7,6 +7,7 @@ name: format-check
|
||||
jobs:
|
||||
prettier:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == 'true'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -25,6 +26,7 @@ jobs:
|
||||
|
||||
eslint:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == 'true'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
1
.github/workflows/manual-release.yaml
vendored
1
.github/workflows/manual-release.yaml
vendored
@@ -20,6 +20,7 @@ permissions:
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == 'true'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
20
README.md
20
README.md
@@ -212,6 +212,26 @@ The generated XML file contains your project's text-based source files in a stru
|
||||
|
||||
📋 **[Read CONTRIBUTING.md](CONTRIBUTING.md)** - Complete guide to contributing, including guidelines, process, and requirements
|
||||
|
||||
### Working with Forks
|
||||
|
||||
When you fork this repository, CI/CD workflows are **disabled by default** to save resources. This is intentional and helps keep your fork clean.
|
||||
|
||||
#### Need CI/CD in Your Fork?
|
||||
|
||||
See our [Fork CI/CD Guide](.github/FORK_GUIDE.md) for instructions on enabling workflows in your fork.
|
||||
|
||||
#### Contributing Workflow
|
||||
|
||||
1. **Fork the repository** - Click the Fork button on GitHub
|
||||
2. **Clone your fork** - `git clone https://github.com/YOUR-USERNAME/BMAD-METHOD.git`
|
||||
3. **Create a feature branch** - `git checkout -b feature/amazing-feature`
|
||||
4. **Make your changes** - Test locally with `npm test`
|
||||
5. **Commit your changes** - `git commit -m 'feat: add amazing feature'`
|
||||
6. **Push to your fork** - `git push origin feature/amazing-feature`
|
||||
7. **Open a Pull Request** - CI/CD will run automatically on the PR
|
||||
|
||||
Your contributions are tested when you submit a PR - no need to enable CI in your fork!
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see [LICENSE](LICENSE) for details.
|
||||
|
||||
229
implement-fork-friendly-ci.sh
Executable file
229
implement-fork-friendly-ci.sh
Executable file
@@ -0,0 +1,229 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Fork-Friendly CI/CD Implementation Script
|
||||
# Usage: ./implement-fork-friendly-ci.sh
|
||||
#
|
||||
# This script automates the implementation of fork-friendly CI/CD
|
||||
# by adding fork detection conditions to all GitHub Actions workflows
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Implementing Fork-Friendly CI/CD..."
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 1. Check if .github/workflows directory exists
|
||||
if [ ! -d ".github/workflows" ]; then
|
||||
echo -e "${RED}✗${NC} No .github/workflows directory found"
|
||||
echo "This script must be run from the repository root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. Backup existing workflows
|
||||
echo "📦 Backing up workflows..."
|
||||
backup_dir=".github/workflows.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
cp -r .github/workflows "$backup_dir"
|
||||
echo -e "${GREEN}✓${NC} Workflows backed up to $backup_dir"
|
||||
|
||||
# 3. Count workflow files and jobs
|
||||
WORKFLOW_COUNT=$(ls -1 .github/workflows/*.yml .github/workflows/*.yaml 2>/dev/null | wc -l)
|
||||
echo "📊 Found ${WORKFLOW_COUNT} workflow files"
|
||||
|
||||
# 4. Process each workflow file
|
||||
UPDATED_FILES=0
|
||||
MANUAL_REVIEW_NEEDED=0
|
||||
|
||||
for file in .github/workflows/*.yml .github/workflows/*.yaml; do
|
||||
if [ -f "$file" ]; then
|
||||
filename=$(basename "$file")
|
||||
echo -n "Processing ${filename}... "
|
||||
|
||||
# Create temporary file
|
||||
temp_file="${file}.tmp"
|
||||
|
||||
# Track if file needs manual review
|
||||
needs_review=0
|
||||
|
||||
# Process the file with awk
|
||||
awk '
|
||||
BEGIN {
|
||||
in_jobs = 0
|
||||
job_count = 0
|
||||
modified = 0
|
||||
}
|
||||
|
||||
/^jobs:/ {
|
||||
in_jobs = 1
|
||||
print
|
||||
next
|
||||
}
|
||||
|
||||
# Match job definitions (2 spaces + name + colon)
|
||||
in_jobs && /^ [a-z][a-z0-9_-]*:/ {
|
||||
job_name = $0
|
||||
print job_name
|
||||
job_count++
|
||||
|
||||
# Look ahead for existing conditions
|
||||
getline next_line
|
||||
|
||||
# Check if next line is already an if condition
|
||||
if (next_line ~ /^ if:/) {
|
||||
# Job already has condition - combine with fork detection
|
||||
existing_condition = next_line
|
||||
sub(/^ if: /, "", existing_condition)
|
||||
|
||||
# Check if fork condition already exists
|
||||
if (existing_condition !~ /github\.event\.repository\.fork/) {
|
||||
print " # Fork-friendly CI: Combined with existing condition"
|
||||
print " if: (" existing_condition ") && (github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == '\''true'\'')"
|
||||
modified++
|
||||
} else {
|
||||
# Already has fork detection
|
||||
print next_line
|
||||
}
|
||||
} else if (next_line ~ /^ runs-on:/) {
|
||||
# No condition exists, add before runs-on
|
||||
print " if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == '\''true'\''"
|
||||
print next_line
|
||||
modified++
|
||||
} else {
|
||||
# Some other configuration, preserve as-is
|
||||
print next_line
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
# Reset when leaving jobs section
|
||||
/^[a-z]/ && in_jobs {
|
||||
in_jobs = 0
|
||||
}
|
||||
|
||||
# Print all other lines
|
||||
{
|
||||
if (!in_jobs) print
|
||||
}
|
||||
|
||||
END {
|
||||
if (modified > 0) {
|
||||
exit 0 # Success - file was modified
|
||||
} else {
|
||||
exit 1 # No modifications needed
|
||||
}
|
||||
}
|
||||
' "$file" > "$temp_file"
|
||||
|
||||
# Check if modifications were made
|
||||
if [ $? -eq 0 ]; then
|
||||
mv "$temp_file" "$file"
|
||||
echo -e "${GREEN}✓${NC} Updated"
|
||||
((UPDATED_FILES++))
|
||||
else
|
||||
rm -f "$temp_file"
|
||||
echo -e "${YELLOW}○${NC} No changes needed"
|
||||
fi
|
||||
|
||||
# Check for complex conditions that might need manual review
|
||||
if grep -q "needs:" "$file" || grep -q "strategy:" "$file"; then
|
||||
echo " ⚠️ Complex workflow detected - manual review recommended"
|
||||
((MANUAL_REVIEW_NEEDED++))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "${GREEN}✓${NC} Updated ${UPDATED_FILES} workflow files"
|
||||
|
||||
# 5. Create Fork Guide if it doesn't exist
|
||||
if [ ! -f ".github/FORK_GUIDE.md" ]; then
|
||||
echo "📝 Creating Fork Guide documentation..."
|
||||
cat > .github/FORK_GUIDE.md << 'EOF'
|
||||
# Fork Guide - CI/CD Configuration
|
||||
|
||||
## CI/CD in Forks
|
||||
|
||||
By default, CI/CD workflows are **disabled in forks** to conserve GitHub Actions resources.
|
||||
|
||||
### Enabling CI/CD in Your Fork
|
||||
|
||||
If you need to run CI/CD workflows in your fork:
|
||||
|
||||
1. Navigate to **Settings** → **Secrets and variables** → **Actions** → **Variables**
|
||||
2. Click **New repository variable**
|
||||
3. Create variable:
|
||||
- **Name**: `ENABLE_CI_IN_FORK`
|
||||
- **Value**: `true`
|
||||
4. Click **Add variable**
|
||||
|
||||
### Disabling CI/CD Again
|
||||
|
||||
Either:
|
||||
- Delete the `ENABLE_CI_IN_FORK` variable, or
|
||||
- Set its value to `false`
|
||||
|
||||
### Alternative Testing Options
|
||||
|
||||
- **Local testing**: Run tests locally before pushing
|
||||
- **Pull Request CI**: Workflows automatically run when you open a PR
|
||||
- **GitHub Codespaces**: Full development environment
|
||||
EOF
|
||||
echo -e "${GREEN}✓${NC} Fork Guide created"
|
||||
else
|
||||
echo "ℹ️ Fork Guide already exists"
|
||||
fi
|
||||
|
||||
# 6. Validate YAML files (if yamllint is available)
|
||||
if command -v yamllint &> /dev/null; then
|
||||
echo "🔍 Validating YAML syntax..."
|
||||
VALIDATION_ERRORS=0
|
||||
for file in .github/workflows/*.yml .github/workflows/*.yaml; do
|
||||
if [ -f "$file" ]; then
|
||||
filename=$(basename "$file")
|
||||
if yamllint -d relaxed "$file" &>/dev/null; then
|
||||
echo -e " ${GREEN}✓${NC} ${filename}"
|
||||
else
|
||||
echo -e " ${RED}✗${NC} ${filename} - YAML validation failed"
|
||||
((VALIDATION_ERRORS++))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $VALIDATION_ERRORS -gt 0 ]; then
|
||||
echo -e "${YELLOW}⚠${NC} ${VALIDATION_ERRORS} files have YAML errors"
|
||||
fi
|
||||
else
|
||||
echo "ℹ️ yamllint not found - skipping YAML validation"
|
||||
echo " Install with: pip install yamllint"
|
||||
fi
|
||||
|
||||
# 7. Summary
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════"
|
||||
echo " Fork-Friendly CI/CD Summary"
|
||||
echo "═══════════════════════════════════════"
|
||||
echo " 📁 Files updated: ${UPDATED_FILES}"
|
||||
echo " 📊 Total workflows: ${WORKFLOW_COUNT}"
|
||||
echo " 📝 Fork Guide: .github/FORK_GUIDE.md"
|
||||
if [ $MANUAL_REVIEW_NEEDED -gt 0 ]; then
|
||||
echo " ⚠️ Files needing review: ${MANUAL_REVIEW_NEEDED}"
|
||||
fi
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Review the changes: git diff"
|
||||
echo "2. Test workflows locally (if possible)"
|
||||
echo "3. Commit changes: git commit -m 'feat: implement fork-friendly CI/CD'"
|
||||
echo "4. Push and create PR"
|
||||
echo ""
|
||||
echo "Remember to update README.md with fork information!"
|
||||
echo "═══════════════════════════════════════"
|
||||
|
||||
# Exit with appropriate code
|
||||
if [ $UPDATED_FILES -gt 0 ]; then
|
||||
exit 0
|
||||
else
|
||||
echo "No files were updated - workflows may already be fork-friendly"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user