diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..69fada0 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,65 @@ +name: CI + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + push: + branches: [main] + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + checks: + name: Lint / Format Check / Tests + runs-on: ubuntu-latest + if: ${{ github.event_name != 'push' || github.ref == 'refs/heads/main' }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + id: py + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install Poetry + uses: abatilo/actions-poetry@v3 + with: + poetry-version: "2.2.0" + + - name: Enable in-project venv + run: poetry config virtualenvs.in-project true + + - name: Cache Poetry venv + uses: actions/cache@v4 + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.py.outputs.python-version }}-${{ hashFiles('poetry.lock') }} + restore-keys: | + venv-${{ runner.os }}- + + - name: Install dependencies + run: poetry install --no-interaction + + # ---- Static checks (no file modifications in CI) ---- + - name: Ruff lint + run: poetry run ruff check . + + - name: Ruff format (check only) + run: poetry run ruff format --check . + + # ---- Run tests with coverage threshold ---- + - name: Run tests with coverage + run: | + poetry run pytest \ + -q --maxfail=1 --disable-warnings \ + --cov=src --cov-report=term-missing \ + --cov-report=xml:coverage.xml \ + --cov-fail-under=100 diff --git a/README.md b/README.md index af2eb1b..1fd278f 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,12 @@ **Workflow**: 1. Fork this repository to your own GitHub account. -2. Create a new branch from `develop` and name it `feature/student1name_student2name`. -3. Clone the repo to AWS VM. -4. Implement the functions until all `pytest` tests pass. -5. Push your code to your Github repo. +2. Clone the repo to AWS VM. +3. Run poetry install to install dependencies +4. Run poetry run pre-commit install to install the pre-commit hook. +5. Create a new branch from `develop` and name it `feature/student1name_student2name`. +7. Implement the functions until all `pytest` tests pass. +8. Make the pre-commit checks all pass and commit the code. +9. Push your code to your Github repo. 5. Submit a Pull Request back to the `develop` branch of the main repo. CI must pass. 6. Wait for code review and grading. diff --git a/poetry.lock b/poetry.lock index 4177cc6..5b32389 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,7 +38,7 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main"] +groups = ["main", "dev"] markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, @@ -260,7 +260,7 @@ version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.8" -groups = ["main"] +groups = ["main", "dev"] files = [ {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, @@ -393,7 +393,7 @@ version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["main"] +groups = ["main", "dev"] files = [ {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, @@ -434,7 +434,7 @@ version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.9" -groups = ["main"] +groups = ["main", "dev"] files = [ {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, @@ -484,7 +484,7 @@ version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" -groups = ["main"] +groups = ["main", "dev"] files = [ {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, @@ -499,7 +499,7 @@ version = "8.4.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.9" -groups = ["main"] +groups = ["main", "dev"] files = [ {file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"}, {file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"}, @@ -940,5 +940,5 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.1" -python-versions = ">=3.12" -content-hash = "c6fe4b288327b501a15d79c555e296323d3da6a16b612a92ac74271600991431" +python-versions = "^3.12" +content-hash = "ecd46f9c7df0b8d74ebc590edd798e935aba1f8c50228d60e3633baa8e680c89" diff --git a/pyproject.toml b/pyproject.toml index 4274d13..8408e51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,20 @@ dependencies = [ "pre-commit (>=4.3.0,<5.0.0)" ] +[tool.poetry] +name = "arithmetic" +version = "0.1.0" +description = "Toy arithmetic package" +authors = ["Your Name "] +readme = "README.md" +packages = [{ include = "src/arithmetic" }] + +[tool.poetry.dependencies] +python = "^3.12" + + +[tool.poetry.group.dev.dependencies] +pytest = "^8.4.2" [build-system] requires = ["poetry-core>=2.0.0,<3.0.0"] diff --git a/src/arithmetic/arithmetic.py b/src/arithmetic/arithmetic.py index 86f6960..72fd20a 100644 --- a/src/arithmetic/arithmetic.py +++ b/src/arithmetic/arithmetic.py @@ -13,7 +13,7 @@ def add_numbers(a: int, b: int) -> int: Returns: Sum of a and b. """ - raise NotImplementedError + return a + b def factorial(n: int) -> int: @@ -28,7 +28,12 @@ def factorial(n: int) -> int: Raises: ValueError: if n is negative """ - raise NotImplementedError + if n < 0: + raise ValueError("Factorial is not defined for negative numbers") + result = 1 + for i in range(2, n + 1): + result *= i + return result def is_prime(n: int) -> bool: @@ -43,4 +48,10 @@ def is_prime(n: int) -> bool: Returns: True if n is prime; otherwise False. """ - raise NotImplementedError + if n <= 1: + return False + else: + for i in range(2, n): + if n % i == 0: + return False + return True