This is an automated email from the ASF dual-hosted git repository.

bobbai00 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/main by this push:
     new 92affb56c6 chore(build): ship LICENSE-binary, NOTICE-binary, and 
licenses/ in dist zips and images (#4449)
92affb56c6 is described below

commit 92affb56c686b5ed4fc6780bd23e798157865ed4
Author: Jiadong Bai <[email protected]>
AuthorDate: Wed Apr 29 01:35:59 2026 -0700

    chore(build): ship LICENSE-binary, NOTICE-binary, and licenses/ in dist 
zips and images (#4449)
    
    ### What changes were proposed in this PR?
    
    Route the binary-distribution compliance files into `sbt dist` zips and
    Docker images.
    
    **sbt wiring:**
    
    - `project/AddMetaInfLicenseFiles.scala` — replace `distSettings` with
    `distMappings(existing, rootDir)` that maps `LICENSE-binary` →
    `LICENSE`, `NOTICE-binary` → `NOTICE`, `DISCLAIMER-WIP` →
    `DISCLAIMER-WIP` (optional), and every `licenses/*.txt` into a top-level
    `licenses/` directory. Fails the build via `require(...)` if any
    compliance file is missing.
    - Root `build.sbt` — drop the `asfDistLicensingSettings` shortcut.
    - Six per-module `build.sbt` (access-control-service, amber,
    config-service, computing-unit-managing-service, file-service,
    workflow-compiling-service) — invoke `distMappings` on `Universal /
    mappings`.
    
    **Docker wiring** (8 `bin/*.dockerfile`):
    
    - Copy `LICENSE-binary`, `NOTICE-binary`, and `licenses/` into the build
    context.
    - At runtime, install `LICENSE-binary` as `/texera/LICENSE`,
    `NOTICE-binary` as `/texera/NOTICE`, and ship `licenses/` verbatim.
    - `computing-unit-master` / `computing-unit-worker` additionally run
    `pip-licenses` to emit `/texera/licenses/python-3rdparty.txt`.
    
    ### Any related issues, documentation, discussions?
    
    Closes #4448. Depends on #4387 landing first (provides `LICENSE-binary`
    / `NOTICE-binary` / `licenses/*.txt`).
    
    ### How was this PR tested?
    
    - `sbt dist` for each dist-producing module; unzipped output shows
    `LICENSE`, `NOTICE`, and `licenses/` at the top level with the expected
    contents.
    - Run `docker build` locallay and verified that the image include
    LICENSE and NOTICE properly
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Claude Opus 4.7)
    
    ---------
    
    Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
 access-control-service/build.sbt                   |  8 ++++
 amber/build.sbt                                    |  8 ++++
 bin/access-control-service.dockerfile              | 11 ++++-
 bin/computing-unit-master.dockerfile               | 11 ++++-
 bin/computing-unit-worker.dockerfile               | 11 ++++-
 bin/config-service.dockerfile                      | 11 ++++-
 bin/file-service.dockerfile                        | 11 ++++-
 bin/texera-web-application.dockerfile              | 13 +++++-
 bin/workflow-compiling-service.dockerfile          | 11 ++++-
 ...flow-computing-unit-managing-service.dockerfile | 11 ++++-
 build.sbt                                          |  9 +---
 computing-unit-managing-service/build.sbt          |  8 ++++
 config-service/build.sbt                           |  8 ++++
 file-service/build.sbt                             |  8 ++++
 project/AddMetaInfLicenseFiles.scala               | 48 ++++++++++++++--------
 workflow-compiling-service/build.sbt               |  8 ++++
 16 files changed, 161 insertions(+), 34 deletions(-)

diff --git a/access-control-service/build.sbt b/access-control-service/build.sbt
index ea09a451e5..4dcd74c7ac 100644
--- a/access-control-service/build.sbt
+++ b/access-control-service/build.sbt
@@ -22,6 +22,14 @@ name := "access-control-service"
 
 enablePlugins(JavaAppPackaging)
 
