howto:git:classroom50:cli

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
howto:git:classroom50:cli [2026/08/17 08:54] – Sync aus BZZ-Commons/pygrader50 adminhowto:git:classroom50:cli [2026/08/25 10:07] (aktuell) – Veraltet - Inhalt jetzt unter github.com/BZZ-Commons/pygrader50/docs admin
Zeile 1: Zeile 1:
-====== Classroom 50: CLI-Referenz ====== 
- 
-Zwei Kommandos aus [[https://github.com/BZZ-Commons/pygrader50|pygrader50]]: 
-eines bewertet, eines überträgt. Dazu ein Migrationsskript. 
- 
-===== python -m pygrader50 — bewerten ===== 
- 
-Wird vom Classroom-50-Runner im Studi-Checkout aufgerufen. Keine Argumente — 
-alles kommt aus der Umgebung. 
- 
-==== Umgebung ==== 
- 
-^ Variable ^ Bedeutung ^ Pflicht ^ 
-| ''CLASSROOM'' | Kurzname des Klassenzimmers | ja | 
-| ''ASSIGNMENT'' | Slug der Aufgabe | ja | 
-| ''SUBMISSION_TAG'' | ''submit/<Zeitstempel>-<Kurz-SHA>'' | ja | 
-| ''OWNER'' / ''USERNAME'' | GitHub-Login der besitzenden Person | ersatzweise ''GITHUB_ACTOR'' | 
-| ''ASSIGNMENT_TYPE'' | ''individual'' oder ''group'' | Vorgabe ''individual'' | 
-| ''COMMIT_URL'', ''RELEASE_URL'', ''REVIEW_URL'' | Links fürs Payload | ersatzweise aus ''GITHUB_SERVER_URL'' / ''GITHUB_REPOSITORY'' / ''GITHUB_SHA'' | 
-| ''RUNNER_TEMP'' | Wurzel für das entpackte Bundle | ohne die Variable entfällt die Bundle-Suche | 
-| ''PYGRADER50_CONFIG_DIR'' | zusätzlicher Config-Ort, nur lokal | nein | 
- 
-==== Ausgabe ==== 
- 
-^ Datei ^ Inhalt ^ 
-| ''./result.json'' | ''classroom50/result/v1'', vom Runner ans Release gehängt | 
-| ''./release-body.md'' | Feedback-Tabellen, Release-Text und Job-Summary | 
- 
-==== Exit-Codes ==== 
- 
-^ Code ^ Bedeutung ^ 
-| ''0'' | Bewertung abgeschlossen — **auch** wenn alle Tests scheitern | 
-| ''1'' | Infrastrukturfehler: Umgebung fehlt, Konfiguration kaputt, Absturz. Der Runner zeichnet die Abgabe als ''error'' auf | 
- 
-Eine fehlende Bewertungs-Konfiguration ist **kein** Fehler: 0/0 mit Warnung im 
-Log, Exit 0. 
- 
-==== Lokal ausprobieren ==== 
- 
-<code bash> 
-cd /pfad/zum/studi-repo 
-CLASSROOM=m320-ix25 \ 
-ASSIGNMENT=m320-lu04-a4-objektkommunikation \ 
-SUBMISSION_TAG=submit/2026-08-13T12-00-00Z-abc1234 \ 
-OWNER=anna \ 
-python -m pygrader50 
-cat release-body.md 
-</code> 
- 
-===== python -m pygrader50.moodle — übertragen ===== 
- 
-Liest ''scores.json'' aus dem Config-Repo und schickt die Punkte an Moodle. Je 
-Kombination aus Aufgabe und Person geht die **neueste** Abgabe raus. 
- 
-<code> 
-python -m pygrader50.moodle SCORES [Optionen] 
-</code> 
- 
-==== Argumente und Optionen ==== 
- 
-^ Option ^ Wirkung ^ 
-| ''SCORES'' | Pfad zu ''<CLASSROOM>/scores.json'' (Pflicht) | 
-| ''--assignment SLUG'' | nur diese Aufgabe | 
-| ''--user LOGIN'' | nur diesen GitHub-Login | 
-| ''--state PFAD'' | Zustandsfile; ohne Angabe wird jedes Mal alles übertragen | 
-| ''--force'' | auch Unverändertes erneut senden | 
-| ''--dry-run'' | nur anzeigen, nichts senden; funktioniert ohne Zugangsdaten | 
-| ''--no-feedback'' | ohne Feedback-Text (spart einen API-Aufruf pro Abgabe) | 
- 
-Der bei ''--user'' angegebene Login muss im Moodle-Kurs eingeschrieben sein. Der 
-eigene Lehrer-Account ist es meist nicht — Moodle antwortet dann 
-''No matching assignment found'', obwohl die Aktivität existiert. 
- 
-==== Umgebung ==== 
- 
-^ Variable ^ Bedeutung ^ 
-| ''MOODLE_URL'' | Basis-URL der Moodle-Instanz, z.B. ''https://moodle.bzz.ch'' | 
-| ''MOODLE_TOKEN'' | Webservice-Token | 
-| ''MOODLE_FUNCTION'' | Vorgabe ''mod_externalassignment_update_grade'' | 
-| ''GH_TOKEN'' / ''GITHUB_TOKEN'' | optional, liest die Release-Bodies für den Feedback-Text | 
- 
-Ohne ''--dry-run'' sind ''MOODLE_URL'' und ''MOODLE_TOKEN'' Pflicht. 
- 
-==== Zustandsfile ==== 
- 
-<code javascript> 
-{ 
-  "schema": "pygrader50/moodle-state/v1", 
-  "entries": { 
-    "m323-lu01-a02-imperativer-ggt/graphics80": { 
-      "submission": "submit/2026-08-13T08-41-09Z-35bdcb2", 
-      "score": 5, 
-      "max-score": 7 
-    } 
-  } 
-} 
-</code> 
- 
-Übersprungen wird nur, wenn Abgabe **und** Punktzahl identisch sind — eine 
-Nachbewertung derselben Abgabe geht also erneut raus. Nur erfolgreiche 
-Übertragungen werden vermerkt; gescheiterte versucht der nächste Lauf wieder. 
- 
-==== Exit-Codes ==== 
- 
-^ Code ^ Bedeutung ^ 
-| ''0'' | alles übertragen oder übersprungen | 
-| ''1'' | mindestens eine Übertragung scheiterte, oder Zugangsdaten/Datei fehlen | 
- 
-Ein Fehler bricht den Lauf **nicht** ab: die übrigen Abgaben gehen trotzdem raus. 
- 
-==== Beispiele ==== 
- 
-<code bash> 
-# Trockenlauf über alles, ohne Zugangsdaten 
-python -m pygrader50.moodle <CLASSROOM>/scores.json --dry-run --no-feedback 
- 
-# Eine einzelne Person nachtragen 
-python -m pygrader50.moodle <CLASSROOM>/scores.json --user anna 
- 
-# Eine Aufgabe nach einer Nachbewertung komplett neu schicken 
-python -m pygrader50.moodle <CLASSROOM>/scores.json --assignment <SLUG> --force 
- 
-# Wie der Nachtlauf 
-python -m pygrader50.moodle <CLASSROOM>/scores.json \ 
-  --state <CLASSROOM>/moodle-state.json 
-</code> 
- 
-Ohne lokalen Klon des Config-Repos reicht die Datei allein: 
- 
-<code bash> 
-gh api repos/<ORG>/classroom50/contents/<CLASSROOM>/scores.json \ 
-   -H 'Accept: application/vnd.github.raw' > scores.json 
-GH_TOKEN=$(gh auth token) python -m pygrader50.moodle scores.json --dry-run 
-</code> 
- 
-==== Von Hand auslösen ==== 
- 
-<code bash> 
-gh workflow run moodle-sync.yaml --repo <ORG>/classroom50 \ 
-  -f classroom=<CLASSROOM> -f dry_run=true 
-</code> 
- 
-Oder im Config-Repo unter **Actions → Moodle Sync → Run workflow**. Bleibt das 
-Klassenzimmer leer, laufen alle Ordner mit einer ''scores.json''. 
- 
-===== scripts/remove-legacy-classroom-yml.sh — migrieren ===== 
- 
-Entfernt den alten GitHub-Classroom-Workflow aus den Template-Repos einer 
-migrierten Klasse und aus den bereits angenommenen Studi-Repos. 
- 
-<code> 
-scripts/remove-legacy-classroom-yml.sh <ORG> <CLASSROOM> [--apply] 
-</code> 
- 
-^ Aufruf ^ Wirkung ^ 
-| ohne ''--apply'' | Trockenlauf, listet jedes Ziel als ''would rm'' oder ''absent'' | 
-| mit ''--apply'' | löscht ''.github/workflows/classroom.yml'', ein Commit pro Repo | 
- 
-Die Zielliste kommt aus dem ''template''-Block von 
-''<CLASSROOM>/assignments.json'', **nicht** aus dem Repo-Listing der 
-Template-Organisation. Wiederholbar; fehlende Dateien sind ''absent'', kein 
-Fehler. Exit 1, sobald ein Repo scheitert. 
- 
-Hintergrund und die nötige Token-Rotation: [[.:migration|Migration]]. 
- 
-===== scripts/sync-template-pins.py — Pins aktualisieren ===== 
- 
-Hebt die Werkzeug-Versionen in den Template-Repos einer Klasse und legt 
-''.python-version'' an. 
- 
-<code> 
-scripts/sync-template-pins.py <ORG> <CLASSROOM> [--apply] 
-</code> 
- 
-^ Was ^ Verhalten ^ 
-| ''pylint'', ''pytest'' | werden überall gesetzt, fehlende Zeilen angehängt | 
-| ''httpx'', ''pytest-asyncio'' | nur dort gehoben, wo sie schon stehen | 
-| alles andere | bleibt Zeile für Zeile erhalten, inkl. Kommentaren | 
-| ''.python-version'' | wird auf die konfigurierte Version gesetzt | 
- 
-Die Versionen stehen als Block am Kopf des Skripts und werden einmal pro 
-Semester angefasst. Wiederholbar: ein aktuelles Template meldet ''ok''. 
- 
-<WRAP center round important 90%> 
-''pytest-asyncio'' muss mit ''pytest'' mitziehen — 0.23.8 und pytest 9 lassen 
-sich nicht gemeinsam auflösen. Pakete, welche die Lernenden im Rahmen der 
-Aufgabe selbst eintragen sollen (Flask in den lu06-Aufgaben), gehören **nicht** 
-in die Pin-Liste. 
-</WRAP> 
- 
-===== scripts/publish-wiki.py — diese Seiten aktualisieren ===== 
- 
-Spiegelt den Ordner ''wiki/'' aus dem Repo hierher. Pfad = Seiten-ID: 
-''wiki/howto/git/classroom50/start.txt'' wird zu 
-''howto:git:classroom50:start''. 
- 
-<code> 
-scripts/publish-wiki.py [--apply] [--summary "Text"] 
-</code> 
- 
-Geschrieben wird nur, was abweicht — ein erneuter Lauf meldet alles als 
-''gleich'' und hinterlässt keine leeren Versionen. Zugangsdaten kommen aus der 
-Umgebung: ''DOKUWIKI_TOKEN'', sonst ''DOKUWIKI_USER'' und 
-''DOKUWIKI_PASSWORD''. 
- 
-<WRAP center round important 90%> 
-Ein untauglicher API-Token wird **nicht abgelehnt, sondern ignoriert** — die 
-Aufrufe laufen dann als Gast weiter und scheitern erst beim Schreiben mit einer 
-401, die wie ein falsches Passwort aussieht. Das Skript prüft deshalb vor dem 
-Schreiben per ''core.whoAmI'', als wer es angemeldet ist, gibt das aus und 
-fällt bei totem Token auf die Anmeldung per ''core.login'' zurück. 
-</WRAP> 
- 
-===== gh teacher — Klassenzimmer verwalten ===== 
- 
-<code bash> 
-gh extension install foundation50/gh-teacher 
-gh auth refresh -h github.com -s admin:org,read:org,repo,workflow 
- 
-gh teacher classroom list <ORG> 
-gh teacher autograder show <ORG> <CLASSROOM> 
-gh teacher autograder list <ORG> <CLASSROOM> 
-gh teacher autograder set-default <ORG> <CLASSROOM> --from bootstrap/autograder.py 
-gh teacher rotate-service-token <ORG> 
-</code> 
- 
-Vollständige Referenz: [[https://github.com/foundation50/classroom50/wiki|Wiki von foundation50/classroom50]]. 
  
  • howto/git/classroom50/cli.1786949652.txt.gz
  • Zuletzt geändert: 2026/08/17 08:54
  • von admin