Skip to content

Commit 7c71f4a

Browse files
authored
Merge branch 'main' into gallery-subcomponents-body
2 parents 5d45d81 + dca15dc commit 7c71f4a

File tree

90 files changed

+4428
-693
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+4428
-693
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Checks
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
workflow_call:
8+
inputs:
9+
save_build_artifact:
10+
description: 'Whether to save the built files as an artifact'
11+
required: false
12+
type: boolean
13+
default: false
14+
secrets:
15+
FASTLY_AB_TESTING_CONFIG:
16+
required: true
17+
FASTLY_API_TOKEN:
18+
required: true
19+
20+
jobs:
21+
checks:
22+
runs-on: ubuntu-latest
23+
defaults:
24+
run:
25+
working-directory: ab-testing
26+
env:
27+
FASTLY_AB_TESTING_CONFIG: ${{ secrets.FASTLY_AB_TESTING_CONFIG }}
28+
FASTLY_API_TOKEN: ${{ secrets.FASTLY_API_TOKEN }}
29+
steps:
30+
- uses: actions/checkout@v4
31+
32+
# https://github.com/denoland/setup-deno#latest-stable-for-a-major
33+
- uses: denoland/setup-deno@v1
34+
with:
35+
deno-version: v2.3
36+
37+
- name: Test
38+
run: deno test
39+
40+
- name: Validate
41+
run: deno run scripts/validation/index.ts
42+
43+
- name: Build
44+
run: deno task build
45+
46+
- if: ${{ inputs.save_build_artifact }}
47+
uses: actions/[email protected]
48+
with:
49+
name: ab-testing-build
50+
path: ab-testing/dist
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: 🧪 AB testing
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
pull_request:
8+
paths:
9+
- 'ab-testing/**'
10+
11+
jobs:
12+
checks:
13+
uses: ./.github/workflows/ab-testing-checks.yml
14+
secrets:
15+
FASTLY_AB_TESTING_CONFIG: ${{ secrets.FASTLY_CODE_AB_TESTING_CONFIG }}
16+
FASTLY_API_TOKEN: ${{ secrets.FASTLY_CODE_API_TOKEN }}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: 🧪 Deploy CODE AB Testing Config
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
workflow_dispatch:
8+
9+
jobs:
10+
ci:
11+
uses: ./.github/workflows/ab-testing-checks.yml
12+
with:
13+
save_build_artifact: true
14+
secrets:
15+
FASTLY_AB_TESTING_CONFIG: ${{ secrets.FASTLY_CODE_AB_TESTING_CONFIG }}
16+
FASTLY_API_TOKEN: ${{ secrets.FASTLY_CODE_API_TOKEN }}
17+
18+
deploy:
19+
name: Deploy CODE
20+
needs: ci
21+
uses: ./.github/workflows/ab-testing-deploy.yml
22+
with:
23+
stage: code
24+
secrets:
25+
FASTLY_AB_TESTING_CONFIG: ${{ secrets.FASTLY_CODE_AB_TESTING_CONFIG }}
26+
FASTLY_API_TOKEN: ${{ secrets.FASTLY_CODE_API_TOKEN }}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: 🧪 Deploy PROD AB Testing Config
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
workflow_dispatch:
8+
# push:
9+
# branches:
10+
# - main
11+
# paths:
12+
# - 'ab-testing/**'
13+
14+
jobs:
15+
ci:
16+
uses: ./.github/workflows/ab-testing-checks.yml
17+
with:
18+
save_build_artifact: true
19+
secrets:
20+
FASTLY_AB_TESTING_CONFIG: ${{ secrets.FASTLY_PROD_AB_TESTING_CONFIG }}
21+
FASTLY_API_TOKEN: ${{ secrets.FASTLY_PROD_API_TOKEN }}
22+
23+
deploy:
24+
name: Deploy PROD
25+
needs: ci
26+
uses: ./.github/workflows/ab-testing-deploy.yml
27+
with:
28+
stage: prod
29+
secrets:
30+
FASTLY_AB_TESTING_CONFIG: ${{ secrets.FASTLY_PROD_AB_TESTING_CONFIG }}
31+
FASTLY_API_TOKEN: ${{ secrets.FASTLY_PROD_API_TOKEN }}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: 🧪 Deploy AB Testing Config
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
workflow_call:
8+
inputs:
9+
stage:
10+
description: 'Stage to deploy to (e.g., code, prod)'
11+
required: true
12+
type: string
13+
secrets:
14+
FASTLY_AB_TESTING_CONFIG:
15+
required: true
16+
FASTLY_API_TOKEN:
17+
required: true
18+
19+
jobs:
20+
deploy:
21+
name: Deploy
22+
runs-on: ubuntu-latest
23+
defaults:
24+
run:
25+
working-directory: ab-testing
26+
steps:
27+
- uses: actions/checkout@v4
28+
29+
# https://github.com/denoland/setup-deno#latest-stable-for-a-major
30+
- uses: denoland/setup-deno@v1
31+
with:
32+
deno-version: v2.3
33+
34+
- name: Download build artifact
35+
uses: actions/[email protected]
36+
with:
37+
name: ab-testing-build
38+
path: ab-testing/dist
39+
40+
- name: Deploy
41+
run: deno run deploy
42+
env:
43+
FASTLY_AB_TESTING_CONFIG: ${{ secrets.FASTLY_AB_TESTING_CONFIG }}
44+
FASTLY_API_TOKEN: ${{ secrets.FASTLY_API_TOKEN }}

