/ .github / helper_scripts / build_frontend.py
build_frontend.py
  1  import os
  2  import shutil
  3  import subprocess
  4  from sys import exit as sys_exit
  5  from sys import stdout
  6  
  7  from hatchling.builders.hooks.plugin.interface import BuildHookInterface
  8  
  9  
 10  class CustomBuildHook(BuildHookInterface):
 11      def initialize(self, version, build_data):
 12          super().initialize(version, build_data)
 13  
 14          # Check if we should skip UI builds (static assets already present)
 15          skip_ui_build = os.environ.get("SAM_SKIP_UI_BUILD", "").lower() in (
 16              "true",
 17              "1",
 18              "yes",
 19          )
 20  
 21          if skip_ui_build:
 22              self.app.display_info("SAM_SKIP_UI_BUILD is set, skipping UI build steps\n")
 23              self.app.display_info("Verifying static assets exist...\n")
 24  
 25              required_paths = [
 26                  "config_portal/frontend/static",
 27                  "client/webui/frontend/static",
 28                  "docs/build",
 29              ]
 30  
 31              missing = [p for p in required_paths if not os.path.exists(p)]
 32              if missing:
 33                  raise RuntimeError(
 34                      f"SAM_SKIP_UI_BUILD is set but required static assets are missing: {', '.join(missing)}"
 35                  )
 36  
 37              self.app.display_info(
 38                  "All required static assets found, proceeding with Python build only\n"
 39              )
 40              return
 41  
 42          npm = shutil.which("npm")
 43          if npm is None:
 44              raise RuntimeError(
 45                  "NodeJS `npm` is required for building Solace Agent Mesh but it was not found"
 46              )
 47          build_log_file = "build.log"
 48          log_file = open(build_log_file, "w", encoding="utf-8")
 49  
 50          def log(message):
 51              stdout.write(message)
 52              log_file.write(message)
 53  
 54          def build_failed(message):
 55              log(f"\nError during build: {message}\n")
 56              log(
 57                  f"Build failed. Please check the logs for details at {os.path.abspath(log_file.name)}\n"
 58              )
 59              if log_file:
 60                  log_file.close()
 61              sys_exit(1)
 62  
 63          log(f"Build logs will be written to {os.path.abspath(log_file.name)}\n")
 64          log(">>> Building Solace Agent Mesh Config Portal\n")
 65          os.chdir("config_portal/frontend")
 66          try:
 67              log("### npm ci")
 68              subprocess.run(
 69                  [npm, "ci"], check=True, stdout=log_file, stderr=subprocess.STDOUT
 70              )
 71              log("\n### npm run build\n")
 72              subprocess.run(
 73                  [npm, "run", "build"],
 74                  check=True,
 75                  stdout=log_file,
 76                  stderr=subprocess.STDOUT,
 77              )
 78          except subprocess.CalledProcessError:
 79              build_failed("Config Portal build failed with error")
 80          finally:
 81              os.chdir("../..")
 82  
 83          log(">>> Building Solace Agent Mesh Web UI\n")
 84          os.chdir("client/webui/frontend")
 85          try:
 86              log("### npm ci")
 87              subprocess.run(
 88                  [npm, "ci"], check=True, stdout=log_file, stderr=subprocess.STDOUT
 89              )
 90              log("\n### npm run build\n")
 91              subprocess.run(
 92                  [npm, "run", "build"],
 93                  check=True,
 94                  stdout=log_file,
 95                  stderr=subprocess.STDOUT,
 96              )
 97          except subprocess.CalledProcessError:
 98              build_failed(
 99                  "Web UI build failed with error",
100              )
101          finally:
102              os.chdir("../../..")
103  
104          log(">>> Building Solace Agent Mesh Documentation\n")
105          os.chdir("docs")
106          try:
107              log("### npm ci")
108              subprocess.run(
109                  [npm, "ci"], check=True, stdout=log_file, stderr=subprocess.STDOUT
110              )
111              log("\n### npm run build\n")
112              subprocess.run(
113                  [npm, "run", "build"],
114                  check=True,
115                  stdout=log_file,
116                  stderr=subprocess.STDOUT,
117              )
118          except subprocess.CalledProcessError:
119              build_failed("Documentation build failed with error")
120          finally:
121              os.chdir("..")
122  
123          log(">>> Build completed successfully\n")
124          log_file.close()