+// Ship LICENSE-binary, NOTICE-binary, DISCLAIMER-WIP, and the licenses/
+// directory at the top of the Universal dist zip.
+// See project/AddMetaInfLicenseFiles.scala.
+Universal / mappings := AddMetaInfLicenseFiles.distMappings(
+  (Universal / mappings).value,
+  (ThisBuild / baseDirectory).value
+)
+
 // Enable semanticdb for Scalafix
 ThisBuild / semanticdbEnabled := true
 ThisBuild / semanticdbVersion := scalafixSemanticdb.revision
diff --git a/amber/build.sbt b/amber/build.sbt
index ff7c722ca9..8b35af7449 100644
--- a/amber/build.sbt
+++ b/amber/build.sbt
@@ -20,6 +20,14 @@ name := "amber"
 
 enablePlugins(JavaAppPackaging)
 
+// Ship LICENSE-binary, NOTICE-binary, DISCLAIMER-WIP, and the licenses/
+// directory at the top of the Universal dist zip.
+// See project/AddMetaInfLicenseFiles.scala.
+Universal / mappings := AddMetaInfLicenseFiles.distMappings(
+  (Universal / mappings).value,
+  (ThisBuild / baseDirectory).value
+)
+
 semanticdbEnabled := true
 semanticdbVersion := scalafixSemanticdb.revision
 
diff --git a/bin/access-control-service.dockerfile 
b/bin/access-control-service.dockerfile
index 208fb4f40c..046f291f02 100644
--- a/bin/access-control-service.dockerfile
+++ b/bin/access-control-service.dockerfile
@@ -35,7 +35,8 @@ RUN apt-get update && apt-get install -y \
 
 # Add .git for runtime calls to jgit from OPversion
 COPY .git .git
-COPY LICENSE NOTICE DISCLAIMER-WIP ./
+COPY LICENSE LICENSE-binary NOTICE NOTICE-binary DISCLAIMER-WIP ./
+COPY licenses/ licenses/
 
 RUN sbt clean AccessControlService/dist
 
@@ -51,6 +52,14 @@ COPY --from=build /texera/.git /texera/.git
 COPY --from=build /texera/target/access-control-service* /texera/
 # Copy resources directories from build phase
 COPY --from=build /texera/access-control-service/src/main/resources 
/texera/access-control-service/src/main/resources
+# Copy ASF licensing files. LICENSE-binary and NOTICE-binary describe the
+# bundled third-party contents of this image and ship as /texera/LICENSE
+# and /texera/NOTICE; licenses/ holds the per-license full texts referenced
+# by LICENSE-binary.
+COPY --from=build /texera/LICENSE-binary /texera/LICENSE
+COPY --from=build /texera/NOTICE-binary /texera/NOTICE
+COPY --from=build /texera/licenses /texera/licenses
+COPY --from=build /texera/DISCLAIMER-WIP /texera/
 CMD ["bin/access-control-service"]
 
 EXPOSE 9096
\ No newline at end of file
diff --git a/bin/computing-unit-master.dockerfile 
b/bin/computing-unit-master.dockerfile
index ff0fbcff25..166bf8613f 100644
--- a/bin/computing-unit-master.dockerfile
+++ b/bin/computing-unit-master.dockerfile
@@ -35,7 +35,8 @@ RUN apt-get update && apt-get install -y \
 
 # Add .git for runtime calls to jgit from OPversion
 COPY .git .git
-COPY LICENSE NOTICE DISCLAIMER-WIP ./
+COPY LICENSE LICENSE-binary NOTICE NOTICE-binary DISCLAIMER-WIP ./
+COPY licenses/ licenses/
 
 RUN sbt clean WorkflowExecutionService/dist
 
@@ -69,6 +70,14 @@ COPY --from=build /texera/common/config/src/main/resources 
/texera/amber/common/
 COPY --from=build /texera/amber/src/main/resources 
/texera/amber/src/main/resources
 # Copy code for python UDF
 COPY --from=build /texera/amber/src/main/python /texera/amber/src/main/python
+# Copy ASF licensing files. LICENSE-binary and NOTICE-binary describe the
+# bundled third-party contents of this image and ship as /texera/LICENSE
+# and /texera/NOTICE; licenses/ holds the per-license full texts referenced
+# by LICENSE-binary.
+COPY --from=build /texera/LICENSE-binary /texera/LICENSE
+COPY --from=build /texera/NOTICE-binary /texera/NOTICE
+COPY --from=build /texera/licenses /texera/licenses
+COPY --from=build /texera/DISCLAIMER-WIP /texera/
 CMD ["bin/computing-unit-master"]
 
 EXPOSE 8085
