diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index 2e177e9..ac65d26 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -14,10 +14,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 + - uses: actions/checkout@v4 + - name: Set up JDK + uses: actions/setup-java@v4 with: - java-version: 1.8 + distribution: temurin + java-version: 17 + - uses: sbt/setup-sbt@v1 - name: Run tests + shell: bash run: sbt test diff --git a/.gitignore b/.gitignore index 8d77446..c1ea2b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ +.bloop/ +.bsp/ .DS_Store .idea/ target/ local_env.sh *.iml + +.env diff --git a/.jvmopts b/.jvmopts new file mode 100644 index 0000000..e6e135d --- /dev/null +++ b/.jvmopts @@ -0,0 +1,2 @@ +--add-opens=java.base/java.util=ALL-UNNAMED +--add-opens=java.base/java.lang=ALL-UNNAMED diff --git a/README.md b/README.md index ae08af2..f2b8356 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Experimental plugin for sbt to create Azure Function artefacts (function.json) n in your `project/plugins.sbt` add sbt-assembly and sbt-azure-functions: - addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") + addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") addSbtPlugin("nl.codestar" % "sbt-azure-functions" % "") in your `build.sbt` provide values for the assembly and azure-functions plugins: @@ -19,6 +19,11 @@ in your `build.sbt` provide values for the assembly and azure-functions plugins: lazy val root = (project in file(".")) .settings( ... + // replace these values with appropriate values for your Azure Function + azfunFunctionAppName := "ScalaFunction", + azfunLocation := "azure-location", // e.g. "westeurope", "eastus", etc. + azfunResourceGroup := "your-resource-group", + azfunStorageAccount := "yourstorageaccount" // optional: override the zip and/or jar name (defaults are AzureFunction.zip and AzureFunction.jar) azfunZipName := "myFunctions.zip", @@ -26,7 +31,7 @@ in your `build.sbt` provide values for the assembly and azure-functions plugins: // you need this dependency to be able to use the annotations libraryDependencies ++= Seq( - "com.microsoft.azure.functions" % "azure-functions-java-library" % "1.3.1" + "com.microsoft.azure.functions" % "azure-functions-java-library" % "3.1.0" ) ) @@ -52,13 +57,12 @@ in your `build.sbt` provide values for the assembly and azure-functions plugins: and logged in to the correct Azure Subscription. You will also have to install the app-insights extension to the CLI, by running `az extension add -n application-insights` - You can provide the following settings to determine the destination: + You must provide the following settings to determine the destination: * `azfunResourceGroup` * `azfunStorageAccount` ## TODO: -1. add task to upload to Azure 1. add support for App Insights workspaces 1. add tests against multiple Java versions (java 8 and Java 11) @@ -70,19 +74,19 @@ released for different scala versions and different sbt versions. I have not (ye what Scala version is used for each sbt release, except for https://github.com/sbt/sbt/issues/5032, so I am also keeping track here: -| SBT release(s)| Scala version | Remarks | -|---------------|-------------------|--------------------------------------------------| -| 0.x | 2.10.x | -| 1.x | 2.12.x | -| 2.x | 2.13.x or 3.0.x | -| 3.x | 3.0.x or 3.1.x | +| SBT release(s) | Scala version | Remarks | +|-----------------|-----------------|---------| +| 0.x | 2.10.x | | +| 1.x | 2.12.x | | +| 2.x | 2.13.x or 3.0.x | | +| 3.x | 3.0.x or 3.1.x | | For now, I will focus only on sbt 1.x and Scala 2.12.x ### Microsoft Azure Dependencies This plugin uses artifacts from Microsoft: -* "com.microsoft.azure" % "azure-tools-common" % "0.10.0" -* "com.microsoft.azure.functions" % "azure-functions-java-library" % "1.3.1" % "test" +* `"com.microsoft.azure" % "azure-tools-common" % "0.10.0"` +* `"com.microsoft.azure.functions" % "azure-functions-java-library" % "1.3.1" % "test"` For now I will use these versions @@ -90,17 +94,40 @@ For now I will use these versions #### Unit tests * `sbt clean test` #### Scripted tests +* `sbt publishLocal` * `sbt scripted` -## Releasing (for plugin maintainers) -To release a new version: -* Get a [bintray](https://bintray.com) account and make sure you're a member of the [`code-star`](https://bintray.com/code-star) organization. -* Set your credentials - you can use `sbt bintrayChangeCredentials`, but when run from the interactive sbt prompt - you will not see the requests for username and password. So blindly first type your username, press enter, then - paste your API key and press enter again. - - (found a workaround that shows the prompt again: add to build.sbt: `ThisBuild / useSuperShell := false`) -* reload to make new settings known to sbt -* Run `sbt release` +Note: to successfully run the `deploy` scripted test, you need to have the Azure CLI installed and logged in to Azure with proper access +to a subscription that has a resource group and storage account as specified in the `sbt-test/sbt-azure-functions/deploy/build.sbt` file. -Update Feb 2021: we started moving away from Bintray. We will start using sbt-ci-release and release to Maven Central. +## Releasing (for plugin maintainers) +To release a new version, make sure you have: +* proper access to the `nl.codestar` namespace on Sonatype. +* GnuPG (`gpg`) installed and a signing key configured. + * We use `sbt-pgp` plugin to sign, which relies on the `gpg` command line tool +* create a `.env` file in the project root with the following variables: + ``` + PGP_KEYID= + PGP_PASSPHRASE= + SONATYPE_USER= + SONATYPE_PASSWORD= + + ``` + +Note: The `.env` file needs to be kept out of the git repository (it is `.gitignore`d). + +See [Using Sonatype](https://www.scala-sbt.org/1.x/docs/Using-Sonatype.html) in the SBT documentation. + +### SNAPSHOT versions +Steps to release SNAPSHOT version: +1. Make sure HEAD is not directly pointing to a tag +2. `sbt publishSigned` +3. make note of the SNAPSHOT version that is used (Sonatype does not allow searching/browsing for SNAPSHOT versions) + +### Production versions +Steps to release production version: +1. Tag the current commit with the new version number, e.g. `git tag v0.5.0` +2. `sbt publishSigned` +3. `sbt sonaUpload` +4. Go to https://central.sonatype.com/publishing/deployments and publish the deployment. + * or run `sbt sonaRelease` to publish the deployment automatically diff --git a/build.sbt b/build.sbt index 11edba1..bbe41f9 100644 --- a/build.sbt +++ b/build.sbt @@ -1,34 +1,83 @@ lazy val commonSettings = Seq( organization := "nl.codestar", homepage := Some(url("https://github.com/code-star/sbt-azure-functions-plugin")), - // version is set by sbt-dynver plugin (included through sbt-ci-assembly) + // version is set by sbt-dynver plugin (included through sbt-ci-release) description := "SBT Plugin to generate function.json artefacts needed to publish code as an Azure Function", + organization := "nl.codestar", + organizationName := "Codestar powered by Sopra Steria", + organizationHomepage := Some(url("https://codestar.nl")), + homepage := Some(url("https://codestar.nl/sbt-azure-functions-plugin")), licenses += ("MIT", url("https://opensource.org/licenses/MIT")), developers := List( Developer( "jeanmarc", "Jean-Marc van Leerdam", - "jean-marc.van.leerdam@ordina.nl", - url("https://github.com/jeanmarc") + "jean-marc.vanleerdam@soprasteria.com", + url("https://soprasteria.com") + ) + ), + scmInfo := Some( + ScmInfo( + url("https://github.com/code-star/sbt-azure-functions-plugin"),"scm:git@github.com:code-star/sbt-azure-functions-plugin.git") + ), + credentials ++= Seq( + Credentials( + "GnuPG Key ID", + "gpg", + System.getenv("PGP_KEYID"), // key identifier + "ignored" // this field is ignored; passwords are supplied by pinentry + ), + Credentials( + "Sonatype Nexus Repository Manager", + "oss.sonatype.org", + System.getenv("SONATYPE_USER"), + System.getenv("SONATYPE_PASSWORD") // Use environment variable for security + ), + Credentials( + "Sonatype Nexus Repository Manager", + "central.sonatype.com", + System.getenv("SONATYPE_USER"), + System.getenv("SONATYPE_PASSWORD") // Use environment variable for security + ), + Credentials( + "central-snapshots", + "central.sonatype.com", + System.getenv("SONATYPE_USER"), + System.getenv("SONATYPE_PASSWORD") // Use environment variable for security ) ) + ) -lazy val root = (project in file(".")) +lazy val root = project.in(file(".")) .aggregate(plugin) .settings( name := "sbt-azure-functions-plugin", commonSettings, // the root project should not produce any artifacts publishArtifact := false, - publish := {} + publish := {}, + sonaDeploymentName := { + val o = organization.value + val n = "sbt-azure-functions" + val v = version.value + val dt = java.time.LocalDateTime.now.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + s"$o:$n:$v:$dt" + }, ) -lazy val plugin = (project in file("plugin")) +lazy val plugin = project.in(file("plugin")) .enablePlugins(SbtPlugin) .settings( name := "sbt-azure-functions", commonSettings, + + scalaVersion := "2.12.18", + pluginCrossBuild / sbtVersion := { + scalaBinaryVersion.value match { + case "2.12" => "1.11.4" // set minimum version + } + }, scalacOptions ++= Seq( "-encoding", "UTF8", @@ -41,22 +90,31 @@ lazy val plugin = (project in file("plugin")) "-Ywarn-adapted-args" ), libraryDependencies ++= Seq( - "com.fasterxml.jackson.core" % "jackson-databind" % "2.12.0", - "com.microsoft.azure" % "azure-tools-common" % "0.10.0", - "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2", - "com.microsoft.azure.functions" % "azure-functions-java-library" % "1.3.1" % "test", - "org.scalatest" %% "scalatest" % "3.2.2" % "test", + "com.fasterxml.jackson.core" % "jackson-databind" % "2.19.2", + "com.microsoft.azure" % "azure-tools-common" % "0.14.0", + "com.typesafe.scala-logging" %% "scala-logging" % "3.9.5", + "com.microsoft.azure.functions" % "azure-functions-java-library" % "3.1.0" % "test", + "org.scalatest" %% "scalatest" % "3.2.19" % "test", "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value ), - addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10"), + addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1"), scriptedLaunchOpts := { scriptedLaunchOpts.value ++ Seq("-Xmx1024M", "-Dplugin.version=" + version.value) }, scriptedBufferLog := false, - logBuffered in Test := false, - publishArtifact in Test := false + Test / logBuffered := false, + Test / publishArtifact := false ) // workaround for interactive sessions that do not echo the user input (https://github.com/sbt/sbt-bintray/issues/177) ThisBuild / useSuperShell := false + +ThisBuild / pomIncludeRepository := { _ => false } +ThisBuild / publishMavenStyle := true + +ThisBuild / publishTo := { + val centralSnapshots = "https://central.sonatype.com/repository/maven-snapshots/" + if (isSnapshot.value) Some("central-snapshots" at centralSnapshots) + else localStaging.value +} diff --git a/plugin/src/main/scala/sbtazurefunctions/CreateZipFileTask.scala b/plugin/src/main/scala/sbtazurefunctions/CreateZipFileTask.scala index c52b21d..d99de29 100644 --- a/plugin/src/main/scala/sbtazurefunctions/CreateZipFileTask.scala +++ b/plugin/src/main/scala/sbtazurefunctions/CreateZipFileTask.scala @@ -19,7 +19,7 @@ object CreateZipFileTask { val log = sbt.Keys.streams.value.log - val tgtFolder = (target in Compile).value + val tgtFolder = (Compile / target).value log.info("Running azfunCreateZipFile task...") log.info( @@ -28,7 +28,7 @@ object CreateZipFileTask { val src = azfunTargetFolder.value val tgt = tgtFolder / ensureExtension(azfunZipName.value, "zip") - IO.zip(allSubpaths(src), tgt) + IO.zip(allSubpaths(src), tgt, None) tgt } ) diff --git a/plugin/src/main/scala/sbtazurefunctions/DefaultSettings.scala b/plugin/src/main/scala/sbtazurefunctions/DefaultSettings.scala index a108be1..a773aed 100644 --- a/plugin/src/main/scala/sbtazurefunctions/DefaultSettings.scala +++ b/plugin/src/main/scala/sbtazurefunctions/DefaultSettings.scala @@ -18,11 +18,11 @@ object DefaultSettings { def settings: Seq[Setting[_]] = Seq( azfunAppInsightsName := azfunFunctionAppName.value, - azfunHostJsonFile := (baseDirectory in Compile).value / "host.json", + azfunHostJsonFile := (Compile / baseDirectory).value / "host.json", azfunJarName := "AzureFunction.jar", - azfunLocalSettingsFile := (baseDirectory in Compile).value / "local.settings.json", + azfunLocalSettingsFile := (Compile / baseDirectory).value / "local.settings.json", azfunSKU := "Standard_LRS", - azfunTargetFolder := (target in Compile).value / stripExtension(azfunZipName.value), + azfunTargetFolder := (Compile / target).value / stripExtension(azfunZipName.value), azfunZipName := "AzureFunction.zip" ) diff --git a/plugin/src/sbt-test/sbt-azure-functions/deploy/build.sbt b/plugin/src/sbt-test/sbt-azure-functions/deploy/build.sbt index 8c5081e..e75b33a 100644 --- a/plugin/src/sbt-test/sbt-azure-functions/deploy/build.sbt +++ b/plugin/src/sbt-test/sbt-azure-functions/deploy/build.sbt @@ -3,13 +3,13 @@ import sbt.Keys.libraryDependencies lazy val root = (project in file(".")) .settings( version := "0.1", - scalaVersion := "2.12.7", + scalaVersion := "2.12.18", libraryDependencies ++= Seq( - "com.microsoft.azure.functions" % "azure-functions-java-library" % "1.3.1" + "com.microsoft.azure.functions" % "azure-functions-java-library" % "3.1.0" ), - assemblyJarName in assembly := "ScalaFunctions.jar", + assembly / assemblyJarName := "ScalaFunctions.jar", azfunFunctionAppName := "rd-scala-functions", azfunLocation := "westeurope", - azfunResourceGroup := "rg-rd-scala-functions", - azfunStorageAccount := "a77a749630954151919e" + azfunResourceGroup := "rg-function-showcase", + azfunStorageAccount := "rgfunctionshowcasebaa9" ) diff --git a/plugin/src/sbt-test/sbt-azure-functions/deploy/host.json b/plugin/src/sbt-test/sbt-azure-functions/deploy/host.json index 4ac8957..b2eb067 100644 --- a/plugin/src/sbt-test/sbt-azure-functions/deploy/host.json +++ b/plugin/src/sbt-test/sbt-azure-functions/deploy/host.json @@ -2,6 +2,6 @@ "version": "2.0", "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", - "version": "[1.*, 2.0.0)" + "version": "[2.*, 3.0.0)" } } \ No newline at end of file diff --git a/plugin/src/sbt-test/sbt-azure-functions/deploy/project/plugins.sbt b/plugin/src/sbt-test/sbt-azure-functions/deploy/project/plugins.sbt index 8111a40..1326da4 100644 --- a/plugin/src/sbt-test/sbt-azure-functions/deploy/project/plugins.sbt +++ b/plugin/src/sbt-test/sbt-azure-functions/deploy/project/plugins.sbt @@ -1,4 +1,4 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") sys.props.get("plugin.version") match { case Some(x) => addSbtPlugin("nl.codestar" % "sbt-azure-functions" % x) diff --git a/plugin/src/sbt-test/sbt-azure-functions/simple/build.sbt b/plugin/src/sbt-test/sbt-azure-functions/simple/build.sbt index 6ea06be..e75b33a 100644 --- a/plugin/src/sbt-test/sbt-azure-functions/simple/build.sbt +++ b/plugin/src/sbt-test/sbt-azure-functions/simple/build.sbt @@ -3,9 +3,13 @@ import sbt.Keys.libraryDependencies lazy val root = (project in file(".")) .settings( version := "0.1", - scalaVersion := "2.12.7", + scalaVersion := "2.12.18", libraryDependencies ++= Seq( - "com.microsoft.azure.functions" % "azure-functions-java-library" % "1.3.1" + "com.microsoft.azure.functions" % "azure-functions-java-library" % "3.1.0" ), - assemblyJarName in assembly := "ScalaFunctions.jar" + assembly / assemblyJarName := "ScalaFunctions.jar", + azfunFunctionAppName := "rd-scala-functions", + azfunLocation := "westeurope", + azfunResourceGroup := "rg-function-showcase", + azfunStorageAccount := "rgfunctionshowcasebaa9" ) diff --git a/plugin/src/sbt-test/sbt-azure-functions/simple/host.json b/plugin/src/sbt-test/sbt-azure-functions/simple/host.json index 4ac8957..b2eb067 100644 --- a/plugin/src/sbt-test/sbt-azure-functions/simple/host.json +++ b/plugin/src/sbt-test/sbt-azure-functions/simple/host.json @@ -2,6 +2,6 @@ "version": "2.0", "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", - "version": "[1.*, 2.0.0)" + "version": "[2.*, 3.0.0)" } } \ No newline at end of file diff --git a/plugin/src/sbt-test/sbt-azure-functions/simple/project/plugins.sbt b/plugin/src/sbt-test/sbt-azure-functions/simple/project/plugins.sbt index 8111a40..1326da4 100644 --- a/plugin/src/sbt-test/sbt-azure-functions/simple/project/plugins.sbt +++ b/plugin/src/sbt-test/sbt-azure-functions/simple/project/plugins.sbt @@ -1,4 +1,4 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") sys.props.get("plugin.version") match { case Some(x) => addSbtPlugin("nl.codestar" % "sbt-azure-functions" % x) diff --git a/plugin/src/test/scala/nl/codestar/azurefunctions/FunctionConfigGeneratorTest.scala b/plugin/src/test/scala/nl/codestar/azurefunctions/FunctionConfigGeneratorTest.scala index a4c5e57..bca3bc5 100644 --- a/plugin/src/test/scala/nl/codestar/azurefunctions/FunctionConfigGeneratorTest.scala +++ b/plugin/src/test/scala/nl/codestar/azurefunctions/FunctionConfigGeneratorTest.scala @@ -30,14 +30,14 @@ class FunctionConfigGeneratorTest extends AnyFlatSpec { "An annotated function" should "be found" in { val result = FunctionConfigGenerator.getFunctions(List(getClassUrl)) - assert(result.isEmpty == false) + assert(result.nonEmpty) } "An annotated function" should "produce a configuration" in { val result = FunctionConfigGenerator.getConfigs(List(getClassUrl)) - assert(result.isEmpty == false) + assert(result.nonEmpty) assert(result.get("ScalaFunction") != null) - val config = result.get("ScalaFunction").get + val config = result("ScalaFunction") assert(config.getEntryPoint == "nl.codestar.azurefunctions.FunctionConfigGeneratorTest.SampleAzureFunctions.run") assert(config.getScriptFile == null) val binding = config.getBindings.get(0) diff --git a/project/build.properties b/project/build.properties index 654fe70..61c9b1c 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.12 +sbt.version=1.11.1 diff --git a/project/plugins.sbt b/project/plugins.sbt index e131dc0..8811210 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,2 +1,5 @@ -addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.7") -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.13") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") +addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.11.1") +addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") +addSbtPlugin("nl.gn0s1s" % "sbt-dotenv" % "3.1.1") diff --git a/releasenotes.md b/releasenotes.md index e905417..3294fc4 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,6 +1,15 @@ # Release notes ## Version 0.5.0 +Updates: +* version updates to our dependencies +* use the 2.x series of the Microsoft Extension Bundle (1.x is no longer supported) + + + +## Version 0.4.6 +Based on latest develop (August 2025), used to release to Sonatype instead of Bintray + New features: * New task to deploy function to azure (`azfunDeploy`) diff --git a/showcase/build.sbt b/showcase/build.sbt index 2a8b30d..0dd849f 100644 --- a/showcase/build.sbt +++ b/showcase/build.sbt @@ -3,6 +3,10 @@ lazy val root = (project in file(".")) name := "showcase", version := "1.0", libraryDependencies ++= Seq( - "com.microsoft.azure.functions" % "azure-functions-java-library" % "1.3.1" - ) + "com.microsoft.azure.functions" % "azure-functions-java-library" % "3.1.0" + ), + azfunFunctionAppName := "ScalaFunction", + azfunLocation := "West Europe", + azfunResourceGroup := "your-resource-group", + azfunStorageAccount := "yourstorageaccount" ) diff --git a/showcase/host.json b/showcase/host.json index 4ac8957..b2eb067 100644 --- a/showcase/host.json +++ b/showcase/host.json @@ -2,6 +2,6 @@ "version": "2.0", "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", - "version": "[1.*, 2.0.0)" + "version": "[2.*, 3.0.0)" } } \ No newline at end of file diff --git a/showcase/project/build.properties b/showcase/project/build.properties index 654fe70..6520f69 100644 --- a/showcase/project/build.properties +++ b/showcase/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.12 +sbt.version=1.11.0 diff --git a/showcase/project/plugins.sbt b/showcase/project/plugins.sbt index 25fefef..c44d62d 100644 --- a/showcase/project/plugins.sbt +++ b/showcase/project/plugins.sbt @@ -1,4 +1,4 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") // build root project lazy val root = Project("showcase", file(".")) dependsOn (ProjectRef(pluginParent, "plugin"))