Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 172 173 | 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 7x 7x 1x 1x 1x 1x 1x 7x 6x 6x 7x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 10x 10x 10x 10x 10x 10x 7x 7x 7x 6x 6x 6x 4x 4x 4x 4x 2x 2x 1x 1x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 10x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 193x 193x | import { getAllDeployments } from '@clevercloud/client/esm/api/v2/application.js';
import dedent from 'dedent';
import { z } from 'zod';
import { defineCommand } from '../../lib/define-command.js';
import { defineOption } from '../../lib/define-option.js';
import { slugify } from '../../lib/slugify.js';
import { styleText } from '../../lib/style-text.js';
import { Logger } from '../../logger.js';
import * as AppConfig from '../../models/app_configuration.js';
import * as Application from '../../models/application.js';
import * as ExitStrategy from '../../models/exit-strategy-option.js';
import { Git } from '../../models/git.js';
import * as Log from '../../models/log.js';
import { sendToApi } from '../../models/send-to-api.js';
import { aliasOption, exitOnDeployOption, followDeployLogsOption, quietOption } from '../global.options.js';
async function restartOnSameCommit(ownerId, appId, commitIdToPush, quiet, withoutCache, exitStrategy) {
const cacheSuffix = withoutCache ? ' without using cache' : '';
Logger.println(`π Restarting ${styleText('bold', appId)}${cacheSuffix} ${styleText('grey', `(${commitIdToPush})`)}`);
const restart = await Application.redeploy(ownerId, appId, commitIdToPush, withoutCache);
return Log.watchDeploymentAndDisplayLogs({ ownerId, appId, deploymentId: restart.deploymentId, quiet, exitStrategy });
}
async function getBranchToDeploy(git, branchName, tagName) {
if (tagName) {
const useTag = await git.isExistingTag(tagName);
if (useTag) {
const tagRefspec = await git.getFullBranch(tagName);
return tagRefspec;
} else {
throw new Error(`Tag ${tagName} doesn't exist locally`);
}
} else {
return await git.getFullBranch(branchName);
}
}
export const deployCommand = defineCommand({
description: 'Deploy an application',
since: '0.2.0',
options: {
branch: defineOption({
name: 'branch',
schema: z.string().default(''),
description: 'Branch to push (current branch by default)',
aliases: ['b'],
placeholder: 'branch',
complete: async () => {
const git = await Git.get();
return git.completeBranches();
},
}),
tag: defineOption({
name: 'tag',
schema: z.string().default(''),
description: 'Tag to push (none by default)',
aliases: ['t'],
placeholder: 'tag',
}),
force: defineOption({
name: 'force',
schema: z.boolean().default(false),
description: "Force deploy even if it's not fast-forwardable",
aliases: ['f'],
}),
sameCommitPolicy: defineOption({
name: 'same-commit-policy',
schema: z.enum(['error', 'ignore', 'restart', 'rebuild']).default('error'),
description: 'What to do when local and remote commit are identical',
aliases: ['p'],
placeholder: 'policy',
}),
alias: aliasOption,
quiet: quietOption,
follow: followDeployLogsOption,
exitOnDeploy: exitOnDeployOption,
},
args: [],
async handler(options) {
const { alias, branch: branchName, tag: tagName, quiet, force, follow, sameCommitPolicy, exitOnDeploy } = options;
const exitStrategy = ExitStrategy.get(follow, exitOnDeploy);
const git = await Git.get();
const appData = await AppConfig.getAppDetails({ alias });
const { ownerId, appId } = appData;
const branchRefspec = await getBranchToDeploy(git, branchName, tagName);
const commitIdToPush = await git.getBranchCommit(branchRefspec);
const remoteHeadCommitId = await git.getRemoteCommit(appData.deployUrl);
const deployedCommitId = await Application.get(ownerId, appId).then(({ commitId }) => commitId);
await git.addRemote(appData.alias, appData.deployUrl);
if (commitIdToPush === remoteHeadCommitId) {
switch (sameCommitPolicy) {
case 'ignore':
Logger.printSuccess(`The application is up-to-date (${styleText('grey', remoteHeadCommitId)})`);
return;
case 'restart':
return restartOnSameCommit(ownerId, appId, commitIdToPush, quiet, false, exitStrategy);
case 'rebuild':
return restartOnSameCommit(ownerId, appId, commitIdToPush, quiet, true, exitStrategy);
case 'error':
default: {
const restartCommand =
commitIdToPush !== deployedCommitId ? `clever restart --commit ${commitIdToPush}` : 'clever restart';
throw new Error(dedent`
Remote HEAD has the same commit as the one to push ${styleText('grey', `(${remoteHeadCommitId})`)}, your application is up-to-date.
Create a new commit, use ${styleText('blue', restartCommand)} or the ${styleText('blue', '--same-commit-policy')} option.
`);
}
}
}
// It's sometimes tricky to figure out the deployment ID for the current git push.
// We on have the commit ID but there in a situation where the last deployment was cancelled, it may have the same commit ID.
// So before pushing, we get the last deployments so we can after the push figure out which deployment is newβ¦
const knownDeployments = await getAllDeployments({ id: ownerId, appId, limit: 5 }).then(sendToApi);
Logger.println(dedent`
${styleText('bold', `π Deploying ${styleText('green', appData.name)}`)}
Application ID ${styleText('grey', `${appId}`)}
Organisation ID ${styleText('grey', `${ownerId}`)}
`);
Logger.println();
Logger.println(styleText('bold', 'π Git information'));
if (remoteHeadCommitId == null || deployedCommitId == null) {
Logger.println(` ${styleText('yellow', '!')} App is brand new, no commits on remote yet`);
} else {
Logger.println(` Remote head ${styleText('yellow', remoteHeadCommitId)} (${branchRefspec})`);
Logger.println(` Deployed commit ${styleText('yellow', deployedCommitId)}`);
}
Logger.println(
` Local commit ${styleText('yellow', commitIdToPush)} ${styleText('blue', '[will be deployed]')}`,
);
Logger.println();
Logger.println(dedent`
${styleText('bold', 'π Deployment progress')}
${styleText('blue', 'β Pushing source code to Clever Cloudβ¦')}
`);
const pushStart = Date.now();
await git.push(appData.deployUrl, commitIdToPush, force, slugify(appData.alias)).catch(async (e) => {
const isShallow = await git.isShallow();
if (isShallow) {
throw new Error(
'Failed to push your source code because your repository is shallow and therefore cannot be pushed to the Clever Cloud remote.',
);
} else {
throw e;
}
});
const pushDuration = ((Date.now() - pushStart) / 1000).toFixed(1);
await Logger.println(` ${styleText('green', `β Code pushed to Clever Cloud (${pushDuration}s)`)}`);
return Log.watchDeploymentAndDisplayLogs({
ownerId,
appId,
commitId: commitIdToPush,
knownDeployments,
quiet,
exitStrategy,
});
},
});
|