-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathpublish.ts
More file actions
171 lines (144 loc) · 5.75 KB
/
Copy pathpublish.ts
File metadata and controls
171 lines (144 loc) · 5.75 KB
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import { BuildResult } from '@vtex/api'
import retry from 'async-retry'
import chalk from 'chalk'
import { region } from '../../api/env'
import { createPathToFileObject } from '../../api/files/ProjectFilesManager'
import { toAppLocator } from '../../api/locator'
import log from '../../api/logger'
import { ManifestEditor, getAppRoot } from '../../api/manifest'
import { listLocalFiles } from '../../api/modules/apps/file'
import { ProjectUploader } from '../../api/modules/apps/ProjectUploader'
import { listenBuild } from '../../api/modules/build'
import { promptConfirm } from '../../api/modules/prompts'
import {
checkBuilderHubMessage,
continueAfterReactTermsAndConditions,
showBuilderHubMessage,
} from '../../api/modules/utils'
import { SessionManager } from '../../api/session/SessionManager'
import * as conf from '../../api/conf'
import { returnToPreviousAccount, switchAccount } from '../../api/modules/auth/switch'
import { runYarnIfPathExists } from '../utils'
const buildersToRunLocalYarn = ['node', 'react']
const automaticTag = (version: string): string => (version.indexOf('-') > 0 ? null : 'latest')
const publisher = (workspace = 'master') => {
const publishApp = async (
appRoot: string,
tag: string,
force: boolean,
projectUploader: ProjectUploader
): Promise<BuildResult> => {
const paths = await listLocalFiles(appRoot)
const retryOpts = {
retries: 2,
minTimeout: 1000,
factor: 2,
}
const publish = async (_, tryCount) => {
const filesWithContent = paths.map(createPathToFileObject(appRoot))
if (tryCount === 1) {
log.debug('Sending files:', `\n${paths.join('\n')}`)
}
if (tryCount > 1) {
log.info(`Retrying...${tryCount - 1}`)
}
try {
return await projectUploader.sendToPublish(filesWithContent, tag, { skipSemVerEnsure: force })
} catch (err) {
const { response } = err
const { status } = response
const data = response?.data
const { message } = data
const statusMessage = status ? `: Status ${status}` : ''
log.error(`Error publishing app${statusMessage} (try: ${tryCount})`)
if (message) {
log.error(`Message: ${message}`)
}
if (status && status < 500) {
return
}
throw err
}
}
return retry(publish, retryOpts)
}
const publishApps = async (path: string, tag: string, force: boolean): Promise<void | never> => {
const session = SessionManager.getSingleton()
const manifest = await ManifestEditor.getManifestEditor()
const builderHubMessage = await checkBuilderHubMessage('publish')
if (builderHubMessage != null) {
await showBuilderHubMessage(builderHubMessage.message, builderHubMessage.prompt, manifest)
}
const { account: previousAccount, workspace: previousWorkspace } = session
if (manifest.vendor !== session.account) {
const switchToVendorMsg = `You are trying to publish this app in an account that differs from the indicated vendor. Do you want to publish in account ${chalk.blue(
manifest.vendor
)}?`
const canSwitchToVendor = await promptConfirm(switchToVendorMsg)
if (!canSwitchToVendor) {
return
}
await switchAccount(manifest.vendor, {})
}
const pubTag = tag || automaticTag(manifest.version)
const appId = toAppLocator(manifest)
const context = { account: manifest.vendor, workspace, region: region(), authToken: session.token }
const projectUploader = ProjectUploader.getProjectUploader(appId, context)
try {
const senders = ['vtex.builder-hub', 'apps']
await listenBuild(appId, () => publishApp(path, pubTag, force, projectUploader), {
waitCompletion: true,
context,
senders,
})
log.info(`${appId} was published successfully!`)
log.info(`You can deploy it with: ${chalk.blueBright(`vtex deploy ${appId}`)}`)
if (manifest.builders?.docs) {
log.info(
`Your app documentation will be available at: ${chalk.yellowBright(`https://vtex.io/docs/app/${appId}`)}`
)
}
} catch (e) {
log.error(`Failed to publish ${appId}`)
}
await returnToPreviousAccount({ previousAccount, previousWorkspace })
}
return { publishApp, publishApps }
}
export default async (path: string, options, pipeline: boolean) => {
log.debug(`Starting to publish app in ${conf.getEnvironment()}`)
const { account } = SessionManager.getSingleton()
const manifest = await ManifestEditor.getManifestEditor()
const mustContinue = await continueAfterReactTermsAndConditions(manifest)
if (!mustContinue) {
process.exit(1)
}
const versionMsg = chalk.bold.yellow(manifest.version)
const appNameMsg = chalk.bold.yellow(`${manifest.vendor}.${manifest.name}`)
const yesFlag = options.y || options.yes
if (!pipeline && !yesFlag) {
const confirmVersion = await promptConfirm(
`Are you sure that you want to release version ${chalk.bold(`${versionMsg} of ${appNameMsg}?`)}`,
false
)
if (!confirmVersion) {
process.exit(1)
}
}
if (yesFlag && manifest.vendor !== account) {
log.error(`When using the 'yes' flag, you need to be logged in to the same account as your app’s vendor.`)
process.exit(1)
}
const workspace = options.w || options.workspace
if (workspace && manifest.vendor !== account) {
log.error(`When using the 'workspace' flag, you need to be logged in to the same account as your app’s vendor.`)
process.exit(1)
}
const root = getAppRoot()
path = path || root
const force = options.f || options.force
// Always run yarn locally for some builders
buildersToRunLocalYarn.map(runYarnIfPathExists)
const { publishApps } = publisher(workspace)
await publishApps(path, options.tag, force)
}