{"id":18088231,"url":"https://github.com/earldouglas/sbt-war","last_synced_at":"2025-12-16T21:40:12.743Z","repository":{"id":1019436,"uuid":"1656266","full_name":"earldouglas/sbt-war","owner":"earldouglas","description":"Package and run WAR files from sbt","archived":false,"fork":false,"pushed_at":"2025-05-01T21:26:34.000Z","size":1923,"stargazers_count":382,"open_issues_count":1,"forks_count":102,"subscribers_count":18,"default_branch":"main","last_synced_at":"2025-05-06T10:09:46.505Z","etag":null,"topics":["j2ee","sbt","sbt-plugin","servlet","war"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/earldouglas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2011-04-24T10:27:46.000Z","updated_at":"2025-05-04T21:21:33.000Z","dependencies_parsed_at":"2023-10-15T14:53:48.006Z","dependency_job_id":"6d625836-f955-4872-8828-6182ea370196","html_url":"https://github.com/earldouglas/sbt-war","commit_stats":{"total_commits":1053,"total_committers":34,"mean_commits":"30.970588235294116","dds":"0.19183285849952514","last_synced_commit":"726afd8f81f178f29f0220170dc1ee01010e9569"},"previous_names":["earldouglas/sbt-war","earldouglas/xsbt-web-plugin"],"tags_count":58,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earldouglas%2Fsbt-war","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earldouglas%2Fsbt-war/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earldouglas%2Fsbt-war/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earldouglas%2Fsbt-war/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/earldouglas","download_url":"https://codeload.github.com/earldouglas/sbt-war/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254384982,"owners_count":22062422,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["j2ee","sbt","sbt-plugin","servlet","war"],"created_at":"2024-10-31T17:12:24.895Z","updated_at":"2025-12-16T21:40:12.730Z","avatar_url":"https://github.com/earldouglas.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build status](https://github.com/earldouglas/sbt-war/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/earldouglas/sbt-war/actions/workflows/test.yml)\n[![Latest version](https://img.shields.io/github/v/tag/earldouglas/sbt-war)](https://github.com/earldouglas/sbt-war/tags)\n[![Maven Central](https://img.shields.io/maven-central/v/com.earldouglas/sbt-war_2.12_1.0)](https://repo1.maven.org/maven2/com/earldouglas/sbt-war_2.12_1.0/)\n\n# sbt-war\n\nsbt-war is an [sbt](https://www.scala-sbt.org/) plugin for packaging and\nrunning [WAR](https://en.wikipedia.org/wiki/WAR_(file_format)) files.\n\nsbt-war is formerly known as xsbt-web-plugin.  For documentation and\nsource code of prior versions, browse this repository from the desired\ngit tag.  The most recent prior version is\n[4.2.5](https://github.com/earldouglas/sbt-war/tree/4.2.5).\n\n## Requirements\n\n* sbt 1.x or sbt 2.x\n* Scala 2.12.x and up\n\n## Getting help\n\n* Submit a question, bug report, or feature request as a [new GitHub\n  issue](https://github.com/earldouglas/sbt-war/issues/new)\n* Look for *earldouglas* in the `#sbt` channel on the [Scala Discord\n  server](https://discord.com/invite/scala)\n\n## Project structure\n\nA project that uses sbt-war looks something like this:\n\n```\n$ tree my-web-project/\nmy-web-project/\n├── build.sbt\n├── project\n│   ├── build.properties\n│   └── plugins.sbt\n└── src\n    ├── main\n    │   ├── scala\n    │   │   └── mypackage\n    │   │       └── MyServlet.scala\n    │   └── webapp\n    │       ├── images\n    │       │   └── logo.png\n    │       ├── index.html\n    │       └── styles\n    │           └── style.css\n    └── test\n        └── scala\n            ├── http.scala\n            └── mypackage\n                └── MyServletSuite.scala\n```\n\nA packaged WAR file looks something like this:\n\n```\n$ sbt \"show package\"\n[info] /path/to/my-web-project/target/scala-3.1.0/my-web-project_3-0.1.0-SNAPSHOT.war\n\n$ jar -tf target/scala-3.1.0/my-web-project_3-0.1.0-SNAPSHOT.war | LC_COLLATE=C sort\nMETA-INF/MANIFEST.MF\nWEB-INF/\nWEB-INF/classes/\nWEB-INF/classes/mypackage/\nWEB-INF/classes/mypackage/Servlet.class\nWEB-INF/classes/mypackage/Servlet.tasty\nWEB-INF/lib/\nWEB-INF/lib/scala-library-2.13.6.jar\nWEB-INF/lib/scala3-library_3-3.1.0.jar\nimages/\nimages/logo.png\nindex.html\nstyles/\nstyles/style.css\n```\n\nClasses under *src/main/scala* are compiled and included in the WAR\nfile under *WEB-INF/classes*.\n\nDependencies are copied as JAR files into the *WEB-INF/lib/* directory.\n\nStatic assets (such as .html files, stylesheets, images, etc.) are\ncopied from *src/main/webapp* to to the root of the WAR file.\n\n## Getting started from a template\n\n```\n$ sbt new earldouglas/sbt-war.g8\n\nname [My Web Project]: hello sbt-war\n\nTemplate applied in ./hello-sbt-war\n\n$ cd hello-sbt-war/\n$ sbt\n\u003e warStart\n```\n\n```\n$ curl localhost:8080/hello\n\u003ch1\u003eHello, world!\u003c/h1\u003e\n```\n\n```\n\u003e warStop\n```\n\n## Getting started from scratch\n\nCreate a new empty project:\n\n```\n$ mkdir myproject\n$ cd myproject\n```\n\nSet up the project structure:\n\n```\n$ mkdir project\n$ mkdir -p src/main/scala/mypackage\n```\n\nConfigure sbt:\n\n*project/build.properties:*\n\n```\nsbt.version=1.10.2\n```\n\n*project/plugins.sbt:*\n\n```scala\naddSbtPlugin(\"com.earldouglas\" % \"sbt-war\" % \"5.1.1\")\n```\n\n*build.sbt:*\n\n```scala\nscalaVersion := \"3.5.1\"\nenablePlugins(SbtWar)\n```\n\nAdd a servlet:\n\n*src/main/scala/mypackage/MyServlet.scala*:\n\n```scala\npackage mypackage\n\nimport jakarta.servlet.annotation.WebServlet\nimport jakarta.servlet.http.HttpServlet\nimport jakarta.servlet.http.HttpServletRequest\nimport jakarta.servlet.http.HttpServletResponse\n\n@WebServlet(urlPatterns = Array(\"/hello\"))\nclass MyServlet extends HttpServlet:\n  override def doGet(\n      req: HttpServletRequest,\n      res: HttpServletResponse\n  ): Unit =\n    res.setContentType(\"text/html\")\n    res.setCharacterEncoding(\"UTF-8\")\n    res.getWriter.write(\"\"\"\u003ch1\u003eHello, world!\u003c/h1\u003e\"\"\")\n```\n\nRun it from sbt with `warStart`:\n\n```\n$ sbt\n\u003e warStart\n```\n\n```\n$ curl localhost:8080/hello\n\u003ch1\u003eHello, world!\u003c/h1\u003e\n```\n\nStop it with `warStop`:\n\n```\n\u003e warStop\n```\n\nCreate a WAR file with `package`:\n\n```\n\u003e package\n```\n\n## Settings\n\n| Key                | Type               | Default            | Notes                                                                       |\n| ------------------ | ------------------ | ------------------ | --------------------------------------------------------------------------- |\n| `warResources`     | `Map[String,File]` | *src/main/webapp*  | Static files (HTML, CSS, JS, images, etc.) to serve directly                |\n| `warClasses`       | `Map[String,File]` | project classes    | .class files to copy into the *WEB-INF/classes* directory                   |\n| `warLib`           | `Map[String,File]` | project libs       | JAR files to copy into the *WEB-INF/lib* directory                          |\n| `warPort`          | `Int`              | `8080`             | The local container port to use when running with `warStart`                |\n| `warForkOptions`   | [`ForkOptions`][1] | [`forkOptions`][2] | Options for the forked JVM used when running with `warStart`                |\n\n## Commands\n\n| Key               | Notes                                                                   |\n| ----------------- | ----------------------------------------------------------------------- |\n| `warStart`        | Starts a local container, serving content directly from project sources |\n| `warStartPackage` | Starts a local container, serving content from the packaged WAR file    |\n| `warJoin`         | Blocks until the container shuts down                                   |\n| `warStop`         | Shuts down the container                                                |\n\n### `warResources`\n\nResources are the various static files, deployment descriptors, etc.\nthat go into a WAR file.\n\nThe `warResources` setting is a mapping from destination to source of\nthese files.  The destination is a path relative to the contents of the\nWAR file.  The source is a path on the local filesystem.\n\nBy default, everything in *src/main/webapp* is included.\n\nFor example, given the following WAR file:\n\n```\nmyproject.war\n├── index.html\n├── styles/\n│   └── theme.css\n├── WEB-INF/\n│   └── web.xml\n└── META-INF/\n    └── MANIFEST.MF\n```\n\nThe `warResources` mapping would look like this:\n\n```\n\"index.html\" -\u003e File(\".../src/main/webapp/index.html\")\n\"styles/theme.css\" -\u003e File(\".../src/main/webapp/styles/theme.css\")\n\"WEB-INF/web.xml\" -\u003e File(\".../src/main/webapp/WEB-INF/web.xml\")\n```\n\nTo use a different directory, e.g. *src/main/WebContent*:\n\n```scala\nwarResources :=\n  (Compile / sourceDirectory)\n    .map(_ / \"WebContent\")\n    .map(WebappComponents.getResources)\n```\n\nManifest attributes of the WAR file can be configured via\n`packageOptions`:\n\n```scala\nsbt.Keys.`package` / packageOptions +=\n  Package.ManifestAttributes(\n    java.util.jar.Attributes.Name.SEALED -\u003e \"true\"\n  )\n```\n\n### `warClasses`\n\nBy default, project classes are copied into the *WEB-INF/classes*\ndirectory of the WAR file.  To package them in a JAR file in the\n*WEB-INF/lib* directory instead, set `exportJars`:\n\n```scala\nexportJars := true\n```\n\nSee [\"Configure\npackaging\"](https://www.scala-sbt.org/1.x/docs/Howto-Package.html) in\nthe sbt documentation for additional information.\n\n### `warLib`\n\nBy default, all runtime dependencies are copied into the *WEB-INF/lib*\ndirectory.\n\nTo use a dependency at compile time but exclude it from the WAR file,\nset its scope to `Provided`:\n\n```scala\nlibraryDependencies += \"foo\" % \"bar\" % \"1.0.0\" % Provided\n```\n\n### `warPort`\n\nBy default, the container runs on port *8080*.  To use a different port,\nset `warPort`:\n\n```scala\nwarPort := 9090\n```\n\n### `warForkOptions`\n\nTo set environment variables, system properties, and more for the\nforked container JVM, set a\n[ForkOptions](https://www.scala-sbt.org/1.x/api/sbt/ForkOptions.html)\ninstance via `warForkOptions`.\n\nFor example: to be able to attach a debugger, set `-Xdebug` and\n`-Xrunjdwp`:\n\n*build.sbt:*\n\n```scala\nwarForkOptions :=\n  ForkOptions()\n    .withRunJVMOptions(\n      Seq(\n        \"-Xdebug\",\n        \"-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000\"\n      )\n    )\n```\n\n### `warStart` and `warStartPackage`\n\nTo run the webapp directly from project sources, use `warStart`:\n\n```\n\u003e warStart\n```\n\nTo run the webapp from the packaged WAR file, use `warStartPackage`:\n\n```\n\u003e warStartPackage\n```\n\nBoth of these can be used with [triggered\nexecution](https://www.scala-sbt.org/1.x/docs/Triggered-Execution.html)\nto automatically restart the container when source code is modified:\n\n```\n\u003e ~ warStart\n```\n\n[Container logs](https://www.scala-sbt.org/1.x/docs/Howto-Logging.html)\nwill appear both in the console and under the `target/streams/`.\n\n### `warJoin`\n\nTo block sbt while the container is running, use `warJoin`:\n\n```\n$ sbt warStart warJoin\n```\n\nThis is useful for running sbt in production (e.g. in a Docker\ncontainer), if you're into that kind of thing.\n\n### `warStop`\n\nTo stop the running container, use `warStop`:\n\n```\n\u003e warStop\n```\n\n[1]: https://www.scala-sbt.org/1.x/api/sbt/ForkOptions.html\n[2]: https://www.scala-sbt.org/1.x/api/sbt/Keys$.html#forkOptions:sbt.TaskKey[sbt.ForkOptions]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fearldouglas%2Fsbt-war","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fearldouglas%2Fsbt-war","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fearldouglas%2Fsbt-war/lists"}