bicep-assets
Version:
172 lines (169 loc) • 7.34 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BuildCommand = void 0;
const clipanion_1 = require("clipanion");
const folder_hash_1 = require("folder-hash");
const promises_1 = require("fs/promises");
const fs_1 = require("fs");
const path_1 = require("path");
const copy_1 = require("../build-plugins/copy");
const nodejs_1 = require("../build-plugins/nodejs");
const vite_1 = require("../build-plugins/vite");
const configuration_1 = require("../configuration");
const plugin_manager_1 = require("../utils/plugin-manager");
class BuildCommand extends clipanion_1.Command {
constructor() {
super(...arguments);
this.outFolder = clipanion_1.Option.String('--output,-o', '.bicep-assets', {
description: 'The output folder for the assets. Defaults to .bicep-assets',
});
}
execute() {
return __awaiter(this, void 0, void 0, function* () {
const configuration = yield configuration_1.Configuration.load(false);
const pluginManager = new plugin_manager_1.PluginManager();
pluginManager.register('nodejs', new nodejs_1.NodeJsBuildPlugin());
pluginManager.register('vite', new vite_1.ViteBuildPlugin());
pluginManager.register('copy', new copy_1.CopyBuildPlugin());
const commands = yield pluginManager.load(configuration.assets);
const manifestContent = {
// resourceProviderId: configuration.customResourceProviderId,
storageAccountName: configuration.storageAccountName,
subscription: configuration.subscription,
resourceGroup: configuration.resourceGroup,
assets: {},
};
for (const command of commands) {
const hash = yield this.execBuild(command, this.outFolder);
manifestContent.assets[command.name] = hash !== null && hash !== void 0 ? hash : 'ERROR';
}
yield (0, promises_1.mkdir)(this.outFolder, {
recursive: true,
});
yield (0, promises_1.writeFile)((0, path_1.join)(this.outFolder, 'manifest.json'), JSON.stringify(manifestContent, null, 2), 'utf-8');
const bicepContent = this.generateBicep(manifestContent, this.outFolder);
yield (0, promises_1.writeFile)((0, path_1.join)('bicep-assets.bicep'), bicepContent, 'utf-8');
});
}
execBuild(command, outputFolder) {
return __awaiter(this, void 0, void 0, function* () {
console.log(`➤ Building ${command.name}`);
yield this.retry((0, promises_1.mkdir)(outputFolder, {
recursive: true,
}));
const tempFolder = yield (0, promises_1.mkdtemp)((0, path_1.resolve)((0, path_1.join)(outputFolder, 'tmp-asset-')));
try {
const result = yield command.buildInFolder(tempFolder);
const hash = (yield (0, folder_hash_1.hashElement)('.', tempFolder, {
encoding: 'hex',
})).hash;
let filename = hash;
if (typeof result === 'string') {
const extension = (0, path_1.extname)(result);
if (extension.length > 1) {
filename = filename + extension;
}
}
const output = (0, path_1.join)(outputFolder, filename);
if ((0, fs_1.existsSync)(output)) {
yield this.retry((0, promises_1.rm)(output, {
recursive: true,
}));
}
if (typeof result === 'string') {
yield this.retry((0, promises_1.rename)(result, (0, path_1.join)(outputFolder, filename)));
yield this.retry((0, promises_1.rm)(tempFolder, {
recursive: true,
}));
}
else {
yield this.retry((0, promises_1.rename)(tempFolder, (0, path_1.join)(outputFolder, filename)));
}
console.log(`➤ Finished building ${command.name}`);
return filename;
}
catch (error) {
yield this.retry((0, promises_1.rm)(tempFolder, {
recursive: true,
}));
throw error;
}
});
}
retry(command) {
return __awaiter(this, void 0, void 0, function* () {
const backOffInterval = 1000; // 1 second
const maxRetries = 10;
let retry = 0;
let lastError = undefined;
while (retry < maxRetries) {
try {
return yield command;
}
catch (error) {
retry++;
yield new Promise(resolve => setTimeout(resolve, backOffInterval * retry));
if (retry >= maxRetries) {
lastError = error;
break;
}
}
}
throw lastError;
});
}
generateBicep(manifestContent, outFolder) {
if (Object.keys(manifestContent.assets).length === 0) {
return '';
}
const assets = Object.entries(manifestContent.assets).map(([k, v]) => {
const stats = (0, fs_1.statSync)((0, path_1.join)(outFolder, v));
const filename = stats.isDirectory() ? `${v}.zip` : v;
// return `${k.replace(/[-.]/g, '_')}: {
// resourceProviderId: '${manifestContent.resourceProviderId}'
// filename: '${filename}'
// }`;
return `${k.replace(/[-.]/g, '_')}: {
subscription: '${manifestContent.subscription}'
resourceGroup: '${manifestContent.resourceGroup}'
storageAccountName: '${manifestContent.storageAccountName}'
containerName: 'assets'
filename: '${filename}'
}`;
});
return `
@export()
type Asset = {
storageAccountName: string
subscription: string
resourceGroup: string
containerName: string
filename: string
}
@export()
var assets = {
${assets.join('\n ')}
}
`;
}
}
exports.BuildCommand = BuildCommand;
BuildCommand.paths = [
['build'],
];
BuildCommand.usage = clipanion_1.Command.Usage({
description: 'Build the assets for the bicep template',
details: `
This command will build the assets for the bicep template.
It will generate a distribution folder with all assets.
`,
});
;