Skip to content
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
81 changes: 81 additions & 0 deletions .github/workflows/test_and_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Test code, update coverage, and release master branch

on: [ push, pull_request ]

jobs:
test:
strategy:
matrix:
os: [ windows-latest, ubuntu-latest ]
java: [ '11', '17', '21' ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4.2.2
- name: Setup JDK
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: ${{ matrix.java }}
- name: Setup sbt launcher
uses: sbt/setup-sbt@v1.1.7
- name: Run tests
shell: bash
run: sbt +test
coverage:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4.2.2
- name: Setup JDK
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- name: Setup sbt launcher
uses: sbt/setup-sbt@v1.1.7
- name: Analyze coverage
run: sbt clean coverage +test
- name: Update coverage report
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_FLAG_NAME: Scala ${{ matrix.scala }}
run: sbt coverageReport coveralls
release:
runs-on: ubuntu-latest
needs: [ test, coverage ]
steps:
- uses: actions/checkout@v4.2.2
- name: Check if we are head of master
id: check_head_of_master
run: |
git fetch origin master &&
MASTER=`git rev-parse origin/master` &&
echo "::set-output name=head_of_master::$MASTER" &&
CURRENT=`git rev-list -n 1 ${{ github.ref }} || echo "NOT_MASTER"` &&
echo "::set-output name=current_job_ref::$CURRENT"
- name: Set up JDK
if: steps.check_head_of_master.outputs.head_of_master == steps.check_head_of_master.outputs.current_job_ref
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- name: Set up SBT
if: steps.check_head_of_master.outputs.head_of_master == steps.check_head_of_master.outputs.current_job_ref
uses: sbt/setup-sbt@v1.1.7
- name: Build and release
if: steps.check_head_of_master.outputs.head_of_master == steps.check_head_of_master.outputs.current_job_ref
env:
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
SONA_USER: ${{ secrets.SONATYPE_USERNAME }}
SONA_PASS: ${{ secrets.SONATYPE_PASSWORD }}
GPG_PRIVATE: ${{ secrets.GPG_PRIVATE }}
PGP_PASS: ${{ secrets.PGP_PASS }}
CI: github
run: |
git fetch --prune --unshallow --tags &&
export GPG_TTY=$(tty) &&
echo $GPG_PRIVATE | base64 -d | gpg --passphrase=$PGP_PASS --yes --batch --pinentry-mode loopback --import &&
export PATH=`pwd`/.github/bin:$PATH &&
sbt + test ciReleaseTagNextVersion ciReleaseSonatype

10 changes: 10 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version = 3.9.4
rewrite.rules = [ AvoidInfix, SortImports ]
runner.dialect = scala36
project {
git = true
excludeFilters = [
plugin/src/sbt-test
]
layout = StandardConvention
}
30 changes: 0 additions & 30 deletions .travis.yml

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ You can search for released versions [here](http://search.maven.org/#search%7Cga

To obtain the latest unreleased development version, clone the repository and run `sbt publishLocal`.

Currently, Scala 2.11, 2.12 and 2.13 are supported.
Currently, Scala 2.13, 3.3 and 3.6 are supported.

## Examples

Expand Down
47 changes: 24 additions & 23 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,28 @@ import sbt.Resolver
lazy val commonSettings = Seq(
organization := "org.combinators",

scalaVersion := "2.13.1",
crossScalaVersions := Seq("2.11.12", "2.12.10", scalaVersion.value),
scalaVersion := "3.6.4",
crossScalaVersions := Seq("2.13.16", "3.3.5", scalaVersion.value),

resolvers ++= Seq(
Resolver.sonatypeRepo("releases"),
Resolver.typesafeRepo("releases"),
Resolver.sonatypeRepo("snapshots"),
Resolver.typesafeRepo("snapshots")
),
resolvers ++= Resolver.sonatypeOssRepos("releases"),
resolvers += Resolver.typesafeRepo("releases"),

headerLicense := Some(HeaderLicense.ALv2("2017-2019", "Jan Bessai")),
headerLicense := Some(HeaderLicense.ALv2("2017-2025", "Jan Bessai")),

scalacOptions ++= Seq(
"-unchecked",
"-deprecation",
"-feature",
"-language:implicitConversions"
)
),
scalacOptions ++= {
if (scalaVersion.value >= "2.13.14" && scalaVersion.value < "3.0") Seq(
// "-Xsource:3",
"-Xsource:3-cross"
)
else Nil
},
ThisBuild/scapegoatVersion := "3.1.8"
) ++ publishSettings

lazy val root = (Project(id = "templating", base = file(".")))
Expand All @@ -31,16 +35,15 @@ lazy val root = (Project(id = "templating", base = file(".")))
.settings(
moduleName := "templating",
libraryDependencies ++= Seq(
"org.scalactic" %% "scalactic" % "3.0.8" % "test",
"org.scalatest" %% "scalatest" % "3.0.8" % "test",
"com.github.javaparser" % "javaparser-core" % "3.14.14",
"org.apache.commons" % "commons-text" % "1.8",
"commons-io" % "commons-io" % "2.6" % "test",
"org.scala-lang.modules" %% "scala-collection-compat" % "2.1.2"
"org.scalactic" %% "scalactic" % "3.2.19" % "test",
"org.scalatest" %% "scalatest" % "3.2.19" % "test",
"com.github.javaparser" % "javaparser-core" % "3.26.4",
"org.apache.commons" % "commons-text" % "1.13.1",
"commons-io" % "commons-io" % "2.19.0" % "test"
),

sourceDirectories in (Test, TwirlKeys.compileTemplates) += sourceDirectory.value / "test" / "java-templates",
resourceDirectories in Test += sourceDirectory.value / "resources",
Test / TwirlKeys.compileTemplates / sourceDirectories += sourceDirectory.value / "test" / "java-templates",
Test / resourceDirectories += sourceDirectory.value / "resources",
TwirlKeys.templateImports := Seq(),
TwirlKeys.templateFormats += ("java" -> "org.combinators.templating.twirl.JavaFormat"),
TwirlKeys.templateImports += "scala.collection.immutable._",
Expand All @@ -53,7 +56,7 @@ lazy val root = (Project(id = "templating", base = file(".")))
TwirlKeys.templateImports += "com.github.javaparser.ast.stmt._",
TwirlKeys.templateImports += "com.github.javaparser.ast.`type`._",

sourceDirectories in (Test, TwirlKeys.compileTemplates) += sourceDirectory.value / "test" / "python-templates",
Test / TwirlKeys.compileTemplates / sourceDirectories += sourceDirectory.value / "test" / "python-templates",
TwirlKeys.templateFormats += ("py" -> "org.combinators.templating.twirl.PythonFormat"),
TwirlKeys.templateImports += "org.combinators.templating.twirl.Python"
)
Expand All @@ -64,13 +67,11 @@ lazy val publishSettings = Seq(
licenses := Seq("Apache 2" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")),
scmInfo := Some(ScmInfo(url("https://www.github.com/combinators/templating"), "scm:git:git@github.com:combinators/templating.git")),
developers := List(
Developer("JanBessai", "Jan Bessai", "jan.bessai@tu-dortmund.de", url("http://janbessai.github.io")),
Developer("JanBessai", "Jan Bessai", "jan.bessai@tu-dortmund.de", url("http://noprotocol.net")),
Developer("heineman", "George T. Heineman", "heineman@wpi.edu", url("http://www.cs.wpi.edu/~heineman")),
Developer("BorisDuedder", "Boris Düdder", "boris.d@di.ku.dk", url("http://duedder.net"))
),

pgpPublicRing := file("travis/local.pubring.asc"),
pgpSecretRing := file("travis/local.secring.asc"),
publishTo := sonatypePublishToBundle.value,
)

lazy val noPublishSettings = Seq(
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version = 1.2.8
sbt.version = 1.10.11
13 changes: 7 additions & 6 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
logLevel := Level.Warn
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.0")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.7")
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.4.2")
addSbtPlugin("ch.epfl.scala" % "sbt-release-early" % "2.1.1")
addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.2.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.1")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.3.15")
addSbtPlugin("org.playframework.twirl" % "sbt-twirl" % "2.0.8")
addSbtPlugin("io.shiftleft" % "sbt-ci-release-early" % "2.0.49")
addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.10.0")
addSbtPlugin("com.sksamuel.scapegoat" %% "sbt-scapegoat" % "1.2.12")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4")
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2019 Jan Bessai
* Copyright 2017-2025 Jan Bessai
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,40 +23,43 @@ import com.github.javaparser.ast.expr.{Name, NameExpr}
import com.github.javaparser.ast.visitor.GenericVisitorAdapter

import scala.collection.immutable._
import scala.collection.compat._
import scala.jdk.CollectionConverters._

trait JavaPersistableInstances {
/** Persistable instance for a compilation unit.
* Derives path and file names from the package and the name of the first declared type.

/** Persistable instance for a compilation unit. Derives path and file names
* from the package and the name of the first declared type.
*/
implicit def compilationUnitInstance: JavaPersistable.Aux[CompilationUnit] =
new Persistable {
type T = CompilationUnit
override def rawText(compilationUnit: CompilationUnit) = compilationUnit.toString.getBytes
override def rawText(compilationUnit: CompilationUnit) =
compilationUnit.toString.getBytes
override def path(compilationUnit: CompilationUnit) = {
val pkg: Seq[String] =
compilationUnit.getPackageDeclaration.orElse(null) match {
case null => Seq.empty
case somePkg =>
somePkg.accept(new GenericVisitorAdapter[Seq[String], Unit] {
override def visit(name: NameExpr, arg: Unit): Seq[String] = Seq(name.getNameAsString)
override def visit(name: Name, arg: Unit): Seq[String] =
Option(name.getQualifier.orElse(null))
.map((q: Name) => q.accept(this, arg))
.getOrElse(Seq.empty[String]) :+ name.getIdentifier
},
somePkg.accept(
new GenericVisitorAdapter[Seq[String], Unit] {
override def visit(name: NameExpr, arg: Unit): Seq[String] =
Seq(name.getNameAsString)
override def visit(name: Name, arg: Unit): Seq[String] =
Option(name.getQualifier.orElse(null))
.map((q: Name) => q.accept(this, arg))
.getOrElse(Seq.empty[String]) :+ name.getIdentifier
},
()
)
}
val clsName = s"${compilationUnit.getTypes.asScala.head.getName}.java"
val fullPath = "src" +: "main" +: "java" +: pkg :+ clsName
Paths.get(fullPath.head, fullPath.tail : _*)
Paths.get(fullPath.head, fullPath.tail*)
}
}
}

object JavaPersistable extends JavaPersistableInstances {
type Aux[TT] = Persistable { type T = TT }
def apply[T](implicit persistable: Aux[T]): Aux[T] = persistable
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2019 Jan Bessai
* Copyright 2017-2025 Jan Bessai
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,24 +21,27 @@ import java.io.File

/** Type class for persistable objects (inhabitants). */
trait Persistable {

/** The type of the object to persist */
type T

/** Serialized representation of the object */
def rawText(elem: T): Array[Byte]
/** Path where to store the object `elem` (relative to some later specified root) */

/** Path where to store the object `elem` (relative to some later specified
* root)
*/
def path(elem: T): Path

/**
* Computes the full path where to place `elem` relative to `basePath`.
/** Computes the full path where to place `elem` relative to `basePath`.
*/
def fullPath(basePath: Path, elem: T): Path = {
basePath.resolve(path(elem))
}


/**
* Persists this object to an object dependent path under `basePath` and returns the persisted file.
* Overwrites any pre-existing files under `basePath` / `path`.
/** Persists this object to an object dependent path under `basePath` and
* returns the persisted file. Overwrites any pre-existing files under
* `basePath` / `path`.
*/
def persistOverwriting(basePath: Path, elem: T): File = {
val fp = fullPath(basePath, elem)
Expand All @@ -48,9 +51,9 @@ trait Persistable {
fp.toFile
}

/**
* Persists this object to an object dependent path under `basePath` and returns the persisted file.
* Throws an `FileAlreadyExistsException` if the file already exists.
/** Persists this object to an object dependent path under `basePath` and
* returns the persisted file. Throws an `FileAlreadyExistsException` if the
* file already exists.
*/
def persist(basePath: Path, elem: T): File = {
val fp = fullPath(basePath, elem)
Expand All @@ -64,4 +67,4 @@ object Persistable {
type Aux[TT] = Persistable { type T = TT }

def apply[T](implicit persistable: Aux[T]): Aux[T] = persistable
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2019 Jan Bessai
* Copyright 2017-2025 Jan Bessai
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,8 +24,10 @@ import org.combinators.templating.twirl.Python
case class PythonWithPath(code: Python, persistTo: Path)

trait PythonWithPathPersistableInstances {

/** Persistable instance for [PythonWithPath]. */
implicit def pythonWithPathPersistable: PythonWithPathPersistable.Aux[PythonWithPath] = new Persistable {
implicit def pythonWithPathPersistable
: PythonWithPathPersistable.Aux[PythonWithPath] = new Persistable {
type T = PythonWithPath
def rawText(elem: PythonWithPath): Array[Byte] = elem.code.getCode.getBytes
def path(elem: PythonWithPath): Path = elem.persistTo
Expand Down
Loading
Loading