Skip to content

Commit

Permalink
Run gif tests from an munit test suite
Browse files Browse the repository at this point in the history
  • Loading branch information
alexarchambault committed Oct 11, 2022
1 parent c1f8919 commit b13dfc2
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 125 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -703,8 +703,6 @@ jobs:
run: .github/scripts/build-website.sh
- name: Test documentation
run: ./mill -i docs-tests.test
- name: Test gifs
run: gifs/generate_gifs.sh $(ls gifs/scenarios/)

checks:
timeout-minutes: 15
Expand Down
6 changes: 5 additions & 1 deletion build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,11 @@ object `docs-tests` extends SbtModule with ScalaCliScalafixModule with HasTests

object test extends Tests with ScalaCliTests with ScalaCliScalafixModule {
def forkEnv = super.forkEnv() ++ extraEnv() ++ Seq(
"SCALA_CLI_EXAMPLES" -> (os.pwd / "examples").toString
"SCALA_CLI_EXAMPLES" -> (os.pwd / "examples").toString,
"SCALA_CLI_GIF_SCENARIOS" -> (os.pwd / "gifs" / "scenarios").toString,
"SCALA_CLI_WEBSITE_IMG" -> (os.pwd / "website" / "static" / "img").toString,
"SCALA_CLI_GIF_RENDERER_DOCKER_DIR" -> (os.pwd / "gifs").toString,
"SCALA_CLI_SVG_RENDERER_DOCKER_DIR" -> (os.pwd / "gifs" / "svg_render").toString
)
def resources = T.sources {
// Adding markdown directories here, so that they're watched for changes in watch mode
Expand Down
6 changes: 3 additions & 3 deletions gifs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ Recordings are possible using https://github.com/paxtonhare/demo-magic licensed

## How does it work?

Our animated svgs are compose of scenarios built using [demo-magic](https://github.com/paxtonhare/demo-magic) and then recorded using [asciinema](https://asciinema.org/) to .json files to be finally rendered to animated svg files using [svg_rendrer_cli](https://github.com/marionebl/svg-term-cli)
Our animated svgs are compose of scenarios built using [demo-magic](https://github.com/paxtonhare/demo-magic) and then recorded using [asciinema](https://asciinema.org/) to .json files to be finally rendered to animated svg files using [svg_rendrer_cli](https://github.com/marionebl/svg-term-cli)

## How to (re)create new gif

1. Copy example.sh into scenarios directory (e.g. `better-error.sh`)
2. Edit its content based on included tips.
3. Run `generate_gifs.sh better-error` to to (re)render svgs based on `better-error.sh` scenario
3. Run `./mill -i docs-tests.test "sclicheck.GifTests.better-error"` to to (re)render svgs based on `better-error.sh` scenario

Gifs will be saved in `website/static/img/gifs` and `website/static/img/dark/gifs` directories based on name of the scenario (so `foo.sh` becomes `foo.svg`)
Gifs will be saved in `website/static/img/gifs` and `website/static/img/dark/gifs` directories based on name of the scenario (so `foo.sh` becomes `foo.svg`)
119 changes: 0 additions & 119 deletions gifs/generate_gifs.sh

This file was deleted.

176 changes: 176 additions & 0 deletions modules/docs-tests/src/test/scala/sclicheck/GifTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package sclicheck

class GifTests extends munit.FunSuite {

val scenariosDir =
Option(System.getenv("SCALA_CLI_GIF_SCENARIOS")).map(os.Path(_, os.pwd)).getOrElse {
sys.error("SCALA_CLI_GIF_SCENARIOS not set")
}
val websiteImgDir =
Option(System.getenv("SCALA_CLI_WEBSITE_IMG")).map(os.Path(_, os.pwd)).getOrElse {
sys.error("SCALA_CLI_WEBSITE_IMG not set")
}
lazy val gifRenderedDockerDir =
Option(System.getenv("SCALA_CLI_GIF_RENDERER_DOCKER_DIR")).map(os.Path(_, os.pwd)).getOrElse {
sys.error("SCALA_CLI_GIF_RENDERER_DOCKER_DIR not set")
}
lazy val svgRenderedDockerDir =
Option(System.getenv("SCALA_CLI_SVG_RENDERER_DOCKER_DIR")).map(os.Path(_, os.pwd)).getOrElse {
sys.error("SCALA_CLI_SVG_RENDERER_DOCKER_DIR not set")
}

val scenarioScripts = os.list(scenariosDir)
.filter(!_.last.startsWith("."))
.filter(_.last.endsWith(".sh"))
.filter(os.isFile(_))

lazy val hasTty =
os.proc("tty").call(stdin = os.Inherit, stdout = os.Inherit, check = false).exitCode == 0
lazy val ttyOpts = if (hasTty) Seq("-it") else Nil

def buildImages = true
def forceBuildImages = false

def columns = 70
def rows = 20
def record = true
def gifs = true
def svgs = true

def maybeBuildImages(): Unit =
if (buildImages || forceBuildImages) {
def hasImage(imageName: String): Boolean = {
val res = os.proc("docker", "images", "-q", imageName).call()
res.out.trim().nonEmpty
}
if (forceBuildImages || !hasImage("gif-renderer"))
os.proc("docker", "build", gifRenderedDockerDir, "--tag", "gif-renderer")
.call(stdin = os.Inherit, stdout = os.Inherit)
if (forceBuildImages || !hasImage("svg_rendrer"))
os.proc("docker", "build", svgRenderedDockerDir, "--tag", "svg_rendrer")
.call(stdin = os.Inherit, stdout = os.Inherit)
}

for (script <- scenarioScripts) {
val name = script.last.stripSuffix(".sh")
test(name) {
maybeBuildImages()

TestUtil.withTmpDir(s"scala-cli-gif-test-$name") { out =>

try {
if (record)
os.proc(
"docker",
"run",
"--rm",
ttyOpts,
"-v",
s"$out/.scala:/data/out",
"gif-renderer",
"./run_scenario.sh",
name
)
.call(stdin = os.Inherit, stdout = os.Inherit)

if (hasTty) {
val svgRenderMappings =
Seq("-v", s"$websiteImgDir:/data", "-v", s"$out/.scala:/out")
if (svgs) {
val svgRenderOps = Seq(
"--in",
s"/out/$name.cast",
"--width",
columns.toString,
"--height",
rows.toString,
"--term",
"iterm2",
"--padding",
"20"
)
os.proc(
"docker",
"run",
"--rm",
svgRenderMappings,
"svg_rendrer",
"a",
svgRenderOps,
"--out",
s"/data/$name.svg",
"--profile",
"/profiles/light"
)
.call(stdin = os.Inherit, stdout = os.Inherit)
os.proc(
"docker",
"run",
"--rm",
svgRenderMappings,
"svg_rendrer",
"a",
svgRenderOps,
"--out",
s"/data/dark/$name.svg",
"--profile",
"/profiles/dark"
)
.call(stdin = os.Inherit, stdout = os.Inherit)
}
if (gifs) {
os.proc(
"docker",
"run",
"--rm",
svgRenderMappings,
"asciinema/asciicast2gif",
"-w",
columns,
"-h",
rows,
"-t",
"monokai",
s"/out/$name.cast",
s"/data/gifs/$name.gif"
)
.call(stdin = os.Inherit, stdout = os.Inherit)
os.proc(
"docker",
"run",
"--rm",
svgRenderMappings,
"asciinema/asciicast2gif",
"-w",
columns,
"-h",
rows,
"-t",
"solarized-dark",
s"/out/$name.cast",
s"/data/dark/gifs/$name.gif"
)
.call(stdin = os.Inherit, stdout = os.Inherit)
}
}
}
finally
// Clean-up out dir with the same rights as the images above (should be root - from docker)
os.proc(
"docker",
"run",
"--rm",
ttyOpts,
"-v",
s"$out:/out",
"alpine:3.16.2",
"sh",
"-c",
"rm -rf /out/* || true; rm -rf /out/.* || true"
)
.call(stdin = os.Inherit, stdout = os.Inherit)
}
}
}

}
13 changes: 13 additions & 0 deletions modules/docs-tests/src/test/scala/sclicheck/TestUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@ package sclicheck

object TestUtil {

def withTmpDir[T](prefix: String)(f: os.Path => T): T = {
val tmpDir = os.temp.dir(prefix = prefix)
try f(tmpDir)
finally tryRemoveAll(tmpDir)
}

def tryRemoveAll(f: os.Path): Unit =
try os.remove.all(f)
catch {
case ex: java.nio.file.FileSystemException =>
System.err.println(s"Could not remove $f ($ex), ignoring it.")
}

lazy val scalaCliPath = Option(System.getenv("SCLICHECK_SCALA_CLI")).getOrElse {
sys.error("SCLICHECK_SCALA_CLI not set")
}
Expand Down

0 comments on commit b13dfc2

Please sign in to comment.