Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Build using Jenkins is missing files

Discussion in 'Web' started by Gillissie, Sep 21, 2018.

  1. Gillissie

    Gillissie

    Joined:
    May 16, 2011
    Posts:
    305
    This is baffling me. I created a python script that launches a headless Unity to do a WebGL build. It works perfectly from my command line, and from the command line of another computer (my build server). However, when it is run from a Jenkins job on the build server, the resulting files are incomplete.

    Here is how it gets called from my repository root folder (BlockFight is the project folder):
    python ./BlockFight/Python/build.py stage=Dev target=WebGL


    Here is a screenshot of the build with all the files after running manually from Terminal:
    https://screencast.com/t/znkczmVb9jgJ

    Here is the same build in Jenkins, where the "index.html" and "TemplateData" folder are missing:

    https://screencast.com/t/EDrCiFVjrw

    The contents of the Build folder in Jenkins:
    https://screencast.com/t/XUyToj0l

    Any thoughts or tips on the Unity build system and/or Jenkins integration is appreciated.

    Here is the python script:
    Code (Python):
    1. import sys
    2. import subprocess
    3. import inspect
    4. import os
    5. import time
    6.  
    7. # Kicks off an instance of Unity to perform a build.
    8. # This script expects args target=XXX and stage=XXX.
    9. # If omitted, defaults to target=WebGL and stage=Dev.
    10. # Valid values are:
    11. #   stage: Dev, Preview, Live, Bundles
    12. #   target: Any of the Unity BuildTarget enum values (case sensitive).
    13.  
    14. scriptPath = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
    15.  
    16. UNITY_PATH = "/Applications/Unity 2018.2.3f1/Unity 2018.2.3f1.app/Contents/MacOS/Unity"
    17. PROJECT_PATH = scriptPath + "/.."
    18. LOG_PATH = scriptPath + "/../Build/BuildLog.log"
    19.  
    20. args = sys.argv;
    21.  
    22. # Add the subprocess parameters.
    23. # The path to the program being launched needs to be the first element in the array.
    24. args.insert(0, UNITY_PATH)
    25.  
    26. # The rest can go anywhere in the array, so just add them to the end.
    27. args.append("-quit")
    28. args.append("-batchmode")
    29. args.extend(["-projectPath", PROJECT_PATH])
    30. args.extend(["-executeMethod", "bnc.BuildOptions.buildFromCommandLineOptions"])
    31. args.extend(["-logFile", LOG_PATH])
    32.  
    33. startTime = time.time()
    34.  
    35. unityProc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    36. output = unityProc.communicate()[0]
    37.  
    38. print output + "Build finished in {} seconds.".format(round(time.time() - startTime, 1))
    39.  
    40. # TODO: Sync the build folder with a S3 bucket.
    41.  
     
  2. Gillissie

    Gillissie

    Joined:
    May 16, 2011
    Posts:
    305
  3. Gillissie

    Gillissie

    Joined:
    May 16, 2011
    Posts:
    305
    While troubleshooting, I tried changing the web template to the default template, and BOOM, that shows up properly. Something related to using a custom template.
     
  4. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
  5. ollyrennardarcticshores

    ollyrennardarcticshores

    Joined:
    Oct 16, 2017
    Posts:
    6
    Did you ever find out what the specific problem was here? I'm having something similar but can't find a fix anywhere
     
  6. Gillissie

    Gillissie

    Joined:
    May 16, 2011
    Posts:
    305
    No, I just ended up scripting my own way of using the template manually. I had to set the Unity setting to use the default template, then wrote code to read in the one I actually want and replace tokens and output it in the build script.
    Maybe you can get this working for you...

    After BuildPipeline.BuildPlayer(), call this...

    Code (CSharp):
    1.  
    2. if (target == BuildTarget.WebGL)
    3. {
    4.     createWebGLTemplateFiles(buildPath, "Universal");
    5. }
    6.  
    7. // There is a bug in Unity's build system that omits the web template files from the build
    8. // when using a custom web template in a build with Jenkins (not sure why only in Jenkins).
    9. // So, we will have the default web template selected in the project,
    10. // then manually create the custom web template files here.
    11. private static void createWebGLTemplateFiles(string buildPath, string templateName)
    12. {
    13.     const string BUILD_FILES_FOLDER = "Build";
    14.  
    15.     // We need to find out the filename of the .js and .json files in the Build folder.
    16.     string jsFilename = "";
    17.     string jsonFilename = "";
    18.  
    19.     string[] buildFiles = Directory.GetFiles(string.Format("{0}/{1}", buildPath, BUILD_FILES_FOLDER));
    20.  
    21.     foreach (string file in buildFiles)
    22.     {
    23.         if (file.EndsWith(".js"))
    24.         {
    25.             jsFilename = Path.GetFileName(file);
    26.         }
    27.         if (file.EndsWith(".json"))
    28.         {
    29.             jsonFilename = Path.GetFileName(file);
    30.         }
    31.     }
    32.  
    33.     // Copy the contents of the Universal template folder to the build folder,
    34.     // then replace some tokens with values in index.html.
    35.  
    36.     string templatePath = string.Format("Assets/WebGLTemplates/{0}", templateName);
    37.     string indexFileBuildPath = string.Format("{0}/index.html", buildPath);
    38.     string templateDataBuildPath = string.Format("{0}/TemplateData", buildPath);
    39.  
    40.     if (File.Exists(indexFileBuildPath))
    41.     {
    42.         File.Delete(indexFileBuildPath);
    43.     }
    44.  
    45.     if (Directory.Exists(templateDataBuildPath))
    46.     {
    47.         Directory.Delete(templateDataBuildPath, true);
    48.     }
    49.  
    50.     CommonEditor.directoryCopy(templatePath, buildPath);
    51.  
    52.     // Delete the .meta files because we don't need them in the build.
    53.     string[] metaFiles = Directory.GetFiles(buildPath, "*.meta", SearchOption.AllDirectories);
    54.     foreach (string file in metaFiles)
    55.     {
    56.         File.Delete(file);
    57.     }
    58.  
    59.     // The build also doesn't need this Unity preview thumbnail image.
    60.     File.Delete(string.Format("{0}/thumbnail.png", buildPath));
    61.  
    62.     // Load the new index.html file to do the token replacement.
    63.     string html = File.ReadAllText(indexFileBuildPath);
    64.  
    65.     html = html.Replace("%UNITY_WEB_NAME%", Application.productName);
    66.     html = html.Replace("%UNITY_WEBGL_LOADER_URL%", string.Format("{0}/{1}", BUILD_FILES_FOLDER, jsFilename));
    67.     html = html.Replace("%UNITY_WEBGL_BUILD_URL%", string.Format("{0}/{1}", BUILD_FILES_FOLDER, jsonFilename));
    68.  
    69.     File.WriteAllText(indexFileBuildPath, html);
    70.     //                Debug.LogFormat("js: {0}, json: {1}", jsFilename, jsonFilename);
    71. }
     
    savely00 likes this.
  7. Gillissie

    Gillissie

    Joined:
    May 16, 2011
    Posts:
    305
    Helper function...
    Code (CSharp):
    1. // Copied from https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories
    2. public static void directoryCopy(string sourceDirName, string destDirName, bool copySubDirs = true)
    3. {
    4.     // Get the subdirectories for the specified directory.
    5.     DirectoryInfo dir = new DirectoryInfo(sourceDirName);
    6.  
    7.     if (!dir.Exists)
    8.     {
    9.         throw new DirectoryNotFoundException(
    10.             "Source directory does not exist or could not be found: "
    11.             + sourceDirName);
    12.     }
    13.  
    14.     DirectoryInfo[] dirs = dir.GetDirectories();
    15.     // If the destination directory doesn't exist, create it.
    16.     if (!Directory.Exists(destDirName))
    17.     {
    18.         Directory.CreateDirectory(destDirName);
    19.     }
    20.  
    21.     // Get the files in the directory and copy them to the new location.
    22.     FileInfo[] files = dir.GetFiles();
    23.     foreach (FileInfo file in files)
    24.     {
    25.         string temppath = Path.Combine(destDirName, file.Name);
    26.         file.CopyTo(temppath, true);
    27.     }
    28.  
    29.     // If copying subdirectories, copy them and their contents to new location.
    30.     if (copySubDirs)
    31.     {
    32.         foreach (DirectoryInfo subdir in dirs)
    33.         {
    34.             string temppath = Path.Combine(destDirName, subdir.Name);
    35.             directoryCopy(subdir.FullName, temppath, copySubDirs);
    36.         }
    37.     }
    38. }
     
    savely00 likes this.