Skip to content

add run task to community build Main #13632

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package dotty.communitybuild

import java.nio.file._
import java.io.{PrintWriter, File}
import java.nio.charset.StandardCharsets.UTF_8

object CommunityBuildRunner:

/** Depending on the mode of operation, either
* runs the test or updates the project. Updating
* means that all the dependencies are fetched but
* minimal other extra other work is done. Updating
* is necessary since we run tests each time on a fresh
* Docker container. We run the update on Docker container
* creation time to create the cache of the dependencies
* and avoid network overhead. See https://github.com/lampepfl/dotty-drone
* for more infrastructural details.
*/
extension (self: CommunityProject) def run()(using suite: CommunityBuildRunner): Unit =
if self.requiresExperimental && !compilerSupportExperimental then
log(s"Skipping ${self.project} - it needs experimental features unsupported in this build.")
return
self.dependencies.foreach(_.publish())
self.testOnlyDependencies().foreach(_.publish())
suite.runProject(self)

trait CommunityBuildRunner:

/** fails the current operation, can be specialised in a concrete Runner
* - overridden in `CommunityBuildTest`
*/
def failWith(msg: String): Nothing = throw IllegalStateException(msg)

/** Build the given project with the published local compiler and sbt plugin.
*
* This test reads the compiler version from community-build/dotty-bootstrapped.version
* and expects community-build/sbt-dotty-sbt to set the compiler plugin.
*
* @param project The project name, should be a git submodule in community-build/
* @param command The binary file of the program used to test the project – usually
* a build tool like SBT or Mill
* @param arguments Arguments to pass to the testing program
*/
def runProject(projectDef: CommunityProject): Unit =
val project = projectDef.project
val command = projectDef.binaryName
val arguments = projectDef.buildCommands

@annotation.tailrec
def execTimes(task: () => Int, timesToRerun: Int): Boolean =
val exitCode = task()
if exitCode == 0
then true
else if timesToRerun == 0
then false
else
log(s"Rerunning tests in $project because of a previous run failure.")
execTimes(task, timesToRerun - 1)

log(s"Building $project with dotty-bootstrapped $compilerVersion...")

val projectDir = communitybuildDir.resolve("community-projects").resolve(project)

if !Files.exists(projectDir.resolve(".git")) then
failWith(s"""
|
|Missing $project submodule. You can initialize this module using
|
| git submodule update --init community-build/community-projects/$project
|
|""".stripMargin)

val testsCompletedSuccessfully = execTimes(projectDef.build, 3)

if !testsCompletedSuccessfully then
failWith(s"""
|
|$command exited with an error code. To reproduce without JUnit, use:
|
| sbt community-build/prepareCommunityBuild
| cd community-build/community-projects/$project
| $command ${arguments.init.mkString(" ")} "${arguments.last}"
|
|For a faster feedback loop on SBT projects, one can try to extract a direct call to dotc
|using the sbt export command. For instance, for scalacheck, use
| sbt export jvm/test:compileIncremental
|
|""".stripMargin)
end runProject

end CommunityBuildRunner
8 changes: 6 additions & 2 deletions community-build/src/scala/dotty/communitybuild/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import java.nio.file.Path
import java.nio.file.Files
import scala.sys.process._

import CommunityBuildRunner.run

object Main:

Expand Down Expand Up @@ -106,12 +107,15 @@ object Main:
println(s"Documentation not found for ${failed.mkString(", ")}")
sys.exit(1)

case "run" :: names if names.nonEmpty =>
given CommunityBuildRunner()
withProjects(names, "Running")(_.run())

case args =>
println("USAGE: <COMMAND> <PROJECT NAME>")
println("COMMAND is one of: publish doc run")
println("COMMAND is one of: publish, build, doc, doc all, run")
println("Available projects are:")
allProjects.foreach { k =>
println(s"\t${k.project}")
}
sys.exit(1)

Original file line number Diff line number Diff line change
Expand Up @@ -7,93 +7,15 @@ import org.junit.{Ignore, Test}
import org.junit.Assert.{assertEquals, fail}
import org.junit.experimental.categories.Category

