Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions learning-room/.github/workflows/autograder-capstone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: "Challenge 16: Capstone Agent File Validation"
# Validates that the student's agent file has valid YAML frontmatter,
# responsibilities, and guardrails sections
# NOTE: This workflow runs in the accessibility-agents repo, not learning-room

on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- "agents/**/*.md"
- "community-agents/**/*.md"

permissions:
contents: read
pull-requests: write

jobs:
validate-agent:
name: Verify Agent File
runs-on: ubuntu-latest

steps:
- name: Checkout PR branch
uses: actions/checkout@v4

- name: Find and validate agent files
id: check
run: |
# Find new/modified .md files in agents/ or community-agents/
AGENTS=$(find agents community-agents -name '*.md' 2>/dev/null || true)

if [ -z "$AGENTS" ]; then
echo "found=false" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "found=true" >> "$GITHUB_OUTPUT"
FIRST=$(echo "$AGENTS" | head -1)
echo "file=$FIRST" >> "$GITHUB_OUTPUT"
CHECK_FILE="/tmp/capstone-agent.md"
sed '1s/^\xEF\xBB\xBF//' "$FIRST" > "$CHECK_FILE"

ERRORS=""

# Check YAML frontmatter exists (starts with ---)
if head -1 "$CHECK_FILE" | grep -q '^---'; then
echo "has_frontmatter=true" >> "$GITHUB_OUTPUT"
else
echo "has_frontmatter=false" >> "$GITHUB_OUTPUT"
ERRORS="missing YAML frontmatter"
fi

# Check for responsibilities section
if grep -qi '## responsibilities\|## what this agent does' "$CHECK_FILE"; then
echo "has_responsibilities=true" >> "$GITHUB_OUTPUT"
else
echo "has_responsibilities=false" >> "$GITHUB_OUTPUT"
ERRORS="$ERRORS${ERRORS:+, }missing responsibilities section"
fi

# Check for guardrails section
if grep -qi '## guardrails\|## limitations\|## boundaries' "$CHECK_FILE"; then
echo "has_guardrails=true" >> "$GITHUB_OUTPUT"
else
echo "has_guardrails=false" >> "$GITHUB_OUTPUT"
ERRORS="$ERRORS${ERRORS:+, }missing guardrails section"
fi

echo "errors=$ERRORS" >> "$GITHUB_OUTPUT"

- name: Post result
if: always()
uses: actions/github-script@v7
with:
script: |
const found = '${{ steps.check.outputs.found }}' === 'true';
const file = '${{ steps.check.outputs.file }}';
const errors = '${{ steps.check.outputs.errors }}';
let body;
if (!found) {
body = [
'## Challenge 16: No agent file found',
'',
'Create an `.md` file in the `agents/` or `community-agents/` directory ',
'with YAML frontmatter, a responsibilities section, and a guardrails section.',
'',
'See [Chapter 20: Build Your Agent](https://github.com/Community-Access/git-going-with-github/blob/main/docs/20-build-your-agent.md) for the template.'
].join('\n');
} else if (errors) {
body = [
'## Challenge 16: Agent file needs work',
'',
'Found `' + file + '` but it has issues: ' + errors + '.',
'',
'Your agent file should have:',
'- YAML frontmatter (between `---` markers)',
'- A responsibilities/purpose section',
'- A guardrails/limitations section',
].join('\n');
} else {
body = [
'## Challenge 16: Agent file looks great!',
'',
'Found `' + file + '` with valid frontmatter, responsibilities, and guardrails. ',
'Excellent capstone work!'
].join('\n');
}
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body
});
} catch (error) {
console.error('Could not post Challenge 16 result:', error.message);
}
87 changes: 87 additions & 0 deletions learning-room/.github/workflows/autograder-conflicts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: "Challenge 7: Merge Conflict Resolution Check"
# Validates that the student resolved all merge conflict markers

on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- "docs/welcome.md"

permissions:
contents: read
pull-requests: write

jobs:
check-conflict-markers:
name: Verify Conflict Resolution
runs-on: ubuntu-latest

steps:
- name: Checkout PR branch
uses: actions/checkout@v4

- name: Check for conflict markers
id: check
run: |
MARKERS=$(grep -rn '<<<<<<< \|======= \|>>>>>>> ' docs/ || true)
if [ -n "$MARKERS" ]; then
echo "found=true" >> "$GITHUB_OUTPUT"
echo "$MARKERS" > /tmp/markers.txt
else
echo "found=false" >> "$GITHUB_OUTPUT"
fi

- name: Check for substantive content
id: content
run: |
LINES=$(wc -l < docs/welcome.md)
if [ "$LINES" -lt 5 ]; then
echo "empty=true" >> "$GITHUB_OUTPUT"
else
echo "empty=false" >> "$GITHUB_OUTPUT"
fi

- name: Post result
if: always()
uses: actions/github-script@v7
with:
script: |
const hasMarkers = '${{ steps.check.outputs.found }}' === 'true';
const isEmpty = '${{ steps.content.outputs.empty }}' === 'true';
let body;
if (hasMarkers) {
body = [
'## Challenge 7: Conflict markers still present',
'',
'Your PR still contains Git conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`). ',
'These need to be removed as part of resolving the merge conflict.',
'',
'**What to do:** Open the file, find the conflict markers, decide which lines to keep, ',
'and delete the marker lines. Then commit and push again.',
'',
'See [Chapter 7: Merge Conflicts](https://github.com/Community-Access/git-going-with-github/blob/main/docs/07-merge-conflicts.md) for help.'
].join('\n');
} else if (isEmpty) {
body = [
'## Challenge 7: File looks empty',
'',
'The conflict was resolved but the file has very little content. ',
'Make sure you kept the lines you intended to keep.',
].join('\n');
} else {
body = [
'## Challenge 7: Conflict resolution looks good!',
'',
'No conflict markers found and the file has substantive content. Well done!'
].join('\n');
}
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body
});
} catch (error) {
console.error('Could not post Challenge 7 result:', error.message);
}
78 changes: 78 additions & 0 deletions learning-room/.github/workflows/autograder-local-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: "Challenge 10: Local Commit Check"
# Validates that the student made at least one commit on a non-default branch

