From 66ad93a9fe46a8b8b33b81d68ed8054f2dbd7842 Mon Sep 17 00:00:00 2001 From: "Jiahao, Woo" Date: Fri, 2 Jan 2026 11:22:18 +0800 Subject: [PATCH 1/6] [tooling] Move scripts into dedicated folder to avoid clutter --- .github/workflows/ci.yml | 4 +- .github/workflows/publish.yml | 2 +- new.sh | 4 +- .../create-exercise-directory.py | 0 new-exercise.py => scripts/new-exercise.py | 0 new-hands-on.py => scripts/new-hands-on.py | 0 scripts/post-contribution-message.py | 82 +++++++++++++++++++ test-download.py => scripts/test-download.py | 0 .../validate-exercise-config.py | 0 test-download.sh | 2 +- 10 files changed, 89 insertions(+), 5 deletions(-) rename create-exercise-directory.py => scripts/create-exercise-directory.py (100%) rename new-exercise.py => scripts/new-exercise.py (100%) rename new-hands-on.py => scripts/new-hands-on.py (100%) create mode 100644 scripts/post-contribution-message.py rename test-download.py => scripts/test-download.py (100%) rename validate-exercise-config.py => scripts/validate-exercise-config.py (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71ae3649..29ad3556 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,13 +14,15 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + - name: Setup Python uses: actions/setup-python@v5 with: python-version: "3.13" + - name: Run validation script run: | - python validate-exercise-config.py + python scripts/validate-exercise-config.py unit_tests: runs-on: ubuntu-latest diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 16194b37..1fb1b2e3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,7 +19,7 @@ jobs: - name: Generate exercise-directory.md run: | - python create-exercise-directory.py + python scripts/create-exercise-directory.py mv exercise-directory.md index.md - name: Deploy to gh-pages diff --git a/new.sh b/new.sh index 81d4fc71..fdd82a55 100755 --- a/new.sh +++ b/new.sh @@ -5,10 +5,10 @@ read choice case "$choice" in "hands-on" | "h" | "H") - python new-hands-on.py + python scripts/new-hands-on.py ;; "exercise" | "e" | "E") - python new-exercise.py + python scripts/new-exercise.py ;; *) echo "Invalid choice. Please enter 'hands-on' (h) or 'exercise' (e)." diff --git a/create-exercise-directory.py b/scripts/create-exercise-directory.py similarity index 100% rename from create-exercise-directory.py rename to scripts/create-exercise-directory.py diff --git a/new-exercise.py b/scripts/new-exercise.py similarity index 100% rename from new-exercise.py rename to scripts/new-exercise.py diff --git a/new-hands-on.py b/scripts/new-hands-on.py similarity index 100% rename from new-hands-on.py rename to scripts/new-hands-on.py diff --git a/scripts/post-contribution-message.py b/scripts/post-contribution-message.py new file mode 100644 index 00000000..c129dae2 --- /dev/null +++ b/scripts/post-contribution-message.py @@ -0,0 +1,82 @@ +import os + +from github import Github + +GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN") +PR_NUMBER = os.environ.get("PR_NUMBER") +COMMIT_AUTHOR = os.environ.get("COMMIT_AUTHOR") +FORK_OWNER = os.environ.get("FORK_OWNER") +FORK_REPO = os.environ.get("FORK_REPO") +FORK_BRANCH = os.environ.get("FORK_BRANCH") + +if not all( + [GITHUB_TOKEN, PR_NUMBER, COMMIT_AUTHOR, FORK_OWNER, FORK_REPO, FORK_BRANCH] +): + raise ValueError("Missing required environment variables") + +assert PR_NUMBER is not None +PR_NUMBER_INT = int(PR_NUMBER) + +gh = Github(GITHUB_TOKEN) +repo = gh.get_repo("git-mastery/exercises") +pr = repo.get_pull(PR_NUMBER_INT) + +comment = f""" +Hi @{COMMIT_AUTHOR}, thank you for your contribution! 🎉 + +This PR comes from your fork `{FORK_OWNER}/{FORK_REPO}` on branch `{FORK_BRANCH}`. + +Before you request for a review, please ensure that you have tested your changes locally! + +> [!IMPORTANT] +> The previously recommended way of using `./test-download.py` is no longer the best way to test your changes locally. +> +> Please read the following instructions for the latest instructions. + +### Prerequisites + +Ensure that you have the `gitmastery` app installed locally ([instructions](https://git-mastery.github.io/companion-app/index.html)) + +### Testing steps + +If you already have a local Git-Mastery root to test, you can skip the following step. + +Create a Git-Mastery root locally: + +```bash +gitmastery setup +``` + +Navigate into the Git-Mastery root (defaults to `gitmastery-exercises/`): + +```bash +cd gitmastery-exercises/ +``` + +Edit the `.gitmastery.json` configuration file. You need to set the following values under the `exercises_source` key. + +```json +{ + # other fields... + "exercises_source": { + "username": "{FORK_OWNER}", + "repository": "{FORK_REPO}", + "branch": "{FORK_BRANCH}", + } +} +``` + +Then, you can use the `gitmastery` app to download and verify your changes locally. + +```bash +gitmastery download +gitmastery verify +``` + +### Checklist + +- [ ] (For exercises and hands-ons) I have verified that the downloading behavior works +- [ ] (For exercises only) I have verified that the verification behavior is accurate +""".lstrip() + +pr.create_issue_comment(comment) diff --git a/test-download.py b/scripts/test-download.py similarity index 100% rename from test-download.py rename to scripts/test-download.py diff --git a/validate-exercise-config.py b/scripts/validate-exercise-config.py similarity index 100% rename from validate-exercise-config.py rename to scripts/validate-exercise-config.py diff --git a/test-download.sh b/test-download.sh index 45d81469..41e63c31 100755 --- a/test-download.sh +++ b/test-download.sh @@ -1,3 +1,3 @@ #!/bin/bash -python test-download.py $1 +python scripts/test-download.py $1 From 2b26ad1d31630ccd753e0e7792b8c9da1f5056c3 Mon Sep 17 00:00:00 2001 From: "Jiahao, Woo" Date: Fri, 2 Jan 2026 11:22:31 +0800 Subject: [PATCH 2/6] [tooling] Add workflow to publish contribution message --- .github/pull_request_template.md | 2 +- .github/workflows/contribution-message.yml | 31 ++++++++++++++++++++++ requirements.txt | 3 +++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/contribution-message.yml diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 6e201a5d..20004184 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -8,7 +8,7 @@ Link the exercise discussion issue - [ ] If you require a new remote repository on the `Git-Mastery` organization, have you [created a request](https://github.com/git-mastery/exercises/issues/new?template=request_exercise_repository.md) for it? - [ ] Have you written unit tests using [`repo-smith`](https://github.com/git-mastery/repo-smith) to validate the exercise grading scheme? -- [ ] Have you tested the download script using `test-download.sh`? +- [ ] Have you tested your changes using the instructions posted? - [ ] Have you verified that this exercise does not already exist or is not currently in review? - [ ] Did you introduce a new grading mechanism that should belong to [`git-autograder`](https://github.com/git-mastery/git-autograder)? - [ ] Did you introduce a new dependency that should belong to [`app`](https://github.com/git-mastery/app)? diff --git a/.github/workflows/contribution-message.yml b/.github/workflows/contribution-message.yml new file mode 100644 index 00000000..adac63c8 --- /dev/null +++ b/.github/workflows/contribution-message.yml @@ -0,0 +1,31 @@ +name: Post contribution message in pull request +on: + pull_request: + types: [opened] + +jobs: + post_contribution_message: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Install dependencies + run: | + pip install requests PyGithub + + - name: Run post contribution message script + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + COMMIT_AUTHOR: ${{ github.event.pull_request.user.login }} + FORK_AUTHOR: ${{ github.event.pull_request.head.repo.owner.login }} + FORK_REPO: ${{ github.event.pull_request.head.repo.name }} + FORK_BRANCH: ${{ github.event.pull_request.head.ref }} + run: | + python scripts/post-contribution-message.py diff --git a/requirements.txt b/requirements.txt index 9b5125b5..df25221b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,6 @@ repo-smith # Developer tooling dependencies ruff mypy +PyGithub +requests +types-requests From f2afd81e8e30b57e15d3b630a76fb623e9e1386d Mon Sep 17 00:00:00 2001 From: "Jiahao, Woo" Date: Fri, 2 Jan 2026 11:23:44 +0800 Subject: [PATCH 3/6] [tooling] Add message to reviewers --- scripts/post-contribution-message.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/post-contribution-message.py b/scripts/post-contribution-message.py index c129dae2..35004f65 100644 --- a/scripts/post-contribution-message.py +++ b/scripts/post-contribution-message.py @@ -77,6 +77,9 @@ - [ ] (For exercises and hands-ons) I have verified that the downloading behavior works - [ ] (For exercises only) I have verified that the verification behavior is accurate + +> [!IMPORTANT] +> To any reviewers of this pull request, please use the same instructions above to test the changes. """.lstrip() pr.create_issue_comment(comment) From 761e3ecedccaaf473bcbc0eabf40f09b36849665 Mon Sep 17 00:00:00 2001 From: "Jiahao, Woo" Date: Fri, 2 Jan 2026 11:26:14 +0800 Subject: [PATCH 4/6] [tooling] Add debugging --- scripts/post-contribution-message.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/post-contribution-message.py b/scripts/post-contribution-message.py index 35004f65..2b05ada0 100644 --- a/scripts/post-contribution-message.py +++ b/scripts/post-contribution-message.py @@ -9,6 +9,18 @@ FORK_REPO = os.environ.get("FORK_REPO") FORK_BRANCH = os.environ.get("FORK_BRANCH") +print( + v is None or v == "" + for v in [ + GITHUB_TOKEN, + PR_NUMBER, + COMMIT_AUTHOR, + FORK_OWNER, + FORK_REPO, + FORK_BRANCH, + ] +) + if not all( [GITHUB_TOKEN, PR_NUMBER, COMMIT_AUTHOR, FORK_OWNER, FORK_REPO, FORK_BRANCH] ): From 1a21580b677add66a86cabde60a4fece27f4840a Mon Sep 17 00:00:00 2001 From: "Jiahao, Woo" Date: Fri, 2 Jan 2026 11:27:24 +0800 Subject: [PATCH 5/6] [tooling] Debugging --- scripts/post-contribution-message.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/post-contribution-message.py b/scripts/post-contribution-message.py index 2b05ada0..268dced8 100644 --- a/scripts/post-contribution-message.py +++ b/scripts/post-contribution-message.py @@ -10,14 +10,16 @@ FORK_BRANCH = os.environ.get("FORK_BRANCH") print( - v is None or v == "" - for v in [ - GITHUB_TOKEN, - PR_NUMBER, - COMMIT_AUTHOR, - FORK_OWNER, - FORK_REPO, - FORK_BRANCH, + [ + v is None or v == "" + for v in [ + GITHUB_TOKEN, + PR_NUMBER, + COMMIT_AUTHOR, + FORK_OWNER, + FORK_REPO, + FORK_BRANCH, + ] ] ) From 51bcbc52da0ce8ca8137426e6da9d37c899e9d01 Mon Sep 17 00:00:00 2001 From: "Jiahao, Woo" Date: Fri, 2 Jan 2026 11:28:33 +0800 Subject: [PATCH 6/6] [tooling] Fix name of env var --- scripts/post-contribution-message.py | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/scripts/post-contribution-message.py b/scripts/post-contribution-message.py index 268dced8..6b7713c8 100644 --- a/scripts/post-contribution-message.py +++ b/scripts/post-contribution-message.py @@ -5,26 +5,12 @@ GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN") PR_NUMBER = os.environ.get("PR_NUMBER") COMMIT_AUTHOR = os.environ.get("COMMIT_AUTHOR") -FORK_OWNER = os.environ.get("FORK_OWNER") +FORK_AUTHOR = os.environ.get("FORK_AUTHOR") FORK_REPO = os.environ.get("FORK_REPO") FORK_BRANCH = os.environ.get("FORK_BRANCH") -print( - [ - v is None or v == "" - for v in [ - GITHUB_TOKEN, - PR_NUMBER, - COMMIT_AUTHOR, - FORK_OWNER, - FORK_REPO, - FORK_BRANCH, - ] - ] -) - if not all( - [GITHUB_TOKEN, PR_NUMBER, COMMIT_AUTHOR, FORK_OWNER, FORK_REPO, FORK_BRANCH] + [GITHUB_TOKEN, PR_NUMBER, COMMIT_AUTHOR, FORK_AUTHOR, FORK_REPO, FORK_BRANCH] ): raise ValueError("Missing required environment variables") @@ -38,7 +24,7 @@ comment = f""" Hi @{COMMIT_AUTHOR}, thank you for your contribution! 🎉 -This PR comes from your fork `{FORK_OWNER}/{FORK_REPO}` on branch `{FORK_BRANCH}`. +This PR comes from your fork `{FORK_AUTHOR}/{FORK_REPO}` on branch `{FORK_BRANCH}`. Before you request for a review, please ensure that you have tested your changes locally! @@ -73,7 +59,7 @@ { # other fields... "exercises_source": { - "username": "{FORK_OWNER}", + "username": "{FORK_AUTHOR}", "repository": "{FORK_REPO}", "branch": "{FORK_BRANCH}", }