Skip to content

Commit 0d3a5b9

Browse files
authored
Merge pull request #1371 from NHSDigital/spike-open-feature
Implement 'open feature' feature flagging
2 parents a29423f + 8531d32 commit 0d3a5b9

21 files changed

Lines changed: 246 additions & 8 deletions

File tree

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ COPY --from=python_builder --chown=${CONTAINER_USER}:${CONTAINER_GROUP} ${VIRTUA
5353
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} ./manage_breast_screening /app/manage_breast_screening
5454
COPY --from=node_builder --chown=${CONTAINER_USER}:${CONTAINER_GROUP} /app/manage_breast_screening/assets/compiled /app/manage_breast_screening/assets/compiled
5555
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} manage.py ./
56+
COPY --chown=${CONTAINER_USER}:${CONTAINER_GROUP} --chmod=444 flags*.yml ./
5657
COPY --chown=root:root --chmod=755 scripts/docker/entrypoint.sh /app/entrypoint.sh
5758

5859
# Run django commands

docs/feature-flags.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Feature flags
2+
3+
Feature flags are implemented using [OpenFeature](https://openfeature.dev/) with an `InMemoryProvider`. Flags are declared in YAML files and loaded at startup.
4+
5+
## Flag files
6+
7+
Each environment has its own flag file. The application selects the file based on the `DEPLOYED_TO` environment variable, falling back to `flags.yml` for local development where `DEPLOYED_TO` is not set.
8+
9+
| Environment | File |
10+
| ---------------------------- | ---------------------- |
11+
| dev | `flags.dev.yml` |
12+
| review | `flags.review.yml` |
13+
| preprod | `flags.preprod.yml` |
14+
| production | `flags.production.yml` |
15+
| local (no `DEPLOYED_TO` set) | `flags.yml` |
16+
17+
## Adding a flag
18+
19+
**1. Declare the flag in each environment's file.**
20+
21+
Add an entry to all five flag files (`flags.yml`, `flags.dev.yml`, `flags.review.yml`, `flags.preprod.yml`, `flags.production.yml`). Set the value to `true` to enable or `false` to disable in that environment.
22+
23+
```yaml
24+
flags:
25+
my_flag: false
26+
```
27+
28+
**2. Check the flag in application code.**
29+
30+
```python
31+
from manage_breast_screening.core.feature_flags import FeatureFlag
32+
33+
if FeatureFlag.is_enabled("my_flag"):
34+
# feature is enabled
35+
```
36+
37+
`FeatureFlag.is_enabled` returns `False` if the flag is missing or the provider is unavailable. If a flag name is not found in the YAML file, OpenFeature silently returns the fallback rather than raising an error — so a typo in a flag name will return `False` without any indication something is wrong.
38+
39+
## Enabling a flag in tests
40+
41+
Use the `with_flag_enabled` fixture to turn a flag on for the duration of a single test:
42+
43+
```python
44+
def test_something(with_flag_enabled):
45+
with_flag_enabled("my_flag")
46+
# flag is enabled for this test only
47+
```
48+
49+
Multiple flags can be enabled by calling it more than once:
50+
51+
```python
52+
def test_something(with_flag_enabled):
53+
with_flag_enabled("my_flag")
54+
with_flag_enabled("another_flag")
55+
```
56+
57+
In class-based tests the fixture must be relayed via an `autouse` fixture so it is accessible to helper methods:
58+
59+
```python
60+
@pytest.fixture(autouse=True)
61+
def flags(self, with_flag_enabled):
62+
self.with_flag_enabled = with_flag_enabled
63+
64+
def and_my_flag_is_enabled(self):
65+
self.with_flag_enabled("my_flag")
66+
```
67+
68+
After each test the flags are reset to the defaults from the YAML file.

docs/infrastructure/environment-variables.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,17 @@ Postgres server port. Defaults to 5432. Required for review apps as each databas
114114

115115
Database server admin user name. When using a managed identity, name of the managed identity.
116116

117+
## DEPLOYED_TO
118+
119+
Describes the environment the application is running in.
120+
121+
**Values:**
122+
123+
- `dev`
124+
- `review`
125+
- `preprod`
126+
- `production`
127+
117128
## DJANGO_ENV
118129

119130
Specifies the Django environment configuration. This variable controls environment-specific behaviour throughout the application. It's primarily for ensuring non-production code is not run or made available in production.

flags.dev.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flags:
2+
gateway_images: false

flags.preprod.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flags:
2+
gateway_images: false

flags.production.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flags:
2+
gateway_images: false

flags.review.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flags:
2+
gateway_images: false

flags.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flags:
2+
gateway_images: false

infrastructure/environments/dev/variables.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
DEPLOYED_TO: dev
12
BASE_URL: https://dev.manage-breast-screening.non-live.screening.nhs.uk
23
BASIC_AUTH_ENABLED: True
34
CIS2_SERVER_METADATA_URL: https://am.nhsint.auth-ptl.cis2.spineservices.nhs.uk/openam/oauth2/realms/root/realms/NHSIdentity/realms/Healthcare/.well-known/openid-configuration

infrastructure/environments/preprod/variables.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
DEPLOYED_TO: preprod
12
BASE_URL: https://preprod.manage-breast-screening.nhs.uk
23
BASIC_AUTH_ENABLED: True
34
CIS2_SERVER_METADATA_URL: https://am.nhsint.auth-ptl.cis2.spineservices.nhs.uk/openam/oauth2/realms/root/realms/NHSIdentity/realms/Healthcare/.well-known/openid-configuration

0 commit comments

Comments
 (0)