on:
pull_request:
types: [opened, synchronize, reopened]
branches:
- main

permissions:
contents: read
pull-requests: write

jobs:
check-local-commit:
name: Verify Local Commit Exists
runs-on: ubuntu-latest

steps:
- name: Checkout full history
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check branch and commits
id: check
run: |
BRANCH="${{ github.head_ref }}"
if [ "$BRANCH" = "main" ]; then
echo "on_main=true" >> "$GITHUB_OUTPUT"
else
echo "on_main=false" >> "$GITHUB_OUTPUT"
fi
COMMITS=$(git log --oneline origin/main..HEAD | wc -l)
echo "count=$COMMITS" >> "$GITHUB_OUTPUT"

- name: Post result
if: always()
uses: actions/github-script@v7
with:
script: |
const onMain = '${{ steps.check.outputs.on_main }}' === 'true';
const count = parseInt('${{ steps.check.outputs.count }}', 10);
let body;
if (onMain) {
body = [
'## Challenge 10: PR is from the main branch',
'',
'This challenge asks you to create a **feature branch**, make a commit locally, ',
'and push it. Your PR appears to come from main itself.',
'',
'See [Chapter 14: Git in Practice](https://github.com/Community-Access/git-going-with-github/blob/main/docs/14-git-in-practice.md) for branching instructions.'
].join('\n');
} else if (count === 0) {
body = [
'## Challenge 10: No new commits found',
'',
'The branch exists but has no commits ahead of main. ',
'Make sure you committed your changes before pushing.',
].join('\n');
} else {
body = [
'## Challenge 10: Local commit verified!',
'',
'Found ' + count + ' commit(s) on branch `' + '${{ github.head_ref }}' + '`. ',
'Your local Git workflow is working. Well done!'
].join('\n');
}
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body
});
} catch (error) {
console.error('Could not post Challenge 10 result:', error.message);
}
104 changes: 104 additions & 0 deletions learning-room/.github/workflows/autograder-template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: "Challenge 14: Issue Template Validation"
# Validates that the student created a custom YAML issue template

on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- ".github/ISSUE_TEMPLATE/**"

permissions:
contents: read
pull-requests: write

jobs:
check-template:
name: Verify Custom Issue Template
runs-on: ubuntu-latest

steps:
- name: Checkout PR branch
uses: actions/checkout@v4

- name: Find and validate template
id: check
run: |
# Look for student-created templates (not our pre-existing ones)
TEMPLATES=$(find .github/ISSUE_TEMPLATE -name '*.yml' \
! -name 'challenge-*.yml' \
! -name 'bonus-*.yml' \
! -name 'config.yml' 2>/dev/null || true)

if [ -z "$TEMPLATES" ]; then
echo "found=false" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "found=true" >> "$GITHUB_OUTPUT"

# Check the first custom template for a name field.
# Normalize a UTF-8 BOM because Windows tooling may add one.
FIRST=$(echo "$TEMPLATES" | head -1)
echo "file=$FIRST" >> "$GITHUB_OUTPUT"
CHECK_FILE="/tmp/custom-issue-template.yml"
sed '1s/^\xEF\xBB\xBF//' "$FIRST" > "$CHECK_FILE"

if grep -q '^name:' "$CHECK_FILE"; then
echo "has_name=true" >> "$GITHUB_OUTPUT"
else
echo "has_name=false" >> "$GITHUB_OUTPUT"
fi

if grep -q '^description:' "$CHECK_FILE"; then
echo "has_desc=true" >> "$GITHUB_OUTPUT"
else
echo "has_desc=false" >> "$GITHUB_OUTPUT"
fi

- name: Post result
if: always()
uses: actions/github-script@v7
with:
script: |
const found = '${{ steps.check.outputs.found }}' === 'true';
const hasName = '${{ steps.check.outputs.has_name }}' === 'true';
const hasDesc = '${{ steps.check.outputs.has_desc }}' === 'true';
const file = '${{ steps.check.outputs.file }}';
let body;
if (!found) {
body = [
'## Challenge 14: No custom template found',
'',
'Create a new `.yml` file in `.github/ISSUE_TEMPLATE/` with at least ',
'a `name:` and `description:` field.',
'',
'See [Chapter 17: Issue Templates](https://github.com/Community-Access/git-going-with-github/blob/main/docs/17-issue-templates.md) for the YAML format.'
].join('\n');
} else if (!hasName || !hasDesc) {
const missing = [];
if (!hasName) missing.push('`name:`');
if (!hasDesc) missing.push('`description:`');
body = [
'## Challenge 14: Template found but missing required fields',
'',
'Found `' + file + '` but it is missing: ' + missing.join(', ') + '.',
'',
'Add the missing fields and push again.'
].join('\n');
} else {
body = [
'## Challenge 14: Custom issue template looks great!',
'',
'Found `' + file + '` with valid `name` and `description` fields. Well done!'
].join('\n');
}
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body
});
} catch (error) {
console.error('Could not post Challenge 14 result:', error.message);
}
Empty file.
Loading