feat: local netlify plugin to sync branches
A custom local Netlify plugin that handles syncing a source branch to multiple destination branches.
This commit is contained in:
179
apps/scandic-web/netlify-plugin-branch-sync/index.js
Normal file
179
apps/scandic-web/netlify-plugin-branch-sync/index.js
Normal file
@@ -0,0 +1,179 @@
|
||||
// @ts-check
|
||||
|
||||
import { existsSync } from "node:fs"
|
||||
|
||||
const SYNC_SOURCE = "master"
|
||||
|
||||
// SYNC_DEST is defined in code and not in an environment variable to
|
||||
// have this config version controlled.
|
||||
const SYNC_DEST = [
|
||||
"test",
|
||||
// "stage",
|
||||
// "prod"
|
||||
]
|
||||
|
||||
const CLONE_DIR = `${process.env.HOME}/branch-sync-clone`
|
||||
|
||||
function error(msg) {
|
||||
throw new Error(`[branch-sync] ${msg}`)
|
||||
}
|
||||
|
||||
function createLogger() {
|
||||
return {
|
||||
debug(msg) {
|
||||
console.log(`[branch-sync] ${msg}`)
|
||||
},
|
||||
info(msg) {
|
||||
// info logs are grey
|
||||
console.log("\x1b[90m%s\x1b[0m", `[branch-sync] ${msg}`)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const onPreBuild = async function ({ utils }) {
|
||||
// Only run for branch builds of source branch.
|
||||
if (
|
||||
process.env.BRANCH === SYNC_SOURCE &&
|
||||
process.env.CONTEXT === "branch-deploy"
|
||||
) {
|
||||
try {
|
||||
const logger = createLogger()
|
||||
|
||||
if (!process.env.BITBUCKET_USER_EMAIL) {
|
||||
error(
|
||||
`Missing commit user email, set env var 'BITBUCKET_USER_EMAIL'. See README.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!process.env.BITBUCKET_ACCESS_TOKEN) {
|
||||
error(
|
||||
`Missing access token for Bitbucket, set env var 'BITBUCKET_ACCESS_TOKEN'. See README.`
|
||||
)
|
||||
}
|
||||
|
||||
const { run } = utils
|
||||
|
||||
await run("git", [
|
||||
"config",
|
||||
"user.email",
|
||||
process.env.BITBUCKET_USER_EMAIL,
|
||||
])
|
||||
|
||||
logger.debug(
|
||||
`Git user configured with email ${process.env.BITBUCKET_USER_EMAIL}`
|
||||
)
|
||||
|
||||
await run("git", ["config", "user.name", "Netlify Branch Sync Bot"])
|
||||
|
||||
logger.debug(`Git user configured with name 'Netlify Branch Sync Bot'`)
|
||||
|
||||
logger.debug(`Clone directory: ${CLONE_DIR}`)
|
||||
|
||||
if (
|
||||
await utils.cache.restore(CLONE_DIR, {
|
||||
move: true,
|
||||
})
|
||||
) {
|
||||
logger.debug(`Restored cached for ${CLONE_DIR}`)
|
||||
} else {
|
||||
logger.debug(`Nothing to restore from cache for ${CLONE_DIR}`)
|
||||
}
|
||||
|
||||
if (existsSync(CLONE_DIR)) {
|
||||
try {
|
||||
await run("git", [
|
||||
"-C",
|
||||
CLONE_DIR,
|
||||
"rev-parse",
|
||||
"--is-bare-repository",
|
||||
])
|
||||
logger.debug(
|
||||
`Verified cached clone directory is a valid bare repository.`
|
||||
)
|
||||
} catch (e) {
|
||||
logger.info(
|
||||
`Cached clone directory is corrupted or invalid. Removing and recloning. Error: ${e.message}`
|
||||
)
|
||||
await run("rm", ["-rf", CLONE_DIR]) // Remove corrupted cache
|
||||
}
|
||||
}
|
||||
|
||||
if (existsSync(CLONE_DIR)) {
|
||||
// Fetch if already cloned.
|
||||
logger.debug(`Fetching from origin`)
|
||||
|
||||
await run("git", [
|
||||
"-C",
|
||||
CLONE_DIR,
|
||||
"fetch",
|
||||
"--no-tags",
|
||||
"origin",
|
||||
SYNC_SOURCE,
|
||||
])
|
||||
} else {
|
||||
// Clone if there is no clone.
|
||||
const token = process.env.BITBUCKET_ACCESS_TOKEN ?? ""
|
||||
const cloneURL = `https://x-token-auth:${token}@bitbucket.org/scandic-swap/web.git`
|
||||
|
||||
logger.debug(`Cloning from ${cloneURL.replace(token, "****")}`)
|
||||
logger.debug(`Cloning to ${CLONE_DIR}`)
|
||||
|
||||
await run("git", [
|
||||
"clone",
|
||||
"--bare",
|
||||
"--branch",
|
||||
SYNC_SOURCE,
|
||||
cloneURL,
|
||||
CLONE_DIR,
|
||||
])
|
||||
}
|
||||
|
||||
logger.debug(`Attempting to sync: ${SYNC_DEST.join(", ")}`)
|
||||
|
||||
for (let i = 0; i < SYNC_DEST.length; ++i) {
|
||||
const branch = SYNC_DEST[i]
|
||||
await run("git", ["-C", CLONE_DIR, "push", "origin", `HEAD:${branch}`])
|
||||
console.log(`Successfully synced '${branch}' with '${SYNC_SOURCE}'`)
|
||||
}
|
||||
|
||||
utils.status.show({
|
||||
title: "Branch sync",
|
||||
summary: "All branches are synced! ✅",
|
||||
text: [
|
||||
`The following branches have been synced with '${SYNC_SOURCE}'@${process.env.COMMIT_REF}:`,
|
||||
"",
|
||||
]
|
||||
.concat(
|
||||
SYNC_DEST.map((branch) => {
|
||||
return `- ${branch} - [Deployment list](https://app.netlify.com/sites/web-scandic-hotels/deploys?filter=${branch})`
|
||||
})
|
||||
)
|
||||
.join("\n"),
|
||||
})
|
||||
} catch (error) {
|
||||
utils.build.failBuild("Failed to sync branches.", { error })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const onPostBuild = async function ({ utils }) {
|
||||
// Only run for branch builds of source branch.
|
||||
if (
|
||||
process.env.BRANCH === SYNC_SOURCE &&
|
||||
process.env.CONTEXT === "branch-deploy"
|
||||
) {
|
||||
try {
|
||||
const logger = createLogger()
|
||||
|
||||
if (
|
||||
await utils.cache.save(CLONE_DIR, {
|
||||
move: true,
|
||||
})
|
||||
) {
|
||||
logger.debug(`Saved cached for ${CLONE_DIR}`)
|
||||
}
|
||||
} catch (error) {
|
||||
utils.build.failBuild("Failed to sync branches.", { error })
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user