Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 7 additions & 18 deletions .github/workflows/pr-build-merge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,30 +38,30 @@ jobs:
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
cache-dependency-glob: "backend/uv.lock"

- name: Install Python
uses: actions/setup-python@v5
with:
python-version-file: ".python-version"
python-version-file: "backend/.python-version"

- name: Install the project dependancies
run: uv sync --all-extras --dev
run: uv --project backend sync --all-extras --dev

- name: Create the .env file
run: cp env.example .env

- name: Run formatting checks
run: uv run ruff format --check --diff .
run: uv --project backend run ruff --config backend/pyproject.toml format --check --diff backend

- name: Run linting
run: uv run ruff check .
run: uv --project backend run ruff --config backend/pyproject.toml check backend

- name: Run security checks
run: uv run bandit -c pyproject.toml -r . -f json -o bandit.json
run: uv --project backend run bandit -c backend/pyproject.toml -r backend -f json -o bandit.json

- name: Run tests
run: uv run pytest
run: uv --project backend run pytest --rootdir=backend -c backend/pyproject.toml backend
env:
FFC_EXT_POSTGRES_HOST: localhost
FFC_EXT_POSTGRES_PORT: 5432
Expand Down Expand Up @@ -122,14 +122,3 @@ jobs:
name: coverage-report
path: htmlcov
retention-days: 10

- name: Generate openapi.json
run: uv run ffcops openapi -f json -o openapi.json