diff --git a/bin/computing-unit-worker.dockerfile 
b/bin/computing-unit-worker.dockerfile
index 620719a3c3..a0608550eb 100644
--- a/bin/computing-unit-worker.dockerfile
+++ b/bin/computing-unit-worker.dockerfile
@@ -35,7 +35,8 @@ RUN apt-get update && apt-get install -y \
 
 # Add .git for runtime calls to jgit from OPversion
 COPY .git .git
-COPY LICENSE NOTICE DISCLAIMER-WIP ./
+COPY LICENSE LICENSE-binary NOTICE NOTICE-binary DISCLAIMER-WIP ./
+COPY licenses/ licenses/
 
 RUN sbt clean WorkflowExecutionService/dist
 
@@ -67,6 +68,14 @@ COPY --from=build /texera/amber/target/amber-* /texera/amber/
 # Copy resources directories from build phase
 COPY --from=build /texera/amber/src/main/resources 
/texera/amber/src/main/resources
 COPY --from=build /texera/common/config/src/main/resources 
/texera/amber/common/config/src/main/resources
+# Copy ASF licensing files. LICENSE-binary and NOTICE-binary describe the
+# bundled third-party contents of this image and ship as /texera/LICENSE
+# and /texera/NOTICE; licenses/ holds the per-license full texts referenced
+# by LICENSE-binary.
+COPY --from=build /texera/LICENSE-binary /texera/LICENSE
+COPY --from=build /texera/NOTICE-binary /texera/NOTICE
+COPY --from=build /texera/licenses /texera/licenses
+COPY --from=build /texera/DISCLAIMER-WIP /texera/
 CMD ["bin/computing-unit-worker"]
 
 EXPOSE 8085
\ No newline at end of file
diff --git a/bin/config-service.dockerfile b/bin/config-service.dockerfile
index a7665eb067..8a883ce5af 100644
--- a/bin/config-service.dockerfile
+++ b/bin/config-service.dockerfile
@@ -35,7 +35,8 @@ RUN apt-get update && apt-get install -y \
 
 # Add .git for runtime calls to jgit from OPversion
 COPY .git .git
-COPY LICENSE NOTICE DISCLAIMER-WIP ./
+COPY LICENSE LICENSE-binary NOTICE NOTICE-binary DISCLAIMER-WIP ./
+COPY licenses/ licenses/
 
 RUN sbt clean ConfigService/dist
 
@@ -52,6 +53,14 @@ COPY --from=build /texera/target/config-service-* /texera/
 # Copy resources directories from build phase
 COPY --from=build /texera/common/config/src/main/resources 
/texera/common/config/src/main/resources
 COPY --from=build /texera/config-service/src/main/resources 
/texera/config-service/src/main/resources
+# Copy ASF licensing files. LICENSE-binary and NOTICE-binary describe the
+# bundled third-party contents of this image and ship as /texera/LICENSE
+# and /texera/NOTICE; licenses/ holds the per-license full texts referenced
+# by LICENSE-binary.
+COPY --from=build /texera/LICENSE-binary /texera/LICENSE
+COPY --from=build /texera/NOTICE-binary /texera/NOTICE
+COPY --from=build /texera/licenses /texera/licenses
+COPY --from=build /texera/DISCLAIMER-WIP /texera/
 CMD ["bin/config-service"]
 
 EXPOSE 9094
\ No newline at end of file
diff --git a/bin/file-service.dockerfile b/bin/file-service.dockerfile
index 88bdf1c6b0..92db1ac3f1 100644
--- a/bin/file-service.dockerfile
+++ b/bin/file-service.dockerfile
@@ -35,7 +35,8 @@ RUN apt-get update && apt-get install -y \
 
 # Add .git for runtime calls to jgit from OPversion
 COPY .git .git
-COPY LICENSE NOTICE DISCLAIMER-WIP ./
+COPY LICENSE LICENSE-binary NOTICE NOTICE-binary DISCLAIMER-WIP ./
+COPY licenses/ licenses/
 
 RUN sbt clean FileService/dist
 
