diff --git a/.github/workflows/python-package-conda.yml b/.github/workflows/python-package-conda.yml new file mode 100644 index 00000000..d79a7e35 --- /dev/null +++ b/.github/workflows/python-package-conda.yml @@ -0,0 +1,177 @@ +name: Python Package using Conda + +on: [push, pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-linux: + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + max-parallel: 5 + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11'] + + steps: + - uses: actions/checkout@v4 + + - name: Setup Miniconda + uses: conda-incubator/setup-miniconda@v2 + with: + miniconda-version: latest + python-version: ${{ matrix.python-version }} + channels: conda-forge,defaults + auto-activate-base: false + activate-environment: braintree + + - name: Install dependencies + shell: bash -l {0} + run: | + echo "Installing dependencies from environment.yml..." + conda env update --file environment.yml --name braintree + if [ $? -ne 0 ]; then + echo "❌ Failed to install dependencies" + exit 1 + fi + echo "✅ Dependencies installed successfully" + conda list + + - name: Install and verify bandit + shell: bash -l {0} + run: | + echo "Installing bandit for security scanning..." + conda install -c conda-forge bandit -y + if [ $? -ne 0 ]; then + echo "❌ Failed to install bandit" + exit 1 + fi + bandit --version + if [ $? -ne 0 ]; then + echo "❌ bandit verification failed" + exit 1 + fi + echo "✅ bandit installed and verified" + + - name: Security check with bandit + shell: bash -l {0} + run: | + echo "Running bandit security scan..." + bandit -r . -f json -o bandit-report.json + bandit -r . -f txt + if [ $? -ne 0 ]; then + echo "⚠️ Security issues detected (see report above)" + else + echo "✅ No security issues found" + fi + + - name: Install and verify safety + shell: bash -l {0} + run: | + echo "Installing safety for dependency vulnerability scanning..." + pip install safety + if [ $? -ne 0 ]; then + echo "❌ Failed to install safety" + exit 1 + fi + safety --version + if [ $? -ne 0 ]; then + echo "❌ safety verification failed" + exit 1 + fi + echo "✅ safety installed and verified" + + - name: Dependency vulnerability check with safety + shell: bash -l {0} + run: | + echo "Running safety dependency vulnerability scan..." + safety check --json > safety-report.json || true + safety check + if [ $? -ne 0 ]; then + echo "⚠️ Vulnerable dependencies detected (see report above)" + else + echo "✅ No vulnerable dependencies found" + fi + + - name: Install and verify flake8 + shell: bash -l {0} + run: | + echo "Installing flake8..." + conda install -c conda-forge flake8 -y + if [ $? -ne 0 ]; then + echo "❌ Failed to install flake8" + exit 1 + fi + flake8 --version + if [ $? -ne 0 ]; then + echo "❌ flake8 verification failed" + exit 1 + fi + echo "✅ flake8 installed and verified" + + - name: Lint with flake8 + shell: bash -l {0} + run: | + echo "Running flake8 checks..." + # Check for syntax errors and undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + if [ $? -ne 0 ]; then + echo "❌ Syntax errors or undefined names found" + exit 1 + fi + echo "✅ Syntax check passed" + + # Run with warnings (exit-zero mode) + echo "Running flake8 with warnings..." + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + echo "✅ Lint check completed" + + - name: Install and verify pytest + shell: bash -l {0} + run: | + echo "Installing pytest and pytest-cov..." + conda install -c conda-forge pytest pytest-cov -y + if [ $? -ne 0 ]; then + echo "❌ Failed to install pytest" + exit 1 + fi + pytest --version + if [ $? -ne 0 ]; then + echo "❌ pytest verification failed" + exit 1 + fi + echo "✅ pytest installed and verified" + + - name: Test with pytest + shell: bash -l {0} + run: | + echo "Running pytest with coverage..." + pytest --cov=braintree_python --cov-report=xml --cov-report=term --cov-fail-under=70 -v + if [ $? -ne 0 ]; then + echo "❌ Tests failed or coverage threshold not met" + exit 1 + fi + echo "✅ All tests passed" + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + if: always() + with: + files: ./coverage.xml + flags: unittests + name: codecov-umbrella-${{ matrix.python-version }} + fail_ci_if_error: false + verbose: true + + - name: Upload security reports + uses: actions/upload-artifact@v3 + if: always() + with: + name: security-reports-py${{ matrix.python-version }} + path: | + bandit-report.json + safety-report.json + retention-days: 30