Search code examples
scalasbtsbt-native-packager

Produce multiple zip artifacts from one sbt module


I have the following project structure:

my-project/
  build.sbt
  ...
  app/
  ...
  config/
    dev/
      file1.properties
      file2.properties
    test/
      file1.properties
      file2.properties
    prod/
      file1.properties
      file2.properties

The module app contains some scala source code and produces a plain jar file.

The problem is with the config module. What I need to do is to create some configuration in build.sbt that will take each folder from config and put its content into a separate zip file.

The result should be as follows:

my-project-config-dev-1.1.zip ~>
  file1.properties
  file2.properties
my-project-config-uat-1.1.zip ~>
  file1.properties
  file2.properties
my-project-config-prod-1.1.zip ~>
  file1.properties
  file2.properties

1.1 is an arbitrary version of the project.

The configuration should work in such way that when I add new environments and new configuration files, more zip files will be produced. In another task all these zip files should be published to Nexus.

Any suggestions?


Solution

  • I managed to resolve the problem by creating a module config and then a separate sub-module for each environment, so the project structure looks exactly as described in question. It all comes now to proper configuration in build.sbt.

    Below is the general idea of what I've done to achieve what I wanted.

    lazy val config = (project in file("config")).
      enablePlugins(UniversalPlugin).
      settings(
        name := "my-project",
        version := "1.1",
        publish in Universal := { },       // disable publishing of config module
        publishLocal in Universal := { }
      ).
      aggregate(configDev, configUat, configProd)
    
    lazy val environment = settingKey[String]("Target environment")
    
    lazy val commonSettings = makeDeploymentSettings(Universal, packageBin in Universal, "zip") ++ Seq(  // set package format
      name := "my-project-config",
      version := "1.1",
      environment := baseDirectory.value.getName,                                               // set 'environment' variable based on a configuration folder name
      topLevelDirectory := None,                                                                // set top level directory for each package
      packageName in Universal := s"my-project-config-${environment.value}-${version.value}",   // set package name (example: my-project-config-dev-1.1)
      mappings in Universal ++= contentOf(baseDirectory.value).filterNot { case (_, path) =>    // do not include target folder
        path contains "target"
      }
    )
    
    lazy val configDev = (project in file("config/dev")).enablePlugins(UniversalPlugin).settings(commonSettings: _*)
    lazy val configUat = (project in file("config/uat")).enablePlugins(UniversalPlugin).settings(commonSettings: _*)
    lazy val configProd = (project in file("config/prod")).enablePlugins(UniversalPlugin).settings(commonSettings: _*)
    

    UniversalPlugin is highly configurable, although not all configuration options may be clear at first. I suggest reading its docs and looking at the source code.

    To actually package artifacts the following command has be issued:

    sbt config/universal:packageBin
    

    Publishing:

    sbt config/universal:publish
    

    As can be seen above adding new environments is very easy - only a new folder and one line in build.sbt need to be added.