Skip to content

Automated Maintenance #18

Automated Maintenance

Automated Maintenance #18

Workflow file for this run

name: Automated Maintenance
on:
schedule:
# Run weekly on Sundays at 3 AM UTC
- cron: '0 3 * * 0'
workflow_dispatch:
inputs:
force_cleanup:
description: 'Force cleanup of old artifacts'
required: false
default: 'false'
type: boolean
jobs:
# ============================================================================
# REPOSITORY MAINTENANCE
# ============================================================================
repo-maintenance:
name: Repository Maintenance
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
actions: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Clean up old artifacts
uses: actions/github-script@v7
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const forceCleanup = '${{ github.event.inputs.force_cleanup }}' === 'true';
// Keep artifacts for different periods based on type
const retentionPolicies = {
'release-': 90, // Release artifacts: 90 days
'debug-': 14, // Debug builds: 14 days
'test-': 7, // Test artifacts: 7 days
'security-': 30, // Security analysis: 30 days
};
const artifacts = await github.rest.actions.listArtifactsForRepo({
owner,
repo,
per_page: 100
});
let deletedCount = 0;
for (const artifact of artifacts.data.artifacts) {
const artifactAge = Date.now() - new Date(artifact.created_at);
const ageDays = Math.floor(artifactAge / (1000 * 60 * 60 * 24));
let retentionDays = 30; // default
// Determine retention policy based on artifact name
for (const [prefix, days] of Object.entries(retentionPolicies)) {
if (artifact.name.startsWith(prefix)) {
retentionDays = days;
break;
}
}
if (ageDays > retentionDays || forceCleanup) {
console.log(`Deleting artifact: ${artifact.name} (${ageDays} days old)`);
await github.rest.actions.deleteArtifact({
owner,
repo,
artifact_id: artifact.id
});
deletedCount++;
}
}
console.log(`Cleaned up ${deletedCount} old artifacts`);
- name: Check repository health
run: |
echo '🔍 Checking repository health...'
# Check repository size
REPO_SIZE=$(du -sh .git | cut -f1)
echo "Repository size: $REPO_SIZE"
# Count files
FILE_COUNT=$(find . -type f -not -path './.git/*' | wc -l)
echo "File count: $FILE_COUNT"
# Check for large files
echo "Large files (>1MB):"
find . -type f -not -path './.git/*' -size +1M -exec ls -lh {} \; || echo "No large files found"
# Check for common issues
echo "Checking for common issues..."
# Check for DS_Store files
if find . -name ".DS_Store" -not -path './.git/*' | grep -q .; then
echo "⚠️ Found .DS_Store files - consider adding to .gitignore"
fi
# Check for backup files
if find . -name "*.bak" -o -name "*~" -not -path './.git/*' | grep -q .; then
echo "⚠️ Found backup files - consider cleanup"
fi
echo "✅ Repository health check completed"
# ============================================================================
# DEPENDENCY HEALTH CHECK
# ============================================================================
dependency-health:
name: Dependency Health Check
runs-on: macos-14
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@v17
- name: Setup Nix Cache
uses: DeterminateSystems/magic-nix-cache-action@v10
- name: Check Swift dependencies
run: |
nix develop --command bash -c "
echo '📦 Checking Swift dependencies health...'
# Show dependency tree
swift package show-dependencies --format json > deps.json
# Count dependencies
DEP_COUNT=\$(jq '.dependencies | length' deps.json)
echo \"Total Swift dependencies: \$DEP_COUNT\"
# Check for development dependencies
if jq -e '.dependencies[] | select(.kind == \"fileSystem\")' deps.json >/dev/null; then
echo '⚠️ Local file dependencies detected'
fi
# Check Package.resolved for version locks
if [ -f Package.resolved ]; then
RESOLVED_COUNT=\$(jq '.pins | length' Package.resolved)
echo \"Resolved packages: \$RESOLVED_COUNT\"
fi
echo '✅ Swift dependency health check completed'
"
- name: Check Zig dependencies
run: |
nix develop --command bash -c "
echo '📦 Checking Zig dependencies health...'
if [ -f build.zig.zon ]; then
echo 'Zig dependencies found:'
cat build.zig.zon
else
echo 'No Zig dependencies file found'
fi
# Check for any .zig files in deps
if [ -d .zigmod ] || [ -d zig-cache ]; then
echo 'Zig cache directories found'
fi
echo '✅ Zig dependency health check completed'
"
- name: Generate dependency report
run: |
echo '📋 Generating dependency report...'
cat > dependency-report.md << 'EOF'
# Dependency Health Report
Generated on: $(date)
## Swift Dependencies
EOF
if [ -f deps.json ]; then
echo '### Package Dependencies' >> dependency-report.md
jq -r '.dependencies[] | "- **\(.identity)**: \(.kind)"' deps.json >> dependency-report.md
fi
echo '' >> dependency-report.md
echo '## Recommendations' >> dependency-report.md
echo '- Review dependencies quarterly for updates' >> dependency-report.md
echo '- Monitor for security advisories' >> dependency-report.md
echo '- Consider dependency count vs. functionality' >> dependency-report.md
# ============================================================================
# BUILD PERFORMANCE MONITORING
# ============================================================================
build-performance:
name: Build Performance Monitoring
runs-on: macos-14
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@v17
- name: Setup Nix Cache
uses: DeterminateSystems/magic-nix-cache-action@v10
- name: Measure build performance
run: |
echo '⏱️ Measuring build performance...'
# Clean build test
echo 'Testing clean build performance...'
time nix develop --command bash -c "
zig build swift --summary all
"
# Incremental build test
echo 'Testing incremental build performance...'
time nix develop --command bash -c "
zig build swift --summary all
"
# Binary size check
BINARY_SIZE=$(stat -f%z .build/release/plue 2>/dev/null || echo "0")
echo "Final binary size: $BINARY_SIZE bytes"
# Create performance report
cat > performance-report.md << EOF
# Build Performance Report
Generated on: $(date)
## Metrics
- Binary size: $BINARY_SIZE bytes
- Platform: macOS (GitHub Actions)
- Build configuration: Release
## Notes
- Build times measured on GitHub Actions runners
- Binary size should be monitored for growth
- Consider optimization if size exceeds reasonable limits
EOF
# ============================================================================
# AUTOMATED ISSUE MANAGEMENT
# ============================================================================
issue-management:
name: Automated Issue Management
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Close stale issues
uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: |
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs within 7 days.
If this issue is still relevant, please:
- Add a comment explaining why it should remain open
- Add the "keep-open" label
- Provide additional context or updates
close-issue-message: |
This issue has been automatically closed due to inactivity.
If you believe this issue should remain open, please:
- Reopen the issue
- Provide additional context
- Add the "keep-open" label to prevent future auto-closure
stale-issue-label: 'stale'
exempt-issue-labels: 'keep-open,pinned,security,critical'
days-before-stale: 60
days-before-close: 7
operations-per-run: 30
- name: Label enhancement requests
uses: actions/github-script@v7
with:
script: |
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100
});
for (const issue of issues.data) {
if (issue.pull_request) continue; // Skip PRs
const body = issue.body?.toLowerCase() || '';
const title = issue.title?.toLowerCase() || '';
// Auto-label based on content
const labels = [];
if (title.includes('feature') || body.includes('feature request')) {
labels.push('enhancement');
}
if (title.includes('bug') || body.includes('bug report')) {
labels.push('bug');
}
if (title.includes('performance') || body.includes('performance')) {
labels.push('performance');
}
if (title.includes('security') || body.includes('security')) {
labels.push('security');
}
if (labels.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: labels
});
}
}
# ============================================================================
# DOCUMENTATION MAINTENANCE
# ============================================================================
documentation-check:
name: Documentation Check
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check documentation completeness
run: |
echo '📚 Checking documentation completeness...'
# Check for essential documentation files
MISSING_DOCS=()
if [ ! -f README.md ]; then
MISSING_DOCS+=("README.md")
fi
if [ ! -f CONTRIBUTING.md ]; then
MISSING_DOCS+=("CONTRIBUTING.md")
fi
if [ ! -f CHANGELOG.md ]; then
MISSING_DOCS+=("CHANGELOG.md")
fi
if [ ! -f LICENSE ] && [ ! -f LICENSE.md ]; then
MISSING_DOCS+=("LICENSE")
fi
if [ ${#MISSING_DOCS[@]} -gt 0 ]; then
echo "⚠️ Missing documentation files:"
printf '%s\n' "${MISSING_DOCS[@]}"
else
echo "✅ All essential documentation files present"
fi
# Check README sections
if [ -f README.md ]; then
echo "Checking README.md structure..."
if ! grep -qi "installation" README.md; then
echo "⚠️ README.md missing installation section"
fi
if ! grep -qi "usage" README.md; then
echo "⚠️ README.md missing usage section"
fi
if ! grep -qi "development" README.md; then
echo "⚠️ README.md missing development section"
fi
fi
# ============================================================================
# MAINTENANCE SUMMARY
# ============================================================================
maintenance-summary:
name: Maintenance Summary
runs-on: ubuntu-latest
needs: [repo-maintenance, dependency-health, build-performance, documentation-check]
if: always()
steps:
- name: Create maintenance summary
run: |
echo "## 🔧 Weekly Maintenance Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Date**: $(date)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Status Overview" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.repo-maintenance.result }}" = "success" ]; then
echo "✅ Repository Maintenance: Completed" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Repository Maintenance: Issues detected" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.dependency-health.result }}" = "success" ]; then
echo "✅ Dependency Health: Good" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Dependency Health: Needs attention" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.build-performance.result }}" = "success" ]; then
echo "✅ Build Performance: Monitored" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Build Performance: Issues detected" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.documentation-check.result }}" = "success" ]; then
echo "✅ Documentation: Up to date" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Documentation: Needs updates" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Next Actions" >> $GITHUB_STEP_SUMMARY
echo "- Review any failed checks above" >> $GITHUB_STEP_SUMMARY
echo "- Update dependencies if needed" >> $GITHUB_STEP_SUMMARY
echo "- Address documentation gaps" >> $GITHUB_STEP_SUMMARY
echo "- Monitor build performance trends" >> $GITHUB_STEP_SUMMARY