@@ -4,16 +4,14 @@ import mcl.utils.env : optional, parseEnv;
44import mcl.utils.nix : nix;
55import mcl.utils.path : getTopLevel;
66import mcl.utils.process : execute;
7+ import mcl.utils.log : errorAndExit;
78
8- import std.typecons : Tuple , tuple;
9- import std.file : mkdirRecurse, exists, rmdirRecurse;
10- import std.format : fmt = format;
11- import std.stdio ;
12- import std.json : JSONValue, parseJSON, JSONOptions;
9+ import std.json : JSONValue;
1310import std.file : write;
14- import std.logger : tracef, errorf, infof;
15- import std.process : environment;
16- import mcl.utils.log : errorAndExit;
11+ import std.logger : infof;
12+ import std.algorithm : uniq;
13+ import std.array ;
14+ import std.meta : Filter;
1715
1816struct Params
1917{
@@ -26,27 +24,58 @@ struct Params
2624 }
2725}
2826
27+ enum ChangeStatus{
28+ Unchanged,
29+ Changed,
30+ Removed,
31+ New
32+ }
33+
2934struct MachineChanges {
3035 string machine;
31- bool _config;
32- bool _create;
36+ ChangeStatus _config;
37+ ChangeStatus _create;
38+ }
39+
40+ enum string [] diskoOptions = [ __traits(allMembers, MachineChanges)[1 .. $] ];
41+
42+ string statusToSymbol (ChangeStatus s) {
43+ final switch (s){
44+ case ChangeStatus.Unchanged:
45+ return " 🟩" ;
46+ break ;
47+ case ChangeStatus.Changed:
48+ return " ⚡" ;
49+ break ;
50+ case ChangeStatus.Removed:
51+ return " 🗑" ;
52+ break ;
53+ case ChangeStatus.New:
54+ return " 🧩" ;
55+ break ;
56+ }
3357}
3458
3559// TODO: handle case where a machine is missing from one branch
3660export void compare_disko (string [] args){
37- nix.eval! JSONValue(" " , [], " " );
3861 const params = parseEnv! Params;
62+
3963 JSONValue configurations = nix.flake! JSONValue(" " , [], " show" );
40- string [] machines;
64+
65+ string [] machinesNew;
4166 foreach (string k, JSONValue v; configurations[" nixosConfigurations" ]){
4267 if (k[$- 3 .. $] != " -vm" &&
4368 k != " gitlab-runner-container" &&
4469 k != " minimal-container" )
4570 {
46- machines ~= k;
71+ machinesNew ~= k;
4772 }
4873 }
4974
75+ auto attr = constructCommandAttr(" ./." , machinesNew);
76+ auto machineOptionsRootNew = nix.eval! JSONValue(" " , [" --impure" , " --expr" , attr]);
77+
78+
5079 string gitRoot = getTopLevel();
5180 string worktreeBaseBranch = gitRoot~ " -" ~ params.baseBranch;
5281
@@ -55,65 +84,55 @@ export void compare_disko(string[] args){
5584 }
5685
5786 execute([" git" , " worktree" , " add" , worktreeBaseBranch, params.baseBranch]);
58- string freshTestsDir = gitRoot~ " /disko-tests" ;
59- string staleTestsDir = worktreeBaseBranch~ " /disko-tests" ;
60- mkdirRecurse(staleTestsDir);
61- mkdirRecurse(freshTestsDir);
6287
63- Tuple ! (string , string )[] machineDiffs;
88+ configurations = nix.flake! JSONValue(worktreeBaseBranch, [], " show" );
89+
90+ string [] machinesOld;
91+ foreach (string k, JSONValue v; configurations[" nixosConfigurations" ]){
92+ if (k[$- 3 .. $] != " -vm" &&
93+ k != " gitlab-runner-container" &&
94+ k != " minimal-container" )
95+ {
96+ machinesOld ~= k;
97+ }
98+ }
99+
100+ attr = constructCommandAttr(worktreeBaseBranch, machinesOld);
101+ auto machineOptionsRootOld = nix.eval! JSONValue(" " , [" --impure" , " --expr" , attr]);
102+
64103 MachineChanges[] machineChanges;
65104
105+ string [] machines = uniq(machinesOld ~ machinesNew).array;
106+
66107 foreach (string m; machines){
67108 MachineChanges mc;
68109 mc.machine = m;
69- foreach (setting; __traits (allMembers , MachineChanges)){
70- static if (is (typeof (__traits(getMember, mc, setting)) == bool )){
71- string new_setting =
72- nix.eval(gitRoot~ " #nixosConfigurations." ~ m~ " .config.disko.devices." ~ setting, [
73- " --option" , " warn-dirty" , " false" ,
74- " --accept-flake-config" ]);
75- tracef(" CREATING %s_%s_new FILE" , m, setting);
76- write(freshTestsDir~ " /" ~ m~ " _" ~ setting~ " _new" , new_setting);
77- string old_setting =
78- nix.eval(worktreeBaseBranch~ " #nixosConfigurations." ~ m~ " .config.disko.devices." ~ setting, [
79- " --option" , " warn-dirty" , " false" ,
80- " --accept-flake-config" ]);
81- tracef(" CREATING %s_%s_old FILE" , m, setting);
82- write(staleTestsDir~ " /" ~ m~ " _" ~ setting~ " _old" , old_setting);
83-
84-
85- string diff = execute([
86- " git" , " --no-pager" , " diff" , " --no-index" ,
87- staleTestsDir~ " /" ~ m~ " _" ~ setting~ " _old" ,
88- freshTestsDir~ " /" ~ m~ " _" ~ setting~ " _new" ]);
89-
90- if (diff == " " ){
91- infof(" ✔ NO DIFFERENCE IN %s" , m);
92- __traits (getMember , mc, setting) = true ;
110+ if (m in machineOptionsRootOld && ! (m in machineOptionsRootNew)){
111+ static foreach (setting; diskoOptions){
112+ __traits (getMember , mc, setting) = ChangeStatus.Removed;
113+ }
114+ }
115+ else if (m in machineOptionsRootNew && ! (m in machineOptionsRootOld)){
116+ static foreach (setting; diskoOptions){
117+ __traits (getMember , mc, setting) = ChangeStatus.New;
118+ }
119+ }
120+ else {
121+ static foreach (setting; diskoOptions){
122+ if (machineOptionsRootOld[m][setting] == machineOptionsRootNew[m][setting]){
123+ __traits (getMember , mc, setting) = ChangeStatus.Unchanged;
93124 }
94125 else {
95- infof(" ✖ DIFFERENCE IN %s" , m);
96- __traits (getMember , mc, setting) = false ;
126+ __traits (getMember , mc, setting) = ChangeStatus.Changed;
97127 }
98128 }
99129 }
100130 machineChanges ~= mc;
101131 }
102- infof(" ------------------------------------------------------" );
103- if (machineDiffs.length == 0 ){
104- infof(" ✔✔✔ NO CONFIGS WITH DIFFS" );
105- }
106- else {
107- infof(" ✖✖✖ LIST OF CONFIGS WITH DIFFS" );
108- foreach (mc; machineChanges){
109- infof(mc.machine);
110- }
111- }
132+
112133 create_comment(machineChanges);
113134
114- // Cleanup
115135 execute([" git" , " worktree" , " remove" , worktreeBaseBranch, " --force" ]);
116- rmdirRecurse(freshTestsDir);
117136}
118137
119138void create_comment (MachineChanges[] machineChanges){
@@ -122,8 +141,12 @@ void create_comment(MachineChanges[] machineChanges){
122141 data ~= " \n\n ✅ There have been no changes to disko configs" ;
123142 }
124143 else {
125- // TODO: Change the generation of the table to have as many collumns as fields in MachineChanges at compile time
126144 data ~= " \n\n Bellow you will find a summary of machines and whether their disko attributes have differences." ;
145+ data ~= " \n\n **Legend:**" ;
146+ data ~= " \n 🟩 = No changes" ;
147+ data ~= " \n ⚡ = Something is different" ;
148+ data ~= " \n 🗑 = Has been removed" ;
149+ data ~= " \n 🧩 = Has been added" ;
127150
128151 data ~= " \n\n " ;
129152 foreach (string field; __traits (allMembers , MachineChanges)){
@@ -137,18 +160,29 @@ void create_comment(MachineChanges[] machineChanges){
137160
138161 foreach (mc; machineChanges){
139162 foreach (string field; __traits (allMembers , MachineChanges)){
140- static if (is (typeof (__traits(getMember, mc, field)) == bool )){
141- data~= " | " ~ (__traits(getMember, mc, field) ? " 🟩" : " ⚠️" ) ~ " " ;
142- }
143- else static if (is (typeof (__traits(getMember, mc, field)) == string )){
163+ static if (is (typeof (__traits(getMember, mc, field)) == string )){
144164 data~= " | " ~ __traits(getMember, mc, field) ~ " " ;
145165 }
146- else {
147- assert ( 0 ) ;
166+ else {
167+ data ~= " | " ~ statusToSymbol(__traits(getMember, mc, field)) ~ " " ;
148168 }
149169 }
150170 data ~= " |\n " ;
151171 }
152172 }
153173 write(" comment.md" , data);
154174}
175+
176+
177+ string constructCommandAttr (string flakePath, string [] machines){
178+ string attr = " let flake = (builtins.getFlake (builtins.toString " ~ flakePath ~ " )); in { " ;
179+ foreach (m; machines){
180+ attr ~= m ~ " = { " ;
181+ foreach (option; diskoOptions){
182+ attr ~= option ~ " = flake.nixosConfigurations." ~ m ~ " .config.disko.devices." ~ option ~ " ; " ;
183+ }
184+ attr ~= " }; " ;
185+ }
186+ attr ~= " }" ;
187+ return attr;
188+ }
0 commit comments