[ i.am.kon ]

[ i.am.kon ]

Unity Package Creation Automation

Context

In my previous post we learned how to create UPM packages out of Unity projects and how to get them inside other projects. In this post we will automate this process.

Tools

There are many different ways to do this. In my personal project I opted out to use combination of Makefile and Node.js scripts. Node.js has a library for just about anything and it is supper simple to use. I chose Makefile, because my development machine already has a correctly configured environment to be able to interact with git. At Lumos Labs, we just use Node.js, but it is a much more complex system than what we will be building here.

Updating Version

We track package version inside Assets/package.json file. It would be nice to update that version whenever we decide to author a new package. For that, I wrote a little Node.js script that reads package.json, updates the values and writes it back. You could do this with a single line in bash, but I find Node.js scripts easier to live with and expand on.


const fs = require ( 'fs-extra' );

async function updatePackageData() {

    const packageJsonPath = './Assets/package.json';

    if ( fs.existsSync( packageJsonPath ) ) {

        // Read the package file
        let packageFileString = fs.readFileSync( packageJsonPath, 'utf8' );
        let packageFileJSON = JSON.parse( packageFileString );

        // Version
        let version = packageFileJSON["version"];
        let versionParts = version.split('.');
        let minorVersion = parseInt(versionParts[versionParts.length - 1]);
        minorVersion += 1;
        versionParts[versionParts.length - 1] = "" + minorVersion;
        packageFileJSON["version"] = versionParts.join('.');

        // Date
        packageFileJSON["timestamp"] = Date.now();
        packageFileJSON["timestamp_readable"] = new Date(Date.now()).toUTCString();

        // Write package file data back
        const jsonString = JSON.stringify( packageFileJSON, null, 2 );
        fs.writeFileSync( packageJsonPath, jsonString );
    }
}

(async () => {
    await updatePackageData();
})();

Reading Version

Similar to the updater, this will just read the version and print it in the output. This will come in handy in a bit.


const fs = require ( 'fs-extra' );

async function readPackageVersion() {

  const packageJsonPath = './Assets/package.json';

  if ( fs.existsSync( packageJsonPath ) ) {

    // Read the package file
    let packageFileString = fs.readFileSync( packageJsonPath, 'utf8' );
    let packageFileJSON = JSON.parse( packageFileString );

    // Version
    let version = packageFileJSON["version"];
    return version;
  }

  return "0.0.-1"; // Version Not Found;
}

(async () => {
    const version = await readPackageVersion();
    console.log(version);
}
)();

Makefile

Final piece of the puzzle is the Makefile that can call the above scripts and interact with the shell and all the SSH keys and other credentials it already holds. You can also code this in a shell script. At Lumos Labs we chose to go full Node.js and it worked really well for us - same scripts ran on developer machines and in various CI environments. Here is a basic Makefile version:

define UpdatePackage
@echo $(shell node ./Scripts/package_version_updater.js)
endef

define GetPackageTag
v$(shell node ./Scripts/package_version_reader.js)
endef

deploy:
  @echo "--------------------------------------------------------------"
  @echo "Creating new Unity Package"
  $(call UpdatePackage)
  git add Assets/package.json
  git commit -m "Updated Unity package file"
  git push
  git tag $(call GetPackageTag)
  git push origin $(call GetPackageTag)

Note that after package file was updated, this change is committed, pushed and then tagged with the version and the package name.

Conclusion

Now you have a project that contains your shared code or a complete game. Once you are happy with the state of the project, you can run a make command in the terminal and it will author a new package for you. You can add this package to any other Unity project and load any scene or prefab or script from it. In near future we will add a way to automatically check for a new version and update the client project.

Created by Konstantin Yavichev. Copyright 2025.