-
Notifications
You must be signed in to change notification settings - Fork 0
287 lines (263 loc) · 13.2 KB
/
codex-code.yml
File metadata and controls
287 lines (263 loc) · 13.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
name: Codex Full Auto (Final and Generic)
on:
workflow_dispatch:
inputs:
CODEX_PROMPT:
description: 'The main instruction/prompt for the AI.'
required: true
default: 'Create a simple placeholder file.'
TICKET_ID:
description: 'The Jira/Ticket ID for branch naming and commits.'
required: true
default: 'default-ticket-id'
CODEX_MODEL:
description: 'The AI model to use (e.g., o3, gpt-4-turbo).'
required: true
default: 'gpt-5'
JIRA_IMAGE_URLS:
description: 'Comma-separated list of image URLs from Jira.'
required: false
JIRA_IMAGE_FILENAMES:
description: 'Comma-separated list of original image filenames from Jira.'
required: false
FIGMA_URL:
description: 'Direct Figma link to the component/frame (will auto-extract file key and node id)'
required: false
FIGMA_FILE_KEY:
description: 'Figma file key (from figma.com/file/<key>/...)'
required: false
FIGMA_NODE_IDS:
description: 'Comma-separated Figma node IDs to fetch (e.g., 0:1,1:2)'
required: false
repository_dispatch:
types: [codex-run]
jobs:
codex-full-auto:
runs-on: ubuntu-latest
container: node:latest
env:
# Secrets for operation
FIGMA_ACCESS_TOKEN: ${{ secrets.FIGMA_ACCESS_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
N8N_MR_WEBHOOK_URL: ${{ secrets.N8N_PR_WEBHOOK_URL }}
CODEX_PUSH_TOKEN: ${{ secrets.CODEX_PUSH_TOKEN }}
# Jira access (optional, for auto-detecting Figma link from ticket)
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
JIRA_EMAIL: ${{ secrets.JIRA_API_USER }}
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
# Inputs from dispatch events
CODEX_PROMPT: |
${{ github.event.inputs.CODEX_PROMPT || github.event.client_payload.CODEX_PROMPT }}
TICKET_ID: ${{ github.event.inputs.TICKET_ID || github.event.client_payload.TICKET_ID }}
CODEX_MODEL: ${{ github.event.inputs.CODEX_MODEL || github.event.client_payload.CODEX_MODEL }}
JIRA_IMAGE_URLS: ${{ github.event.inputs.JIRA_IMAGE_URLS || github.event.client_payload.JIRA_IMAGE_URLS }}
JIRA_IMAGE_FILENAMES: ${{ github.event.inputs.JIRA_IMAGE_FILENAMES || github.event.client_payload.JIRA_IMAGE_FILENAMES }}
FIGMA_URL: ${{ github.event.inputs.FIGMA_URL || github.event.client_payload.FIGMA_URL }}
FIGMA_FILE_KEY: ${{ github.event.inputs.FIGMA_FILE_KEY || github.event.client_payload.FIGMA_FILE_KEY }}
FIGMA_NODE_IDS: ${{ github.event.inputs.FIGMA_NODE_IDS || github.event.client_payload.FIGMA_NODE_IDS }}
# Repository context
GH_REPO: ${{ github.repository }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
steps:
- name: 1. Install System Dependencies
run: |
apt-get update -y && apt-get install -y --no-install-recommends curl jq sed file
- name: 2. Checkout Repository
uses: actions/checkout@v4
with:
token: ${{ env.CODEX_PUSH_TOKEN }}
fetch-depth: 0
- name: 3. Configure Git and Install Codex CLI
run: |
git config --global user.name "GitHub Actions Bot"
git config --global user.email "actions-bot@github.com"
npm install -g @openai/codex
- name: 4. Find Figma URL in Jira ticket (if provided)
if: env.FIGMA_URL == '' && env.JIRA_BASE_URL != '' && env.JIRA_EMAIL != '' && env.JIRA_API_TOKEN != '' && env.TICKET_ID != ''
shell: bash
run: |
set -euo pipefail
echo "Searching Jira ticket $TICKET_ID for a Figma link..."
ISSUE_URL="$JIRA_BASE_URL/rest/api/3/issue/$TICKET_ID?expand=renderedFields&fields=summary,description,comment"
curl -sS -u "$JIRA_EMAIL:$JIRA_API_TOKEN" -H "Accept: application/json" "$ISSUE_URL" -o /tmp/jira_issue.json
CANDIDATE=$(jq -r '.. | strings | select(test("https?://(www\\.)?figma\\.com/(file|design)/"))' /tmp/jira_issue.json | head -n 1 || true)
if [ -n "${CANDIDATE:-}" ]; then
echo "Found Figma URL in Jira: $CANDIDATE"
echo "FIGMA_URL=$CANDIDATE" >> "$GITHUB_ENV"
else
echo "No Figma URL found in Jira ticket $TICKET_ID."
fi
- name: 5. Parse Figma URL (auto-detect file key and node id)
if: env.FIGMA_URL != ''
shell: bash
run: |
set -euo pipefail
RAW_URL="$FIGMA_URL"
FILE_KEY=$(printf "%s" "$RAW_URL" | sed -nE 's#https?://www\\.figma\\.com/(file|design)/([^/]+)/.*#\2#p')
RAW_NODE=$(printf "%s" "$RAW_URL" | sed -nE 's/.*[?&]node-id=([^&]+).*/\1/p' | sed -e 's/%3A/:/gi' -e 's/-/:/g')
if [ -n "${FILE_KEY:-}" ] && [ -z "${FIGMA_FILE_KEY:-}" ]; then echo "FIGMA_FILE_KEY=$FILE_KEY" >> "$GITHUB_ENV"; fi
if [ -n "${RAW_NODE:-}" ] && [ -z "${FIGMA_NODE_IDS:-}" ]; then echo "FIGMA_NODE_IDS=$RAW_NODE" >> "$GITHUB_ENV"; fi
echo "Parsed FIGMA_FILE_KEY=${FILE_KEY:-$FIGMA_FILE_KEY} FIGMA_NODE_IDS=${RAW_NODE:-$FIGMA_NODE_IDS}"
- name: 6. Fetch Figma data (no MCP)
if: env.FIGMA_ACCESS_TOKEN != '' && env.FIGMA_FILE_KEY != ''
shell: bash
run: |
set -euo pipefail
mkdir -p figma-data
echo "Fetching Figma file: $FIGMA_FILE_KEY"
curl -sS -H "X-Figma-Token: $FIGMA_ACCESS_TOKEN" \
"https://api.figma.com/v1/files/$FIGMA_FILE_KEY" \
-o figma-data/file.json
if [ -n "${FIGMA_NODE_IDS:-}" ]; then
echo "Fetching Figma nodes: $FIGMA_NODE_IDS"
curl -sS -G -H "X-Figma-Token: $FIGMA_ACCESS_TOKEN" \
--data-urlencode "ids=$FIGMA_NODE_IDS" \
"https://api.figma.com/v1/files/$FIGMA_FILE_KEY/nodes" \
-o figma-data/nodes.json
echo "Exporting Figma images (SVG) for nodes: $FIGMA_NODE_IDS"
curl -sS -G -H "X-Figma-Token: $FIGMA_ACCESS_TOKEN" \
--data-urlencode "ids=$FIGMA_NODE_IDS" \
--data-urlencode "format=svg" \
--data-urlencode "svg_include_id=true" \
"https://api.figma.com/v1/images/$FIGMA_FILE_KEY" \
-o figma-data/images.json
mkdir -p figma-data/images
for id in $(echo "$FIGMA_NODE_IDS" | tr ',' ' '); do
url=$(jq -r --arg id "$id" '.images[$id]' figma-data/images.json)
if [ -n "$url" ] && [ "$url" != "null" ]; then
curl -sSL "$url" -o "figma-data/images/${id}.svg"
fi
done
else
echo "FIGMA_NODE_IDS not provided; skipping nodes fetch."
fi
echo "Figma data saved under figma-data/"
- name: 7. Install Project Dependencies
run: npm install
- name: 8. Set Workspace Permissions for Non-Root User
run: |
chown -R node:node "$GITHUB_WORKSPACE"
- name: 9. Execute Main AI, Build, and Git Logic
id: main_script
shell: bash
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
FEATURE_BRANCH_NAME="feature/$TICKET_ID"
git fetch origin
if git ls-remote --exit-code --heads origin "$FEATURE_BRANCH_NAME" >/dev/null 2>&1; then
echo "Remote branch $FEATURE_BRANCH_NAME exists. Checking out and rebasing..."
git checkout "$FEATURE_BRANCH_NAME" || git checkout -b "$FEATURE_BRANCH_NAME"
git pull --rebase origin "$FEATURE_BRANCH_NAME" || true
else
echo "Remote branch $FEATURE_BRANCH_NAME does not exist. Creating from origin/$DEFAULT_BRANCH..."
git checkout -b "$FEATURE_BRANCH_NAME" "origin/$DEFAULT_BRANCH"
fi
FIGMA_CONTEXT_PROMPT=""
if [ -n "${FIGMA_FILE_KEY:-}" ]; then
FIGMA_CONTEXT_PROMPT=$'\n\nFigma context:\n- URL: '"${FIGMA_URL:-}"$'\n- File JSON: figma-data/file.json\n- Nodes JSON: figma-data/nodes.json (ids: '"${FIGMA_NODE_IDS:-}"$')\n- Exported SVGs: figma-data/images/*.svg\nGenerate the HTML and CSS for the component(s) to implement as a Franklin block.'
fi
FINAL_PROMPT="${CODEX_PROMPT}${FIGMA_CONTEXT_PROMPT}${DEMO_DATA_PROMPT}"
CODEX_CMD_ARGS=("--full-auto" "-m" "$CODEX_MODEL")
# Running Codex without Figma MCP; any Figma data needed is available in figma-data/
codex exec "${CODEX_CMD_ARGS[@]}" "$FINAL_PROMPT"
rm -f jira_dl_image_*
echo "Compiling EDS Models..."
npm run build:json
echo "EDS Models build completed."
if [ -n "$(git status --porcelain)" ]; then
git add -A
git commit -m "feat($TICKET_ID): Apply AI-generated changes [skip ci]"
if ! git push -u origin "$FEATURE_BRANCH_NAME"; then
echo "Push rejected (likely non-fast-forward). Rebasing with remote and retrying..."
git pull --rebase origin "$FEATURE_BRANCH_NAME" || true
git push -u origin "$FEATURE_BRANCH_NAME"
fi
echo "changes_pushed=true" >> $GITHUB_OUTPUT
else
echo "No file changes detected."
echo "changes_pushed=false" >> $GITHUB_OUTPUT
fi
- name: 8. Wait for EDS Deployment
if: steps.main_script.outputs.changes_pushed == 'true'
run: "sleep 10"
- name: 9. Notify N8N to Create Pull Request
if: steps.main_script.outputs.changes_pushed == 'true'
shell: bash
run: |
set -euo pipefail
FEATURE_BRANCH_NAME="feature/$TICKET_ID"
LATEST_COMMIT_SHA=$(git rev-parse HEAD)
REPO_OWNER=$(echo "$GH_REPO" | cut -d'/' -f1)
REPO_NAME=$(echo "$GH_REPO" | cut -d'/' -f2)
SANITIZED_BRANCH_NAME=$(echo "$FEATURE_BRANCH_NAME" | sed 's/\//-/g')
REPO_OWNER_FORK="comwrap"
PREVIEW_URL="https://$SANITIZED_BRANCH_NAME--$REPO_NAME--$REPO_OWNER_FORK.hlx.page"
LIVE_BEFORE_URL="https://main--$REPO_NAME--$REPO_OWNER_FORK.aem.live/"
LIVE_AFTER_URL="https://$SANITIZED_BRANCH_NAME--$REPO_NAME--$REPO_OWNER_FORK.aem.live/"
PR_TITLE="$TICKET_ID: Implement feature $TICKET_ID (AI Assisted)"
# Build PR body from template if available
PR_TEMPLATE_PATH=".github/pull_request_template.md"
if [ -f "$PR_TEMPLATE_PATH" ]; then
RAW_TEMPLATE=$(cat "$PR_TEMPLATE_PATH")
FILLED_TEMPLATE=$(printf "%s" "$RAW_TEMPLATE" \
| sed -e "s/{repo}/$REPO_NAME/g" \
-e "s/{owner}/$REPO_OWNER_FORK/g" \
-e "s#<branch>#$SANITIZED_BRANCH_NAME#g")
if [ -n "${GITHUB_ISSUE_ID:-}" ]; then
FILLED_TEMPLATE=$(printf "%s" "$FILLED_TEMPLATE" | sed -E "s/Fix #<gh-issue-id>/Fix #${GITHUB_ISSUE_ID}/")
fi
PR_BODY="$FILLED_TEMPLATE"
else
PR_BODY=$(cat <<EOF
This Pull Request was automatically generated by the Codex AI Developer to implement ticket **$TICKET_ID**.
### URL for testing:
- $PREVIEW_URL
Commit SHA: \`$LATEST_COMMIT_SHA\`
EOF
)
fi
JSON_PAYLOAD=$(jq -n \
--arg fb "$FEATURE_BRANCH_NAME" \
--arg tb "$DEFAULT_BRANCH" \
--arg tid "$TICKET_ID" \
--arg commitSha "$LATEST_COMMIT_SHA" \
--arg repo "$GH_REPO" \
--arg prTitle "$PR_TITLE" \
--arg prBody "$PR_BODY" \
'{source_branch: $fb, target_branch: $tb, ticket_id: $tid, commit_sha: $commitSha, repo: $repo, pull_request_title: $prTitle, pull_request_body: $prBody}')
if [ -z "${N8N_MR_WEBHOOK_URL:-}" ]; then
echo "Warning: N8N_PR_WEBHOOK_URL secret is not set."
WEBHOOK_STATUS=""
else
WEBHOOK_STATUS=$(curl -s -w "%{http_code}" -o /tmp/pr_webhook_response.txt \
-X POST -H "Content-Type: application/json" \
-d "$JSON_PAYLOAD" "$N8N_MR_WEBHOOK_URL" || true)
echo "Webhook HTTP status: $WEBHOOK_STATUS"
if [[ "$WEBHOOK_STATUS" =~ ^2 ]]; then
echo "Webhook PR creation succeeded."
exit 0
else
echo "Webhook call failed. Response body:"
cat /tmp/pr_webhook_response.txt || true
fi
fi
echo "Falling back to creating PR directly on GitHub..."
GH_API_URL="https://api.github.com/repos/$GH_REPO/pulls"
GH_PAYLOAD=$(jq -n \
--arg title "$PR_TITLE" \
--arg head "$FEATURE_BRANCH_NAME" \
--arg base "$DEFAULT_BRANCH" \
--arg body "$PR_BODY" \
'{title: $title, head: $head, base: $base, body: $body}')
GH_STATUS=$(curl -s -w "%{http_code}" -o /tmp/gh_pr_response.json \
-X POST \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github+json" \
-d "$GH_PAYLOAD" "$GH_API_URL" || true)
echo "GitHub API HTTP status: $GH_STATUS"
echo "GitHub API response:"
cat /tmp/gh_pr_response.json || true
if [[ ! "$GH_STATUS" =~ ^2 ]]; then
echo "Error: Failed to create PR via GitHub API." >&2
exit 1
fi