diff --git a/.circleci/config.yml b/.circleci/config.yml index edf6a031..fe5ae248 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,11 +1,11 @@ version: 2.1 orbs: - codecov: codecov/codecov@3.0.0 + codecov: codecov/codecov@4 jobs: build: docker: - - image: cimg/python:3.9.6 + - image: cimg/python:3.10 steps: - checkout - run: @@ -13,9 +13,7 @@ jobs: command: pip install -r requirements.txt - run: name: Run tests and collect coverage - command: | - coverage run tests.py - coverage xml + command: pytest --cov app - codecov/upload workflow: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 433eac75..15abf468 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,18 +3,40 @@ on: [push, pull_request] jobs: run: runs-on: ubuntu-latest + permissions: + id-token: write steps: - name: Checkout - uses: actions/checkout@v2 - - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/checkout@v4 + - name: Set up Python 3.10 + uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: '3.10' - name: Install dependencies run: pip install -r requirements.txt - name: Run tests and collect coverage - run: | - coverage run tests.py - coverage xml - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v2 + run: pytest --cov app + - name: Upload coverage to Codecov (arg token) + uses: codecov/codecov-action@main + with: + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true + - name: Upload coverage to Codecov (env token) + uses: codecov/codecov-action@main + with: + fail_ci_if_error: true + verbose: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + - name: Upload coverage to Codecov (no token) + uses: codecov/codecov-action@main + with: + fail_ci_if_error: true + verbose: true + - name: Upload coverage to Codecov (oidc) + uses: codecov/codecov-action@main + with: + fail_ci_if_error: true + use_oidc: true + verbose: true diff --git a/.github/workflows/enforce-license-compliance.yml b/.github/workflows/enforce-license-compliance.yml new file mode 100644 index 00000000..86be7410 --- /dev/null +++ b/.github/workflows/enforce-license-compliance.yml @@ -0,0 +1,14 @@ +name: Enforce License Compliance + +on: + pull_request: + branches: [main, master] + +jobs: + enforce-license-compliance: + runs-on: ubuntu-latest + steps: + - name: 'Enforce License Compliance' + uses: getsentry/action-enforce-license-compliance@57ba820387a1a9315a46115ee276b2968da51f3d # main + with: + fossa_api_key: ${{ secrets.FOSSA_API_KEY }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c18dd8d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..c341b2a0 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Codecov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 50af7780..4251cc84 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,18 @@ # [Codecov](https://codecov.io) Python Example +[![codecov](https://codecov.io/github/codecov/example-python/branch/main/graph/badge.svg?token=tkq655ROg3)](https://app.codecov.io/github/codecov/example-python) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcodecov%2Fexample-python.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcodecov%2Fexample-python?ref=badge_shield) +This example repository shows how Codecov can be integrated with a simple python project. It uses **GitHub Actions** and **CircleCI** as CI/CD providers and **coverage** as the coverage provider. -## Guide - -### GitHub Actions -A minimal configuration might look like: - -```yml -steps: - # (Other steps go here) - - name: "Upload coverage to Codecov" - uses: codecov/codecov-action@v2 - with: - fail_ci_if_error: true - token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos -``` - -See [codecov/codecov-action](https://github.com/codecov/codecov-action) for -more information, a [detailed example](https://github.com/codecov/codecov-action#example-workflowyml-with-codecov-action), -and other options. - -### Produce Coverage Reports -[coverage.py](https://github.com/nedbat/coveragepy) is required to collect coverage metrics. - -Below are some examples on how to include coverage tracking during your tests. You will need to call `coverage xml` to generate the coverage xml output, which will be archived and processed server side. - -You may need to configure a `.coveragerc` file. Learn more [here](http://coverage.readthedocs.org/en/latest/config.html). Start with this [generic .coveragerc](https://gist.github.com/codecov-io/bf15bde2c7db1a011b6e) for example. - -We highly suggest adding `source` to your `.coveragerc` which solves a number of issues collecting coverage. - -```ini -[run] -source=your_package_name -``` -#### unittests -``` -pip install coverage -coverage run tests.py -coverage xml -``` -#### pytest -``` -pip install pytest-cov -pytest --cov=./ --cov-report=xml -``` -#### nosetests -``` -nosetest --with-coverage -``` -See the [Offical Nose coverage docs](http://nose.readthedocs.org/en/latest/plugins/cover.html) for more information. - -### Testing with ``tox`` - -Codecov can be run from inside your `tox.ini` please make sure you pass all the necessary environment variables through: -```ini -[testenv] -passenv = CI TRAVIS TRAVIS_* -deps = codecov -commands = codecov -``` - -### FAQ -- Q: What's the difference between the codecov-bash and codecov-python uploader? - A: As far as python is concerned, *nothing*. You may choose to use either uploader. Codecov recommends **using the bash uploader when possible** as it supports more unique repository setups. Learn more at [codecov/codecov-bash](https://github.com/codecov/codecov-bash) and [codecov/codecov-python](https://github.com/codecov/codecov-python). -- Q: Why am I seeing `No data to report`? - A: This output is written by running the command `coverage xml` and states that there were no `.coverage` files found. - 1. Make sure coverage is enabled. See Enabling Coverage - 2. You may need to run `coverage combine` before running Codecov. - 3. Using Docker? Please follow this step: [Testing with Docker: Codecov Inside Docker](https://docs.codecov.io/docs/testing-with-docker#codecov-inside-docker). -- Q: Can I upload my `.coverage` files? - A: **No**, these files contain coverage data but are not properly mapped back to the source code. We rely on `coveragepy` to handle this by calling `coverage xml` in the uploader. - -## Caveats -### Private Repo -Repository tokens are required for (a) all private repos, (b) public repos not using the GitHub Actions, Travis CI, CircleCI or AppVeyor. - -Find your repository token at Codecov and provide via appending `-t ` to you where you upload reports. - -### Cobertura Reports -Cobertura reports can expire - Codecov will reject reports that are older than 12 hours. The logs contain details if a report expired. +For more information, please see the links below. ## Links +- [Quick Start](https://docs.codecov.com/docs/quick-start) +- [GitHub Tutorial](https://docs.codecov.com/docs/github-tutorial) - [Community Boards](https://community.codecov.io) - [Support](https://codecov.io/support) - [Documentation](https://docs.codecov.io) - ## License [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcodecov%2Fexample-python.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcodecov%2Fexample-python?ref=badge_large) diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/calculator.py b/app/calculator.py new file mode 100644 index 00000000..4f380e8e --- /dev/null +++ b/app/calculator.py @@ -0,0 +1,16 @@ +class Calculator: + + def add(x, y): + return x + y + + def subtract(x, y): + return x - y + + def multiply(x, y): + return x * y + + def divide(x, y): + if y == 0: + return 'Cannot divide by 0' + return x * 1.0 / y + diff --git a/app/test_calculator.py b/app/test_calculator.py new file mode 100644 index 00000000..f5641938 --- /dev/null +++ b/app/test_calculator.py @@ -0,0 +1,31 @@ +from .calculator import Calculator + + +def test_add(): + assert Calculator.add(1, 2) == 3.0 + assert Calculator.add(1.0, 2.0) == 3.0 + assert Calculator.add(0, 2.0) == 2.0 + assert Calculator.add(2.0, 0) == 2.0 + assert Calculator.add(-4, 2.0) == -2.0 + +def test_subtract(): + assert Calculator.subtract(1, 2) == -1.0 + assert Calculator.subtract(2, 1) == 1.0 + assert Calculator.subtract(1.0, 2.0) == -1.0 + assert Calculator.subtract(0, 2.0) == -2.0 + assert Calculator.subtract(2.0, 0.0) == 2.0 + assert Calculator.subtract(-4, 2.0) == -6.0 + +def test_multiply(): + assert Calculator.multiply(1, 2) == 2.0 + assert Calculator.multiply(1.0, 2.0) == 2.0 + assert Calculator.multiply(0, 2.0) == 0.0 + assert Calculator.multiply(2.0, 0.0) == 0.0 + assert Calculator.multiply(-4, 2.0) == -8.0 + +def test_divide(): + # assert Calculator.divide(1, 2) == 0.5 + assert Calculator.divide(1.0, 2.0) == 0.5 + assert Calculator.divide(0, 2.0) == 0 + assert Calculator.divide(-4, 2.0) == -2.0 + # assert Calculator.divide(2.0, 0.0) == 'Cannot divide by 0' diff --git a/awesome/__init__.py b/awesome/__init__.py deleted file mode 100644 index 4d34acc6..00000000 --- a/awesome/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -def smile(): - return ":)" - -def frown(): - return ":(" diff --git a/bitrise.yml b/bitrise.yml new file mode 100644 index 00000000..a09c296d --- /dev/null +++ b/bitrise.yml @@ -0,0 +1,34 @@ +format_version: "13" +default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git +project_type: other +workflows: + primary: + steps: + - activate-ssh-key@4: + run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' + - git-clone@8: {} + - script@1: + inputs: + - script_file_path: null + - content: | + #!/usr/bin/env bash + set -e + set -o pipefail + set -x # debug log + + pip3 install -r requirements.txt + pytest --cov app + - codecov@3: + inputs: + - OS: macos + - CODECOV_TOKEN: $CODECOV_TOKEN + - deploy-to-bitrise-io@2: {} +meta: + bitrise.io: + stack: osx-xcode-14.3.x-ventura + machine_type_id: g2-m1.4core +trigger_map: +- push_branch: main + workflow: primary +- pull_request_source_branch: '*' + workflow: primary diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..1ed5513f --- /dev/null +++ b/codecov.yml @@ -0,0 +1,13 @@ +flag_management: + individual_flags: + - name: smart-tests + carryforward: true + carryforward_mode: "labels" + statuses: + - type: "project" + - type: "patch" + +cli: + plugins: + pycoverage: + report_type: "json" diff --git a/requirements.txt b/requirements.txt index 4ebc8aea..f1e325af 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,10 @@ -coverage +attrs==25.3.0 +coverage==7.8.0 +iniconfig==2.1.0 +packaging==24.2 +pluggy==1.5.0 +py==1.11.0 +pyparsing==3.2.3 +pytest==8.3.5 +pytest-cov==6.1.0 +tomli==2.2.1 diff --git a/tests.py b/tests.py deleted file mode 100644 index 92aa2034..00000000 --- a/tests.py +++ /dev/null @@ -1,12 +0,0 @@ -import unittest - -import awesome - - -class TestMethods(unittest.TestCase): - def test_add(self): - self.assertEqual(awesome.smile(), ":)") - - -if __name__ == '__main__': - unittest.main() diff --git a/time.txt b/time.txt deleted file mode 100644 index a9f3b150..00000000 --- a/time.txt +++ /dev/null @@ -1 +0,0 @@ -1585101003