Skip to content

Commit 264d128

Browse files
committed
Create pr-assistant.yml
1 parent edef1a4 commit 264d128

File tree

1 file changed

+213
-0
lines changed

1 file changed

+213
-0
lines changed

.github/workflows/pr-assistant.yml

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
name: PR Assistant
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened, closed]
6+
push:
7+
branches: [main, master]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: write
12+
pull-requests: write
13+
checks: write
14+
issues: write
15+
16+
env:
17+
REQUIRED_WORKFLOW_SCHEMA_VERSION: "2.0.0"
18+
19+
jobs:
20+
# =================================================================================
21+
# JOB 1: PR Validation & Feedback
22+
# Validates workflow definitions and structure
23+
# =================================================================================
24+
pr-validation:
25+
if: github.event_name == 'pull_request' && github.event.action != 'closed'
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Checkout Code
29+
uses: actions/checkout@v6
30+
31+
- name: Set up Python
32+
uses: actions/setup-python@v6
33+
with:
34+
python-version: '3.12'
35+
36+
- name: Install Dependencies
37+
run: |
38+
pip install pyyaml jsonschema
39+
40+
# --- 1. Validate workflows.json ---
41+
- name: 📋 Validate workflows.json
42+
run: |
43+
python << 'EOF'
44+
import json
45+
import sys
46+
from pathlib import Path
47+
48+
workflows_json = Path("workflows.json")
49+
if not workflows_json.exists():
50+
print("❌ workflows.json not found")
51+
sys.exit(1)
52+
53+
with open(workflows_json) as f:
54+
data = json.load(f)
55+
56+
if "workflows" not in data or not isinstance(data["workflows"], list):
57+
print("❌ workflows.json must contain 'workflows' array")
58+
sys.exit(1)
59+
60+
print(f"✅ workflows.json valid ({len(data['workflows'])} workflows)")
61+
EOF
62+
63+
# --- 2. Validate Workflow YAML Files ---
64+
- name: 📝 Validate Workflow YAML Files
65+
run: |
66+
python << 'EOF'
67+
import yaml
68+
import sys
69+
from pathlib import Path
70+
71+
errors = []
72+
validated = 0
73+
74+
print("Validating workflow YAML files...")
75+
76+
# Load workflows.json to get workflow definitions
77+
workflows_json = Path("workflows.json")
78+
if workflows_json.exists():
79+
import json
80+
with open(workflows_json) as f:
81+
workflows_data = json.load(f)
82+
83+
for workflow in workflows_data.get("workflows", []):
84+
workflow_file = workflow.get("file")
85+
if not workflow_file:
86+
continue
87+
88+
workflow_path = Path(workflow_file)
89+
if not workflow_path.exists():
90+
errors.append(f"Workflow file '{workflow_file}' not found")
91+
continue
92+
93+
try:
94+
with open(workflow_path) as f:
95+
workflow_data = yaml.safe_load(f)
96+
97+
# Basic validation
98+
required_fields = ["id", "name", "trigger"]
99+
for field in required_fields:
100+
if field not in workflow_data:
101+
errors.append(f"{workflow_file}: missing required field '{field}'")
102+
103+
# Validate trigger
104+
trigger = workflow_data.get("trigger", {})
105+
if not isinstance(trigger, dict):
106+
errors.append(f"{workflow_file}: trigger must be an object")
107+
elif "type" not in trigger:
108+
errors.append(f"{workflow_file}: trigger.type is required")
109+
110+
# Validate actions (if present)
111+
actions = workflow_data.get("actions", [])
112+
if actions and not isinstance(actions, list):
113+
errors.append(f"{workflow_file}: actions must be an array")
114+
115+
if not any(e.startswith(workflow_file) for e in errors):
116+
validated += 1
117+
print(f"✅ {workflow_file} valid")
118+
119+
except yaml.YAMLError as e:
120+
errors.append(f"{workflow_file}: Invalid YAML - {e}")
121+
except Exception as e:
122+
errors.append(f"{workflow_file}: {e}")
123+
124+
# Also check for any YAML files in workflow directories
125+
for yaml_file in Path(".").rglob("*.yaml"):
126+
if yaml_file.name == "workflows.json" or ".github" in str(yaml_file):
127+
continue
128+
129+
if yaml_file not in [Path(w.get("file")) for w in workflows_data.get("workflows", [])]:
130+
try:
131+
with open(yaml_file) as f:
132+
yaml.safe_load(f)
133+
print(f"ℹ️ Found additional workflow file: {yaml_file}")
134+
except:
135+
pass
136+
137+
if errors:
138+
print("\n❌ Errors found:")
139+
for e in errors:
140+
print(f" - {e}")
141+
sys.exit(1)
142+
else:
143+
print(f"\n✅ All {validated} workflow(s) valid.")
144+
EOF
145+
146+
# --- 3. Validate manifest.json (if exists) ---
147+
- name: 📄 Validate manifest.json
148+
run: |
149+
python << 'EOF'
150+
import json
151+
from pathlib import Path
152+
153+
manifest_path = Path("manifest.json")
154+
if manifest_path.exists():
155+
try:
156+
with open(manifest_path) as f:
157+
manifest = json.load(f)
158+
159+
required_fields = ["schema_version", "domain", "name", "version"]
160+
for field in required_fields:
161+
if field not in manifest:
162+
print(f"⚠️ manifest.json missing field '{field}'")
163+
else:
164+
print(f"✅ manifest.json valid")
165+
except Exception as e:
166+
print(f"⚠️ Error reading manifest.json: {e}")
167+
else:
168+
print("ℹ️ manifest.json not found (optional)")
169+
EOF
170+
171+
# --- 4. Feedback Comment ---
172+
- name: Feedback Comment
173+
if: always()
174+
uses: actions/github-script@v6
175+
with:
176+
script: |
177+
const outcome = '${{ job.status }}';
178+
if (outcome === 'failure') {
179+
github.rest.issues.createComment({
180+
issue_number: context.issue.number,
181+
owner: context.repo.owner,
182+
repo: context.repo.repo,
183+
body: "❌ **PR Validation Failed**\n\nPlease check:\n- workflows.json is valid\n- All workflow YAML files are valid\n- Required fields (id, name, trigger) are present"
184+
});
185+
} else if (outcome === 'success') {
186+
github.rest.issues.createComment({
187+
issue_number: context.issue.number,
188+
owner: context.repo.owner,
189+
repo: context.repo.repo,
190+
body: "✅ **PR Validation Passed**\n\nAll workflow checks passed successfully!"
191+
});
192+
}
193+
194+
# =================================================================================
195+
# JOB 2: Thank Contributor
196+
# =================================================================================
197+
thank-you:
198+
if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true
199+
runs-on: ubuntu-latest
200+
steps:
201+
- uses: actions/github-script@v6
202+
with:
203+
script: |
204+
const author = context.payload.pull_request.user.login;
205+
const admins = ['FaserF', 'fabia', 'github-actions[bot]'];
206+
if (admins.includes(author)) return;
207+
208+
github.rest.issues.createComment({
209+
issue_number: context.issue.number,
210+
owner: context.repo.owner,
211+
repo: context.repo.repo,
212+
body: `🎉 **Thank you @${author}!**\n\nYour contribution to the **faneX-ID Workflows** repository is valuable! 🚀`
213+
});

0 commit comments

Comments
 (0)