Skip to content

Commit 991ae34

Browse files
Initial commit
0 parents  commit 991ae34

File tree

15 files changed

+880
-0
lines changed

15 files changed

+880
-0
lines changed

.github/dependabot.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
version: 2
2+
updates:
3+
# Maintain dependencies for GitHub Actions
4+
- package-ecosystem: "github-actions"
5+
directory: "/"
6+
schedule:
7+
interval: "weekly"
8+
groups:
9+
actions-deps:
10+
patterns:
11+
- "*"
12+
13+
# Maintain dependencies for Maven
14+
- package-ecosystem: "maven"
15+
directory: "/"
16+
schedule:
17+
interval: "weekly"
18+
groups:
19+
maven-deps:
20+
patterns:
21+
- "*"

.github/workflows/classroom.yml

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
name: Autograding Tests
2+
on:
3+
push:
4+
branches:
5+
- main
6+
pull_request:
7+
branches:
8+
- main
9+
repository_dispatch:
10+
11+
concurrency:
12+
group: autograding-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
permissions:
16+
checks: write
17+
actions: read
18+
contents: read
19+
pull-requests: write
20+
21+
jobs:
22+
run-autograding-tests:
23+
name: AI-Powered Feedback and Autograding
24+
runs-on: ubuntu-latest
25+
env:
26+
OPENROUTER_MODEL: ${{ vars.OPENROUTER_MODEL }}
27+
SYSTEM_PROMPT: ${{ vars.SYSTEM_PROMPT }}
28+
steps:
29+
- name: Checkout repository
30+
uses: actions/checkout@v5
31+
32+
- name: Read assignment instructions
33+
id: instructions
34+
if: ${{ vars.ENABLE_AI_FEEDBACK == 'true' }}
35+
run: |
36+
# Reads the content of the README.md file into an output variable.
37+
# The `EOF` marker is used to handle multi-line file content.
38+
echo "instructions=$(cat README.md | sed 's/\"/\\\"/g' | sed 's/$/\\n/' | tr -d '\n' | sed 's/\\n/\\\\n/g')" >> $GITHUB_OUTPUT
39+
40+
- name: Read source code
41+
id: source_code
42+
if: ${{ vars.ENABLE_AI_FEEDBACK == 'true' }}
43+
run: |
44+
{
45+
echo 'source_code<<EOF'
46+
find src/main/java -type f -name "*.java" | while read -r file; do
47+
echo "=== File: $file ==="
48+
cat "$file"
49+
echo
50+
done
51+
echo 'EOF'
52+
} >> "$GITHUB_OUTPUT"
53+
54+
- name: Read test code
55+
id: test_code
56+
if: ${{ vars.ENABLE_AI_FEEDBACK == 'true' }}
57+
run: |
58+
{
59+
echo 'test_code<<EOF'
60+
if [ -d "src/test/java" ]; then
61+
find src/test/java -type f -name "*.java" | while read -r file; do
62+
echo "=== File: $file ==="
63+
cat "$file"
64+
echo
65+
done
66+
else
67+
echo "No test code found."
68+
fi
69+
echo 'EOF'
70+
} >> "$GITHUB_OUTPUT"
71+
- name: Generate AI Feedback
72+
id: ai_feedback
73+
if: ${{ vars.ENABLE_AI_FEEDBACK == 'true' }}
74+
run: |
75+
# This step sends the collected data to the OpenRouter API.
76+
INSTRUCTIONS=$(jq -Rs . <<'EOF'
77+
${{ steps.instructions.outputs.instructions }}
78+
EOF
79+
)
80+
SOURCE_CODE=$(jq -Rs . <<'EOF'
81+
${{ steps.source_code.outputs.source_code }}
82+
EOF
83+
)
84+
TEST_CODE=$(jq -Rs . <<'EOF'
85+
${{ steps.test_code.outputs.test_code }}
86+
EOF
87+
)
88+
89+
if [ -z "$INSTRUCTIONS" ] || [ -z "$SOURCE_CODE" ] || [ -z "$TEST_CODE" ]; then
90+
echo "Error: One or more required variables are not set."
91+
exit 1
92+
fi
93+
94+
# Assigning to USER_CONTENT with variable expansion
95+
PAYLOAD="Please provide feedback on the following Java assignment.
96+
97+
--- Assignment Instructions ---
98+
${INSTRUCTIONS}
99+
100+
--- Source files ---
101+
${SOURCE_CODE}
102+
103+
--- Test files ---
104+
${TEST_CODE}"
105+
106+
JSON_CONTENT=$(jq -n \
107+
--argjson model "$OPENROUTER_MODEL" \
108+
--arg system_prompt "$SYSTEM_PROMPT" \
109+
--arg payload "$PAYLOAD" \
110+
'{
111+
models: $model,
112+
messages: [
113+
{role: "system", content: $system_prompt},
114+
{role: "user", content: $payload}
115+
]
116+
}')
117+
118+
echo "$JSON_CONTENT"
119+
120+
API_RESPONSE=$(echo "$JSON_CONTENT" | curl https://openrouter.ai/api/v1/chat/completions \
121+
-H "Authorization: Bearer ${{ secrets.OPENROUTER_API_KEY }}" \
122+
-H "Content-Type: application/json" \
123+
-d @-)
124+
125+
echo "$API_RESPONSE"
126+
127+
FEEDBACK_CONTENT=$(echo "$API_RESPONSE" | jq -r '.choices[0].message.content')
128+
echo "feedback<<EOF" >> $GITHUB_OUTPUT
129+
echo "$FEEDBACK_CONTENT" >> $GITHUB_OUTPUT
130+
echo "EOF" >> $GITHUB_OUTPUT
131+
- name: Post Feedback as PR Comment ✍️
132+
if: ${{ vars.ENABLE_AI_FEEDBACK == 'true' && github.event_name == 'pull_request' }}
133+
uses: actions/github-script@v8
134+
env:
135+
FEEDBACK_BODY: ${{ steps.ai_feedback.outputs.feedback }}
136+
with:
137+
github-token: ${{ secrets.GITHUB_TOKEN }}
138+
script: |
139+
const prNumber = context.payload.pull_request.number;
140+
const { owner, repo } = context.repo;
141+
const signature = "🤖 AI Feedback";
142+
const timestamp = new Date().toISOString();
143+
const newEntry = `🕒 _Posted on ${timestamp}_\n\n${process.env.FEEDBACK_BODY}\n\n---\n`;
144+
145+
const { data: comments } = await github.rest.issues.listComments({
146+
owner,
147+
repo,
148+
issue_number: prNumber,
149+
per_page: 100
150+
});
151+
152+
const existing = comments.find(c =>
153+
c.user?.login === "github-actions[bot]" &&
154+
c.body?.includes(signature)
155+
);
156+
157+
if (existing) {
158+
const previousContent = existing.body.replace(/^### 🤖 AI Feedback\s*/, '').trim();
159+
const collapsed = `<details><summary>Previous Feedback</summary>\n\n${previousContent}\n</details>`;
160+
const updatedBody = `### ${signature}\n\n${newEntry}${collapsed}`;
161+
await github.rest.issues.updateComment({
162+
owner,
163+
repo,
164+
comment_id: existing.id,
165+
body: updatedBody
166+
});
167+
} else {
168+
const body = `### ${signature}\n\n${newEntry}`;
169+
await github.rest.issues.createComment({
170+
owner,
171+
repo,
172+
issue_number: prNumber,
173+
body
174+
});
175+
}
176+
- name: Set up Java 25
177+
uses: actions/setup-java@v5
178+
with:
179+
distribution: 'temurin'
180+
java-version: '25'
181+
182+
- name: Compilation Check
183+
id: compilation-check
184+
uses: classroom-resources/autograding-command-grader@v1
185+
with:
186+
test-name: Compilation Check
187+
command: mvn -ntp compile
188+
timeout: 10
189+
max-score: 1
190+
191+
- name: Tests
192+
id: basic-tests
193+
uses: classroom-resources/autograding-command-grader@v1
194+
with:
195+
test-name: Basic Tests
196+
command: mvn -ntp test
197+
timeout: 10
198+
max-score: 1
199+
200+
- name: Autograding Reporter
201+
uses: classroom-resources/autograding-grading-reporter@v1
202+
env:
203+
COMPILATION-CHECK_RESULTS: "${{steps.compilation-check.outputs.result}}"
204+
BASIC-TESTS_RESULTS: "${{steps.basic-tests.outputs.result}}"
205+
with:
206+
runners: compilation-check,basic-tests

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target/
2+
/.idea/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
wrapperVersion=3.3.4
2+
distributionType=only-script
3+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# JavaFX Chat App 💬
2+
3+
A JavaFX-based chat client using [ntfy](https://docs.ntfy.sh/) for backend messaging.
4+
5+
## Features
6+
- MVC architecture
7+
- Send text messages to configurable topic via [JSON POST](https://docs.ntfy.sh/publish/#publish-as-json)
8+
- Receive messages via [JSON stream](https://docs.ntfy.sh/subscribe/api/)
9+
- Backend URL via env variable (not committed)
10+
- Branch + PR workflow (no direct commits to `main`)
11+
- Unit tests for `Model` class
12+
- (Advanced) Send files via "Attach local file" option
13+
14+
## 🚀 Run Instructions
15+
1. Set `JAVA_HOME` to JDK 25
16+
2. Start with:
17+
```bash
18+
./mvnw clean javafx:run

0 commit comments

Comments
 (0)