-
Notifications
You must be signed in to change notification settings - Fork 10
/
action.nix
140 lines (133 loc) · 5.51 KB
/
action.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
{ lib }:
with builtins; with lib; let
stepCommitToInitiallyCheckout = {
name = "Determine which commit to initially checkout";
run = ''
if [ ''${{ github.event_name }} = "push" ]; then
echo "target_commit=''${{ github.sha }}" >> $GITHUB_ENV
else
echo "target_commit=''${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV
fi
'';
};
stepCheckout1 = {
name = "Git checkout";
uses = "actions/checkout@v4";
"with" = {
fetch-depth = 0;
ref = "\${{ env.target_commit }}";
};
};
stepCommitToTest = {
name = "Determine which commit to test";
run = ''
if [ ''${{ github.event_name }} = "push" ]; then
echo "tested_commit=''${{ github.sha }}" >> $GITHUB_ENV
else
merge_commit=$(git ls-remote ''${{ github.event.repository.html_url }} refs/pull/''${{ github.event.number }}/merge | cut -f1)
mergeable=$(git merge --no-commit --no-ff ''${{ github.event.pull_request.base.sha }} > /dev/null 2>&1; echo $?; git merge --abort > /dev/null 2>&1 || true)
if [ -z "$merge_commit" -o "x$mergeable" != "x0" ]; then
echo "tested_commit=''${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV
else
echo "tested_commit=$merge_commit" >> $GITHUB_ENV
fi
fi
'';
};
stepCheckout2 = {
name = "Git checkout";
uses = "actions/checkout@v4";
"with" = {
fetch-depth = 0;
ref = "\${{ env.tested_commit }}";
};
};
stepCachixInstall = {
name = "Cachix install";
uses = "cachix/install-nix-action@v27";
"with".nix_path = "nixpkgs=channel:nixpkgs-unstable";
};
stepCachixUse = { name, authToken ? null,
signingKey ? null, extraPullNames ? null }: {
name = "Cachix setup ${name}";
uses = "cachix/cachix-action@v15";
"with" = { inherit name; } //
(optionalAttrs (!isNull authToken) {
authToken = "\${{ secrets.${authToken} }}";
}) // (optionalAttrs (!isNull signingKey) {
signingKey = "\${{ secrets.${signingKey} }}";
}) // (optionalAttrs (!isNull extraPullNames) {
extraPullNames = concatStringsSep ", " extraPullNames;
});
};
stepCachixUseAll = cachixAttrs: let
cachixList = attrValues
(mapAttrs (name: v: {inherit name;} // v) cachixAttrs); in
if cachixList == [] then [] else let
writableAuth = filter (v: v?authToken) cachixList;
writableToken = filter (v: v?signingKey) cachixList;
readonly = filter (v: !v?authToken && !v?signingKey) cachixList;
reordered = writableAuth ++ writableToken ++ readonly;
in
if length writableToken + length writableAuth > 1 then
throw ("Cannot have more than one authToken " +
"or signingKey over all cachix")
else [ (stepCachixUse (head reordered // {
extraPullNames = map (v: v.name) (tail reordered);
})) ];
stepCheck = { job, bundles ? [] }:
let bundlestr = if isList bundles then "\${{ matrix.bundle }}" else bundles; in {
name = "Checking presence of CI target ${job}";
id = "stepCheck";
run = ''
nb_dry_run=$(NIXPKGS_ALLOW_UNFREE=1 nix-build --no-out-link \
--argstr bundle "${bundlestr}" --argstr job "${job}" \
--dry-run 2>&1 > /dev/null)
echo $nb_dry_run
echo status=$(echo $nb_dry_run | grep "built:" | sed "s/.*/built/") >> $GITHUB_OUTPUT
'';
};
stepBuild = {job, bundles ? [], current ? false}:
let bundlestr = if isList bundles then "\${{ matrix.bundle }}" else bundles; in {
name = if current then "Building/fetching current CI target"
else "Building/fetching previous CI target: ${job}";
"if" = "steps.stepCheck.outputs.status == 'built'";
run = "NIXPKGS_ALLOW_UNFREE=1 nix-build --no-out-link --argstr bundle \"${bundlestr}\" --argstr job \"${job}\"";
};
mkJob = { job, jobs ? [], bundles ? [], deps ? {}, cachix ? {}, suffix ? false }:
let
suffixStr = optionalString (suffix && isString bundles) "-${bundles}";
jdeps = deps.${job} or [];
in {
"${job}${suffixStr}" = rec {
runs-on = "ubuntu-latest";
needs = map (j: "${j}${suffixStr}") (filter (j: elem j jobs) jdeps);
steps = [ stepCommitToInitiallyCheckout stepCheckout1
stepCommitToTest stepCheckout2 stepCachixInstall ]
++ (stepCachixUseAll cachix)
++ [ (stepCheck { inherit job bundles; }) ]
++ (map (job: stepBuild { inherit job bundles; }) jdeps)
++ [ (stepBuild { inherit job bundles; current = true; }) ];
} // (optionalAttrs (isList bundles) {strategy.matrix.bundle = bundles;});
};
mkJobs = { jobs ? [], bundles ? [], deps ? {}, cachix ? {}, suffix ? false }@args:
foldl (action: job: action // (mkJob ({ inherit job; } // args))) {} jobs;
mkActionFromJobs = { actionJobs, bundles ? [], push-branches ? [] }:
let
workflow_path = ".github/workflows/nix-action-${toString bundles}.yml";
in {
name = "Nix CI for bundle ${toString bundles}";
on = {
push.branches = push-branches;
pull_request.paths = [ workflow_path ];
pull_request_target = {
types = [ "opened" "synchronize" "reopened" ];
paths-ignore = [ workflow_path ];
};
};
jobs = actionJobs;
};
mkAction = { jobs ? [], bundles ? [], deps ? {}, cachix ? {} }@args:
{ push-branches ? [] }:
mkActionFromJobs {inherit bundles push-branches; actionJobs = mkJobs args; };
in { inherit mkJob mkJobs mkAction; }