- name: Save openapi.json the artefacts
uses: actions/upload-artifact@v4
if: ${{ !env.ACT }}
with:
name: openapi-spec
path: openapi.json
retention-days: 10
6 changes: 4 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ repos:
hooks:
- id: ruff
args:
- --config
- backend/pyproject.toml
- --fix
- id: ruff-format
- repo: https://github.com/PyCQA/bandit
Expand All @@ -24,6 +26,6 @@ repos:
- id: bandit
args:
- -c
- pyproject.toml
- backend/pyproject.toml
- -r
- .
- backend/
2 changes: 1 addition & 1 deletion LICENSE.txt → LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2024 - SoftwareOne AG
Copyright 2026 - SoftwareOne AG

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
17 changes: 11 additions & 6 deletions pyproject.toml → backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
name = "ffc-extension"
version = "0.1.0"
description = "SWO FinOps For Cloud Extension API"
readme = { file = "README.md", content-type = "text/markdown" }
readme = { file = "../README.md", content-type = "text/markdown" }
authors = [
{ name = "SoftwareOne AG" },
]
license = { file = "LICENSE.txt" }
license = { file = "../LICENSE" }
requires-python = ">=3.12,<4"
dependencies = [
"alembic>=1.14.1,<2",
Expand Down Expand Up @@ -88,17 +88,22 @@ package = true
preview = true
add-bounds = "major"

[tool.setuptools]
py-modules = ["app"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["app"]

[tool.ruff]
line-length = 100
target-version = "py312"
output-format = "full"
extend-exclude = [
"migrations/versions/",
"migrations",
"migrations/versions",
]
cache-dir = ".cache/ruff"
cache-dir = "../.cache/ruff"

[tool.ruff.lint]
preview = true # enable linting rules in preview (e.g. RUF029 as of 2025-02-20)
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
from uuid import uuid4

import pytest
from fastapi import HTTPException, status
from httpx import AsyncClient
from pytest_mock import MockerFixture
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.db.handlers import NotFoundError
from app.db.models import Account, AccountUser, System, User
from app.dependencies.db import AccountRepository
Expand All @@ -18,6 +12,12 @@
validate_required_conditions_before_update,
)
from app.schemas.accounts import AccountCreate
from fastapi import HTTPException, status
from httpx import AsyncClient
from pytest_mock import MockerFixture
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from tests.types import ModelFactory


Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import logging

from _pytest.logging import LogCaptureFixture
from httpx import AsyncClient
from pytest_httpx import HTTPXMock

from app import Settings
from app.db.models import Organization
from app.enums import OrganizationStatus
from httpx import AsyncClient
from pytest_httpx import HTTPXMock

from tests.types import ModelFactory

FAKE_USER_ID = "1bf6f063-d90b-4d45-8e7f-62fefa9f5471"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
from typing import Any

import pytest
from httpx import AsyncClient
from pytest_httpx import HTTPXMock

from app.conf import Settings
from app.db.models import Organization
from app.enums import DatasourceType
from httpx import AsyncClient
from pytest_httpx import HTTPXMock

from tests.types import ModelFactory

# ===========================
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import uuid

from app.conf import Settings
from app.db.models import Organization
from httpx import AsyncClient
from pytest_httpx import HTTPXMock
from pytest_mock import MockerFixture

from app.conf import Settings
from app.db.models import Organization
from tests.types import ModelFactory


Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from datetime import UTC, datetime

import pytest
from app.conf import Settings
from app.db.models import Account, Entitlement, System
from app.enums import AccountStatus, DatasourceType, EntitlementStatus, OrganizationStatus
from httpx import AsyncClient
from pytest_httpx import HTTPXMock
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.conf import Settings
from app.db.models import Account, Entitlement, System
from app.enums import AccountStatus, DatasourceType, EntitlementStatus, OrganizationStatus
from tests.types import ModelFactory

# ====================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
from decimal import Decimal

import pytest
from app.db.models import DatasourceExpense, Organization
from app.enums import DatasourceType, OrganizationStatus
from faker import Faker
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

from app.db.models import DatasourceExpense, Organization
from app.enums import DatasourceType, OrganizationStatus
from tests.types import ModelFactory


Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import pytest
from app.conf import Settings
from app.db.models import Organization, System
from app.enums import OrganizationStatus
from httpx import AsyncClient
from pytest_httpx import HTTPXMock
from pytest_mock import MockerFixture
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.conf import Settings
from app.db.models import Organization, System
from app.enums import OrganizationStatus
from tests.types import ModelFactory

# =================
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pytest
from pytest_mock import MockerFixture

from app.conf import Settings
from pytest_mock import MockerFixture


@pytest.fixture(autouse=True)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import pytest
from sqlalchemy.ext.asyncio import AsyncSession

from app.commands.calculate_accounts_stats import calculate_accounts_stats
from app.conf import Settings
from app.enums import AccountStatus, EntitlementStatus
from sqlalchemy.ext.asyncio import AsyncSession


@pytest.mark.parametrize(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

import pytest
import time_machine
from app.cli import app
from app.commands import cleanup_obsolete_datasource_expenses
from app.conf import Settings
from app.db.models import DatasourceExpense, Organization
from pytest_mock import MockerFixture
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from typer.testing import CliRunner

from app.cli import app
from app.commands import cleanup_obsolete_datasource_expenses
from app.conf import Settings
from app.db.models import DatasourceExpense, Organization
from tests.types import ModelFactory


Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import pytest
from pytest_mock import MockerFixture
from sqlalchemy.ext.asyncio import AsyncSession
from typer.testing import CliRunner

from app.cli import app
from app.commands.create_admin_account import create_admin_account
from app.conf import Settings
from app.db.handlers import AccountHandler
from app.db.models import Account
from app.enums import AccountStatus, AccountType
from pytest_mock import MockerFixture
from sqlalchemy.ext.asyncio import AsyncSession
from typer.testing import CliRunner


async def test_create_admin_account(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@

import pytest
import time_machine
from fastapi import status
from pytest_httpx import HTTPXMock
from pytest_mock import MockerFixture
from sqlalchemy.ext.asyncio import AsyncSession
from typer.testing import CliRunner

from app.cli import app
from app.commands import fetch_datasource_expenses
from app.conf import Settings
from app.db.handlers import DatasourceExpenseHandler
from app.db.models import DatasourceExpense, Organization
from app.enums import DatasourceType, OrganizationStatus
from fastapi import status
from pytest_httpx import HTTPXMock
from pytest_mock import MockerFixture
from sqlalchemy.ext.asyncio import AsyncSession
from typer.testing import CliRunner

from tests.fixtures.mock_api_clients import MockOptscaleClient
from tests.types import ModelFactory

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from pathlib import Path

import yaml
from app.cli import app
from pytest_mock import MockerFixture
from typer.testing import CliRunner

from app.cli import app


def test_openapi(mocker: MockerFixture):
spec = {"test": "openapi"}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@

import pytest
import time_machine
from httpx import HTTPStatusError, ReadTimeout
from pytest_httpx import HTTPXMock
from pytest_mock import MockerFixture
from sqlalchemy.ext.asyncio import AsyncSession
from typer.testing import CliRunner

from app.cli import app
from app.commands.redeem_entitlements import fetch_datasources_for_organization, redeem_entitlements
from app.conf import Settings
from app.db.models import Entitlement, Organization
from app.enums import DatasourceType, EntitlementStatus
from app.notifications import ColumnHeader
from httpx import HTTPStatusError, ReadTimeout
from pytest_httpx import HTTPXMock
from pytest_mock import MockerFixture
from sqlalchemy.ext.asyncio import AsyncSession
from typer.testing import CliRunner


@time_machine.travel("2025-03-07T10:00:00Z", tick=False)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from app.cli import app
from pytest_mock import MockerFixture
from typer.testing import CliRunner

from app.cli import app


def test_serve(mocker: MockerFixture):
mocked_settings = mocker.MagicMock()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from app.cli import app
from pytest_mock import MockerFixture
from typer.testing import CliRunner

from app.cli import app


def test_shell(mocker: MockerFixture):
mocked_ishell = mocker.patch("app.commands.shell.InteractiveShellEmbed")
Expand Down
Loading
Loading