Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# GitHub Actions Workflows

This directory contains automated workflows for the master-plan repository.

## Sync Roadmap Workflow

**File:** `sync-roadmap.yml`

### Purpose

Automatically synchronizes the roadmap section in `README.md` with the actual state of GitHub issues across the deep-assistant organization.

### How It Works

1. **Triggers:**
- Runs daily at 00:00 UTC (scheduled)
- Can be manually triggered from the Actions tab
- Automatically runs when issues are opened, closed, reopened, edited, or deleted

2. **Process:**
- Scans `README.md` for issue references in the roadmap section
- Fetches current state of each issue from GitHub API
- Updates checkboxes: `[ ]` for open issues, `[x]` for closed issues
- Commits changes if any updates are detected

3. **Script:** `sync-roadmap.js`
- Node.js script that performs the actual synchronization
- Parses markdown to find issue links
- Uses GitHub API to check issue states
- Preserves existing roadmap structure and formatting

### Manual Execution

You can manually trigger this workflow from the GitHub Actions tab:

1. Go to the repository's Actions tab
2. Select "Sync Master Plan Roadmap" workflow
3. Click "Run workflow" button

### Configuration

The workflow requires:
- `contents: write` permission to commit changes
- `issues: read` permission to fetch issue states
- `GITHUB_TOKEN` secret (automatically provided by GitHub Actions)

### Maintenance

To update the roadmap structure or add new issues:
1. Manually edit the `README.md` file
2. Add issue references in the format: `[#123](https://github.com/deep-assistant/repo-name/issues/123)`
3. The workflow will automatically sync checkbox states on the next run
153 changes: 153 additions & 0 deletions .github/workflows/sync-roadmap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#!/usr/bin/env node

/**
* Sync Master Plan Roadmap Script
*
* This script automatically updates the roadmap section in README.md
* by synchronizing checkbox states with actual GitHub issue states.
*
* Features:
* - Updates checkboxes: [ ] for open issues, [x] for closed issues
* - Preserves the existing roadmap structure and formatting
* - Works with issues from multiple repositories
*/

const fs = require('fs');
const https = require('https');

const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
const ORG_NAME = 'deep-assistant';

/**
* Fetch data from GitHub API
*/
function fetchGitHub(path) {
return new Promise((resolve, reject) => {
const options = {
hostname: 'api.github.com',
path: path,
method: 'GET',
headers: {
'User-Agent': 'Master-Plan-Sync-Bot',
'Authorization': `token ${GITHUB_TOKEN}`,
'Accept': 'application/vnd.github.v3+json'
}
};

https.get(options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
if (res.statusCode === 200) {
resolve(JSON.parse(data));
} else {
reject(new Error(`GitHub API error: ${res.statusCode} - ${data}`));
}
});
}).on('error', reject);
});
}

/**
* Get issue state (open/closed) from GitHub
*/
async function getIssueState(repo, issueNumber) {
try {
const issue = await fetchGitHub(`/repos/${ORG_NAME}/${repo}/issues/${issueNumber}`);
return issue.state === 'closed' ? 'closed' : 'open';
} catch (error) {
console.error(`Error fetching issue ${repo}#${issueNumber}:`, error.message);
return 'open'; // Default to open if we can't fetch
}
}

/**
* Parse issue reference from markdown link
* Returns: { repo: string, number: number } or null
*/
function parseIssueLink(line) {
// Match patterns like:
// - **Link:** [#46](https://github.com/deep-assistant/telegram-bot/issues/46)
// - **Link:** [#10](https://github.com/deep-assistant/master-plan/issues/10)
const linkPattern = /\[#(\d+)\]\(https:\/\/github\.com\/deep-assistant\/([^\/]+)\/issues\/\d+\)/;
const match = line.match(linkPattern);

if (match) {
return {
repo: match[2],
number: parseInt(match[1], 10)
};
}

return null;
}

/**
* Update checkbox state in a task line
*/
function updateCheckbox(line, isClosed) {
const checkbox = isClosed ? '[x]' : '[ ]';
// Replace existing checkbox at the start of the line
return line.replace(/^(\s*)-\s*\[([ x])\]/, `$1- ${checkbox}`);
}

/**
* Main sync function
*/
async function syncRoadmap() {
console.log('πŸš€ Starting roadmap sync...');

// Read README.md
const readmePath = 'README.md';
let content = fs.readFileSync(readmePath, 'utf8');
const lines = content.split('\n');

let updated = false;
let currentIssue = null;

// Process each line
for (let i = 0; i < lines.length; i++) {
const line = lines[i];

// Check if this line contains an issue link
const issueRef = parseIssueLink(line);
if (issueRef) {
currentIssue = issueRef;
console.log(`πŸ“‹ Found issue reference: ${issueRef.repo}#${issueRef.number}`);
}

// Check if this is a task line with a checkbox and we have a current issue
if (currentIssue && line.match(/^\s*-\s*\[([ x])\]/)) {
// Get the actual state from GitHub
const state = await getIssueState(currentIssue.repo, currentIssue.number);
const isClosed = state === 'closed';

// Update the checkbox if needed
const newLine = updateCheckbox(line, isClosed);
if (newLine !== line) {
console.log(`βœ… Updating ${currentIssue.repo}#${currentIssue.number}: ${state}`);
lines[i] = newLine;
updated = true;
}

// Reset current issue after processing its task line
currentIssue = null;
}
}

// Write back if updated
if (updated) {
fs.writeFileSync(readmePath, lines.join('\n'), 'utf8');
console.log('✨ Roadmap successfully updated!');
} else {
console.log('βœ“ Roadmap is already up to date!');
}

return updated;
}

// Run the sync
syncRoadmap().catch(error => {
console.error('❌ Error syncing roadmap:', error);
process.exit(1);
});
52 changes: 52 additions & 0 deletions .github/workflows/sync-roadmap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Sync Master Plan Roadmap

on:
schedule:
# Run daily at 00:00 UTC
- cron: '0 0 * * *'
workflow_dispatch: # Allow manual trigger
issues:
types: [opened, closed, reopened, edited, deleted]

permissions:
contents: write
issues: read

jobs:
sync-roadmap:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Sync roadmap with issues
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
node .github/workflows/sync-roadmap.js

- name: Check for changes
id: git-check
run: |
git diff --exit-code README.md || echo "changed=true" >> $GITHUB_OUTPUT

- name: Commit and push if changed
if: steps.git-check.outputs.changed == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add README.md
git commit -m "chore: sync roadmap with GitHub issues

πŸ€– Automatically synchronized the roadmap section in README.md with the current state of GitHub issues across the organization.

πŸ€– Generated with GitHub Actions"
git push