Skip to main content

Build and push assets using Make

This page describes how nullplatform uses GNU Make and Makefiles for asset building and pushing to repositories.

Our GitHub Actions, Gitlab Pipelines, Azure Pipelines, etc. provides flexibility allowing for default behavior, customization of Makefiles, and the use of custom build commands, arguments, and options.

Behavior

When no customizations are provided, the make command is executed in your CI/CD pipeline using a Makefile.

The key steps involved are:

  • Makefile Discovery: Our building process checks if a Makefile (makefile or Makefile) exists in the build working directory you provided. If not found, a default Makefile is used.

  • Default Rules: If a Makefile is found, it looks for a default build rule named build and a upload to repository rule named push If found, it executes these rules.

  • Example Command: If no customizations are provided, the command executed is simply: make -C BUILD_WORKING_DIRECTORY=. build and make -C BUILD_WORKING_DIRECTORY=. push.

Execute make command locally

You can run these commands on your local machine to test your own Makefiles and simulate how the CI/CD pipeline builds your application. This can help you quickly identify errors.

Default Makefile Behavior

When no customizations are provided, the default Makefile is used. The key steps involved are:

  • Makefile Discovery: Our building process checks if a Makefile (makefile or Makefile) exists in the build working directory you provided.

  • Default Rule: If a Makefile is found, it looks for a default build rule named build and a upload to repository rule named push If found, it executes these rules.

  • Example Command: If no customizations are provided, the command executed is simply: make -C BUILD_WORKING_DIRECTORY=. build and make -C BUILD_WORKING_DIRECTORY=. push, you can execute these commands in your own machine to test your own Makefiles.

Customizing Arguments and Options

You can change the arguments and options to customize the asset build or push while still using the default make command. For example:

  • Custom Arguments and Options: By specifying different values for arguments and options, you can influence how the default Makefile's build rule is executed. For example you can customize docker build argument by providing a BUILD_ARGS option.

  • Example Command: If custom arguments and options are provided, the command executed might look like this: make -C BUILD_WORKING_DIRECTORY=. BUILD_ARGS=--build-args=TOKEN=secret build or make -C BUILD_WORKING_DIRECTORY=. build custom-argument custom-option.

Custom Makefile

If you have a specific Makefile structure that depends on the build working directory and asset working directory, you can customize the Makefile based on these directories:

  • Makefile Location: The GitHub Action checks for a Makefile in the build working directory provided. If found, it uses this Makefile.

  • Fallback to Defaults: If no Makefile is found in the specified directory, it falls back to using the default Makefile.

Advanced Customization

For advanced customization, you can provide a custom command, custom arguments, and options to execute a completely customized build process. This scenario allows you to specify the exact command you want to run:

  • Custom Command: By specifying a custom command, you can execute a non-Makefile-based build process.

  • Custom Arguments and Options: Additional arguments and options can be provided to fine-tune the custom command execution.

  • Example Command: If a custom command is provided, CI/CD pipeline runs it as-is, along with any specified arguments and options. For instance: custom-command custom-argument custom-option.

Understanding how Makefiles interact with the CI/CD pipeline is essential for effective asset building. By following the outlined scenarios and including recommended customizations, you can streamline the build process for your project's assets, whether using the default Makefile, custom Makefiles, or entirely custom build commands.

Variables in the Makefile

To facilitate the build and push rules, several variables are used in the Makefile:

BUILD_WORKING_DIRECTORY: Specifies the directory where the build process takes place. ASSET_WORKING_DIRECTORY: Denotes the directory containing source code and assets for the build process. ASSET_OUTPUT_DIRECTORY: Specifies the directory where the built assets will be output. ASSET_NAME: The name of the asset being built or pushed. ASSET_TYPE: The type of asset, which determines which rules to apply. ASSET_TARGET_URL: The URL or location where the asset is pushed or deployed.

While the minimum required rules for build and push actions have been outlined, it is recommended to include the following rules in your custom Makefiles:

setup: This rule sets up the necessary environment or dependencies for the asset build. test: Use this rule to run tests related to the asset. compile: This rule is responsible for compiling or preparing the asset for packaging. package: The package rule bundles the asset into a deployable format. push: The push rule pushes the packaged asset to a target location, which can be a Docker registry or an S3 bucket, depending on the asset type.

Examples

Node.js Serverless Asset

ASSET_FILE=$(ASSET_NAME).zip

.PHONY: all clean build setup test compile package push

all: clean build push
build: setup test compile package

clean:
rm -r $(ASSET_OUTPUT_DIRECTORY)
setup:
mkdir -p $(ASSET_OUTPUT_DIRECTORY)
cp $(ASSET_WORKING_DIRECTORY)/package.json $(ASSET_OUTPUT_DIRECTORY)
npm --prefix $(ASSET_OUTPUT_DIRECTORY) install --omit=dev
test:
npm --prefix $(ASSET_WORKING_DIRECTORY) install --only=dev
npm --prefix $(ASSET_WORKING_DIRECTORY) run test
compile:
cp $(ASSET_WORKING_DIRECTORY)/*.js $(ASSET_OUTPUT_DIRECTORY)
package:
cd $(ASSET_OUTPUT_DIRECTORY) && zip -r $(ASSET_FILE) .
push:
aws s3 cp $(ASSET_OUTPUT_DIRECTORY)/$(ASSET_FILE) $(ASSET_TARGET_URL)

Docker image asset

.PHONY: all clean build setup test compile package push

all: clean build push
build: setup test compile package

setup:
docker build -t $(ASSET_NAME)-test --target test -f $(ASSET_WORKING_DIRECTORY)/Dockerfile .
test:
docker run -it --rm --name $(ASSET_NAME)-test-run $(ASSET_NAME)-test
compile:
package:
docker build -t $(ASSET_NAME) --target build -f $(ASSET_WORKING_DIRECTORY)/Dockerfile .
push:
docker tag $(ASSET_NAME):latest $(ASSET_TARGET_URL)
docker push $(ASSET_TARGET_URL)