1 /++
2  + Copyright: Copyright © 2018, Christian Köstlin
3  + License: MIT
4  + Authors: Christian Koestlin
5  +/
6 
7 module ponies.dlang.travis;
8 
9 import dyaml;
10 import ponies.dlang;
11 import ponies;
12 import std.algorithm;
13 import std.conv;
14 import std.experimental.logger;
15 import std..string;
16 
17 abstract class TravisDlangPony : DlangPony
18 {
19     private Node root;
20     private bool upToDate = false;
21 
22     /++
23      + Do the change on the root node and return if something was changed.
24      + Return: true if something was changed
25      +/
26     protected abstract bool change(ref Node root);
27 
28     override CheckStatus check()
29     {
30         root = Loader(travisYml).load;
31         upToDate = !change(root);
32         return upToDate.to!CheckStatus;
33     }
34 
35     override void run()
36     {
37         if (!upToDate)
38         {
39             "Writing new %s".format(travisYml).warning;
40             Dumper(travisYml).dump(root);
41         }
42     }
43 }
44 
45 class LanguageTravisDlangPony : TravisDlangPony
46 {
47     override string name()
48     {
49         return "Setup travis to work with language d";
50     }
51 
52     override bool change(ref Node root)
53     {
54         auto language = "language" in root;
55         if (language)
56         {
57             if (language.isScalar)
58             {
59                 if (language.as!string == "d")
60                 {
61                     return false;
62                 }
63             }
64         }
65         root["language"] = "d";
66         return true;
67     }
68 }
69 
70 class CompilerTravisDlangPony : TravisDlangPony
71 {
72     override string name()
73     {
74         return "Setup dmd and ldc as compilers";
75     }
76 
77     override bool change(ref Node root)
78     {
79         auto dNode = "d" in root;
80         if (dNode)
81         {
82             bool modified = false;
83             if (dNode.isScalar)
84             {
85                 root["d"] = Node([*dNode]);
86                 "Converting d node to array".warning;
87                 modified = true;
88             }
89 
90             dNode = "d" in root;
91             if (!dNode.sequence!string.canFind("dmd"))
92             {
93                 dNode.add(Node("dmd"));
94                 root["d"] = *dNode;
95                 "Adding dmd".warning;
96                 modified = true;
97             }
98             if (!dNode.sequence!string.canFind("ldc"))
99             {
100                 dNode.add(Node("ldc"));
101                 root["d"] = *dNode;
102                 "Adding ldc".warning;
103                 modified = true;
104             }
105             return modified;
106         }
107         else
108         {
109             root["d"] = Node([Node("dmd"), Node("ldc")]);
110             "Adding new node with dmd and ldc".warning;
111             return true;
112         }
113     }
114 }
115 
116 class NoSudoTravisDlangPony : TravisDlangPony
117 {
118     override string name()
119     {
120         return "Setup travis to not run as sudo";
121     }
122 
123     override bool change(ref Node root)
124     {
125         auto sudo = "sudo" in root;
126         if (sudo)
127         {
128             if (sudo.as!string != "false")
129             {
130                 root["sudo"] = false;
131                 return true;
132             }
133             return false;
134         }
135         else
136         {
137             root["sudo"] = false;
138             return true;
139         }
140     }
141 }
142 
143 class GhPagesTravisDlangPony : TravisDlangPony
144 {
145     override string name()
146     {
147         return "Setup travis to autodeploy ddox to ghpages";
148     }
149 
150     override bool change(ref Node root)
151     {
152         return addNeededPackages(root) || addDdoxBuildScript(root) || addDeployNode(root);
153     }
154 
155     private bool addDeployNode(ref Node root)
156     {
157         auto deploy = "deploy" in root;
158         if (!deploy)
159         {
160             "Adding deploy node".warning;
161             // dfmt off
162             root["deploy"] =
163                 Node(["provider" : Node("pages"),
164                       "skip-cleanup" : Node(true),
165                       "local-dir" : Node("docs"),
166                       "github-token" : Node("$GH_REPO_TOKEN"),
167                       "verbose" : Node(true),
168                       "keep-history" : Node(true),
169                       "on" : Node(["branch" : "master"])]);
170             // dfmt on
171             return true;
172         }
173         return false;
174     }
175 
176     private bool addDdoxBuildScript(ref Node root)
177     {
178         const buildDdox = "dub build --compiler=${DC} --build=ddox";
179         auto script = "script" in root;
180         if (!script)
181         {
182             "Adding ddox build script".warning;
183             root["script"] = Node([buildDdox]);
184             return true;
185         }
186 
187         if (script.isScalar)
188         {
189             "Changing script node".warning;
190 
191             if (script.as!string != buildDdox)
192             {
193                 root["script"] = Node([script.as!string, buildDdox]);
194             }
195             else
196             {
197                 root["script"] = Node([buildDdox]);
198             }
199             return true;
200         }
201 
202         if (!script.sequence!string.canFind("dub build --compiler=${DC} --build=ddox"))
203         {
204             "Adding ddox script".warning;
205             script.add("dub build --compiler=${DC} --build=ddox");
206             root["script"] = *script;
207             return true;
208         }
209         return false;
210     }
211 
212     private bool addNeededPackages(ref Node root)
213     {
214         auto addons = "addons" in root;
215         if (!addons)
216         {
217             "Adding addons node".warning;
218             root["addons"] = Node(["apt" : Node(["packages" : Node(["libevent-dev"])])]);
219             return true;
220         }
221 
222         if (addons.isScalar)
223         {
224             "Changing addons node".warning;
225             root["addons"] = Node(["apt" : Node(["packages" : Node(["libevent-dev"])])]);
226             return true;
227         }
228 
229         auto apt = "apt" in root["addons"];
230         if (!apt)
231         {
232             root["addons"]["apt"] = Node(["packages" : Node(["libevent-dev"])]);
233             return true;
234         }
235 
236         if (apt.isScalar)
237         {
238             "Changing addons.apt node".warning;
239             root["addons"]["apt"] = Node(["packages" : Node(["libevent-dev"])]);
240             return true;
241         }
242 
243         auto packages = "packages" in root["addons"]["apt"];
244         if (!packages)
245         {
246             "Adding packages to addons.apt".warning;
247             root["addons"]["apt"]["packages"] = Node(["libevent-dev"]);
248             return true;
249         }
250 
251         if (packages.isScalar)
252         {
253             "Changing addons.apt.packages".warning;
254             root["addons"]["apt"]["packages"] = Node(["libevent-dev"]);
255             return true;
256         }
257 
258         if (!packages.sequence!string.canFind("libevent-dev"))
259         {
260             "Adding libevent-dev to addons.apt.packages".warning;
261             packages.add("libevent-dev");
262             root["addons"]["apt"]["packages"] = *packages;
263             return true;
264         }
265 
266         return false;
267     }
268 }
269 
270 /+
271 class TravisPony : DlangPony
272 {
273     override string name()
274     {
275         return "Setup travis build in %s".format(travisYml);
276     }
277 
278     override CheckStatus check()
279     {
280         return exists(travisYml).to!CheckStatus;
281     }
282 
283     override void run()
284     {
285         "Creating %s file".format(travisYml).info;
286         "userinteraction:Please get gh repo token from https://github.com/settings/tokens".warning;
287         "userinteraction:Please enable travis build".warning;
288         "userinteraction:Please enable coverage on codecov".warning;
289         auto content = "language: d
290 d:
291   - dmd
292   - ldc
293 addons:
294   apt:
295     packages:
296     - libevent-dev
297 before_install: pip install --user codecov
298 script:
299 - dub test --compiler=${DC} --coverage
300 - dub build --build=release
301 - dub build --build=ddox
302 after_success: codecov
303 deploy:
304   provider: pages
305   skip-cleanup: true
306   local-dir: \"docs\"
307   github-token: \"$GH_REPO_TOKEN\"
308   verbose: true
309   keep-history: true
310   on:
311     branch: master
312 env:
313   global:
314     secure: create this token with 'travis encrypt GH_REPO_TOKEN=key from https://github.com/settings/tokens'
315 ";
316         std.file.write(travisYml, content);
317     }
318 }
319 +/