Files
web/netlify/netlify-plugin-branch-sync/index.js
Anton Gunnarsson 2ef891281e Merged in fix/ensure-fetch-head-exists-in-branch-sync (pull request #2770)
fix: Always run git fetch in netlify-branch-sync

* Always run git fetch

If we don't run git fetch `FETCH_HEAD` will
not be set, since git clone does not set it.


Approved-by: Joakim Jäderberg
2025-09-08 11:02:32 +00:00

172 lines
4.5 KiB
JavaScript

// @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)) {
// 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])
}
// Always fetch to ensure FETCH_HEAD is available
logger.debug(`Fetching from origin`)
await run("git", ["-C", CLONE_DIR, "fetch", "--no-tags", "origin", SYNC_SOURCE])
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",
`FETCH_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 })
}
}
}