@@ -51,6 +52,14 @@ COPY --from=build /texera/target/file-service-* /texera/
 # Copy resources directories from build phase
 COPY --from=build /texera/common/config/src/main/resources 
/texera/common/config/src/main/resources
 COPY --from=build /texera/file-service/src/main/resources 
/texera/file-service/src/main/resources
+# Copy ASF licensing files. LICENSE-binary and NOTICE-binary describe the
+# bundled third-party contents of this image and ship as /texera/LICENSE
+# and /texera/NOTICE; licenses/ holds the per-license full texts referenced
+# by LICENSE-binary.
+COPY --from=build /texera/LICENSE-binary /texera/LICENSE
+COPY --from=build /texera/NOTICE-binary /texera/NOTICE
+COPY --from=build /texera/licenses /texera/licenses
+COPY --from=build /texera/DISCLAIMER-WIP /texera/
 CMD ["bin/file-service"]
 
 EXPOSE 9092
\ No newline at end of file
diff --git a/bin/texera-web-application.dockerfile 
b/bin/texera-web-application.dockerfile
index fec179d8d2..1470c71d77 100644
--- a/bin/texera-web-application.dockerfile
+++ b/bin/texera-web-application.dockerfile
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-FROM node:18.17 AS build-frontend
+FROM node:22-bookworm AS build-frontend
 
 RUN apt-get update && apt-get install -y --no-install-recommends \
         python3 build-essential git ca-certificates
@@ -49,7 +49,8 @@ RUN apt-get update && apt-get install -y \
 
 # Add .git for runtime calls to jgit from OPversion
 COPY .git .git
-COPY LICENSE NOTICE DISCLAIMER-WIP ./
+COPY LICENSE LICENSE-binary NOTICE NOTICE-binary DISCLAIMER-WIP ./
+COPY licenses/ licenses/
 
 RUN sbt clean WorkflowExecutionService/dist
 
@@ -67,6 +68,14 @@ COPY --from=build /texera/amber/target/amber-* /texera/amber/
 # Copy resources directories from build phase
 COPY --from=build /texera/amber/src/main/resources 
/texera/amber/src/main/resources
 COPY --from=build /texera/common/config/src/main/resources 
/texera/amber/common/config/src/main/resources
+# Copy ASF licensing files. LICENSE-binary and NOTICE-binary describe the
+# bundled third-party contents of this image and ship as /texera/LICENSE
+# and /texera/NOTICE; licenses/ holds the per-license full texts referenced
+# by LICENSE-binary.
+COPY --from=build /texera/LICENSE-binary /texera/LICENSE
+COPY --from=build /texera/NOTICE-binary /texera/NOTICE
+COPY --from=build /texera/licenses /texera/licenses
+COPY --from=build /texera/DISCLAIMER-WIP /texera/
 CMD ["bin/texera-web-application"]
 
 EXPOSE 8080
\ No newline at end of file
diff --git a/bin/workflow-compiling-service.dockerfile 
b/bin/workflow-compiling-service.dockerfile
index 440dce2777..307786bde5 100644
--- a/bin/workflow-compiling-service.dockerfile
+++ b/bin/workflow-compiling-service.dockerfile
@@ -35,7 +35,8 @@ RUN apt-get update && apt-get install -y \
 
 # Add .git for runtime calls to jgit from OPversion
 COPY .git .git
-COPY LICENSE NOTICE DISCLAIMER-WIP ./
+COPY LICENSE LICENSE-binary NOTICE NOTICE-binary DISCLAIMER-WIP ./
+COPY licenses/ licenses/
 
 RUN sbt clean WorkflowCompilingService/dist
 
@@ -52,6 +53,14 @@ COPY --from=build 
/texera/target/workflow-compiling-service-* /texera/
 # Copy resources directories from build phase
 COPY --from=build /texera/common/config/src/main/resources 
/texera/common/config/src/main/resources
 COPY --from=build /texera/workflow-compiling-service/src/main/resources 