.vscode/settings.json.required

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Copy these to .vscode/settings.json to apply them to your editor – but don't commit it!
33
// https://github.com/guardian/recommendations/blob/main/VSCode.md#do-not-commit-vscode
44
{
5-
"deno.enablePaths": ["scripts/deno"],
5+
"deno.enablePaths": ["scripts/deno", "ab-testing/scripts"],
66
"deno.lint": true,
77
"deno.unstable": false,
88
"typescript.tsdk": "node_modules/typescript/lib",

ab-testing/README.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# AB Testing
2+
3+
This directory contains the code and configuration for the AB testing framework used on theguardian.com.
4+
5+
The [`abTest.ts`](./abTest.ts) module is where you should define your AB tests.
6+
7+
Add your AB tests to the `abTests` array in the `abTest.ts` file. Each test should have a unique name.
8+
9+
```ts
10+
{
11+
name: 'webex-example-test',
12+
description:
13+
'Test something interesting on the site',
14+
owners: ['[email protected]'],
15+
status: 'ON',
16+
expirationDate: '2050-12-30',
17+
type: 'client',
18+
audienceSize: 10 / 100,
19+
audienceSpace: 'A',
20+
groups: ['control', 'variant'],
21+
}
22+
```
23+
24+
When you create a PR that modifies the `abTest.ts` file, a git hook and CI will run checks to ensure that your AB test is valid (not expired, enough space for the test etc.).
25+
26+
When your PR is merged, the AB test will be automatically deployed to Fastly and be available at the same time as your changes.
27+
28+
## Guidelines for AB Tests
29+
30+
### Naming Conventions
31+
32+
AB tests should be prefixed with the team associated with the test, for example `webex-example-test`. This helps to identify the team responsible for the test and is enforce by typescript validation.
33+
34+
### Test Size and Groups
35+
36+
The `audienceSize` is the size of the whole test and is divided between the test groups that you specify. The "resolution" of sizing is down to 0.1%, so groups will be rounded to the nearest 0.1%.
37+
38+
Convention is to have groups named control and variant, but you can name them as you wish.
39+
40+
A single group is also possible, for example if you're rolling out a new feature and don't need a control.
41+
42+
### Client vs Server Side Tests
43+
44+
All requests are processed by Fastly at the edge, however, ab testing of server-side logic in Frontend or DCR will need to be cached separately. Client side tests do not need to be cached separately, as they are applied in the browser after the response is delivered.
45+
46+
Ensure that the `type` field is set to either `client` or `server` to indicate the type of test so that server side tests can be cached correctly, and client side tests are not splitting the cache unnecessarily.
47+
48+
There's a limit of the number of concurrent server-side tests that can be run, enforce by the validation script, so it's important to use client-side tests where possible.
49+
50+
### Test Expiration
51+
52+
AB tests should have an expiration date set in the future. This is to ensure that tests do not run indefinitely.
53+
54+
Expired tests will cause the ab testing validation to fail, and will not be deployed.
55+
56+
Tests that expire while they are are in-flight will not be served by fastly, and should be removed from the `abTest.ts` file as soon as possible.
57+
58+
### Audience Spaces
59+
60+
Ideally AB tests would never overlap (users being in multiple tests), but sometimes this is unavoidable, for example when running a very large 50+% test without interrupting existing tests.
61+
62+
To add a test where there is not enough space in the default audience space (`A`), you can specify a different `audienceSpace` in the test definition.
63+
64+
For example if there are already 3 25% tests in space `A` totalling 75%, and you want to run a 50% test, you can set the `audienceSpace` to `B` to allow this test to overlap with the existing tests.
65+
66+
## How it works
67+
68+
The AB testing framework uses Deno to run scripts that validate and deploy the tests. The `deno.json` file contains the tasks that can be run, such as `validate`, `deploy`, and `build`.
69+
70+
Which tests using which mvt ids is computed by the `build` task, which generates the `dist/mvts.json` file. This file contains the mapping of AB tests to MVT IDs.
71+
72+
The algorithm allocates tests available MVT IDs based on the audience size and space. Allocation is deterministic, so the same test (with the same name) will always be assigned the same MVT ID as long as the test hasn't been removed, allowing for consistent user experience when tests are added/updated/removed. This also means that new/update tests will not use contiguous MVT IDs, but will instead use whichever MVT IDs are available.
73+
74+
However, the allocation is completely separate for each audience space, so if you have a test in space `A` and move it to space `B`, it will be allocated different MVT IDs.
75+
76+
The state of the AB tests is stored in Fastly dictionaries, which are updated when the `deploy` task is run. Logic in fastly VCL will then use these dictionaries to determine which users are in which test groups and set appropriate headers and/or cookies.

ab-testing/abTest.ts

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import type { ABTest } from './types';
2222
export const ABTests: ABTest[] = [
2323
// Sample tests that will be used for testing the AB testing framework
2424
{
25-
name: 'commercial-client-side-test',
25+
name: 'commercial-client-side-test-1',
2626
description:
2727
'Show new ad block ask component in ad slots when we detect ad blocker usage',
2828
owners: ['[email protected]'],
@@ -34,7 +34,7 @@ export const ABTests: ABTest[] = [
3434
shouldForceMetricsCollection: true,
3535
},
3636
{
37-
name: 'commercial-server-side-test',
37+
name: 'commercial-server-side-test-1',
3838
description:
3939
'Show new ad block ask component in ad slots when we detect ad blocker usage',
4040
owners: ['[email protected]'],
@@ -45,20 +45,4 @@ export const ABTests: ABTest[] = [
4545
groups: ['control', 'variant'],
4646
shouldForceMetricsCollection: true,
4747
},
48-
{
49-
name: 'commercial-large-overlap-test',
50-
description:
51-
'Allows viewing the beta version of the Europe network front',
52-
owners: [
53-
54-
55-
],
56-
status: 'ON',
57-
expirationDate: '2050-12-30',
58-
type: 'server',
59-
audienceSize: 50 / 100,
60-
groups: ['control', 'variant'],
61-
audienceSpace: 'B',
62-
shouldForceMetricsCollection: true,
63-
},
6448
];

ab-testing/deno.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"tasks": {
3+
"validate": "deno run scripts/validation/index.ts",
4+
"deploy": "deno run --allow-read=dist --allow-env=FASTLY_AB_TESTING_CONFIG,FASTLY_API_TOKEN --allow-net=api.fastly.com:443 scripts/deploy/index.ts --mvts=dist/mvts.json --ab-tests=dist/ab-tests.json",
5+
"build": "deno run --allow-write=dist --allow-env=FASTLY_AB_TESTING_CONFIG,FASTLY_API_TOKEN --allow-net=api.fastly.com:443 scripts/build/index.ts --mvts=dist/mvts.json --ab-tests=dist/ab-tests.json"
6+
},
7+
"imports": {
8+
"@std/assert": "jsr:@std/assert@^1.0.13",
9+
"@superstruct/core": "jsr:@superstruct/[email protected]"
10+
}
11+
}

0 commit comments

Comments
 (0)