Files
Anton Gunnarsson 36b6685ad5 Merged in feat/partner-sas-netlify-branch-sync (pull request #2758)
feat: Add netlify-plugin-sync to partner-sas

* Add netlify-plugin-sync to partner-sas


Approved-by: Joakim Jäderberg
2025-09-03 13:50:45 +00:00

83 lines
4.5 KiB
Markdown

# netlify-plugin-branch-sync
This is a Netlify build plugin.
Its purpose is to sync a configured source branch to other configured destination branches.
The configuration is done inside of index.js instead of using environment variables so that the branch configurations are version controlled.
`SYNC_SOURCE` is the source branch that will be pushed to the destination branches.
`SYNC_DEST` is an array of destination branches that will receive the push from `SYNC_SOURCE`.
This plugin only executes its sync operations when the branch being built in Netlify is the `SYNC_SOURCE` branch and the build context is 'Branch build'. Any other branch or build context is ignored and this plugin does nothing.
## How to setup
In Bitbucket, create an access token for the repository this plugin will act on, e.g. https://bitbucket.org/scandic-swap/web/admin/access-tokens.
It needs to have the following permissions:
- `repository`
- `repository:write`
Add the following environment variables in the Netlify dashboard.
> **IMPORTANT!**
>
> Be sure to set them to only be available in the "Builds" scope and only set a value for the "Branch deploys" configuration.
- **BITBUCKET_USER_EMAIL**: The email for the access token (Bitbucket generates this and provides it when creating an access token)
- **BITBUCKET_ACCESS_TOKEN**: The access token
## How it works
It uses two build plugin events:
- `onPreBuild`
- `onPostBuild`
It fails the whole build if the plugin does not complete the sync to all the branches.
Since it uses `git` directly and we want to sync to latest always, the plugin can be rerun in case of failures and `git` will resume where needed.
### Event: onPreBuild
- Checks that the current branch being built is `SYNC_SOURCE` and the build context is a branch build, otherwise does nothing.
- Checks for the presence of the required environment variables.
- Uses `git` to configure the `user.email` and set it to environment variable `BITBUCKET_USER_EMAIL`
- Attempts to restore the clone from the build cache and if that fails proceeds to clone it.
- Uses `git` to fetches the configured branches, `SYNC_SOURCE` and `SYNC_DEST` from origin, skipping all tags.
- Loops over the branches and uses `git` to sequentially push the latest ref on `SYNC_SOURCE` to each `SYNC_DEST` branch respectively. Since a single push completes fast (under 200 ms), we opt to not push in parallel to try and avoid any rate limits.
- Reports to Netlify the completion and provides some info to the "Deploy summary" for the build.
- If anything throws an error during execution the **whole build is failed**
### Event: onPostBuild
- Checks that the current branch being built is `SYNC_SOURCE` and the build context is a branch build, otherwise does nothing.
- Attempts to save the clone to the build cache. If it fails by throwing an error the **whole build is failed**. If it fails without throwing an error the build will succeed.
## Under the hood
### Bare repository
Since this plugin only does git operations that do not need a working copy, it clones the repository it uses for the operations as a bare repository.
The layout of a bare repository differs from a working copy. The way git identifies a working copy with through the presence of a folder named `.git`. Bare repositories do not have this folder. Instead git uses different heuristics to determine if the directory is a clone, one of which is the presence of a folder named `refs`.
The folder named `refs` only contains two folders after a bare clone operation, `heads` and `tags`. These two folder are both empty themselves.
This fact poses a challenge for the build cache because it only caches files and not empty directories.
#### Build cache usage
This plugin uses the [utilities for caching files in Netlify Build](https://github.com/netlify/build/blob/main/packages/cache-utils/README.md).
This utility uses [cpy](https://www.npmjs.com/package/cpy) to **copy** files to and from the cache and uses [move-file](https://www.npmjs.com/package/move-file) to **move** files to and from the cache.
The use of `cpy` is what causes the build cache to not include empty directories because `cpy` only copies files and skips empty directories.
So to work around the problem this plugin uses the `move mode` of the build cache API which instead uses `move-file` instead of `cpy`, keeping the full directory layout as git requires it.
The `move mode` is required for both the `restore()` and `save()` build cache operations for the workaround to work. It is done by passing `move: true` as options to the calls.