/texera/workflow-compiling-service/src/main/resources
+# Copy ASF licensing files. LICENSE-binary and NOTICE-binary describe the
+# bundled third-party contents of this image and ship as /texera/LICENSE
+# and /texera/NOTICE; licenses/ holds the per-license full texts referenced
+# by LICENSE-binary.
+COPY --from=build /texera/LICENSE-binary /texera/LICENSE
+COPY --from=build /texera/NOTICE-binary /texera/NOTICE
+COPY --from=build /texera/licenses /texera/licenses
+COPY --from=build /texera/DISCLAIMER-WIP /texera/
 CMD ["bin/workflow-compiling-service"]
 
 EXPOSE 9090
\ No newline at end of file
diff --git a/bin/workflow-computing-unit-managing-service.dockerfile 
b/bin/workflow-computing-unit-managing-service.dockerfile
index e11dacc046..0f354876fc 100644
--- a/bin/workflow-computing-unit-managing-service.dockerfile
+++ b/bin/workflow-computing-unit-managing-service.dockerfile
@@ -35,7 +35,8 @@ RUN apt-get update && apt-get install -y \
 
 # Add .git for runtime calls to jgit from OPversion
 COPY .git .git
-COPY LICENSE NOTICE DISCLAIMER-WIP ./
+COPY LICENSE LICENSE-binary NOTICE NOTICE-binary DISCLAIMER-WIP ./
+COPY licenses/ licenses/
 
 RUN sbt clean ComputingUnitManagingService/dist
 
@@ -52,6 +53,14 @@ COPY --from=build 
/texera/target/computing-unit-managing-service-* /texera/
 # Copy resources directories from build phase
 COPY --from=build /texera/common/config/src/main/resources 
/texera/common/config/src/main/resources
 COPY --from=build /texera/computing-unit-managing-service/src/main/resources 
/texera/computing-unit-managing-service/src/main/resources
+# Copy ASF licensing files. LICENSE-binary and NOTICE-binary describe the
+# bundled third-party contents of this image and ship as /texera/LICENSE
+# and /texera/NOTICE; licenses/ holds the per-license full texts referenced
+# by LICENSE-binary.
+COPY --from=build /texera/LICENSE-binary /texera/LICENSE
+COPY --from=build /texera/NOTICE-binary /texera/NOTICE
+COPY --from=build /texera/licenses /texera/licenses
+COPY --from=build /texera/DISCLAIMER-WIP /texera/
 CMD ["bin/computing-unit-managing-service"]
 
 EXPOSE 8888
\ No newline at end of file
diff --git a/build.sbt b/build.sbt
index 980bbe3a65..696fb984cb 100644
--- a/build.sbt
+++ b/build.sbt
@@ -22,9 +22,10 @@ ThisBuild / scalaVersion := "2.13.18"
 // Per-module ASF licensing: each jar's META-INF/LICENSE describes only what 
is in that jar.
 // Modules without vendored code get Apache 2.0 only; workflow-operator 
includes mbknor attribution.
 // See project/AddMetaInfLicenseFiles.scala.
+// Dist-producing modules additionally override Universal / mappings in their 
own
+// build.sbt (not here) — see AddMetaInfLicenseFiles.distMappings.
 lazy val asfLicensingSettings = AddMetaInfLicenseFiles.defaultSettings
 lazy val asfLicensingSettingsWithVendored = 
AddMetaInfLicenseFiles.workflowOperatorSettings
-lazy val asfDistLicensingSettings = AddMetaInfLicenseFiles.distSettings
 
 val jacksonVersion = "2.18.6"
 
@@ -36,7 +37,6 @@ lazy val Auth = (project in file("common/auth"))
 lazy val ConfigService = (project in file("config-service"))
   .dependsOn(Auth, Config)
   .settings(asfLicensingSettings)
