One big challenge in a monorepo is to determine which components need to be rebuilt and consequently – deployed. The market offers us a couple of solutions, with Bazel ahead. All of them force repository owner (and users) to make enormous adaptations to build a system. Long-term earnings from using unified system pays-off, but could we incorporate simpler approach that would do just as well in a smaller environment?
Workflow can be approximated by the following steps:
- Feature work is done on feature branch
- PR to master branch is created
- PR is approved and merged
- Each component directory is checked for changes (with sub-directories filtering)
- Filtered sub-directories are ignored
- Component for which the change is detected is marked as rebuildable
- For a rebuildable component, marker file is placed in S3 bucket
- CodePipeline listens to S3 events and starts rebuilt
- If build succeeds, new artifact (Docker image) is created and the version tag is placed in another S3 bucket
- Component is marked for deployment
- CodePipeline listens to S3 events and starts deployment
- CodePipeline uses version tag from S3 bucket to create new release
- Blue/green is done to replace old version
Let’s elaborate on the highlighted points.
To check if component is buildable, we compare two repository revisions:
- One that was just checked into the master
- One that was successfully built last time
git diff-index --name-only "${sha1}" -- "${component_dir}"
Command is issued on master branch checked and is compared to previously found revision of last successful build. The output of command is a filtered list of files that have changed. When diff is non-empty, list is zipped and uploaded to S3.
Build CodePipeline is started when change to S3 file is detected. If the build succeeds, Docker image is pushed and another S3 file with version tag is uploaded to a separate S3 bucket. File contains just a precise version of tagged Docker image:
0.1.4-7fb7da8
CodeBuild uses freshly uploaded S3 file to determine the version tag of Docker image that has to be released:
export TAG="$(cat "$CODEBUILD_SRC_DIR_VersionArtifact/$REF_NAME")"
make create_component_name
make release_component_name
Where create_*
and release_*
targets are used correspondingly to register new TaskDefinition and new TaskSet.
And that’s it!