abstract class CommunityBuildTest:
given CommunityBuildTest = this

/** Depending on the mode of operation, either
* runs the test or updates the project. Updating
* means that all the dependencies are fetched but
* minimal other extra other work is done. Updating
* is necessary since we run tests each time on a fresh
* Docker container. We run the update on Docker container
* creation time to create the cache of the dependencies
* and avoid network overhead. See https://github.com/lampepfl/dotty-drone
* for more infrastructural details.
*/
extension (self: CommunityProject) def run()(using suite: CommunityBuildTest): Unit =
if self.requiresExperimental && !compilerSupportExperimental then
println(
s"Skipping ${self.project} - it needs experimental features unsupported in this build."
)
return
self.dependencies.foreach(_.publish())
self.testOnlyDependencies().foreach(_.publish())
suite.test(self)

/** Build the given project with the published local compiler and sbt plugin.
*
* This test reads the compiler version from community-build/dotty-bootstrapped.version
* and expects community-build/sbt-dotty-sbt to set the compiler plugin.
*
* @param project The project name, should be a git submodule in community-build/
* @param command The binary file of the program used to test the project – usually
* a build tool like SBT or Mill
* @param arguments Arguments to pass to the testing program
*/
def test(projectDef: CommunityProject): Unit = {
val project = projectDef.project
val command = projectDef.binaryName
val arguments = projectDef.buildCommands

@annotation.tailrec
def execTimes(task: () => Int, timesToRerun: Int): Boolean =
val exitCode = task()
if exitCode == 0
then true
else if timesToRerun == 0
then false
else
log(s"Rerunning tests in $project because of a previous run failure.")
execTimes(task, timesToRerun - 1)

log(s"Building $project with dotty-bootstrapped $compilerVersion...")

val projectDir = communitybuildDir.resolve("community-projects").resolve(project)

if (!Files.exists(projectDir.resolve(".git"))) {
fail(s"""
|
|Missing $project submodule. You can initialize this module using
|
| git submodule update --init community-build/community-projects/$project
|
|""".stripMargin)
}

val testsCompletedSuccessfully = execTimes(projectDef.build, 3)

if (!testsCompletedSuccessfully) {
fail(s"""
|
|$command exited with an error code. To reproduce without JUnit, use:
|
| sbt community-build/prepareCommunityBuild
| cd community-build/community-projects/$project
| $command ${arguments.init.mkString(" ")} "${arguments.last}"
|
|For a faster feedback loop on SBT projects, one can try to extract a direct call to dotc
|using the sbt export command. For instance, for scalacheck, use
| sbt export jvm/test:compileIncremental
|
|""".stripMargin)
}
}
end CommunityBuildTest
import CommunityBuildRunner.run

class TestCategory

given testRunner: CommunityBuildRunner with
override def failWith(msg: String) = { fail(msg); ??? }

@Category(Array(classOf[TestCategory]))
class CommunityBuildTestA extends CommunityBuildTest:
class CommunityBuildTestA:
@Test def izumiReflect = projects.izumiReflect.run()
@Test def scalaSTM = projects.scalaSTM.run()
@Test def scalatest = projects.scalatest.run()
Expand All @@ -112,7 +34,7 @@ class CommunityBuildTestA extends CommunityBuildTest:
end CommunityBuildTestA

@Category(Array(classOf[TestCategory]))
class CommunityBuildTestB extends CommunityBuildTest:
class CommunityBuildTestB:
@Test def cats = projects.cats.run()
@Test def catsEffect3 = projects.catsEffect3.run()
@Test def catsMtl = projects.catsMtl.run()
Expand All @@ -132,7 +54,7 @@ class CommunityBuildTestB extends CommunityBuildTest:
end CommunityBuildTestB

@Category(Array(classOf[TestCategory]))
class CommunityBuildTestC extends CommunityBuildTest:
class CommunityBuildTestC:
@Test def akka = projects.akka.run()
@Test def algebra = projects.algebra.run()
@Test def betterfiles = projects.betterfiles.run()
Expand Down