🌐 Add cross-repo index system (Tier 1)
Some checks failed
BlackRoad AI Agents / agent-response (push) Has been cancelled
🔍 BlackRoad CodeQL Security Analysis / CodeQL Analysis (javascript) (push) Has been cancelled
🔍 BlackRoad CodeQL Security Analysis / CodeQL Analysis (python) (push) Has been cancelled
Deploy to Cloudflare Pages / deploy (push) Has been cancelled
Trinity Compliance Check / check-compliance (push) Has been cancelled
Check Dependencies / check-deps (push) Failing after 43s
Some checks failed
BlackRoad AI Agents / agent-response (push) Has been cancelled
🔍 BlackRoad CodeQL Security Analysis / CodeQL Analysis (javascript) (push) Has been cancelled
🔍 BlackRoad CodeQL Security Analysis / CodeQL Analysis (python) (push) Has been cancelled
Deploy to Cloudflare Pages / deploy (push) Has been cancelled
Trinity Compliance Check / check-compliance (push) Has been cancelled
Check Dependencies / check-deps (push) Failing after 43s
This commit is contained in:
65
.blackroad/README.md
Normal file
65
.blackroad/README.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# .blackroad/ - Cross-Repo Index System
|
||||||
|
|
||||||
|
This directory contains the **Tier 1 local index** for this repository.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- **workflow-index.jsonl** - Append-only log of all workflows in this repo
|
||||||
|
- **workflow-index-schema.json** - JSON schema for validation
|
||||||
|
- **last-sync.txt** - Last sync timestamp
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. When an issue is created/updated with a workflow ID label
|
||||||
|
2. `workflow-index-sync.yml` runs automatically
|
||||||
|
3. Extracts metadata (state, scope, risk, dependencies, etc.)
|
||||||
|
4. Appends to `workflow-index.jsonl`
|
||||||
|
5. Commits the update
|
||||||
|
|
||||||
|
## Querying
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find all Active workflows
|
||||||
|
jq 'select(.state=="Active")' .blackroad/workflow-index.jsonl
|
||||||
|
|
||||||
|
# Find workflows with dependencies
|
||||||
|
jq 'select(.deps | length > 0)' .blackroad/workflow-index.jsonl
|
||||||
|
|
||||||
|
# Find System-scope workflows
|
||||||
|
jq 'select(.scope=="System")' .blackroad/workflow-index.jsonl
|
||||||
|
|
||||||
|
# Find Red traffic light workflows
|
||||||
|
jq 'select(.traffic_light=="🔴")' .blackroad/workflow-index.jsonl
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cross-Repo Dependencies
|
||||||
|
|
||||||
|
Format: `{owner}/{repo}#{WORKFLOW_ID}`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "WF-20260213-SVC-0005",
|
||||||
|
"deps": [
|
||||||
|
"WF-20260212-SYS-0001", // Local dependency
|
||||||
|
"BlackRoad-OS/api#SEC-20260213-PUB-0006" // Cross-repo dependency
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
This is **Tier 1** (Local Index) of a 3-tier system:
|
||||||
|
|
||||||
|
- **Tier 1**: Local repo index (this file)
|
||||||
|
- **Tier 2**: Organization-wide GitHub Project
|
||||||
|
- **Tier 3**: Global discovery API (optional)
|
||||||
|
|
||||||
|
See: ~/CROSS_REPO_INDEX_STRATEGY.md
|
||||||
|
|
||||||
|
## Maintenance
|
||||||
|
|
||||||
|
- Index is **append-only** (never delete entries)
|
||||||
|
- Updates replace old entries by ID
|
||||||
|
- No manual editing required
|
||||||
|
- Scales to millions of workflows
|
||||||
69
.blackroad/workflow-index-schema.json
Normal file
69
.blackroad/workflow-index-schema.json
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["id", "repo", "title", "state", "timestamp"],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^(WF|SEC|INF|EXP|FIX)-\\d{8}-[A-Z]{3}-\\d{4}$",
|
||||||
|
"description": "Workflow ID in format: PREFIX-YYYYMMDD-SCOPE-SEQ"
|
||||||
|
},
|
||||||
|
"repo": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[a-zA-Z0-9-]+/[a-zA-Z0-9-_]+$",
|
||||||
|
"description": "Repository in format: owner/repo"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
"description": "Human-readable workflow title"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["Active", "Paused", "Speculative", "Archived", "Done", "Merged"],
|
||||||
|
"description": "Workflow state (posture, not progress)"
|
||||||
|
},
|
||||||
|
"scope": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["Local", "Service", "System", "Public", "Experimental"],
|
||||||
|
"description": "Blast radius of changes"
|
||||||
|
},
|
||||||
|
"risk": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["Unknown", "Low", "Medium", "High", "Critical"],
|
||||||
|
"description": "Risk level"
|
||||||
|
},
|
||||||
|
"intent": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["Build", "Fix", "Explore", "Research", "Deploy", "Monitor", "Deprecate", "Migrate"],
|
||||||
|
"description": "Why this workflow exists"
|
||||||
|
},
|
||||||
|
"traffic_light": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["🟢", "🟡", "🔴"],
|
||||||
|
"description": "Coordination status"
|
||||||
|
},
|
||||||
|
"deps": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Array of dependency IDs (local or cross-repo format)"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uri",
|
||||||
|
"description": "GitHub issue/PR URL"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "Creation timestamp"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"description": "Last update timestamp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
277
.github/workflows/check-dependencies.yml
vendored
Normal file
277
.github/workflows/check-dependencies.yml
vendored
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
name: Check Dependencies
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 */6 * * *' # Every 6 hours
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-deps:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check if index exists
|
||||||
|
id: check_index
|
||||||
|
run: |
|
||||||
|
if [ -f .blackroad/workflow-index.jsonl ]; then
|
||||||
|
echo "exists=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "exists=false" >> $GITHUB_OUTPUT
|
||||||
|
echo "⚠️ No workflow index found in this repo"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Parse dependencies
|
||||||
|
if: steps.check_index.outputs.exists == 'true'
|
||||||
|
id: parse
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const indexPath = '.blackroad/workflow-index.jsonl';
|
||||||
|
|
||||||
|
if (!fs.existsSync(indexPath)) {
|
||||||
|
console.log('No index file found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = fs.readFileSync(indexPath, 'utf8').split('\n').filter(l => l);
|
||||||
|
const workflows = lines.map(l => JSON.parse(l));
|
||||||
|
|
||||||
|
// Find workflows with dependencies
|
||||||
|
const withDeps = workflows.filter(w => w.deps && w.deps.length > 0);
|
||||||
|
|
||||||
|
if (withDeps.length === 0) {
|
||||||
|
console.log('No workflows with dependencies');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate local and cross-repo deps
|
||||||
|
const localDeps = [];
|
||||||
|
const crossRepoDeps = [];
|
||||||
|
|
||||||
|
for (const workflow of withDeps) {
|
||||||
|
for (const dep of workflow.deps) {
|
||||||
|
if (dep.includes('#')) {
|
||||||
|
// Cross-repo dependency
|
||||||
|
crossRepoDeps.push({
|
||||||
|
workflow: workflow.id,
|
||||||
|
dep: dep,
|
||||||
|
repo: dep.split('#')[0],
|
||||||
|
depId: dep.split('#')[1]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Local dependency
|
||||||
|
localDeps.push({
|
||||||
|
workflow: workflow.id,
|
||||||
|
dep: dep
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core.setOutput('local_deps', JSON.stringify(localDeps));
|
||||||
|
core.setOutput('cross_repo_deps', JSON.stringify(crossRepoDeps));
|
||||||
|
core.setOutput('has_deps', 'true');
|
||||||
|
|
||||||
|
- name: Check local dependencies
|
||||||
|
if: steps.parse.outputs.has_deps == 'true'
|
||||||
|
id: check_local
|
||||||
|
run: |
|
||||||
|
LOCAL_DEPS='${{ steps.parse.outputs.local_deps }}'
|
||||||
|
|
||||||
|
if [ "$LOCAL_DEPS" = "[]" ]; then
|
||||||
|
echo "No local dependencies to check"
|
||||||
|
echo "blocked=false" >> $GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Checking local dependencies..."
|
||||||
|
echo "$LOCAL_DEPS" | jq -r '.[] | "\(.workflow) depends on \(.dep)"'
|
||||||
|
|
||||||
|
BLOCKED=false
|
||||||
|
|
||||||
|
# Check each dependency
|
||||||
|
for dep_id in $(echo "$LOCAL_DEPS" | jq -r '.[].dep'); do
|
||||||
|
# Check if dep exists and is Done
|
||||||
|
if grep -q "\"id\":\"$dep_id\"" .blackroad/workflow-index.jsonl; then
|
||||||
|
STATE=$(grep "\"id\":\"$dep_id\"" .blackroad/workflow-index.jsonl | jq -r '.state')
|
||||||
|
if [ "$STATE" != "Done" ]; then
|
||||||
|
echo "⚠️ Dependency $dep_id is not Done (state: $STATE)"
|
||||||
|
BLOCKED=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "⚠️ Dependency $dep_id not found in index"
|
||||||
|
BLOCKED=true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "blocked=$BLOCKED" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Check cross-repo dependencies
|
||||||
|
if: steps.parse.outputs.has_deps == 'true'
|
||||||
|
id: check_cross
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
CROSS_DEPS='${{ steps.parse.outputs.cross_repo_deps }}'
|
||||||
|
|
||||||
|
if [ "$CROSS_DEPS" = "[]" ]; then
|
||||||
|
echo "No cross-repo dependencies to check"
|
||||||
|
echo "blocked=false" >> $GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Checking cross-repo dependencies..."
|
||||||
|
echo "$CROSS_DEPS" | jq -r '.[] | "\(.workflow) depends on \(.repo)#\(.depId)"'
|
||||||
|
|
||||||
|
BLOCKED=false
|
||||||
|
|
||||||
|
# For each cross-repo dep, try to fetch the workflow index
|
||||||
|
for repo in $(echo "$CROSS_DEPS" | jq -r '.[].repo' | sort -u); do
|
||||||
|
echo "Fetching index from $repo..."
|
||||||
|
|
||||||
|
# Try to download the workflow index from the dependency repo
|
||||||
|
if gh api "/repos/$repo/contents/.blackroad/workflow-index.jsonl" \
|
||||||
|
--jq '.content' 2>/dev/null | base64 -d > /tmp/dep-index.jsonl; then
|
||||||
|
echo "✅ Found index in $repo"
|
||||||
|
|
||||||
|
# Check each dep from this repo
|
||||||
|
for dep_id in $(echo "$CROSS_DEPS" | jq -r "select(.repo==\"$repo\") | .depId"); do
|
||||||
|
if grep -q "\"id\":\"$dep_id\"" /tmp/dep-index.jsonl; then
|
||||||
|
STATE=$(grep "\"id\":\"$dep_id\"" /tmp/dep-index.jsonl | jq -r '.state')
|
||||||
|
if [ "$STATE" != "Done" ]; then
|
||||||
|
echo "⚠️ Dependency $repo#$dep_id is not Done (state: $STATE)"
|
||||||
|
BLOCKED=true
|
||||||
|
else
|
||||||
|
echo "✅ Dependency $repo#$dep_id is Done"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "⚠️ Dependency $dep_id not found in $repo"
|
||||||
|
BLOCKED=true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "⚠️ Could not fetch index from $repo (may be private or not exist)"
|
||||||
|
BLOCKED=true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "blocked=$BLOCKED" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Create or update alert issue
|
||||||
|
if: steps.check_local.outputs.blocked == 'true' || steps.check_cross.outputs.blocked == 'true'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const localDeps = JSON.parse('${{ steps.parse.outputs.local_deps }}');
|
||||||
|
const crossDeps = JSON.parse('${{ steps.parse.outputs.cross_repo_deps }}');
|
||||||
|
|
||||||
|
// Build alert body
|
||||||
|
let body = '## ⚠️ Blocked Dependencies Detected\n\n';
|
||||||
|
body += '_This issue is auto-generated by dependency checker_\n\n';
|
||||||
|
body += `**Last checked**: ${new Date().toISOString()}\n\n`;
|
||||||
|
|
||||||
|
if (localDeps.length > 0) {
|
||||||
|
body += '### Local Dependencies\n\n';
|
||||||
|
for (const dep of localDeps) {
|
||||||
|
body += `- \`${dep.workflow}\` depends on \`${dep.dep}\`\n`;
|
||||||
|
}
|
||||||
|
body += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crossDeps.length > 0) {
|
||||||
|
body += '### Cross-Repo Dependencies\n\n';
|
||||||
|
for (const dep of crossDeps) {
|
||||||
|
body += `- \`${dep.workflow}\` depends on \`${dep.repo}#${dep.depId}\`\n`;
|
||||||
|
}
|
||||||
|
body += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
body += '---\n\n';
|
||||||
|
body += '**Next Steps**:\n';
|
||||||
|
body += '1. Check status of blocked dependencies\n';
|
||||||
|
body += '2. Coordinate with dependency owners if needed\n';
|
||||||
|
body += '3. Update traffic lights (🔴 Red if blocked, 🟡 Yellow if waiting)\n';
|
||||||
|
body += '4. This issue will auto-close when all dependencies are Done\n';
|
||||||
|
|
||||||
|
// Check for existing alert
|
||||||
|
const { data: issues } = await github.rest.issues.listForRepo({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
labels: 'dependency-alert',
|
||||||
|
state: 'open'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (issues.length > 0) {
|
||||||
|
// Update existing alert
|
||||||
|
await github.rest.issues.update({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issues[0].number,
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
console.log(`Updated alert issue #${issues[0].number}`);
|
||||||
|
} else {
|
||||||
|
// Create new alert
|
||||||
|
await github.rest.issues.create({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
title: '⚠️ Dependency Alert: Blocked Workflows',
|
||||||
|
body: body,
|
||||||
|
labels: ['dependency-alert', '🔴']
|
||||||
|
});
|
||||||
|
console.log('Created new dependency alert issue');
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Close alert if all clear
|
||||||
|
if: steps.check_local.outputs.blocked == 'false' && steps.check_cross.outputs.blocked == 'false'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
// Find open alert issues
|
||||||
|
const { data: issues } = await github.rest.issues.listForRepo({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
labels: 'dependency-alert',
|
||||||
|
state: 'open'
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const issue of issues) {
|
||||||
|
await github.rest.issues.update({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
state: 'closed'
|
||||||
|
});
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
body: '✅ All dependencies resolved. Auto-closing.'
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Closed alert issue #${issue.number}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Generate summary
|
||||||
|
run: |
|
||||||
|
echo "## 🔍 Dependency Check Results" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
if [ "${{ steps.check_local.outputs.blocked }}" = "true" ] || [ "${{ steps.check_cross.outputs.blocked }}" = "true" ]; then
|
||||||
|
echo "**Status**: ⚠️ **BLOCKED**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Some workflows have unresolved dependencies." >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Check the dependency alert issue for details." >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "**Status**: ✅ **ALL CLEAR**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "All dependencies are resolved." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
152
.github/workflows/workflow-index-sync.yml
vendored
Normal file
152
.github/workflows/workflow-index-sync.yml
vendored
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
name: Workflow Index Sync
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened, edited, closed, reopened]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
issues: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync-index:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Create .blackroad directory
|
||||||
|
run: |
|
||||||
|
mkdir -p .blackroad
|
||||||
|
|
||||||
|
- name: Extract workflow metadata
|
||||||
|
id: metadata
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const issue = context.payload.issue;
|
||||||
|
if (!issue) {
|
||||||
|
console.log('No issue in payload, skipping');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract workflow ID from labels or title
|
||||||
|
const workflowIdLabel = issue.labels.find(l =>
|
||||||
|
l.name.match(/^(WF|SEC|INF|EXP|FIX)-\d{8}-[A-Z]{3}-\d{4}$/)
|
||||||
|
);
|
||||||
|
|
||||||
|
const workflowId = workflowIdLabel
|
||||||
|
? workflowIdLabel.name
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (!workflowId) {
|
||||||
|
console.log('No workflow ID found, skipping');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse workflow ID components
|
||||||
|
const [prefix, date, scope, seq] = workflowId.split('-');
|
||||||
|
|
||||||
|
// Extract dependencies from body
|
||||||
|
const depsMatch = issue.body?.match(/Dependencies?:\s*([^\n]+)/i);
|
||||||
|
const deps = depsMatch
|
||||||
|
? depsMatch[1].split(',').map(d => d.trim()).filter(d => d)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// Extract other metadata from labels
|
||||||
|
const trafficLight = issue.labels.find(l =>
|
||||||
|
l.name.match(/[🟢🟡🔴]/)
|
||||||
|
)?.name || '🟢';
|
||||||
|
|
||||||
|
const state = issue.state === 'closed' ? 'Done' : 'Active';
|
||||||
|
|
||||||
|
const scope = issue.labels.find(l =>
|
||||||
|
['Local', 'Service', 'System', 'Public', 'Experimental'].includes(l.name)
|
||||||
|
)?.name || 'Service';
|
||||||
|
|
||||||
|
const risk = issue.labels.find(l =>
|
||||||
|
['Low', 'Medium', 'High', 'Critical'].includes(l.name)
|
||||||
|
)?.name || 'Unknown';
|
||||||
|
|
||||||
|
const intent = issue.labels.find(l =>
|
||||||
|
['Build', 'Fix', 'Explore', 'Research', 'Deploy', 'Monitor'].includes(l.name)
|
||||||
|
)?.name || 'Build';
|
||||||
|
|
||||||
|
// Create index entry
|
||||||
|
const entry = {
|
||||||
|
id: workflowId,
|
||||||
|
repo: context.repo.owner + '/' + context.repo.repo,
|
||||||
|
title: issue.title,
|
||||||
|
state: state,
|
||||||
|
scope: scope,
|
||||||
|
risk: risk,
|
||||||
|
intent: intent,
|
||||||
|
traffic_light: trafficLight,
|
||||||
|
deps: deps,
|
||||||
|
url: issue.html_url,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
updated_at: issue.updated_at
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write to output
|
||||||
|
core.setOutput('entry', JSON.stringify(entry));
|
||||||
|
core.setOutput('workflow_id', workflowId);
|
||||||
|
|
||||||
|
- name: Append to index
|
||||||
|
if: steps.metadata.outputs.entry
|
||||||
|
run: |
|
||||||
|
ENTRY='${{ steps.metadata.outputs.entry }}'
|
||||||
|
WORKFLOW_ID='${{ steps.metadata.outputs.workflow_id }}'
|
||||||
|
|
||||||
|
# Create index file if it doesn't exist
|
||||||
|
touch .blackroad/workflow-index.jsonl
|
||||||
|
|
||||||
|
# Check if entry already exists (by ID)
|
||||||
|
if grep -q "\"id\":\"$WORKFLOW_ID\"" .blackroad/workflow-index.jsonl; then
|
||||||
|
# Update existing entry (remove old, append new)
|
||||||
|
grep -v "\"id\":\"$WORKFLOW_ID\"" .blackroad/workflow-index.jsonl > .blackroad/workflow-index.tmp
|
||||||
|
mv .blackroad/workflow-index.tmp .blackroad/workflow-index.jsonl
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Append new entry
|
||||||
|
echo "$ENTRY" >> .blackroad/workflow-index.jsonl
|
||||||
|
|
||||||
|
echo "✅ Updated workflow index: $WORKFLOW_ID"
|
||||||
|
|
||||||
|
- name: Update sync timestamp
|
||||||
|
if: steps.metadata.outputs.entry
|
||||||
|
run: |
|
||||||
|
date -u +"%Y-%m-%dT%H:%M:%SZ" > .blackroad/last-sync.txt
|
||||||
|
|
||||||
|
- name: Commit changes
|
||||||
|
if: steps.metadata.outputs.entry
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
git add .blackroad/workflow-index.jsonl .blackroad/last-sync.txt
|
||||||
|
|
||||||
|
if git diff --staged --quiet; then
|
||||||
|
echo "No changes to commit"
|
||||||
|
else
|
||||||
|
git commit -m "📇 Update workflow index: ${{ steps.metadata.outputs.workflow_id }}"
|
||||||
|
git push
|
||||||
|
echo "✅ Pushed workflow index update"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Generate summary
|
||||||
|
if: steps.metadata.outputs.entry
|
||||||
|
run: |
|
||||||
|
echo "## 📇 Workflow Index Updated" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Workflow ID**: \`${{ steps.metadata.outputs.workflow_id }}\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "**Index Location**: \`.blackroad/workflow-index.jsonl\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Total workflows in this repo:" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
wc -l < .blackroad/workflow-index.jsonl >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||||
Reference in New Issue
Block a user