Skip to content
81 changes: 57 additions & 24 deletions scripts/release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,15 @@ export const deriveReleaseState = ({
releaseSha,
mainSha,
developSha,
privateSha,
privateContentMatchesMain,
latestTagSha,
openPrereleasePr,
openReleasePr,
}: {
releaseSha: string
mainSha: string
developSha: string
privateSha: string
privateContentMatchesMain: boolean
latestTagSha: string
openPrereleasePr: GitHubPr | undefined
openReleasePr: GitHubPr | undefined
Expand All @@ -88,7 +88,7 @@ export const deriveReleaseState = ({

if (mainSha !== latestTagSha) return 'merged_untagged'

if (privateSha !== mainSha) return 'tagged_private_stale'
if (!privateContentMatchesMain) return 'tagged_private_stale'

if (releaseSha === mainSha && developSha === mainSha) return 'done'

Expand All @@ -97,18 +97,18 @@ export const deriveReleaseState = ({

export const deriveHotfixState = ({
mainSha,
privateSha,
privateContentMatchesMain,
latestTagSha,
openHotfixPr,
}: {
mainSha: string
privateSha: string
privateContentMatchesMain: boolean
latestTagSha: string
openHotfixPr: GitHubPr | undefined
}): HotfixState => {
if (openHotfixPr) return 'hotfix_pr_open'
if (mainSha !== latestTagSha) return 'merged_untagged'
if (privateSha !== mainSha) return 'tagged_private_stale'
if (!privateContentMatchesMain) return 'tagged_private_stale'
return 'idle'
}

Expand Down Expand Up @@ -402,7 +402,7 @@ const createPr = async ({
head: string
title: string
body: string
}): Promise<string> => {
}): Promise<string | null> => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'shapeshift-release-body-'))
const bodyPath = path.join(tmpDir, 'body.md')

Expand All @@ -424,6 +424,9 @@ const createPr = async ({
])
const stdout = typeof result === 'string' ? result : (result as { stdout: string }).stdout
return stdout.trim()
} catch (err) {
if (String(err).includes('No commits between')) return null
throw err
} finally {
try {
fs.rmSync(tmpDir, { recursive: true, force: true })
Expand Down Expand Up @@ -484,24 +487,26 @@ const doRegularRelease = async () => {
const nextVersion = await getNextVersion('minor')
const latestTag = await getLatestSemverTag()

const [releaseSha, mainSha, developSha, privateSha, latestTagSha] = await Promise.all([
const [releaseSha, mainSha, developSha, latestTagSha] = await Promise.all([
getSha('origin/release'),
getSha('origin/main'),
getSha('origin/develop'),
getSha('origin/private'),
getTagSha(latestTag),
])

const [openPrereleasePr, openReleasePr] = await Promise.all([
const [openPrereleasePr, openReleasePr, privateContentMatchesMain] = await Promise.all([
findOpenPr('develop', 'release'),
findOpenPr('release', 'main'),
git()
.diff(['origin/main', 'origin/private'])
.then(diff => !diff),
])

const state = deriveReleaseState({
releaseSha,
mainSha,
developSha,
privateSha,
privateContentMatchesMain,
latestTagSha,
openPrereleasePr,
openReleasePr,
Expand Down Expand Up @@ -617,13 +622,17 @@ const doRegularRelease = async () => {
title: `chore: sync private to ${nextVersion}`,
body: `Sync private branch to main after release ${nextVersion}.`,
})
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
console.log(chalk.green('Merge it on GitHub to complete the release.'))
if (privatePrUrl) {
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
console.log(chalk.green('Merge it on GitHub to complete the release.'))
} else {
console.log(chalk.green('private already in sync with main - nothing to do.'))
}
break
}

case 'tagged_private_stale': {
console.log(chalk.yellow(`${nextVersion} is tagged but private is behind main.`))
console.log(chalk.yellow(`${latestTag} is tagged but private is behind main.`))

const existingPrivatePr = await findOpenPr('main', 'private')
if (existingPrivatePr) {
Expand All @@ -640,7 +649,11 @@ const doRegularRelease = async () => {
title: `chore: sync private to ${nextVersion}`,
body: `Sync private branch to main after release ${nextVersion}.`,
})
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
if (privatePrUrl) {
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
} else {
console.log(chalk.green('private already in sync with main - nothing to do.'))
}
}
break
}
Expand All @@ -663,18 +676,22 @@ const doHotfixRelease = async () => {
const nextVersion = await getNextVersion('patch')
const latestTag = await getLatestSemverTag()

const [mainSha, privateSha, latestTagSha] = await Promise.all([
const [mainSha, latestTagSha] = await Promise.all([
getSha('origin/main'),
getSha('origin/private'),
getTagSha(latestTag),
])

const hotfixBranch = `hotfix/${nextVersion}`
const openHotfixPr = await findOpenPr(hotfixBranch, 'main')
const [openHotfixPr, privateContentMatchesMain] = await Promise.all([
findOpenPr(hotfixBranch, 'main'),
git()
.diff(['origin/main', 'origin/private'])
.then(diff => !diff),
])

const state = deriveHotfixState({
mainSha,
privateSha,
privateContentMatchesMain,
latestTagSha,
openHotfixPr,
})
Expand Down Expand Up @@ -770,7 +787,11 @@ const doHotfixRelease = async () => {
title: `chore: sync private to ${nextVersion}`,
body: `Sync private branch to main after hotfix ${nextVersion}.`,
})
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
if (privatePrUrl) {
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
} else {
console.log(chalk.green('private already in sync with main - nothing to do.'))
}

console.log(chalk.green('Creating backmerge PR (main -> develop)...'))
const backmergeUrl = await createPr({
Expand All @@ -779,13 +800,17 @@ const doHotfixRelease = async () => {
title: `chore: backmerge ${nextVersion} into develop`,
body: `Backmerge main into develop after hotfix ${nextVersion} to sync cherry-picked commits.`,
})
console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`))
if (backmergeUrl) {
console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`))
} else {
console.log(chalk.green('develop already in sync with main - nothing to do.'))
}
console.log(chalk.green('Merge both PRs on GitHub to complete the hotfix.'))
break
}

case 'tagged_private_stale': {
console.log(chalk.yellow(`${nextVersion} is tagged but private is behind main.`))
console.log(chalk.yellow(`${latestTag} is tagged but private is behind main.`))

const existingPrivatePr = await findOpenPr('main', 'private')
if (existingPrivatePr) {
Expand All @@ -802,7 +827,11 @@ const doHotfixRelease = async () => {
title: `chore: sync private to ${nextVersion}`,
body: `Sync private branch to main after hotfix ${nextVersion}.`,
})
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
if (privatePrUrl) {
console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`))
} else {
console.log(chalk.green('private already in sync with main - nothing to do.'))
}
}

const existingBackmerge = await findOpenPr('main', 'develop')
Expand All @@ -816,7 +845,11 @@ const doHotfixRelease = async () => {
title: `chore: backmerge ${nextVersion} into develop`,
body: `Backmerge main into develop after hotfix ${nextVersion}.`,
})
console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`))
if (backmergeUrl) {
console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`))
} else {
console.log(chalk.green('develop already in sync with main - nothing to do.'))
}
}
}
break
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useMobileFeaturesCompatibility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export enum MobileFeature {

export const MOBILE_FEATURE_MINIMUM_VERSIONS: Record<MobileFeature, string> = {
[MobileFeature.RatingModal]: '3.3.1',
[MobileFeature.NativeQrScanner]: '3.4.0',
[MobileFeature.NativeQrScanner]: '3.7.2',
}

type MobileFeatureInfo = {
Expand Down