-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refs #8638 nimble-wide CI: first pass #10247
Closed
Closed
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
fb8211b
refs #8638 nimble-wide CI: first pass
timotheecour b148788
CI tests now run nimble test; better error reporting
timotheecour a0efd9a
refactor nimbleci into separate standalone module, and also run `nimb…
timotheecour 2c58644
* format nimble CI results using aligned table
timotheecour File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
#[ | ||
nimble wide CI | ||
]# | ||
|
||
import std/[os, strutils, json, tables, macros, times] | ||
import compiler/asciitables | ||
|
||
proc getNimblePkgPath(nimbleDir: string): string = | ||
nimbleDir / "packages_official.json" | ||
|
||
template withDir*(dir, body) = | ||
let old = getCurrentDir() | ||
try: | ||
setCurrentDir(dir) | ||
body | ||
finally: | ||
setCurrentdir(old) | ||
|
||
proc execEcho(cmd: string): bool = | ||
echo "running cmd:", cmd | ||
let status = execShellCmd(cmd) | ||
if status != 0: | ||
echo "failed: cmd: `", cmd, "` status:", status | ||
result = status == 0 | ||
|
||
type Stats = object | ||
seenOK: int | ||
foundOK: int ## whether nimble can still access it | ||
cloneOK: int | ||
installOK: int | ||
developOK: int | ||
buildOK: int | ||
testOK: int | ||
totalTime: float | ||
|
||
type TestResult = ref object | ||
# we can add further test fields here (eg running time, mem usage etc) | ||
pkg: string | ||
stats: Stats | ||
|
||
type TestResultAll = object | ||
tests: seq[TestResult] | ||
stats: Stats | ||
failures: seq[string] | ||
|
||
proc parseNimble(data: JsonNode): Table[string, JsonNode] = | ||
result = initTable[string, JsonNode]() | ||
for a in data: | ||
result[a["name"].getStr()] = a | ||
|
||
type Config = ref object | ||
pkgs: Table[string, JsonNode] | ||
pkgInstall: string | ||
pkgClone: string | ||
|
||
proc runCIPackage(config: Config, data: var TestResult) = | ||
let t0 = epochTime() | ||
defer: | ||
data.stats.totalTime = epochTime() - t0 | ||
let pkg = data.pkg | ||
echo "runCIPackage:", pkg | ||
data.stats.seenOK.inc | ||
if not(pkg in config.pkgs): | ||
echo "not found: ", pkg | ||
return | ||
data.stats.foundOK.inc | ||
let url = config.pkgs[pkg]["url"].getStr() | ||
|
||
when true: | ||
let cmd = "nimble install --nimbleDir:$# -y $# " % [config.pkgInstall, | ||
pkg] | ||
if execEcho(cmd): | ||
data.stats.installOK.inc | ||
|
||
echo config.pkgClone | ||
createDir config.pkgClone | ||
withDir config.pkgClone: | ||
if not existsDir pkg: | ||
if execEcho("nimble develop --nimbleDir:$# -y $#" % [config.pkgInstall, | ||
pkg]): | ||
data.stats.developOK.inc | ||
if not execEcho("git clone $# $#" % [url, pkg]): | ||
return # nothing left to do without a clone | ||
data.stats.cloneOK.inc | ||
|
||
withDir config.pkgClone / pkg: | ||
data.stats.buildOK = ord execEcho("nimble build -N --nimbleDir:$#" % [ | ||
config.pkgInstall]) | ||
# note: see caveat https://github.com/nim-lang/nimble/issues/558 | ||
# where `nimble test` suceeds even if no tests are defined. | ||
data.stats.testOK = ord execEcho "nimble test" | ||
|
||
proc tabFormat[T](result: var string, a: T) = | ||
# TODO: more generic, flattens anything into 1 line of a table | ||
var first = true | ||
for k, v in fieldPairs(a): | ||
if first: first = false | ||
else: result.add "\t" | ||
result.add k | ||
result.add ":\t" | ||
result.add v | ||
|
||
proc `$`(a: TestResultAll): string = | ||
var s = "" | ||
for i, ai in a.tests: | ||
s.tabFormat (i: i, pkg: ai.pkg) | ||
s.add "\t" | ||
s.tabFormat ai.stats | ||
s.add "\n" | ||
when true: # add total | ||
s.add("TOTAL\t$#\t\t\t" % [$a.tests.len]) | ||
s.tabFormat a.stats | ||
s.add "\n" | ||
result = "TestResultAll:\n" & alignTable(s) | ||
|
||
proc updateResults(a: var TestResultAll, b: TestResult) = | ||
a.tests.add b | ||
if b.stats.testOK == 0: | ||
a.failures.add b.pkg | ||
macro domixin(s: static[string]): untyped = parseStmt(s) | ||
for k, v in fieldPairs(b.stats): | ||
domixin("a.stats.$# += b.stats.$#" % [k, k]) | ||
|
||
proc runCIPackages*(dirOutput: string) = | ||
echo "runCIPackages", (dirOutput: dirOutput, pid: getCurrentProcessId()) | ||
# pid useful to kill process, since because of a bug, ^C doesn't work inside exec | ||
|
||
var data: TestResult | ||
let pkgs0 = """ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a |
||
# add more packages here; lines starting with `#` are skipped | ||
|
||
#TODO: jester@#head or jester? etc | ||
jester | ||
|
||
cligen | ||
|
||
# CT failures | ||
libffi | ||
|
||
glob | ||
nimongo | ||
nimx | ||
karax | ||
freeimage | ||
regex | ||
nimpy | ||
zero_functional | ||
arraymancer | ||
inim | ||
c2nim | ||
sdl1 | ||
iterutils | ||
gnuplot | ||
nimpb | ||
lazy | ||
choosenim | ||
""" | ||
|
||
var config = Config( | ||
pkgInstall: dirOutput/"nimbleRoot", | ||
pkgClone: dirOutput/"nimbleCloneRoot", | ||
) | ||
|
||
doAssert execEcho "nimble refresh --nimbleDir:$#" % [config.pkgInstall] | ||
# doing it by hand until nimble exposes this API | ||
config.pkgs = config.pkgInstall.getNimblePkgPath.readFile.parseJson.parseNimble() | ||
|
||
var pkgs: seq[string] | ||
for a in pkgs0.splitLines: | ||
var a = a.strip | ||
if a.len == 0: continue | ||
if a.startsWith '#': continue | ||
pkgs.add a | ||
|
||
echo (pkgs: pkgs) | ||
|
||
var testsAll: TestResultAll | ||
|
||
for i, pkg in pkgs: | ||
var data = TestResult(pkg: pkg) | ||
runCIPackage(config, data) | ||
updateResults(testsAll, data) | ||
if data.stats.testOK == 0: echo "FAILURE:CI pkg:" & pkg | ||
echo testsAll | ||
# consider sending a notification, gather stats on failed packages | ||
|
||
when isMainModule: | ||
runCIPackages(".") |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.