Skip to content

Commit fda80a1

Browse files
committed
feat(ci): split nix build workflow into separate extensions and checks jobs
Split the monolithic nix-build job into two workflows: one for building PostgreSQL extensions and another for checks. Building extensions can be resource-intensive and time-consuming, so isolating them allows for better resource allocation and parallelism. Once they are built, the checks job can run tests and validations on the already built extensions.
1 parent 07b2be4 commit fda80a1

File tree

3 files changed

+114
-25
lines changed

3 files changed

+114
-25
lines changed

.github/workflows/nix-build.yml

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ permissions:
1515
packages: write
1616

1717
jobs:
18-
nix-matrix:
18+
extensions-matrix:
1919
runs-on:
2020
group: self-hosted-runners-nix
2121
labels:
@@ -29,15 +29,74 @@ jobs:
2929
name: Generate Nix Matrix
3030
run: |
3131
set -Eeu
32-
echo matrix="$(python scripts/github-matrix.py)" >> "$GITHUB_OUTPUT"
32+
echo matrix="$(python scripts/github-matrix.py extensions)" >> "$GITHUB_OUTPUT"
3333
34-
build-run-image:
34+
build-extensions:
35+
name: ${{matrix.postgresql_version}}.${{ matrix.name }} (${{ matrix.system }})
36+
needs: extensions-matrix
37+
runs-on: ${{ matrix.runs_on.group && matrix.runs_on || matrix.runs_on.labels }}
38+
strategy:
39+
fail-fast: false
40+
max-parallel: 3
41+
matrix: ${{fromJSON(needs.extensions-matrix.outputs.matrix)}}
42+
steps:
43+
- name: Checkout Repo
44+
uses: actions/checkout@v4
45+
- name: aws-oidc
46+
uses: aws-actions/[email protected]
47+
with:
48+
aws-region: us-east-2
49+
role-to-assume: arn:aws:iam::279559813984:role/supabase-github-oidc-role # Shared Services
50+
role-session-name: gha-oidc-${{ github.run_id }}
51+
- name: aws-creds
52+
uses: aws-actions/[email protected]
53+
with:
54+
disable-retry: true
55+
aws-region: us-east-2
56+
role-to-assume: arn:aws:iam::436098097459:role/nix-artifacts-deploy-role # supabase-dev
57+
role-session-name: gha-oidc-${{ github.run_id }}
58+
role-chaining: true
59+
role-skip-session-tagging: true
60+
role-duration-seconds: 3600
61+
- name: Write creds files
62+
run: |
63+
umask 006
64+
cat > /etc/nix/aws/nix-aws-credentials <<EOF
65+
[ci-uploader]
66+
aws_access_key_id = ${AWS_ACCESS_KEY_ID}
67+
aws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}
68+
aws_session_token = ${AWS_SESSION_TOKEN}
69+
EOF
70+
- name: nix build
71+
run: |
72+
nix build -L .#${{ matrix.attr }}
73+
74+
75+
checks-matrix:
76+
needs: [build-extensions]
77+
runs-on:
78+
group: self-hosted-runners-nix
79+
labels:
80+
- aarch64-darwin
81+
outputs:
82+
matrix: ${{ steps.set-matrix.outputs.matrix }}
83+
steps:
84+
- name: Checkout Repo
85+
uses: actions/checkout@v4
86+
- id: set-matrix
87+
name: Generate Nix Matrix
88+
run: |
89+
set -Eeu
90+
echo matrix="$(python scripts/github-matrix.py checks)" >> "$GITHUB_OUTPUT"
91+
92+
93+
build-checks:
3594
name: ${{ matrix.name }} (${{ matrix.system }})
36-
needs: nix-matrix
95+
needs: [checks-matrix, build-extensions]
3796
runs-on: ${{ matrix.runs_on.group && matrix.runs_on || matrix.runs_on.labels }}
3897
strategy:
3998
fail-fast: false
40-
matrix: ${{fromJSON(needs.nix-matrix.outputs.matrix)}}
99+
matrix: ${{fromJSON(needs.checks-matrix.outputs.matrix)}}
41100
steps:
42101
- name: Checkout Repo
43102
uses: actions/checkout@v4
@@ -56,7 +115,7 @@ jobs:
56115
role-session-name: gha-oidc-${{ github.run_id }}
57116
role-chaining: true
58117
role-skip-session-tagging: true
59-
role-duration-seconds: 900 # TODO: switch to 18000 (5 hours)
118+
role-duration-seconds: 3600
60119
- name: Write creds files
61120
run: |
62121
umask 006
@@ -68,13 +127,9 @@ jobs:
68127
EOF
69128
- name: nix build
70129
run: |
71-
if ${{ matrix.already_cached }}; then
72-
echo "${{ matrix.attr }} already cached, skipping build"
73-
exit 0
74-
fi
75130
nix build -L .#${{ matrix.attr }}
76131
77132
run-tests:
78-
needs: build-run-image
133+
needs: build-checks
79134
if: ${{ success() }}
80135
uses: ./.github/workflows/test.yml

