@@ -10,181 +10,12 @@ permissions:
1010 pull-requests : write
1111
1212jobs :
13- ai_feedback :
14- name : AI-Powered Feedback
15- runs-on : ubuntu-latest
16- env :
17- OPENROUTER_MODEL : ${{ vars.OPENROUTER_MODEL }}
18- SYSTEM_PROMPT : ${{ vars.SYSTEM_PROMPT }}
19- steps :
20- - name : Checkout repository
21- uses : actions/checkout@v5
22-
23- - name : Read assignment instructions
24- id : instructions
25- run : |
26- # Reads the content of the README.md file into an output variable.
27- # The `EOF` marker is used to handle multi-line file content.
28- echo "instructions=$(cat README.md | sed 's/\"/\\\"/g' | sed 's/$/\\n/' | tr -d '\n' | sed 's/\\n/\\\\n/g')" >> $GITHUB_OUTPUT
29-
30- - name : Read source code
31- id : source_code
32- run : |
33- {
34- echo 'source_code<<EOF'
35- find src/main/java -type f -name "*.java" | while read -r file; do
36- echo "=== File: $file ==="
37- cat "$file"
38- echo
39- done
40- echo 'EOF'
41- } >> "$GITHUB_OUTPUT"
42-
43- - name : Read test code
44- id : test_code
45- run : |
46- {
47- echo 'test_code<<EOF'
48- if [ -d "src/test/java" ]; then
49- find src/test/java -type f -name "*.java" | while read -r file; do
50- echo "=== File: $file ==="
51- cat "$file"
52- echo
53- done
54- else
55- echo "No test code found."
56- fi
57- echo 'EOF'
58- } >> "$GITHUB_OUTPUT"
59- - name : Generate AI Feedback
60- id : ai_feedback
61- run : |
62- # This step sends the collected data to the OpenRouter API.
63- INSTRUCTIONS=$(jq -Rs . <<'EOF'
64- ${{ steps.instructions.outputs.instructions }}
65- EOF
66- )
67- SOURCE_CODE=$(jq -Rs . <<'EOF'
68- ${{ steps.source_code.outputs.source_code }}
69- EOF
70- )
71- TEST_CODE=$(jq -Rs . <<'EOF'
72- ${{ steps.test_code.outputs.test_code }}
73- EOF
74- )
75-
76- if [ -z "$INSTRUCTIONS" ] || [ -z "$SOURCE_CODE" ] || [ -z "$TEST_CODE" ]; then
77- echo "Error: One or more required variables are not set."
78- exit 1
79- fi
80-
81- # Assigning to USER_CONTENT with variable expansion
82- PAYLOAD="Please provide feedback on the following Java assignment.
83-
84- --- Assignment Instructions ---
85- ${INSTRUCTIONS}
86-
87- --- Source files ---
88- ${SOURCE_CODE}
89-
90- --- Test files ---
91- ${TEST_CODE}"
92-
93- JSON_CONTENT=$(jq -n \
94- --argjson model "$OPENROUTER_MODEL" \
95- --arg system_prompt "$SYSTEM_PROMPT" \
96- --arg payload "$PAYLOAD" \
97- '{
98- models: $model,
99- messages: [
100- {role: "system", content: $system_prompt},
101- {role: "user", content: $payload}
102- ]
103- }')
104-
105- echo "$JSON_CONTENT"
106-
107- API_RESPONSE=$(echo "$JSON_CONTENT" | curl https://openrouter.ai/api/v1/chat/completions \
108- -H "Authorization: Bearer ${{ secrets.OPENROUTER_API_KEY }}" \
109- -H "Content-Type: application/json" \
110- -d @-)
111-
112- echo "$API_RESPONSE"
113-
114- FEEDBACK_CONTENT=$(echo "$API_RESPONSE" | jq -r '.choices[0].message.content')
115- echo "feedback<<EOF" >> $GITHUB_OUTPUT
116- echo "$FEEDBACK_CONTENT" >> $GITHUB_OUTPUT
117- echo "EOF" >> $GITHUB_OUTPUT
118- - name : Post Feedback as PR Comment ✍️
119- uses : actions/github-script@v8
120- env :
121- FEEDBACK_BODY : ${{ steps.ai_feedback.outputs.feedback }}
122- with :
123- github-token : ${{ secrets.GITHUB_TOKEN }}
124- script : |
125- const { owner, repo } = context.repo;
126- const targetTitle = "Feedback";
127- const signature = "🤖 AI Feedback";
128-
129- const { data: pullRequests } = await github.rest.pulls.list({
130- owner,
131- repo,
132- state: "open",
133- per_page: 100
134- });
135-
136- const matchingPR = pullRequests.find(pr => pr.title.trim().toLowerCase() === targetTitle.toLowerCase());
137- if (!matchingPR) {
138- throw new Error(`No open pull request found with title '${targetTitle}'`);
139- }
140-
141- const prNumber = matchingPR.number;
142-
143- const { data: comments } = await github.rest.issues.listComments({
144- owner,
145- repo,
146- issue_number: prNumber,
147- per_page: 100
148- });
149-
150- const existing = comments.find(c =>
151- c.user?.login === "github-actions[bot]" &&
152- c.body?.includes(signature)
153- );
154-
155- const timestamp = new Date().toISOString();
156- const newEntry = `🕒 _Posted on ${timestamp}_\n\n${process.env.FEEDBACK_BODY}\n\n---\n`;
157-
158- if (existing) {
159- // Extract previous entries and wrap them in a collapsible block
160- const previousContent = existing.body.replace(/^### 🤖 AI Feedback\s*/, '').trim();
161- const collapsed = `<details><summary>Previous Feedback</summary>\n\n${previousContent}\n</details>`;
162-
163- const updatedBody = `### ${signature}\n\n${newEntry}${collapsed}`;
164- await github.rest.issues.updateComment({
165- owner,
166- repo,
167- comment_id: existing.id,
168- body: updatedBody
169- });
170- console.log(`🔄 Updated existing comment on PR #${prNumber}`);
171- } else {
172- const body = `### ${signature}\n\n${newEntry}`;
173- await github.rest.issues.createComment({
174- owner,
175- repo,
176- issue_number: prNumber,
177- body
178- });
179- console.log(`🆕 Posted new comment on PR #${prNumber}`);
180- }
18113 run-autograding-tests :
18214 name : AI-Powered Feedback and Autograding
18315 runs-on : ubuntu-latest
18416 env :
18517 OPENROUTER_MODEL : ${{ vars.OPENROUTER_MODEL }}
18618 SYSTEM_PROMPT : ${{ vars.SYSTEM_PROMPT }}
187- if : github.actor != 'github-classroom[bot]'
18819 steps :
18920 - name : Checkout repository
19021 uses : actions/checkout@v5
@@ -285,7 +116,7 @@ jobs:
285116 echo "$FEEDBACK_CONTENT" >> $GITHUB_OUTPUT
286117 echo "EOF" >> $GITHUB_OUTPUT
287118 - name : Post Feedback as PR Comment ✍️
288- uses : actions/github-script@v8
119+ uses : actions/github-script@v7
289120 env :
290121 FEEDBACK_BODY : ${{ steps.ai_feedback.outputs.feedback }}
291122 with :
0 commit comments