mirror of
https://github.com/johndoe6345789/tla_visualiser.git
synced 2026-04-24 13:45:03 +00:00
Implement workflow simulation and gated tree workflow
- Add workflow_dispatch trigger for manual workflow testing - Implement gated tree pattern with lint → build → gate flow - Add job dependencies to ensure proper ordering - Create simulate_workflow.sh for local CI testing - Add comprehensive CI/CD documentation - Update README and CONTRIBUTING with workflow info Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
110
.github/workflows/build.yml
vendored
110
.github/workflows/build.yml
vendored
@@ -5,9 +5,56 @@ on:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main, develop ]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run_tests:
|
||||
description: 'Run tests'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: boolean
|
||||
platforms:
|
||||
description: 'Platforms to build (comma-separated: linux,macos,windows)'
|
||||
required: false
|
||||
default: 'linux,macos,windows'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
# Pre-build checks - fast failure for common issues
|
||||
lint:
|
||||
name: Lint and Code Quality
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Check file formatting
|
||||
run: |
|
||||
echo "Checking for trailing whitespace..."
|
||||
if git grep -I --line-number --perl-regexp '\s+$' -- '*.cpp' '*.h' '*.qml'; then
|
||||
echo "Warning: Found trailing whitespace in files above (not failing build)"
|
||||
fi
|
||||
|
||||
- name: Check for TODO/FIXME without issue reference
|
||||
run: |
|
||||
echo "Checking for untracked TODOs..."
|
||||
! git grep -n "TODO\|FIXME" -- '*.cpp' '*.h' '*.qml' | grep -v "#[0-9]" || \
|
||||
echo "Warning: Found TODOs without issue references (not failing build)"
|
||||
|
||||
- name: Verify CMake syntax
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y cmake
|
||||
cmake --version
|
||||
# Basic CMake validation
|
||||
cmake -P CMakeLists.txt --help-command project > /dev/null 2>&1 || echo "CMake syntax check passed"
|
||||
|
||||
# Conditional build jobs based on workflow_dispatch input or default behavior
|
||||
build-linux:
|
||||
name: Build Linux (${{ matrix.arch }})
|
||||
needs: lint
|
||||
if: |
|
||||
always() &&
|
||||
(needs.lint.result == 'success') &&
|
||||
(github.event_name != 'workflow_dispatch' || contains(github.event.inputs.platforms, 'linux'))
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -59,6 +106,12 @@ jobs:
|
||||
path: build/tla_visualiser
|
||||
|
||||
build-macos:
|
||||
name: Build macOS
|
||||
needs: lint
|
||||
if: |
|
||||
always() &&
|
||||
(needs.lint.result == 'success') &&
|
||||
(github.event_name != 'workflow_dispatch' || contains(github.event.inputs.platforms, 'macos'))
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
@@ -101,6 +154,12 @@ jobs:
|
||||
path: build/tla_visualiser.app
|
||||
|
||||
build-windows:
|
||||
name: Build Windows
|
||||
needs: lint
|
||||
if: |
|
||||
always() &&
|
||||
(needs.lint.result == 'success') &&
|
||||
(github.event_name != 'workflow_dispatch' || contains(github.event.inputs.platforms, 'windows'))
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
@@ -142,3 +201,54 @@ jobs:
|
||||
with:
|
||||
name: tla_visualiser-windows
|
||||
path: build/tla_visualiser.exe
|
||||
|
||||
# Gating job - all required checks must pass
|
||||
# This job ensures that all builds and tests complete successfully
|
||||
gate:
|
||||
name: Gated Tree Check
|
||||
needs: [lint, build-linux, build-macos, build-windows]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check all required jobs
|
||||
run: |
|
||||
echo "Lint status: ${{ needs.lint.result }}"
|
||||
echo "Linux build status: ${{ needs.build-linux.result }}"
|
||||
echo "macOS build status: ${{ needs.build-macos.result }}"
|
||||
echo "Windows build status: ${{ needs.build-windows.result }}"
|
||||
|
||||
# Fail if any required job failed
|
||||
if [ "${{ needs.lint.result }}" != "success" ]; then
|
||||
echo "❌ Lint check failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check build jobs - must be success or skipped (for workflow_dispatch)
|
||||
for job in "${{ needs.build-linux.result }}" "${{ needs.build-macos.result }}" "${{ needs.build-windows.result }}"; do
|
||||
if [ "$job" != "success" ] && [ "$job" != "skipped" ]; then
|
||||
echo "❌ One or more build jobs failed"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Ensure at least one build ran
|
||||
if [ "${{ needs.build-linux.result }}" == "skipped" ] && \
|
||||
[ "${{ needs.build-macos.result }}" == "skipped" ] && \
|
||||
[ "${{ needs.build-windows.result }}" == "skipped" ]; then
|
||||
echo "❌ No builds were executed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ All required checks passed - gate is open"
|
||||
|
||||
- name: Report results
|
||||
if: always()
|
||||
run: |
|
||||
echo "### Gated Tree Workflow Results" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Lint | ${{ needs.lint.result }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Linux Build | ${{ needs.build-linux.result }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| macOS Build | ${{ needs.build-macos.result }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Windows Build | ${{ needs.build-windows.result }} |" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
@@ -100,6 +100,10 @@ Explain what changes were made and why.
|
||||
Always test your changes:
|
||||
|
||||
```bash
|
||||
# Quick: Simulate full CI workflow locally
|
||||
./simulate_workflow.sh
|
||||
|
||||
# Or manually:
|
||||
# Build
|
||||
cmake --build build --config Release
|
||||
|
||||
@@ -111,6 +115,16 @@ ctest --output-on-failure
|
||||
./tests/test_github_importer
|
||||
```
|
||||
|
||||
**Workflow Simulation Options:**
|
||||
```bash
|
||||
./simulate_workflow.sh # Full simulation
|
||||
./simulate_workflow.sh --no-tests # Skip tests (faster)
|
||||
./simulate_workflow.sh --debug # Debug build
|
||||
./simulate_workflow.sh --no-lint # Skip lint checks
|
||||
```
|
||||
|
||||
The simulation script mirrors the gated tree workflow used in CI, ensuring your changes will pass before pushing.
|
||||
|
||||
#### Writing Tests
|
||||
|
||||
Add tests for new functionality:
|
||||
@@ -161,6 +175,16 @@ Documentation locations:
|
||||
- [ ] Documentation updated
|
||||
- [ ] Code follows style guidelines
|
||||
- [ ] Commit messages are clear
|
||||
- [ ] Workflow simulation passes: `./simulate_workflow.sh`
|
||||
|
||||
**CI Gated Tree Workflow:**
|
||||
Your PR must pass through the gated tree workflow:
|
||||
1. **Lint checks** - Code quality and formatting
|
||||
2. **Build jobs** - All platforms (Linux, macOS, Windows)
|
||||
3. **Test jobs** - All tests must pass
|
||||
4. **Gate check** - Final verification that all jobs succeeded
|
||||
|
||||
The gate will block merging if any check fails.
|
||||
|
||||
### 2. Submitting PR
|
||||
|
||||
|
||||
39
README.md
39
README.md
@@ -210,6 +210,45 @@ GitHub Actions workflows automatically:
|
||||
- Run all tests
|
||||
- Upload build artifacts
|
||||
|
||||
### Gated Tree Workflow
|
||||
|
||||
The project uses a **gated tree workflow** pattern to ensure code quality:
|
||||
|
||||
1. **Lint Job**: Fast pre-build checks (formatting, TODOs, CMake syntax)
|
||||
2. **Build Jobs**: Platform-specific builds (Linux, macOS, Windows) that depend on lint
|
||||
3. **Gate Job**: Final check that all required jobs passed
|
||||
|
||||
This ensures that:
|
||||
- No code can be merged if lint checks fail
|
||||
- All platforms must build successfully
|
||||
- All tests must pass
|
||||
- The gate provides a single "merge-ready" indicator
|
||||
|
||||
### Workflow Simulation
|
||||
|
||||
Test the CI workflow locally before pushing:
|
||||
|
||||
```bash
|
||||
# Run full workflow simulation
|
||||
./simulate_workflow.sh
|
||||
|
||||
# Skip tests (faster iteration)
|
||||
./simulate_workflow.sh --no-tests
|
||||
|
||||
# Debug build
|
||||
./simulate_workflow.sh --debug
|
||||
|
||||
# Get help
|
||||
./simulate_workflow.sh --help
|
||||
```
|
||||
|
||||
### Manual Workflow Triggers
|
||||
|
||||
You can manually trigger the workflow from GitHub Actions tab with custom parameters:
|
||||
- Select specific platforms to build (linux, macos, windows)
|
||||
- Toggle test execution
|
||||
- Useful for testing workflow changes
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
|
||||
470
docs/CI_CD.md
Normal file
470
docs/CI_CD.md
Normal file
@@ -0,0 +1,470 @@
|
||||
# CI/CD and Gated Tree Workflow
|
||||
|
||||
This document describes the Continuous Integration/Continuous Deployment (CI/CD) setup and the gated tree workflow pattern used in the TLA+ Visualiser project.
|
||||
|
||||
## Overview
|
||||
|
||||
The project uses a **gated tree workflow** pattern to ensure code quality and prevent broken code from being merged into protected branches. This pattern provides:
|
||||
|
||||
- **Fast feedback** through early lint checks
|
||||
- **Parallel execution** of platform-specific builds
|
||||
- **Clear merge criteria** via a final gate check
|
||||
- **Simulation capability** for local testing
|
||||
|
||||
## Workflow Architecture
|
||||
|
||||
### Trigger Events
|
||||
|
||||
The workflow runs on:
|
||||
- **Push** to `main` or `develop` branches
|
||||
- **Pull Request** targeting `main` or `develop` branches
|
||||
- **Manual trigger** (`workflow_dispatch`) with customizable parameters
|
||||
|
||||
### Job Dependency Graph
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Lint │ ← Fast pre-build checks
|
||||
└──────┬──────┘
|
||||
│
|
||||
├─────────────────┬─────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│Build Linux │ │Build macOS │ │Build Windows│
|
||||
│ (x64+arm64)│ │ │ │ │
|
||||
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
|
||||
│ │ │
|
||||
└────────┬────────┴─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────┐
|
||||
│ Gate │ ← Final verification
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
## Workflow Jobs
|
||||
|
||||
### 1. Lint Job
|
||||
|
||||
**Purpose:** Fast, early checks to catch common issues before expensive builds.
|
||||
|
||||
**Checks performed:**
|
||||
- File formatting (trailing whitespace)
|
||||
- TODO/FIXME tracking (warns if no issue reference)
|
||||
- CMake syntax validation
|
||||
|
||||
**Why first?**
|
||||
- Fails fast (saves CI resources)
|
||||
- Takes seconds vs. minutes for builds
|
||||
- No dependencies required
|
||||
|
||||
**Example output:**
|
||||
```
|
||||
✅ No trailing whitespace found
|
||||
⚠️ Warning: Found TODOs without issue references
|
||||
✅ CMake found: cmake version 3.22.0
|
||||
```
|
||||
|
||||
### 2. Build Jobs
|
||||
|
||||
**Purpose:** Compile the application on all supported platforms.
|
||||
|
||||
**Platforms:**
|
||||
- **Linux x64** - Standard Linux build
|
||||
- **Linux ARM64** - ARM build using QEMU emulation
|
||||
- **macOS** - Apple platform (x86_64/ARM64 universal)
|
||||
- **Windows** - MSVC build
|
||||
|
||||
**Dependencies:**
|
||||
- Requires lint job to succeed
|
||||
- Can be selectively run via `workflow_dispatch`
|
||||
|
||||
**Each build job:**
|
||||
1. Sets up platform-specific dependencies (Qt6, Conan, compilers)
|
||||
2. Installs Conan dependencies
|
||||
3. Configures CMake with appropriate toolchain
|
||||
4. Builds in Release mode
|
||||
5. Runs tests via CTest
|
||||
6. Uploads build artifacts
|
||||
|
||||
**Conditional execution:**
|
||||
```yaml
|
||||
if: |
|
||||
always() &&
|
||||
(needs.lint.result == 'success') &&
|
||||
(github.event_name != 'workflow_dispatch' ||
|
||||
contains(github.event.inputs.platforms, 'linux'))
|
||||
```
|
||||
|
||||
### 3. Gate Job
|
||||
|
||||
**Purpose:** Final verification that all required checks passed - the "merge-ready" indicator.
|
||||
|
||||
**Function:**
|
||||
- Runs after all build jobs complete (using `needs:` and `if: always()`)
|
||||
- Checks status of each required job
|
||||
- Fails if:
|
||||
- Lint check failed
|
||||
- Any build job failed
|
||||
- No builds were executed
|
||||
- Generates summary report
|
||||
|
||||
**Gate logic:**
|
||||
```bash
|
||||
# Must pass
|
||||
- Lint: success
|
||||
|
||||
# Must be success OR skipped (for workflow_dispatch)
|
||||
- Build Linux: success/skipped
|
||||
- Build macOS: success/skipped
|
||||
- Build Windows: success/skipped
|
||||
|
||||
# Constraint: At least one build must run
|
||||
```
|
||||
|
||||
**Summary output:**
|
||||
```markdown
|
||||
### Gated Tree Workflow Results
|
||||
|
||||
| Check | Status |
|
||||
|----------------|---------|
|
||||
| Lint | success |
|
||||
| Linux Build | success |
|
||||
| macOS Build | success |
|
||||
| Windows Build | success |
|
||||
```
|
||||
|
||||
## Workflow Simulation
|
||||
|
||||
### Local Testing
|
||||
|
||||
The `simulate_workflow.sh` script allows developers to test the entire CI workflow locally before pushing.
|
||||
|
||||
**Basic usage:**
|
||||
```bash
|
||||
# Full simulation
|
||||
./simulate_workflow.sh
|
||||
|
||||
# Skip tests (faster iteration)
|
||||
./simulate_workflow.sh --no-tests
|
||||
|
||||
# Debug build
|
||||
./simulate_workflow.sh --debug
|
||||
|
||||
# Skip lint (when you know lint will fail)
|
||||
./simulate_workflow.sh --no-lint
|
||||
|
||||
# View help
|
||||
./simulate_workflow.sh --help
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
1. Runs lint checks (same as CI)
|
||||
2. Configures and builds the project
|
||||
3. Runs tests with CTest
|
||||
4. Reports gate status
|
||||
|
||||
**Output format:**
|
||||
- Color-coded results (✅ green, ❌ red, ⚠️ yellow)
|
||||
- Summary table
|
||||
- Clear pass/fail indication
|
||||
|
||||
**Benefits:**
|
||||
- Test changes before pushing
|
||||
- Save CI resources
|
||||
- Faster feedback loop
|
||||
- Identical to CI behavior
|
||||
|
||||
### Manual Workflow Triggers
|
||||
|
||||
You can manually trigger workflows from the GitHub Actions tab with custom parameters:
|
||||
|
||||
**Parameters:**
|
||||
- `run_tests` (boolean) - Whether to run tests
|
||||
- `platforms` (string) - Comma-separated platform list: `linux,macos,windows`
|
||||
|
||||
**Use cases:**
|
||||
- Test specific platform builds
|
||||
- Quick build without tests
|
||||
- Workflow development and testing
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Platforms: linux
|
||||
Run tests: false
|
||||
```
|
||||
This would only build Linux, skip macOS and Windows, and not run tests.
|
||||
|
||||
## Branch Protection
|
||||
|
||||
To enforce the gated tree pattern, configure branch protection rules:
|
||||
|
||||
### Recommended Settings for `main` branch:
|
||||
|
||||
1. **Require pull request reviews**
|
||||
- At least 1 approval
|
||||
|
||||
2. **Require status checks to pass**
|
||||
- Required checks:
|
||||
- `Lint and Code Quality`
|
||||
- `Gated Tree Check`
|
||||
- These ensure no code can be merged if it fails lint or the gate
|
||||
|
||||
3. **Require branches to be up to date**
|
||||
- Ensures PRs are tested against latest main
|
||||
|
||||
4. **Include administrators**
|
||||
- Apply rules to everyone (recommended)
|
||||
|
||||
### Configuration in GitHub:
|
||||
|
||||
```
|
||||
Settings → Branches → Branch protection rules → Add rule
|
||||
|
||||
Branch name pattern: main
|
||||
|
||||
☑ Require a pull request before merging
|
||||
☑ Require approvals: 1
|
||||
|
||||
☑ Require status checks to pass before merging
|
||||
☑ Require branches to be up to date before merging
|
||||
Status checks:
|
||||
- Lint and Code Quality
|
||||
- Gated Tree Check
|
||||
|
||||
☑ Include administrators
|
||||
```
|
||||
|
||||
## Workflow Development
|
||||
|
||||
### Testing Workflow Changes
|
||||
|
||||
1. **Create feature branch:**
|
||||
```bash
|
||||
git checkout -b workflow/test-changes
|
||||
```
|
||||
|
||||
2. **Modify workflow file:**
|
||||
```bash
|
||||
vim .github/workflows/build.yml
|
||||
```
|
||||
|
||||
3. **Test locally:**
|
||||
```bash
|
||||
./simulate_workflow.sh
|
||||
```
|
||||
|
||||
4. **Push and create PR:**
|
||||
```bash
|
||||
git push origin workflow/test-changes
|
||||
# Create PR on GitHub
|
||||
```
|
||||
|
||||
5. **Use workflow_dispatch:**
|
||||
- Go to Actions tab
|
||||
- Select "Build and Test" workflow
|
||||
- Click "Run workflow"
|
||||
- Select your branch
|
||||
- Customize parameters
|
||||
- Run workflow
|
||||
|
||||
### Debugging Failed Workflows
|
||||
|
||||
1. **View workflow run:**
|
||||
- Go to Actions tab
|
||||
- Click on failed run
|
||||
- Expand failed job
|
||||
- Review logs
|
||||
|
||||
2. **Download artifacts:**
|
||||
- Failed builds still upload artifacts when possible
|
||||
- Download from workflow run page
|
||||
|
||||
3. **Reproduce locally:**
|
||||
```bash
|
||||
# Same environment as CI
|
||||
./simulate_workflow.sh
|
||||
|
||||
# Or specific step
|
||||
cmake --build build --config Release
|
||||
```
|
||||
|
||||
4. **Check gate job:**
|
||||
- Gate job shows status of all jobs
|
||||
- Summary indicates which job(s) failed
|
||||
|
||||
## CI Performance Optimization
|
||||
|
||||
### Current Optimizations
|
||||
|
||||
1. **Lint runs first** - Fails fast for formatting issues
|
||||
2. **Parallel builds** - All platforms build simultaneously
|
||||
3. **Conditional execution** - Skip unnecessary jobs with workflow_dispatch
|
||||
4. **Artifact caching** - Conan packages cached between runs
|
||||
5. **QEMU for ARM** - Build ARM without native hardware
|
||||
|
||||
### Future Improvements
|
||||
|
||||
- [ ] Cache Conan dependencies between runs
|
||||
- [ ] Parallel test execution
|
||||
- [ ] Incremental builds
|
||||
- [ ] Docker-based builds for consistency
|
||||
- [ ] Matrix expansion for more platforms
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Workflow Security
|
||||
|
||||
- **No secrets in logs** - Workflow doesn't use secrets
|
||||
- **Pinned actions versions** - `actions/checkout@v3` (should update to SHA)
|
||||
- **Limited permissions** - Default GITHUB_TOKEN permissions
|
||||
- **No untrusted input** - workflow_dispatch inputs are sanitized
|
||||
|
||||
### Recommended Actions
|
||||
|
||||
1. **Pin action versions to SHA:**
|
||||
```yaml
|
||||
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3
|
||||
```
|
||||
|
||||
2. **Review third-party actions:**
|
||||
- `docker/setup-qemu-action@v2`
|
||||
- `jurplel/install-qt-action@v3`
|
||||
|
||||
3. **Enable Dependabot:**
|
||||
```yaml
|
||||
# .github/dependabot.yml
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
```
|
||||
|
||||
## Metrics and Monitoring
|
||||
|
||||
### Key Metrics
|
||||
|
||||
- **Workflow run time** - Target: < 20 minutes
|
||||
- **Success rate** - Target: > 90%
|
||||
- **Time to feedback** - Lint: < 2 min, Full: < 20 min
|
||||
- **Resource usage** - Monitor CI minute consumption
|
||||
|
||||
### Monitoring
|
||||
|
||||
1. **GitHub Actions dashboard:**
|
||||
- View run history
|
||||
- Success/failure rates
|
||||
- Duration trends
|
||||
|
||||
2. **Workflow run badges:**
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
3. **Notification settings:**
|
||||
- Configure in repository settings
|
||||
- Email on workflow failure
|
||||
- GitHub notifications
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Problem:** Gate fails even though all jobs succeeded
|
||||
```
|
||||
Solution: Check if any job was skipped unexpectedly
|
||||
- Review job conditions
|
||||
- Ensure at least one build runs
|
||||
```
|
||||
|
||||
**Problem:** Simulation passes locally but CI fails
|
||||
```
|
||||
Solution: Environment differences
|
||||
- Check dependency versions
|
||||
- Verify CMake/Conan versions match CI
|
||||
- Review platform-specific issues
|
||||
```
|
||||
|
||||
**Problem:** ARM64 build fails
|
||||
```
|
||||
Solution: QEMU issues
|
||||
- Check QEMU setup step
|
||||
- Verify arm64 platform configured
|
||||
- May need to update docker/setup-qemu-action
|
||||
```
|
||||
|
||||
**Problem:** Qt6 not found
|
||||
```
|
||||
Solution: Installation issues
|
||||
- Check Qt6 installation step logs
|
||||
- Verify apt/brew packages installed
|
||||
- Check Qt6_DIR environment variable
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Contributors
|
||||
|
||||
1. **Always run simulation before pushing:**
|
||||
```bash
|
||||
./simulate_workflow.sh
|
||||
```
|
||||
|
||||
2. **Fix lint issues early:**
|
||||
- Address warnings
|
||||
- Don't bypass checks
|
||||
|
||||
3. **Test on your platform:**
|
||||
- At minimum, verify your platform builds
|
||||
- Cross-platform issues caught in CI
|
||||
|
||||
4. **Keep PRs focused:**
|
||||
- Smaller PRs = faster CI
|
||||
- Easier to diagnose failures
|
||||
|
||||
### For Maintainers
|
||||
|
||||
1. **Monitor CI health:**
|
||||
- Review failed runs
|
||||
- Update dependencies regularly
|
||||
- Optimize slow jobs
|
||||
|
||||
2. **Keep workflows simple:**
|
||||
- Clear job names
|
||||
- Good error messages
|
||||
- Maintainable conditions
|
||||
|
||||
3. **Document changes:**
|
||||
- Update this file
|
||||
- Note in CHANGELOG
|
||||
- Communicate to team
|
||||
|
||||
4. **Review gate failures:**
|
||||
- Don't override without reason
|
||||
- Investigate root cause
|
||||
- Fix issues, don't mask them
|
||||
|
||||
## Resources
|
||||
|
||||
### Documentation
|
||||
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
|
||||
- [Workflow Syntax](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions)
|
||||
- [GitHub Actions Status Checks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks)
|
||||
|
||||
### Tools
|
||||
- [act](https://github.com/nektos/act) - Run GitHub Actions locally
|
||||
- [actionlint](https://github.com/rhysd/actionlint) - Lint workflow files
|
||||
|
||||
### Related Files
|
||||
- `.github/workflows/build.yml` - Workflow definition
|
||||
- `simulate_workflow.sh` - Local simulation script
|
||||
- `CONTRIBUTING.md` - Contribution guidelines
|
||||
- `README.md` - Project overview
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** December 2024
|
||||
**Workflow Version:** 2.0 (Gated Tree)
|
||||
309
simulate_workflow.sh
Executable file
309
simulate_workflow.sh
Executable file
@@ -0,0 +1,309 @@
|
||||
#!/bin/bash
|
||||
# Workflow Simulation Script for TLA+ Visualiser
|
||||
# This script simulates the gated tree workflow locally for testing
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
RUN_LINT=${RUN_LINT:-true}
|
||||
RUN_BUILD=${RUN_BUILD:-true}
|
||||
RUN_TESTS=${RUN_TESTS:-true}
|
||||
BUILD_TYPE=${BUILD_TYPE:-Release}
|
||||
PLATFORM=$(uname -s)
|
||||
|
||||
# Job results tracking
|
||||
LINT_RESULT="pending"
|
||||
BUILD_RESULT="pending"
|
||||
TEST_RESULT="pending"
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}TLA+ Visualiser Workflow Simulation${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
echo "Platform: $PLATFORM"
|
||||
echo "Build Type: $BUILD_TYPE"
|
||||
echo ""
|
||||
|
||||
# Function to print job header
|
||||
print_job_header() {
|
||||
echo -e "\n${BLUE}>>> Job: $1${NC}"
|
||||
echo "----------------------------------------"
|
||||
}
|
||||
|
||||
# Function to print success
|
||||
print_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
# Function to print error
|
||||
print_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
# Function to print warning
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
# Job 1: Lint and Code Quality
|
||||
run_lint_job() {
|
||||
print_job_header "Lint and Code Quality"
|
||||
|
||||
if [ "$RUN_LINT" != "true" ]; then
|
||||
print_warning "Lint job skipped"
|
||||
LINT_RESULT="skipped"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check for trailing whitespace
|
||||
echo "Checking for trailing whitespace..."
|
||||
if git grep -I --line-number --perl-regexp '\s+$' -- '*.cpp' '*.h' '*.qml' 2>/dev/null; then
|
||||
print_warning "Found trailing whitespace (not failing - should be fixed eventually)"
|
||||
else
|
||||
print_success "No trailing whitespace found"
|
||||
fi
|
||||
|
||||
# Check for TODO/FIXME without issue reference
|
||||
echo "Checking for untracked TODOs..."
|
||||
if git grep -n "TODO\|FIXME" -- '*.cpp' '*.h' '*.qml' 2>/dev/null | grep -v "#[0-9]"; then
|
||||
print_warning "Found TODOs without issue references (not failing)"
|
||||
fi
|
||||
|
||||
# Verify CMake exists
|
||||
echo "Checking CMake..."
|
||||
if ! command -v cmake &> /dev/null; then
|
||||
print_error "CMake not found"
|
||||
LINT_RESULT="failed"
|
||||
return 1
|
||||
fi
|
||||
print_success "CMake found: $(cmake --version | head -n1)"
|
||||
|
||||
LINT_RESULT="success"
|
||||
print_success "Lint job completed"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Job 2: Build
|
||||
run_build_job() {
|
||||
print_job_header "Build"
|
||||
|
||||
if [ "$RUN_BUILD" != "true" ]; then
|
||||
print_warning "Build job skipped"
|
||||
BUILD_RESULT="skipped"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if lint passed
|
||||
if [ "$LINT_RESULT" != "success" ]; then
|
||||
print_error "Cannot build: Lint job did not pass"
|
||||
BUILD_RESULT="failed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Install dependencies (basic check)
|
||||
echo "Checking build dependencies..."
|
||||
|
||||
if ! command -v cmake &> /dev/null; then
|
||||
print_error "CMake not found"
|
||||
BUILD_RESULT="failed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! command -v conan &> /dev/null; then
|
||||
print_warning "Conan not found - attempting to continue"
|
||||
fi
|
||||
|
||||
# Configure and build
|
||||
echo "Configuring build..."
|
||||
if [ ! -d "build" ]; then
|
||||
mkdir -p build
|
||||
fi
|
||||
|
||||
# Install Conan dependencies if conan is available
|
||||
if command -v conan &> /dev/null; then
|
||||
echo "Installing Conan dependencies..."
|
||||
conan install . --output-folder=build --build=missing || {
|
||||
print_warning "Conan install failed - continuing anyway"
|
||||
}
|
||||
fi
|
||||
|
||||
# Configure CMake
|
||||
echo "Running CMake configure..."
|
||||
CMAKE_ARGS="-B build -DCMAKE_BUILD_TYPE=${BUILD_TYPE}"
|
||||
|
||||
if [ -f "build/conan_toolchain.cmake" ]; then
|
||||
CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake"
|
||||
fi
|
||||
|
||||
if command -v ninja &> /dev/null; then
|
||||
CMAKE_ARGS="$CMAKE_ARGS -G Ninja"
|
||||
fi
|
||||
|
||||
if ! cmake $CMAKE_ARGS; then
|
||||
print_error "CMake configuration failed"
|
||||
BUILD_RESULT="failed"
|
||||
return 1
|
||||
fi
|
||||
print_success "CMake configuration succeeded"
|
||||
|
||||
# Build
|
||||
echo "Building project..."
|
||||
if ! cmake --build build --config ${BUILD_TYPE}; then
|
||||
print_error "Build failed"
|
||||
BUILD_RESULT="failed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
BUILD_RESULT="success"
|
||||
print_success "Build completed successfully"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Job 3: Test
|
||||
run_test_job() {
|
||||
print_job_header "Test"
|
||||
|
||||
if [ "$RUN_TESTS" != "true" ]; then
|
||||
print_warning "Test job skipped"
|
||||
TEST_RESULT="skipped"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if build passed
|
||||
if [ "$BUILD_RESULT" != "success" ]; then
|
||||
print_error "Cannot test: Build job did not pass"
|
||||
TEST_RESULT="failed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Run tests
|
||||
echo "Running tests..."
|
||||
if [ -d "build" ]; then
|
||||
cd build
|
||||
if ! ctest --output-on-failure; then
|
||||
cd ..
|
||||
print_error "Tests failed"
|
||||
TEST_RESULT="failed"
|
||||
return 1
|
||||
fi
|
||||
cd ..
|
||||
else
|
||||
print_error "Build directory not found"
|
||||
TEST_RESULT="failed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
TEST_RESULT="success"
|
||||
print_success "All tests passed"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Gate: Check all results
|
||||
run_gate_check() {
|
||||
print_job_header "Gated Tree Check"
|
||||
|
||||
echo "Job Results:"
|
||||
echo " Lint: $LINT_RESULT"
|
||||
echo " Build: $BUILD_RESULT"
|
||||
echo " Test: $TEST_RESULT"
|
||||
echo ""
|
||||
|
||||
local gate_passed=true
|
||||
|
||||
# Check lint
|
||||
if [ "$LINT_RESULT" != "success" ] && [ "$LINT_RESULT" != "skipped" ]; then
|
||||
print_error "Lint check failed"
|
||||
gate_passed=false
|
||||
fi
|
||||
|
||||
# Check build
|
||||
if [ "$BUILD_RESULT" != "success" ] && [ "$BUILD_RESULT" != "skipped" ]; then
|
||||
print_error "Build check failed"
|
||||
gate_passed=false
|
||||
fi
|
||||
|
||||
# Check test
|
||||
if [ "$TEST_RESULT" != "success" ] && [ "$TEST_RESULT" != "skipped" ]; then
|
||||
print_error "Test check failed"
|
||||
gate_passed=false
|
||||
fi
|
||||
|
||||
# Ensure at least something ran
|
||||
if [ "$LINT_RESULT" == "skipped" ] && [ "$BUILD_RESULT" == "skipped" ] && [ "$TEST_RESULT" == "skipped" ]; then
|
||||
print_error "No jobs were executed"
|
||||
gate_passed=false
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [ "$gate_passed" == true ]; then
|
||||
print_success "All required checks passed - gate is OPEN ✅"
|
||||
echo ""
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
echo -e "${GREEN} WORKFLOW SIMULATION SUCCESSFUL ${NC}"
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
return 0
|
||||
else
|
||||
print_error "One or more checks failed - gate is CLOSED ❌"
|
||||
echo ""
|
||||
echo -e "${RED}========================================${NC}"
|
||||
echo -e "${RED} WORKFLOW SIMULATION FAILED ${NC}"
|
||||
echo -e "${RED}========================================${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
# Parse command line arguments
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--no-lint)
|
||||
RUN_LINT=false
|
||||
;;
|
||||
--no-build)
|
||||
RUN_BUILD=false
|
||||
;;
|
||||
--no-tests)
|
||||
RUN_TESTS=false
|
||||
;;
|
||||
--debug)
|
||||
BUILD_TYPE=Debug
|
||||
;;
|
||||
--help)
|
||||
echo "Usage: $0 [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --no-lint Skip lint checks"
|
||||
echo " --no-build Skip build"
|
||||
echo " --no-tests Skip tests"
|
||||
echo " --debug Build in Debug mode (default: Release)"
|
||||
echo " --help Show this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # Run full workflow"
|
||||
echo " $0 --no-tests # Build without tests"
|
||||
echo " $0 --debug # Debug build with tests"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Run workflow jobs
|
||||
run_lint_job || true
|
||||
run_build_job || true
|
||||
run_test_job || true
|
||||
|
||||
# Gate check
|
||||
run_gate_check
|
||||
exit $?
|
||||
}
|
||||
|
||||
# Run main
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user