nix/packages/postgres.nix

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{ self, inputs, ... }:
22
{
33
perSystem =
4-
{ pkgs, ... }:
4+
{ pkgs, lib, ... }:
55
let
66
gitRev = "vcs=${self.shortRev or "dirty"}+${
77
builtins.substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101")
@@ -158,10 +158,9 @@
158158
# install.
159159
# - exts: an attrset containing all the extensions, mapped to their
160160
# package names.
161-
makePostgres = version: {
161+
makePostgres = version: lib.recurseIntoAttrs {
162162
bin = makePostgresBin version;
163163
exts = makeOurPostgresPkgsSet version;
164-
recurseForDerivations = true;
165164
};
166165
basePackages = {
167166
psql_15 = makePostgres "15";
@@ -171,5 +170,6 @@
171170
in
172171
{
173172
packages = inputs.flake-utils.lib.flattenTree basePackages;
173+
legacyPackages = basePackages;
174174
};
175175
}

scripts/github-matrix.py

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env python3
22

3+
import argparse
34
import json
45
import os
56
import subprocess
@@ -47,6 +48,7 @@ class GitHubActionPackage(TypedDict):
4748
system: str
4849
already_cached: bool
4950
runs_on: RunsOnConfig
51+
postgresql_version: NotRequired[str]
5052

5153

5254
BUILD_RUNNER_MAP: Dict[str, RunsOnConfig] = {
@@ -76,22 +78,23 @@ def get_worker_count() -> int:
7678
return 1
7779

7880

79-
def build_nix_eval_command(max_workers: int) -> List[str]:
81+
def build_nix_eval_command(max_workers: int, target: str) -> List[str]:
8082
"""Build the nix-eval-jobs command with appropriate flags."""
81-
return [
83+
nix_eval_cmd = [
8284
"nix-eval-jobs",
8385
"--flake",
84-
".#checks",
86+
f".#{target}",
8587
"--check-cache-status",
8688
"--force-recurse",
8789
"--quiet",
8890
"--workers",
8991
str(max_workers),
9092
]
93+
return nix_eval_cmd
9194

9295

9396
def parse_nix_eval_line(
94-
line: str, drv_paths: Set[str]
97+
line: str, drv_paths: Set[str], target: str
9598
) -> Optional[GitHubActionPackage]:
9699
"""Parse a single line of nix-eval-jobs output"""
97100
if not line.strip():
@@ -102,12 +105,11 @@ def parse_nix_eval_line(
102105
if data["drvPath"] in drv_paths:
103106
return None
104107
drv_paths.add(data["drvPath"])
105-
print(f"Processing package: {data}", file=sys.stderr)
106108

107109
runs_on_config = BUILD_RUNNER_MAP[data["system"]]
108110

109111
return {
110-
"attr": "checks." + data["attr"],
112+
"attr": f"{target}.{data['attr']}",
111113
"name": data["name"],
112114
"system": data["system"],
113115
"already_cached": data.get("cacheStatus") != "notBuilt",
@@ -118,7 +120,9 @@ def parse_nix_eval_line(
118120
return None
119121

120122

121-
def run_nix_eval_jobs(cmd: List[str]) -> Generator[GitHubActionPackage, None, None]:
123+
def run_nix_eval_jobs(
124+
cmd: List[str], target: str
125+
) -> Generator[GitHubActionPackage, None, None]:
122126
"""Run nix-eval-jobs and yield parsed package data."""
123127
print(f"Running command: {' '.join(cmd)}", file=sys.stderr)
124128

@@ -128,8 +132,8 @@ def run_nix_eval_jobs(cmd: List[str]) -> Generator[GitHubActionPackage, None, No
128132
drv_paths = set()
129133

130134
for line in process.stdout:
131-
package = parse_nix_eval_line(line, drv_paths)
132-
if package:
135+
package = parse_nix_eval_line(line, drv_paths, target)
136+
if package and not package["already_cached"]:
133137
yield package
134138

135139
if process.returncode and process.returncode != 0:
@@ -138,11 +142,41 @@ def run_nix_eval_jobs(cmd: List[str]) -> Generator[GitHubActionPackage, None, No
138142
sys.exit(process.returncode)
139143

140144

145+
def is_extension_pkg(pkg: GitHubActionPackage) -> bool:
146+
"""Check if the package is a postgresql extension package."""
147+
attrs = pkg["attr"].split(".")
148+
return attrs[-2] == "exts"
149+
150+
141151
def main() -> None:
152+
parser = argparse.ArgumentParser(
153+
description="Generate GitHub Actions matrix for Nix builds"
154+
)
155+
parser.add_argument(
156+
"target", choices=["checks", "extensions"], help="Type of matrix to generate"
157+
)
158+
159+
args = parser.parse_args()
160+
142161
max_workers = get_worker_count()
143-
cmd = build_nix_eval_command(max_workers)
144162

145-
gh_action_packages = list(run_nix_eval_jobs(cmd))
163+
if args.target == "checks":
164+
flake_output = "checks"
165+
else:
166+
flake_output = "legacyPackages"
167+
168+
cmd = build_nix_eval_command(max_workers, flake_output)
169+
170+
gh_action_packages = list(run_nix_eval_jobs(cmd, flake_output))
171+
172+
if args.target == "extensions":
173+
# filter to only include extension packages and add postgresql_version field
174+
gh_action_packages = [
175+
{**pkg, "postgresql_version": pkg["attr"].split(".")[-3]}
176+
for pkg in gh_action_packages
177+
if is_extension_pkg(pkg)
178+
]
179+
146180
gh_output = {"include": gh_action_packages}
147181
print(json.dumps(gh_output))
148182

0 commit comments

Comments
 (0)