-  .settings(asfDistLicensingSettings)
   .settings(
     dependencyOverrides ++= Seq(
       // override it as io.dropwizard 4 require 2.16.1 or higher
@@ -46,7 +46,6 @@ lazy val ConfigService = (project in file("config-service"))
 lazy val AccessControlService = (project in file("access-control-service"))
   .dependsOn(Auth, Config, DAO)
   .settings(asfLicensingSettings)
-  .settings(asfDistLicensingSettings)
   .settings(
     dependencyOverrides ++= Seq(
       // override it as io.dropwizard 4 require 2.16.1 or higher
@@ -71,7 +70,6 @@ lazy val WorkflowCore = (project in 
file("common/workflow-core"))
 lazy val ComputingUnitManagingService = (project in 
file("computing-unit-managing-service"))
   .dependsOn(WorkflowCore, Auth, Config)
   .settings(asfLicensingSettings)
-  .settings(asfDistLicensingSettings)
   .settings(
     dependencyOverrides ++= Seq(
       // override it as io.dropwizard 4 require 2.16.1 or higher
@@ -80,7 +78,6 @@ lazy val ComputingUnitManagingService = (project in 
file("computing-unit-managin
   )
 lazy val FileService = (project in file("file-service"))
   .settings(asfLicensingSettings)
-  .settings(asfDistLicensingSettings)
   .dependsOn(WorkflowCore, Auth, Config)
   .configs(Test)
   .dependsOn(DAO % "test->test") // test scope dependency
@@ -97,7 +94,6 @@ lazy val WorkflowOperator = (project in 
file("common/workflow-operator")).settin
 lazy val WorkflowCompilingService = (project in 
file("workflow-compiling-service"))
   .dependsOn(WorkflowOperator, Config)
   .settings(asfLicensingSettings)
-  .settings(asfDistLicensingSettings)
   .settings(
     dependencyOverrides ++= Seq(
       // override it as io.dropwizard 4 require 2.16.1 or higher
@@ -110,7 +106,6 @@ lazy val WorkflowCompilingService = (project in 
file("workflow-compiling-service
 lazy val WorkflowExecutionService = (project in file("amber"))
   .dependsOn(WorkflowOperator, Auth, Config)
   .settings(asfLicensingSettings)
-  .settings(asfDistLicensingSettings)
   .settings(
     dependencyOverrides ++= Seq(
       "com.fasterxml.jackson.core" % "jackson-core" % jacksonVersion,
diff --git a/computing-unit-managing-service/build.sbt 
b/computing-unit-managing-service/build.sbt
index a97f9ec2b2..5d5b368de1 100644
--- a/computing-unit-managing-service/build.sbt
+++ b/computing-unit-managing-service/build.sbt
@@ -22,6 +22,14 @@ name := "computing-unit-managing-service"
 
 enablePlugins(JavaAppPackaging)
 
+// Ship LICENSE-binary, NOTICE-binary, DISCLAIMER-WIP, and the licenses/
+// directory at the top of the Universal dist zip.
+// See project/AddMetaInfLicenseFiles.scala.
+Universal / mappings := AddMetaInfLicenseFiles.distMappings(
+  (Universal / mappings).value,
+  (ThisBuild / baseDirectory).value
+)
+
 // Dependency Versions
 val dropwizardVersion = "4.0.7"
 
diff --git a/config-service/build.sbt b/config-service/build.sbt
index dd4e255804..e88216913f 100644
--- a/config-service/build.sbt
+++ b/config-service/build.sbt
@@ -22,6 +22,14 @@ name := "config-service"
 
 enablePlugins(JavaAppPackaging)
 
+// Ship LICENSE-binary, NOTICE-binary, DISCLAIMER-WIP, and the licenses/
+// directory at the top of the Universal dist zip.
+// See project/AddMetaInfLicenseFiles.scala.
+Universal / mappings := AddMetaInfLicenseFiles.distMappings(
+  (Universal / mappings).value,
+  (ThisBuild / baseDirectory).value
+)
+
 // Enable semanticdb for Scalafix
 ThisBuild / semanticdbEnabled := true
 ThisBuild / semanticdbVersion := scalafixSemanticdb.revision
diff --git a/file-service/build.sbt b/file-service/build.sbt
index 0168c2db23..1bf992c6bb 100644
--- a/file-service/build.sbt
+++ b/file-service/build.sbt
@@ -22,6 +22,14 @@ name := "file-service"
 
 enablePlugins(JavaAppPackaging)
 
+// Ship LICENSE-binary, NOTICE-binary, DISCLAIMER-WIP, and the licenses/
+// directory at the top of the Universal dist zip.
+// See project/AddMetaInfLicenseFiles.scala.
+Universal / mappings := AddMetaInfLicenseFiles.distMappings(
+  (Universal / mappings).value,
+  (ThisBuild / baseDirectory).value
+)
+
 // Enable semanticdb for Scalafix
 ThisBuild / semanticdbEnabled := true
 ThisBuild / semanticdbVersion := scalafixSemanticdb.revision
diff --git a/project/AddMetaInfLicenseFiles.scala 
b/project/AddMetaInfLicenseFiles.scala
index 30f191a0db..12bcaa0eba 100644
--- a/project/AddMetaInfLicenseFiles.scala
+++ b/project/AddMetaInfLicenseFiles.scala
@@ -120,23 +120,35 @@ object AddMetaInfLicenseFiles {
     }.taskValue
   )
 
-  /** Additional settings for dist-producing modules: places the same files
-   *  at the top level of the sbt-native-packager Universal zip so they
-   *  appear alongside lib/ and bin/ in the distribution. */
-  lazy val distSettings: Seq[Setting[_]] = Seq(
-    Universal / mappings := {
-      val existing = (Universal / mappings).value
-      val root = rootDir.value
-      val licenseFile = root / "LICENSE"
-      val noticeFile = root / "NOTICE"
-      val disclaimerFile = root / "DISCLAIMER-WIP"
-      val reserved = Set("LICENSE", "NOTICE", "DISCLAIMER-WIP")
-      val filtered = existing.filterNot { case (_, path) => 
reserved.contains(path) }
-      val extras = Seq(
-        licenseFile -> "LICENSE",
-        noticeFile -> "NOTICE"
-      ) ++ (if (disclaimerFile.exists()) Seq(disclaimerFile -> 
"DISCLAIMER-WIP") else Seq.empty)
-      filtered ++ extras
+  /** Ships LICENSE-binary, NOTICE-binary, DISCLAIMER-WIP (if present), and
+   *  licenses/ at the Universal zip's top level. LICENSE-binary and
+   *  NOTICE-binary are required; DISCLAIMER-WIP is optional (it will be
+   *  removed at graduation). */
+  def distMappings(existing: Seq[(File, String)], rootDir: File): Seq[(File, 
String)] = {
+    val licenseBinary = rootDir / "LICENSE-binary"
+    val noticeBinary = rootDir / "NOTICE-binary"
+    val disclaimerFile = rootDir / "DISCLAIMER-WIP"
+    val licensesDir = rootDir / "licenses"
+
+    require(licenseBinary.isFile,
+      s"LICENSE-binary not found at $licenseBinary; required for 
binary-distribution packaging.")
+    require(noticeBinary.isFile,
+      s"NOTICE-binary not found at $noticeBinary; required for 
binary-distribution packaging.")
+    require(licensesDir.isDirectory,
+      s"licenses/ directory not found at $licensesDir; required for 
binary-distribution packaging.")
+
+    val reserved = Set("LICENSE", "NOTICE", "DISCLAIMER-WIP")
+    val filtered = existing.filterNot {
+      case (_, path) => reserved.contains(path) || path.startsWith("licenses/")
     }
-  )
+
+    val licenseTexts = (licensesDir ** "*.txt").get.map(f => f -> 
s"licenses/${f.getName}")
+
+    val base = Seq(licenseBinary -> "LICENSE", noticeBinary -> "NOTICE")
+    val disclaimer =
+      if (disclaimerFile.isFile) Seq(disclaimerFile -> "DISCLAIMER-WIP")
+      else Seq.empty
+
+    filtered ++ base ++ disclaimer ++ licenseTexts
+  }
 }
diff --git a/workflow-compiling-service/build.sbt 
b/workflow-compiling-service/build.sbt
index f1355f4b13..66b23379c1 100644
--- a/workflow-compiling-service/build.sbt
+++ b/workflow-compiling-service/build.sbt
@@ -24,6 +24,14 @@ name := "workflow-compiling-service"
 
 enablePlugins(JavaAppPackaging)
 
+// Ship LICENSE-binary, NOTICE-binary, DISCLAIMER-WIP, and the licenses/
+// directory at the top of the Universal dist zip.
+// See project/AddMetaInfLicenseFiles.scala.
+Universal / mappings := AddMetaInfLicenseFiles.distMappings(
+  (Universal / mappings).value,
+  (ThisBuild / baseDirectory).value
+)
+
 // Enable semanticdb for Scalafix
 ThisBuild / semanticdbEnabled := true
 ThisBuild / semanticdbVersion := scalafixSemanticdb.revision

Reply via email to