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