create-agentic-pdlc 2.4.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,139 +0,0 @@
1
- name: AI QA Agent
2
- on:
3
- pull_request:
4
- types: [opened, synchronize, reopened]
5
-
6
- permissions:
7
- pull-requests: write
8
- contents: read
9
- issues: read
10
- models: read
11
-
12
- jobs:
13
- qa:
14
- name: AC Coverage Verification (GitHub Models)
15
- runs-on: ubuntu-latest
16
- env:
17
- PROJECT_TOKEN: ${{ secrets.PROJECT_TOKEN }}
18
- PROJECT_ID: "PVT_kwHODpFFL84BXg7h"
19
- STATUS_FIELD_ID: "PVTSSF_lAHODpFFL84BXg7hzhStRHI"
20
- STATUS_CODE_REVIEW_PR: "86ca9720"
21
- steps:
22
- - uses: actions/checkout@v5.0.1
23
- with:
24
- fetch-depth: 0
25
-
26
- - name: Verify AC Coverage via GitHub Models
27
- env:
28
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29
- run: |
30
- set -e
31
-
32
- PR_NUMBER="${{ github.event.pull_request.number }}"
33
- BASE="${{ github.event.pull_request.base.sha }}"
34
- HEAD="${{ github.event.pull_request.head.sha }}"
35
-
36
- # Get PR diff (truncated to 8000 chars to stay within context limits)
37
- DIFF=$(git diff "$BASE" "$HEAD" | head -c 8000)
38
-
39
- # Extract linked issues from PR body
40
- PR_BODY=$(gh pr view "$PR_NUMBER" --json body --jq '.body // ""')
41
- ISSUE_NUMS=$(echo "$PR_BODY" | grep -oiE '(Closes?|Fixes?|Resolves?)\s+#([0-9]+)' | grep -oE '[0-9]+' || true)
42
-
43
- # Build acceptance criteria context
44
- AC_CONTEXT=""
45
- if [ -n "$ISSUE_NUMS" ]; then
46
- for NUM in $ISSUE_NUMS; do
47
- ISSUE_BODY=$(gh issue view "$NUM" --json body --jq '.body // ""' 2>/dev/null || echo "")
48
- AC_CONTEXT="${AC_CONTEXT}\\n\\n--- Issue #${NUM} ---\\n${ISSUE_BODY}"
49
- done
50
- fi
51
-
52
- if [ -z "$AC_CONTEXT" ]; then
53
- AC_CONTEXT="No linked issue found. Evaluate if the PR description is self-contained."
54
- fi
55
-
56
- # Serialize prompt as JSON string and call GitHub Models API (3 attempts, 20s backoff)
57
- PROMPT_JSON=$(printf '%s' "You are a senior QA engineer. Review whether this PR diff satisfies the Acceptance Criteria below.\n\nACCEPTANCE CRITERIA:\n${AC_CONTEXT}\n\nPR DIFF:\n${DIFF}\n\nFirst line of your response must be exactly one word: PASS or FAIL. Second line: brief explanation (max 3 sentences)." | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')
58
-
59
- RESPONSE="API_ERROR"
60
- for attempt in 1 2 3; do
61
- RESULT=$(curl -s -X POST \
62
- "https://models.github.ai/inference/chat/completions" \
63
- -H "Authorization: Bearer ${GITHUB_TOKEN}" \
64
- -H "Content-Type: application/json" \
65
- -d "{\"model\":\"gpt-4o-mini\",\"messages\":[{\"role\":\"user\",\"content\":${PROMPT_JSON}}]}" \
66
- -w "\n__HTTP_STATUS__:%{http_code}" \
67
- --max-time 45 2>/dev/null)
68
- HTTP_STATUS=$(echo "$RESULT" | grep -o '__HTTP_STATUS__:[0-9]*' | cut -d: -f2)
69
- BODY=$(echo "$RESULT" | sed 's/__HTTP_STATUS__:[0-9]*$//')
70
- echo "Attempt $attempt: HTTP $HTTP_STATUS"
71
- if [ "$HTTP_STATUS" = "200" ]; then RESPONSE="$BODY"; break; fi
72
- [ $attempt -lt 3 ] && sleep 20
73
- done
74
-
75
- if [ "$RESPONSE" = "API_ERROR" ]; then
76
- GH_TOKEN="$PROJECT_TOKEN" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
77
- gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not reach GitHub Models API. Manual review required."
78
- # exit 1 marks this check as failed; qa-gate.yml enforces the merge block via infra:qa-broken label
79
- exit 1
80
- fi
81
-
82
- VERDICT=$(echo "$RESPONSE" | python3 -c 'import json,sys,re; d=json.load(sys.stdin); t=d.get("choices",[{}])[0].get("message",{}).get("content","").strip(); first=t.split("\n")[0].upper() if t else ""; print("FAIL" if re.search(r"\bFAIL\b",first) else "PASS" if re.search(r"\bPASS\b",first) else "API_ERROR")')
83
- EXPLANATION=$(echo "$RESPONSE" | python3 -c 'import json,sys; d=json.load(sys.stdin); t=d.get("choices",[{}])[0].get("message",{}).get("content","").strip(); lines=t.split("\n",1); print(lines[1].strip() if len(lines)>1 else "")')
84
-
85
- if echo "$VERDICT" | grep -q "^PASS"; then
86
- GH_TOKEN="$PROJECT_TOKEN" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=qa:approved'
87
- gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** AC coverage verified. ${EXPLANATION}"
88
- elif echo "$VERDICT" | grep -q "^FAIL"; then
89
- GH_TOKEN="$PROJECT_TOKEN" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=qa:needs-work'
90
- gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** AC coverage insufficient. ${EXPLANATION}"
91
- else
92
- GH_TOKEN="$PROJECT_TOKEN" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
93
- gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not parse GitHub Models response. Manual review required."
94
- exit 1
95
- fi
96
-
97
- - name: Move board card to Code Review on qa:approved
98
- if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
99
- uses: actions/github-script@v8
100
- with:
101
- github-token: ${{ env.PROJECT_TOKEN }}
102
- script: |
103
- const prNumber = context.payload.pull_request.number;
104
- const { owner, repo } = context.repo;
105
-
106
- const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
107
- if (!pr.labels.some(l => l.name === 'qa:approved')) {
108
- console.log('qa:approved not on PR — skipping board move');
109
- return;
110
- }
111
-
112
- const body = pr.body ?? '';
113
- const linkedIssues = [...body.matchAll(/(?:Closes?|Fixes?|Resolves?)\s+#(\d+)/gi)]
114
- .map(m => parseInt(m[1]));
115
-
116
- const moveItem = async (nodeId) => {
117
- const { addProjectV2ItemById: { item } } = await github.graphql(`
118
- mutation($p: ID!, $c: ID!) {
119
- addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
120
- }`, { p: process.env.PROJECT_ID, c: nodeId });
121
- await github.graphql(`
122
- mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
123
- updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
124
- projectV2Item { id }
125
- }
126
- }`, { p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
127
- v: { singleSelectOptionId: process.env.STATUS_CODE_REVIEW_PR } });
128
- };
129
-
130
- if (linkedIssues.length > 0) {
131
- for (const n of linkedIssues) {
132
- const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: n });
133
- await moveItem(issue.node_id);
134
- console.log(`Issue #${n} → Code Review / PR`);
135
- }
136
- } else {
137
- await moveItem(pr.node_id);
138
- console.log(`PR #${prNumber} → Code Review / PR (no linked issue)`);
139
- }
@@ -1,51 +0,0 @@
1
- name: QA Gate
2
-
3
- on:
4
- pull_request:
5
- types: [opened, synchronize, reopened, labeled, unlabeled]
6
-
7
- permissions:
8
- pull-requests: read
9
-
10
- jobs:
11
- qa-gate:
12
- name: QA Gate
13
- runs-on: ubuntu-latest
14
- steps:
15
- - name: Check QA status label
16
- env:
17
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18
- run: |
19
- set -e
20
- PR_NUMBER="${{ github.event.pull_request.number }}"
21
- REPO="${{ github.repository }}"
22
-
23
- PR_LABELS=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json labels --jq '.labels[].name')
24
-
25
- if echo "$PR_LABELS" | grep -qx "hotfix"; then
26
- echo "✅ QA Gate: hotfix label — bypassed."
27
- exit 0
28
- fi
29
-
30
- if echo "$PR_LABELS" | grep -qx "human-approved"; then
31
- echo "✅ QA Gate: human-approved label — manual QA sign-off, bypassed."
32
- exit 0
33
- fi
34
-
35
- if echo "$PR_LABELS" | grep -qx "qa:approved"; then
36
- echo "✅ QA Gate: qa:approved — merge allowed."
37
- exit 0
38
- fi
39
-
40
- if echo "$PR_LABELS" | grep -qx "infra:qa-broken"; then
41
- echo "❌ QA Gate: infra:qa-broken — GitHub Models API unreachable. Manual QA review required before merge."
42
- exit 1
43
- fi
44
-
45
- if echo "$PR_LABELS" | grep -qx "qa:needs-work"; then
46
- echo "❌ QA Gate: qa:needs-work — acceptance criteria not fully met. Fix required before merge."
47
- exit 1
48
- fi
49
-
50
- echo "❌ QA Gate: no QA label found — AC Coverage Verification has not completed. Wait for the check to finish."
51
- exit 1
File without changes
File without changes