From 15a32e92a64306bfa7494eb85b70ca3b72fed624 Mon Sep 17 00:00:00 2001 From: ShangHungWan Date: Wed, 13 Mar 2024 00:21:39 +0800 Subject: [PATCH 01/17] fix: checklist-check workflow's regex --- .github/workflows/PR.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index 10f942ec..c4aad3f8 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -49,12 +49,12 @@ jobs: const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); const body = pr.data.body; - const checkboxes = body.match(/\- \[[x ]\]/g); + const checkboxes = body.match(/^\ ?(-|*) \[[x ]\]/gi); if (!checkboxes || checkboxes.length !== 5) { core.setFailed('The PR description must contain exactly 5 checkboxes.'); } - const unchecked = body.match(/\- \[ \]/g); + const unchecked = body.match(/^\ ?(-|*) \[ \]/g); if (unchecked && unchecked.length > 0) { core.setFailed(`There are ${unchecked.length} unchecked items in the PR description.`); } From a1dc1e283fd09062b0707a522e1d8c38a289a811 Mon Sep 17 00:00:00 2001 From: ShangHungWan Date: Wed, 13 Mar 2024 00:22:46 +0800 Subject: [PATCH 02/17] fix: install node from setup-node instead of script installation --- .github/workflows/lab1.yml | 7 +++---- .github/workflows/lab2.yml | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/lab1.yml b/.github/workflows/lab1.yml index 49a5d578..befe2593 100644 --- a/.github/workflows/lab1.yml +++ b/.github/workflows/lab1.yml @@ -16,10 +16,9 @@ jobs: - uses: actions/checkout@v1 with: fetch-depth: 1 - - name: dependency (ubuntu) - run: | - curl -fsSL https://deb.nodesource.com/setup_21.x | sudo -E bash - &&\ - sudo apt-get install -y nodejs + - uses: actions/setup-node@v4 + with: + node-version: latest - name: grading run: | cd lab1 diff --git a/.github/workflows/lab2.yml b/.github/workflows/lab2.yml index 2cb76fa7..f62e24e6 100644 --- a/.github/workflows/lab2.yml +++ b/.github/workflows/lab2.yml @@ -16,10 +16,9 @@ jobs: - uses: actions/checkout@v1 with: fetch-depth: 1 - - name: dependency (ubuntu) - run: | - curl -fsSL https://deb.nodesource.com/setup_21.x | sudo -E bash - &&\ - sudo apt-get install -y nodejs + - uses: actions/setup-node@v4 + with: + node-version: latest - name: grading run: | cd lab2 From 656d908d0eb457758e7fa80ef737eab823093ebc Mon Sep 17 00:00:00 2001 From: ShangHungWan Date: Wed, 13 Mar 2024 20:48:38 +0800 Subject: [PATCH 03/17] feat: fix buggy regex and add changed-files-check in pr.yml --- .github/workflows/PR.yml | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index c4aad3f8..92297ece 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -16,7 +16,7 @@ jobs: const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); const title = pr.data.title; const labRegex = /\[LAB(\d+)\]/; - const titleRegex = /^\[LAB\d+\] [\da-zA-Z]+$/; + const titleRegex = /^\[LAB\d+\] [a-zA-Z]?\d+$/; if (!titleRegex.test(title)) { core.setFailed('PR title does not match the required format. Please use the format [LAB#] student#.'); @@ -49,12 +49,33 @@ jobs: const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); const body = pr.data.body; - const checkboxes = body.match(/^\ ?(-|*) \[[x ]\]/gi); + const checkboxes = body.match(/^ ?(-|\*) \[[x ]\]/gi); if (!checkboxes || checkboxes.length !== 5) { core.setFailed('The PR description must contain exactly 5 checkboxes.'); } - const unchecked = body.match(/^\ ?(-|*) \[ \]/g); + const unchecked = body.match(/^ ?(-|\*) \[ \]/g); if (unchecked && unchecked.length > 0) { core.setFailed(`There are ${unchecked.length} unchecked items in the PR description.`); } + changed-files-check: + runs-on: ubuntu-latest + steps: + - name: Check no changes other than specific files + uses: actions/github-script@v5 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { owner, repo, number: issue_number } = context.issue; + const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); + const files = await github.rest.pulls.listFiles({ owner, repo, pull_number: issue_number }); + const changedFiles = files.data.map((file) => file.filename); + echo changedFiles; + + const allowedFiles = [ + 'lab1/main_test.js', + 'lab2/main_test.js', + ]; + if (!changedFiles.every((file) => allowedFiles.includes(file))) { + core.setFailed('The PR contains changes to files other than the allowed files.'); + } From 68ee1986dd6c6cae2a5a9ddaabc217f1f3c0e0b5 Mon Sep 17 00:00:00 2001 From: ShangHungWan Date: Wed, 13 Mar 2024 21:24:25 +0800 Subject: [PATCH 04/17] feat: use one autograding workflow instead of each lab's --- .github/workflows/lab-autograding.yml | 56 +++++++++++++++++++++++++++ .github/workflows/lab1.yml | 25 ------------ .github/workflows/lab2.yml | 25 ------------ 3 files changed, 56 insertions(+), 50 deletions(-) create mode 100644 .github/workflows/lab-autograding.yml delete mode 100644 .github/workflows/lab1.yml delete mode 100644 .github/workflows/lab2.yml diff --git a/.github/workflows/lab-autograding.yml b/.github/workflows/lab-autograding.yml new file mode 100644 index 00000000..2cd4a9df --- /dev/null +++ b/.github/workflows/lab-autograding.yml @@ -0,0 +1,56 @@ +name: Autograding + +on: + pull_request: + types: [labeled, synchronize, opened, reopened, ready_for_review] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-22.04] + fail-fast: false + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 1 + - uses: actions/setup-node@v4 + with: + node-version: latest + - name: Extract lab number and Check no changes other than specific files + uses: actions/github-script@v5 + id: lab + with: + result-encoding: string + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { owner, repo, number: issue_number } = context.issue; + const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); + const labels = pr.data.labels; + const lab = labels.find((label) => label.name.startsWith('lab')); + if (!lab) { + core.setFailed('No lab label found on the PR.'); + return { number: 0 }; + } + const labNumberMatch = lab.name.match(/lab(\d+)/); + if (!labNumberMatch) { + core.setFailed('Invalid lab label found on the PR.'); + return { number: 0 }; + } + const labNumber = labNumberMatch[1]; + console.log(`Lab number: ${labNumber}`) + + const files = await github.rest.pulls.listFiles({ owner, repo, pull_number: issue_number }); + const changedFiles = files.data.map((file) => file.filename); + const allowedFiles = [ + `lab${labNumber}/main_test.js`, + ]; + if (!changedFiles.every((file) => allowedFiles.includes(file))) { + core.setFailed('The PR contains changes to files other than the allowed files.'); + } + return labNumber; + - name: Grading + run: | + cd lab${{ steps.lab.outputs.result }} + ./validate.sh diff --git a/.github/workflows/lab1.yml b/.github/workflows/lab1.yml deleted file mode 100644 index befe2593..00000000 --- a/.github/workflows/lab1.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: lab1 autograding - -on: - pull_request: - types: [labeled, synchronize, opened, reopened, ready_for_review] - -jobs: - build: - if: contains(github.event.pull_request.labels.*.name, 'lab1') - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-22.04] - fail-fast: false - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - uses: actions/setup-node@v4 - with: - node-version: latest - - name: grading - run: | - cd lab1 - ./validate.sh diff --git a/.github/workflows/lab2.yml b/.github/workflows/lab2.yml deleted file mode 100644 index f62e24e6..00000000 --- a/.github/workflows/lab2.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: lab2 autograding - -on: - pull_request: - types: [labeled, synchronize, opened, reopened, ready_for_review] - -jobs: - build: - if: contains(github.event.pull_request.labels.*.name, 'lab2') - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-22.04] - fail-fast: false - steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - - uses: actions/setup-node@v4 - with: - node-version: latest - - name: grading - run: | - cd lab2 - ./validate.sh From 7d4c24aaa2f81c64eec805aa82fe99cecdc1a290 Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 14 Mar 2024 00:24:07 +0800 Subject: [PATCH 05/17] feat: rewrite source branch's naming rules --- .github/workflows/PR.yml | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index 92297ece..5dbfdfa7 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -15,27 +15,31 @@ jobs: const { owner, repo, number: issue_number } = context.issue; const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); const title = pr.data.title; - const labRegex = /\[LAB(\d+)\]/; - const titleRegex = /^\[LAB\d+\] [a-zA-Z]?\d+$/; - if (!titleRegex.test(title)) { - core.setFailed('PR title does not match the required format. Please use the format [LAB#] student#.'); + const titleRegex = /^\[LAB(\d+)\] [a-zA-Z]?\d+$/; + const match = title.match(titleRegex); + + const labNumberStr = undefined; + if (match) { + labNumberStr = match[1]; + } else { + core.setFailed('PR title does not match the required format. Please use the format: [LAB#] .'); } - if (pr.data.head.ref !== pr.data.base.ref) { - core.setFailed('The source branch and target branch must be the same.'); + const labelToAdd = `lab${labNumberStr}`; + if (labNumberStr) { + await github.rest.issues.addLabels({ owner, repo, issue_number, labels: [labelToAdd] }); } if (pr.data.base.ref === 'main') { core.setFailed('The target branch cannot be main.'); } - const match = title.match(labRegex); - if (match) { - const labelToAdd = 'lab' + match[1]; - await github.rest.issues.addLabels({ owner, repo, issue_number, labels: [labelToAdd] }); - } else { - core.setFailed('No match found in PR title. Please add a label in the format [LAB#] to the PR title.'); + if (labNumberStr < 3 && pr.data.head.ref !== pr.data.base.ref) { + core.setFailed('The source branch and target branch must be the same.'); + } + if (labNumberStr >= 3 && pr.data.head.ref !== labelToAdd) { + core.setFailed(`The source branch must be '${labelToAdd}'`); } checklist-check: runs-on: ubuntu-latest From d44bbe34c41c0e6f1095f4076a5ea3cd1ac8d539 Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 14 Mar 2024 00:58:21 +0800 Subject: [PATCH 06/17] feat: use pull_request_target instead of pull_request --- .github/workflows/lab-autograding.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lab-autograding.yml b/.github/workflows/lab-autograding.yml index 2cd4a9df..918d29b8 100644 --- a/.github/workflows/lab-autograding.yml +++ b/.github/workflows/lab-autograding.yml @@ -1,7 +1,7 @@ name: Autograding on: - pull_request: + pull_request_target: types: [labeled, synchronize, opened, reopened, ready_for_review] jobs: From f02c1ea1384ad0419bc30ebc15ca1e5e400e9029 Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 14 Mar 2024 01:57:31 +0800 Subject: [PATCH 07/17] fix: multiple errors in workflows --- .github/workflows/PR.yml | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml index 5dbfdfa7..54b7d6b2 100644 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -19,7 +19,7 @@ jobs: const titleRegex = /^\[LAB(\d+)\] [a-zA-Z]?\d+$/; const match = title.match(titleRegex); - const labNumberStr = undefined; + let labNumberStr = undefined; if (match) { labNumberStr = match[1]; } else { @@ -53,33 +53,12 @@ jobs: const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); const body = pr.data.body; - const checkboxes = body.match(/^ ?(-|\*) \[[x ]\]/gi); + const checkboxes = body.match(/^ ?(-|\*) \[[x ]\]/gmi); if (!checkboxes || checkboxes.length !== 5) { core.setFailed('The PR description must contain exactly 5 checkboxes.'); } - const unchecked = body.match(/^ ?(-|\*) \[ \]/g); + const unchecked = body.match(/^ ?(-|\*) \[ \]/gm); if (unchecked && unchecked.length > 0) { - core.setFailed(`There are ${unchecked.length} unchecked items in the PR description.`); - } - changed-files-check: - runs-on: ubuntu-latest - steps: - - name: Check no changes other than specific files - uses: actions/github-script@v5 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { owner, repo, number: issue_number } = context.issue; - const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); - const files = await github.rest.pulls.listFiles({ owner, repo, pull_number: issue_number }); - const changedFiles = files.data.map((file) => file.filename); - echo changedFiles; - - const allowedFiles = [ - 'lab1/main_test.js', - 'lab2/main_test.js', - ]; - if (!changedFiles.every((file) => allowedFiles.includes(file))) { - core.setFailed('The PR contains changes to files other than the allowed files.'); + core.setFailed(`There are ${unchecked.length} unchecked item(s) in the PR description.`); } From 2d4b5d3cf5680ff2d8f4a19f887f1d0e931743dc Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 14 Mar 2024 02:02:18 +0800 Subject: [PATCH 08/17] feat: merge and squash script --- scripts/merge-all.sh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100755 scripts/merge-all.sh diff --git a/scripts/merge-all.sh b/scripts/merge-all.sh new file mode 100755 index 00000000..a3be7f90 --- /dev/null +++ b/scripts/merge-all.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +if [ $# -ne 1 ]; then + echo "./merge-all.sh " + exit 1 +fi + +git fetch origin + +for branch in $(git branch -r | grep -v HEAD); do + # Remove the "origin/" prefix + branch=${branch#origin/} + + if [[ "$branch" != "main" ]]; then + git checkout "$branch" + if [[ $? -ne 0 ]]; then + echo "Checkout failed for branch $branch" + exit 1 + fi + git merge --squash main + if [[ $? -ne 0 ]]; then + echo "Merge failed for branch $branch" + exit 1 + fi + git commit -m "$1" + fi +done + +git checkout main \ No newline at end of file From 91270f22e4625e0f70f9ba322ec21bbe0cfce9b8 Mon Sep 17 00:00:00 2001 From: Sun Date: Thu, 14 Mar 2024 13:17:48 +0800 Subject: [PATCH 09/17] fix: didn't checkout when grading --- .github/workflows/lab-autograding.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lab-autograding.yml b/.github/workflows/lab-autograding.yml index 918d29b8..502b9631 100644 --- a/.github/workflows/lab-autograding.yml +++ b/.github/workflows/lab-autograding.yml @@ -12,12 +12,12 @@ jobs: os: [ubuntu-22.04] fail-fast: false steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - uses: actions/setup-node@v4 with: node-version: latest + - uses: actions/checkout@v1 + with: + fetch-depth: 1 - name: Extract lab number and Check no changes other than specific files uses: actions/github-script@v5 id: lab @@ -50,6 +50,9 @@ jobs: core.setFailed('The PR contains changes to files other than the allowed files.'); } return labNumber; + - uses: actions/checkout@v1 + with: + fetch-depth: 1 - name: Grading run: | cd lab${{ steps.lab.outputs.result }} From 2c9fd78581c28c9b3d7d98008cd1eac4818a4312 Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 14 Mar 2024 13:55:59 +0800 Subject: [PATCH 10/17] feat: add lab3 --- lab3/main.js | 34 ++++++++++++++++++++++++++++++++++ lab3/main_test.js | 5 +++++ lab3/validate.sh | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 lab3/main.js create mode 100644 lab3/main_test.js create mode 100755 lab3/validate.sh diff --git a/lab3/main.js b/lab3/main.js new file mode 100644 index 00000000..cee5de7f --- /dev/null +++ b/lab3/main.js @@ -0,0 +1,34 @@ +class Calculator { + exp(x) { + if (!Number.isFinite(x)) { + throw Error('unsupported operand type'); + } + const result = Math.exp(x); + if (result === Infinity) { + throw Error('overflow'); + } + return result; + } + + log(x) { + if (!Number.isFinite(x)) { + throw Error('unsupported operand type'); + } + const result = Math.log(x); + if (result === -Infinity) { + throw Error('math domain error (1)'); + } + if (Number.isNaN(result)) { + throw Error('math domain error (2)'); + } + return result; + } +} + +// const calculator = new Calculator(); +// console.log(calculator.exp(87)); +// console.log(calculator.log(48763)); + +module.exports = { + Calculator +}; \ No newline at end of file diff --git a/lab3/main_test.js b/lab3/main_test.js new file mode 100644 index 00000000..e6d6414e --- /dev/null +++ b/lab3/main_test.js @@ -0,0 +1,5 @@ +const {describe, it} = require('node:test'); +const assert = require('assert'); +const { Calculator } = require('./main'); + +// TODO: write your tests here diff --git a/lab3/validate.sh b/lab3/validate.sh new file mode 100755 index 00000000..7a758fb3 --- /dev/null +++ b/lab3/validate.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Check for unwanted files +for file in *; do + if [[ $file != "main.js" && $file != "main_test.js" && $file != "README.md" && $file != "validate.sh" ]]; then + echo "[!] Unwanted file detected: $file." + exit 1 + fi +done + +node=$(which node) +test_path="${BASH_SOURCE[0]}" +solution_path="$(realpath .)" +tmp_dir=$(mktemp -d -t lab3-XXXXXXXXXX) + +cd $tmp_dir + +rm -rf * +cp $solution_path/*.js . +result=$($"node" --test --experimental-test-coverage) ; ret=$? +if [ $ret -ne 0 ] ; then + echo "[!] testing fails" + exit 1 +else + coverage=$(echo "$result" | grep 'all files' | awk -F '|' '{print $2}' | sed 's/ //g') + if (( $(echo "$coverage < 100" | bc -l) )); then + echo "[!] Coverage is only $coverage%" + exit 1 + else + echo "[V] Coverage is 100%" + fi +fi + +rm -rf $tmp_dir + +exit 0 + +# vim: set fenc=utf8 ff=unix et sw=2 ts=2 sts=2: \ No newline at end of file From f6b8b88b075b01d8cc3e4b3a26e7d22393693d7d Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 14 Mar 2024 13:56:26 +0800 Subject: [PATCH 11/17] doc: add lab3 requirements --- lab3/README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 lab3/README.md diff --git a/lab3/README.md b/lab3/README.md new file mode 100644 index 00000000..f95c2ca0 --- /dev/null +++ b/lab3/README.md @@ -0,0 +1,29 @@ +# Lab3 + +## Introduction + +In this lab, you will write unit tests for functions implemented in `main.js`. You can learn how to use classes and functions in it by uncommenting the code in it. (But remember don't commit them on GitHub) + +## Preparation (Important!!!) + +1. Sync fork on GitHub +2. `git checkout -b lab3` (**NOT** your student ID !!!) + +## Requirement + +1. (40%) Write test cases in `main_test.js` and achieve 100% code coverage. +2. (30%) For each function, parameterize their testcases to test the error-results. +3. (30%) For each function, use at least 3 parameterized testcases to test the non-error-results. + +You can run `validate.sh` in your local to test if you satisfy the requirements. + +Please note that you must not alter files other than `main_test.js`. You will get 0 points if + +1. you modify other files to achieve requirements. +2. you can't pass all CI on your PR. + +## Submission + +You need to open a pull request to your branch (e.g. 311XXXXXX, your student number) and contain the code that satisfies the abovementioned requirements. + +Moreover, please submit the URL of your PR to E3. Your submission will only be accepted when you present at both places. From 06329c2ee1e95dc713abad6cf49c78d9b847dfa6 Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 14 Mar 2024 14:21:04 +0800 Subject: [PATCH 12/17] fix: wrong GITHUB SHA in workflows --- .github/workflows/lab-autograding.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lab-autograding.yml b/.github/workflows/lab-autograding.yml index 502b9631..52f68ea6 100644 --- a/.github/workflows/lab-autograding.yml +++ b/.github/workflows/lab-autograding.yml @@ -12,12 +12,13 @@ jobs: os: [ubuntu-22.04] fail-fast: false steps: + - uses: actions/checkout@v4 + with: + ref: "${{ github.event.pull_request.merge_commit_sha }}" + fetch-depth: 1 - uses: actions/setup-node@v4 with: node-version: latest - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - name: Extract lab number and Check no changes other than specific files uses: actions/github-script@v5 id: lab @@ -50,9 +51,6 @@ jobs: core.setFailed('The PR contains changes to files other than the allowed files.'); } return labNumber; - - uses: actions/checkout@v1 - with: - fetch-depth: 1 - name: Grading run: | cd lab${{ steps.lab.outputs.result }} From ebef053faafb840b57ebd7c042ec7b42f792230e Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 14 Mar 2024 16:07:59 +0800 Subject: [PATCH 13/17] hotfix: remove changed files --- .github/workflows/lab-autograding.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lab-autograding.yml b/.github/workflows/lab-autograding.yml index 52f68ea6..595dc5ce 100644 --- a/.github/workflows/lab-autograding.yml +++ b/.github/workflows/lab-autograding.yml @@ -47,9 +47,9 @@ jobs: const allowedFiles = [ `lab${labNumber}/main_test.js`, ]; - if (!changedFiles.every((file) => allowedFiles.includes(file))) { - core.setFailed('The PR contains changes to files other than the allowed files.'); - } + // if (!changedFiles.every((file) => allowedFiles.includes(file))) { + // core.setFailed('The PR contains changes to files other than the allowed files.'); + // } return labNumber; - name: Grading run: | From 9fcdccdfbf51a4a3407dcf938396d18604f67123 Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 21 Mar 2024 14:25:09 +0800 Subject: [PATCH 14/17] feat: an easy check for changed files --- .github/workflows/lab-autograding.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/lab-autograding.yml b/.github/workflows/lab-autograding.yml index 595dc5ce..47a49147 100644 --- a/.github/workflows/lab-autograding.yml +++ b/.github/workflows/lab-autograding.yml @@ -30,7 +30,7 @@ jobs: const pr = await github.rest.pulls.get({ owner, repo, pull_number: issue_number }); const labels = pr.data.labels; const lab = labels.find((label) => label.name.startsWith('lab')); - if (!lab) { + if (!lab) { core.setFailed('No lab label found on the PR.'); return { number: 0 }; } @@ -44,12 +44,10 @@ jobs: const files = await github.rest.pulls.listFiles({ owner, repo, pull_number: issue_number }); const changedFiles = files.data.map((file) => file.filename); - const allowedFiles = [ - `lab${labNumber}/main_test.js`, - ]; - // if (!changedFiles.every((file) => allowedFiles.includes(file))) { - // core.setFailed('The PR contains changes to files other than the allowed files.'); - // } + const allowedFileRegex = /^lab\d+\/main_test.js$/; + if (!changedFiles.every((file) => allowedFileRegex.test(file))) { + core.setFailed('The PR contains changes to files other than the allowed files.'); + } return labNumber; - name: Grading run: | From e02ce022e5a75b5c992b92fee1a3c221d31d5847 Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 21 Mar 2024 14:25:42 +0800 Subject: [PATCH 15/17] feat: add node_modules into gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..40b878db --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file From afcb7709d1ebea818c5e89e842f56f9d2f691862 Mon Sep 17 00:00:00 2001 From: AlaRduTP Date: Thu, 21 Mar 2024 14:26:12 +0800 Subject: [PATCH 16/17] feat: specify the strategy of merging --- scripts/merge-all.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/merge-all.sh b/scripts/merge-all.sh index a3be7f90..4743ac08 100755 --- a/scripts/merge-all.sh +++ b/scripts/merge-all.sh @@ -1,7 +1,7 @@ #!/bin/bash if [ $# -ne 1 ]; then - echo "./merge-all.sh " + echo "$0 " exit 1 fi @@ -17,7 +17,7 @@ for branch in $(git branch -r | grep -v HEAD); do echo "Checkout failed for branch $branch" exit 1 fi - git merge --squash main + git merge --squash -s recursive -X theirs main if [[ $? -ne 0 ]]; then echo "Merge failed for branch $branch" exit 1 @@ -26,4 +26,4 @@ for branch in $(git branch -r | grep -v HEAD); do fi done -git checkout main \ No newline at end of file +git checkout main From 877282084bee8a6e95fe3035ee7b561ff70caa6d Mon Sep 17 00:00:00 2001 From: YingMuo Date: Thu, 20 Jun 2024 23:13:17 +0800 Subject: [PATCH 17/17] Finish lab3 --- lab3/main_test.js | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/lab3/main_test.js b/lab3/main_test.js index e6d6414e..ed5bb9a3 100644 --- a/lab3/main_test.js +++ b/lab3/main_test.js @@ -3,3 +3,83 @@ const assert = require('assert'); const { Calculator } = require('./main'); // TODO: write your tests here + +const { mock } = require('node:test'); + +describe('Calculator', () => { + it('should throw an error on non-numeric input when calculate exponential of a number', () => { + const calculator = new Calculator(); + const testcases = [ + { params: 'a', expected: Error('unsupported operand type') }, + { params: '123abc', expected: Error('unsupported operand type') }, + { params: '1', expected: Error('unsupported operand type') }, + { params: '0', expected: Error('unsupported operand type') }, + { params: true, expected: Error('unsupported operand type') }, + { params: false, expected: Error('unsupported operand type') }, + { params: NaN, expected: Error('unsupported operand type') }, + { params: Infinity, expected: Error('unsupported operand type') }, + { params: -Infinity, expected: Error('unsupported operand type') }, + ] + for (const testcase of testcases) { + assert.throws(() => calculator.exp(testcase.params), testcase.expected); + } + }); + it('show throw an error on overflow when calculate exponential of a number', () => { + const calculator = new Calculator(); + mock.method(Math, 'exp', () => Infinity); + assert.throws(() => calculator.exp(1), Error('overflow')); + mock.reset(); + }); + it('should return the exponential of a number', () => { + const calculator = new Calculator(); + + function getRndInteger(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + for (let i = 0; i < 20; i++) { + const number = getRndInteger(-100, 100); + assert.strictEqual(calculator.exp(number), Math.exp(number)); + } + }); + it('should throw an error on non-numeric input when calculate logarithm of a number', () => { + const calculator = new Calculator(); + const testcases = [ + { params: 'a', expected: Error('unsupported operand type') }, + { params: '123abc', expected: Error('unsupported operand type') }, + { params: '1', expected: Error('unsupported operand type') }, + { params: '0', expected: Error('unsupported operand type') }, + { params: true, expected: Error('unsupported operand type') }, + { params: false, expected: Error('unsupported operand type') }, + { params: NaN, expected: Error('unsupported operand type') }, + { params: Infinity, expected: Error('unsupported operand type') }, + { params: -Infinity, expected: Error('unsupported operand type') }, + ] + for (const testcase of testcases) { + assert.throws(() => calculator.log(testcase.params), testcase.expected); + } + }); + it('show throw an error on math domain error when calculate logarithm of a number', () => { + const calculator = new Calculator(); + + mock.method(Math, 'log', () => -Infinity); + assert.throws(() => calculator.log(1), Error('math domain error (1)')); + mock.reset(); + + mock.method(Math, 'log', () => NaN); + assert.throws(() => calculator.log(1), Error('math domain error (2)')); + mock.reset(); + }); + it('should return the logarithm of a number', () => { + const calculator = new Calculator(); + + function getRndInteger(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + for (let i = 0; i < 20; i++) { + const number = getRndInteger(1, 1000); + assert.strictEqual(calculator.log(number), Math.log(number)); + } + }); +}); \ No newline at end of file