forked from transloadit/uppy
/
getUpToDateRefsFromGitHub.js
117 lines (104 loc) · 3.69 KB
/
getUpToDateRefsFromGitHub.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import fetch from 'node-fetch'
import { spawnSync } from 'node:child_process'
import prompts from 'prompts'
import { TARGET_BRANCH, REPO_NAME, REPO_OWNER, STABLE_BRANCH } from './config.js'
async function apiCall (endpoint, errorMessage) {
const response = await fetch(
`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}${endpoint}`,
)
if (response.ok) {
return response.json()
}
console.warn(response)
throw new Error(errorMessage)
}
export async function getRemoteHEAD () {
return (
await apiCall(
`/git/ref/heads/${TARGET_BRANCH}`,
'Cannot get remote HEAD, check your internet connection.',
)
).object.sha
}
async function getLatestReleaseSHA () {
const response = await fetch(`https://raw.githubusercontent.com/${REPO_OWNER}/${REPO_NAME}/${TARGET_BRANCH}/packages/uppy/package.json`)
if (!response.ok) throw new Error(`Network call failed: ${response.status} ${response.statusText}`)
const { version } = await response.json()
const tag_name = `uppy@${version}`
console.log(`Last release was ${tag_name}.`)
return (
await apiCall(
`/git/ref/tags/${encodeURIComponent(tag_name)}`,
`Failed to fetch information for release ${JSON.stringify(tag_name)}`,
)
).object.sha
}
function getStableBranchMergeBase (REMOTE_HEAD) {
spawnSync('git', ['fetch', `https://github.com/${REPO_OWNER}/${REPO_NAME}.git`, STABLE_BRANCH])
const STABLE_HEAD = spawnSync('git', ['rev-parse', 'FETCH_HEAD']).stdout.toString().trim()
return [[
spawnSync('git', ['merge-base', REMOTE_HEAD, 'FETCH_HEAD']).stdout.toString().trim(),
STABLE_HEAD,
].join('..'), STABLE_HEAD]
}
async function getLocalHEAD () {
return spawnSync('git', ['rev-parse', 'HEAD']).stdout.toString().trim()
}
export function rewindGitHistory (spawnOptions, sha) {
return spawnSync('git', ['reset', sha, '--hard'], spawnOptions).status === 0
}
export async function validateGitStatus (spawnOptions) {
const latestRelease = getLatestReleaseSHA() // run in parallel to speed things up
const [REMOTE_HEAD, LOCAL_HEAD] = await Promise.all([getRemoteHEAD(), getLocalHEAD()])
const { status, stderr } = spawnSync(
'git',
['diff', '--exit-code', '--quiet', REMOTE_HEAD, '--', '.'],
spawnOptions,
)
if (status !== 0) {
console.error(stderr.toString())
console.log(
`git repository is not clean and/or not in sync with ${REPO_OWNER}/${REPO_NAME}`,
)
if (spawnSync(
'git',
['diff', '--exit-code', '--quiet', LOCAL_HEAD, '--', '.'],
spawnOptions,
).status !== 0) {
const { value } = await prompts({
type: 'confirm',
name: 'value',
message:
'Do you want to hard reset your local repository (all uncommitted changes will be lost)?',
})
if (!value) {
throw new Error(
'Please ensure manually that your local repository is clean and up to date.',
)
}
}
if (stderr.indexOf('bad object') !== -1) {
// eslint-disable-next-line no-shadow
const { status, stdout, stderr } = spawnSync(
'git',
[
'fetch',
`https://github.com/${REPO_OWNER}/${REPO_NAME}.git`,
TARGET_BRANCH,
],
spawnOptions,
)
if (status) {
console.log(stdout.toString())
console.error(stderr.toString())
throw new Error('Failed to fetch, please ensure manually that your local repository is up to date')
}
}
if (!rewindGitHistory(spawnOptions, REMOTE_HEAD)) {
throw new Error(
'Failed to reset, please ensure manually that your local repository is clean and up to date.',
)
}
}
return [await latestRelease, LOCAL_HEAD, ...getStableBranchMergeBase(REMOTE_HEAD)]
}