forked from makenotion/notion-mcp-server
-
Notifications
You must be signed in to change notification settings - Fork 0
[Self-Heal] Add self-scheduling auto-repair workflow #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
badMade
wants to merge
1
commit into
main
Choose a base branch
from
self-heal-pipeline-10089540312545322
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| schedule: "0 3 * * 1,3,5" | ||
| rationale: "Initial bootstrap schedule (standard tier)." | ||
| last_updated: "2023-01-01T00:00:00.000Z" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| name: Compute Self-Heal Schedule | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: "0 0 * * 0" # Runs weekly on Sunday | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| actions: read | ||
|
|
||
| jobs: | ||
| compute: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 5 | ||
| if: github.ref == 'refs/heads/main' | ||
|
|
||
| steps: | ||
| - name: Check out repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Set up Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20' | ||
| cache: 'npm' | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci | ||
|
|
||
| - name: Configure Git | ||
| run: | | ||
| git config --global user.name "github-actions[bot]" | ||
| git config --global user.email "github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| - name: Check for open schedule PRs | ||
| id: check_duplicate | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| RECENT_PR=$(gh pr list --label self-heal-schedule --state open --json createdAt -q '.[0].createdAt' 2>/dev/null || true) | ||
| if [ ! -z "$RECENT_PR" ] && [ "$RECENT_PR" != "null" ]; then | ||
| echo "duplicate_exists=true" >> $GITHUB_OUTPUT | ||
| echo "Found an existing open self-heal-schedule PR. Skipping." | ||
| else | ||
| echo "duplicate_exists=false" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Compute New Schedule | ||
| if: steps.check_duplicate.outputs.duplicate_exists != 'true' | ||
| run: node scripts/compute_schedule.mjs | ||
|
|
||
| - name: Verify YAML & Workflow Parseability | ||
| if: steps.check_duplicate.outputs.duplicate_exists != 'true' | ||
| run: | | ||
| node -e "require('js-yaml').load(require('fs').readFileSync('.github/self-heal-schedule.yml', 'utf8'))" | ||
| node -e "require('js-yaml').load(require('fs').readFileSync('.github/workflows/self-heal.yml', 'utf8'))" | ||
|
|
||
| - name: Create PR if changed | ||
| if: steps.check_duplicate.outputs.duplicate_exists != 'true' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| if [ -n "$(git status --porcelain)" ]; then | ||
| git add .github/self-heal-schedule.yml .github/workflows/self-heal.yml | ||
|
|
||
| BRANCH_NAME="selfheal-schedule-$(date +%s)" | ||
| git checkout -b "$BRANCH_NAME" | ||
| git commit -m "Auto-update self-heal schedule based on telemetry" | ||
| git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" | ||
| git -c core.askpass=true push -u origin "$BRANCH_NAME" | ||
|
|
||
| gh pr create \ | ||
| --title "[Self-Heal Schedule] Update cadence" \ | ||
| --body "Telemetry detected a change in repository velocity. Updating schedule accordingly." \ | ||
| --label "automation,self-heal-schedule" \ | ||
| --base main | ||
| else | ||
| echo "No schedule changes computed." | ||
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| name: Self-Heal Repair Pipeline | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: "0 3 * * 1,3,5" # AUTO-UPDATED | ||
| workflow_run: | ||
| workflows: ["ci"] | ||
| types: | ||
| - completed | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| actions: read | ||
|
|
||
| concurrency: | ||
| group: selfheal-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| repair: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 15 | ||
| if: | | ||
| !startsWith(github.ref_name, 'selfheal-') && | ||
| (github.event_name == 'schedule' || | ||
| github.event_name == 'workflow_dispatch' || | ||
| (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'failure')) | ||
|
|
||
| steps: | ||
| - name: Check out repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Set up Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20' | ||
| cache: 'npm' | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci | ||
|
|
||
| - name: Configure Git | ||
| run: | | ||
| git config --global user.name "github-actions[bot]" | ||
| git config --global user.email "github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| - name: Close Stale Self-Heal PRs | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| DATE=$(date -d "7 days ago" +%Y-%m-%d) | ||
| PR_LIST=$(gh pr list --label self-heal --search "created:<$DATE" --json number -q '.[].number' 2>/dev/null || true) | ||
| for PR in $PR_LIST; do | ||
| gh pr close "$PR" -c "Closing stale self-heal PR." | ||
| done | ||
|
|
||
| - name: Check for duplicate PRs | ||
| id: check_duplicate | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| RECENT_PR=$(gh pr list --label self-heal --state open --json createdAt -q '.[0].createdAt' 2>/dev/null || true) | ||
| if [ ! -z "$RECENT_PR" ] && [ "$RECENT_PR" != "null" ]; then | ||
| echo "duplicate_exists=true" >> $GITHUB_OUTPUT | ||
| echo "Found an existing open self-heal PR. Skipping." | ||
| else | ||
| echo "duplicate_exists=false" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Run Pre-Healthcheck | ||
| if: steps.check_duplicate.outputs.duplicate_exists != 'true' | ||
| run: node scripts/healthcheck.mjs > pre-check.log 2>&1 || true | ||
|
|
||
| - name: Execute Self-Heal Scripts | ||
| id: self_heal | ||
| if: steps.check_duplicate.outputs.duplicate_exists != 'true' | ||
| run: node scripts/self_heal.mjs > repair.log 2>&1 | ||
|
|
||
| - name: Run Post-Healthcheck | ||
| id: post_check | ||
| if: steps.check_duplicate.outputs.duplicate_exists != 'true' | ||
| run: node scripts/healthcheck.mjs > post-check.log 2>&1 | ||
|
|
||
| - name: Check for Diff & Secrets | ||
| id: verify_diff | ||
| if: steps.check_duplicate.outputs.duplicate_exists != 'true' | ||
| run: | | ||
| if [ -n "$(git status --porcelain)" ]; then | ||
| git add package.json package-lock.json src/ tests/ .eslintrc* eslint.config* prettier* *.ts *.js 2>/dev/null || true | ||
| if git diff --cached | grep -iE 'api[_-]?key|secret|token|password'; then | ||
| echo "Error: Potential secret found in diff. Aborting." | ||
| sh -c 'exit 1' | ||
| fi | ||
| echo "has_diff=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "has_diff=false" >> $GITHUB_OUTPUT | ||
| fi | ||
|
|
||
| - name: Create Pull Request | ||
| if: steps.check_duplicate.outputs.duplicate_exists != 'true' && steps.verify_diff.outputs.has_diff == 'true' && steps.post_check.outcome == 'success' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| BRANCH_NAME="selfheal-$(date +%s)" | ||
| git checkout -b "$BRANCH_NAME" | ||
| git commit -m "Auto-repair drift/CI failures" | ||
| git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" | ||
| git -c core.askpass=true push -u origin "$BRANCH_NAME" | ||
|
|
||
| TITLE="[Self-Heal Reactive] CI fix" | ||
| if [ "${{ github.event_name }}" == "schedule" ]; then | ||
| TITLE="[Self-Heal Scheduled] Drift fixes" | ||
| elif [ "${{ github.event_name }}" == "workflow_dispatch" ]; then | ||
| TITLE="[Self-Heal Manual] Repair" | ||
| fi | ||
|
|
||
| gh pr create \ | ||
| --title "$TITLE" \ | ||
| --body "Automated repair pipeline triggered by ${{ github.event_name }}. Review attached logs for details." \ | ||
| --label "automation,self-heal" \ | ||
| --base main | ||
|
|
||
| - name: Upload Logs | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: self-heal-logs | ||
| path: | | ||
| pre-check.log | ||
| repair.log | ||
| post-check.log |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,3 +10,4 @@ bin/ | |
| .cursor | ||
|
|
||
| .DS_Store | ||
| *.log | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # Self-Healing Pipeline Setup | ||
|
|
||
| This project utilizes an automated self-healing CI pipeline to detect drift, auto-repair common issues, and submit changes for human review via Pull Requests. | ||
|
|
||
| ## Overview | ||
|
|
||
| The automation relies on 3 main triggers: | ||
| 1. **Scheduled (Proactive)**: Computed based on repository velocity telemetry to prevent bit-rot and keep dependencies/snapshots up to date. | ||
| 2. **CI Failure (Reactive)**: Triggered whenever the main `ci` workflow fails. | ||
| 3. **Manual Dispatch**: Available on-demand via the GitHub Actions UI. | ||
|
|
||
| ## How It Works | ||
|
|
||
| The repair pipeline consists of scripts located in `scripts/`: | ||
| - `healthcheck.mjs`: Acts as a gate, ensuring tests, linting, and builds pass. | ||
| - `self_heal.mjs`: Runs 6 idempotent repair steps: | ||
| 1. **Rebuild/reinstall**: `npm ci || npm install` | ||
| 2. **Lint/format auto-fix**: `npx eslint --fix . && npx prettier -w .` | ||
| 3. **Snapshot updates**: `npx vitest run -u --passWithNoTests` | ||
| 4. **Type config/analyzer**: `npx tsc --build` | ||
| 5. **Dependency re-resolve**: `npm update` | ||
| 6. **Static asset generation**: `npm run build` | ||
| - `compute_schedule.mjs`: Analyzes commit velocity to compute an optimal schedule cadence and avoid thrashing. | ||
|
|
||
| ### Safety Guards | ||
|
|
||
| - PR duplication is prevented. | ||
| - A branch guard prevents automated loops from triggering themselves. | ||
| - A simple heuristic secret scanner checks for introduced tokens before creating a PR. | ||
| - Changes must pass the `healthcheck.mjs` before being submitted. | ||
|
|
||
| ## Reviewer Checklist | ||
|
|
||
| When reviewing a PR prefixed with `[Self-Heal ...]`, please check: | ||
| - [ ] Ensure the changes only affect formatting, lockfiles, snapshots, or dependencies. | ||
| - [ ] Ensure there are no logic changes or inadvertently removed code. | ||
| - [ ] Review the artifact logs (`pre-check.log`, `repair.log`, `post-check.log`) attached to the PR. | ||
| - [ ] Validate no secrets or sensitive data were pushed. | ||
|
|
||
| ## Manual Schedule Override | ||
|
|
||
| If you wish to override the telemetry-based schedule: | ||
| 1. Edit `.github/self-heal-schedule.yml` directly. | ||
| 2. Change the `schedule` to the desired cron value. | ||
| 3. Optionally disable `.github/workflows/compute-schedule.yml` to prevent it from reverting your override. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import eslint from '@eslint/js'; | ||
| import tseslint from 'typescript-eslint'; | ||
| import globals from 'globals'; | ||
|
|
||
| export default tseslint.config( | ||
| eslint.configs.recommended, | ||
| ...tseslint.configs.recommended, | ||
| { | ||
| languageOptions: { | ||
| globals: { | ||
| ...globals.node, | ||
| ...globals.browser, | ||
| ...globals.jest, | ||
| }, | ||
| }, | ||
| rules: { | ||
| '@typescript-eslint/no-explicit-any': 'off', | ||
| '@typescript-eslint/no-unused-vars': 'off', | ||
| '@typescript-eslint/ban-ts-comment': 'off', | ||
| 'prefer-const': 'off', | ||
| 'no-undef': 'off', | ||
| 'preserve-caught-error': 'off', | ||
| '@typescript-eslint/no-unused-expressions': 'off' | ||
| }, | ||
| ignores: [ | ||
| 'build/**', | ||
| 'dist/**', | ||
| 'coverage/**', | ||
| 'bin/**', | ||
| 'node_modules/**', | ||
| '*.log', | ||
| 'scripts/build-cli.js', | ||
| 'examples/**' | ||
| ], | ||
| } | ||
| ); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rule
preserve-caught-erroris not a valid ESLint ortypescript-eslintrule. Including undefined rules will cause ESLint to throw an error and fail to run. Since it is set to'off', it should be removed.