diff --git a/.github/workflows/sdk-spec.yml b/.github/workflows/sdk-spec.yml new file mode 100644 index 0000000..6952fea --- /dev/null +++ b/.github/workflows/sdk-spec.yml @@ -0,0 +1,17 @@ +name: SDK spec + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + sdk-spec: + # Keep the ref in `uses:` and `spec-ref` in sync. + uses: Flagsmith/sdk-spec/.github/workflows/run-spec.yml@v0.3.0 + with: + spec-ref: v0.3.0 + language: python diff --git a/renovate.json b/renovate.json index 8bdf036..0ccc024 100644 --- a/renovate.json +++ b/renovate.json @@ -3,6 +3,15 @@ "extends": ["config:recommended", ":semanticCommitScopeDisabled"], "ignorePresets": [":semanticPrefixFixDepsChoreOthers"], "semanticCommitType": "deps", + "customManagers": [ + { + "customType": "regex", + "managerFilePatterns": ["/^\\.github/workflows/sdk-spec\\.yml$/"], + "matchStrings": ["spec-ref: (?v[\\d.]+)"], + "depNameTemplate": "Flagsmith/sdk-spec", + "datasourceTemplate": "github-tags" + } + ], "packageRules": [ { "matchManagers": ["pip_requirements", "pip-compile", "pep621", "poetry", "github-actions"], @@ -22,6 +31,11 @@ { "matchPackageNames": ["flagsmith-flag-engine"], "enabled": true + }, + { + "matchPackageNames": ["Flagsmith/sdk-spec"], + "groupName": "SDK spec", + "enabled": true } ] } diff --git a/sdk-spec/Dockerfile b/sdk-spec/Dockerfile new file mode 100644 index 0000000..d565079 --- /dev/null +++ b/sdk-spec/Dockerfile @@ -0,0 +1,13 @@ +# Runs this SDK, built from source, under the Flagsmith SDK behavioural spec. +# docker build -f sdk-spec/Dockerfile --build-context harness=/harness/python . +FROM python:3.12-slim + +WORKDIR /sdk +COPY pyproject.toml poetry.lock README.md ./ +COPY flagsmith ./flagsmith +RUN pip install --no-cache-dir . + +COPY --from=harness harness.py /harness/harness.py +COPY sdk-spec/steps.py ./sdk-spec/steps.py + +ENTRYPOINT ["python", "/harness/harness.py", "sdk-spec/steps.py"] diff --git a/sdk-spec/steps.py b/sdk-spec/steps.py new file mode 100644 index 0000000..5cd373d --- /dev/null +++ b/sdk-spec/steps.py @@ -0,0 +1,37 @@ +""" +Steps for the Flagsmith SDK behavioural spec: https://github.com/Flagsmith/sdk-spec + +Each function implements the Gherkin step in the comment above it. +""" + +import typing + +from flagsmith import Flagsmith +from flagsmith.models import Flags +from flagsmith.types import TraitMapping + +SpecFlag = dict[str, typing.Any] + + +def as_spec_flags(flags: Flags) -> list[SpecFlag]: + return [ + {"feature": flag.feature_name, "enabled": flag.enabled, "value": flag.value} + for flag in flags.all_flags() + ] + + +# Create the SDK client +def create_client(environment_key: str, api_url: str) -> Flagsmith: + return Flagsmith(environment_key=environment_key, api_url=api_url) + + +# When the application gets the environment flags +def get_environment_flags(flagsmith: Flagsmith) -> list[SpecFlag]: + return as_spec_flags(flagsmith.get_environment_flags()) + + +# When the application gets the flags for identity "{identifier}" with traits: +def get_identity_flags( + flagsmith: Flagsmith, identifier: str, traits: TraitMapping +) -> list[SpecFlag]: + return as_spec_flags(flagsmith.get_identity_flags(identifier, traits=traits))