Skip to content

Commit

Permalink
feat: allow service selection when deploying
Browse files Browse the repository at this point in the history
example: hexa deploy -j k8s
  • Loading branch information
manekinekko committed Oct 31, 2019
1 parent 25b3704 commit e8908fd
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 43 deletions.
48 changes: 33 additions & 15 deletions src/commands/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import chalk from "chalk";
import { az, Config, func, isProjectFileExists, joinPath, kubectl, npm, readWorkspace } from "../core/utils";
import { az, Config, func, isProjectFileExists, joinPath, kubectl, npm, readWorkspace, FEATURES } from "../core/utils";
const debug = require("debug")("push");

module.exports = async function() {
module.exports = async function(options: HexaInitOptions) {
if (isProjectFileExists() === false) {
console.log(chalk.red(`✗ The ${chalk.cyan("hexa deploy")} command can only be run inside a Hexa project.`));
console.log(chalk.red(`✗ Run ${chalk.cyan("hexa init")} first.`));
Expand All @@ -16,17 +16,36 @@ module.exports = async function() {
// Get all other required configs from the current workspace
const workspace: HexaWorkspace = readWorkspace();

const validFeatures = FEATURES.map(feat => feat.value);

// validate the services that need to be deployed
let requestedServices = (options.requestedServices || []) as string[];
if (requestedServices.length) {
const workspaceKeys = Object.keys(workspace);
workspaceKeys.filter(service => validFeatures.includes(service)).map(service => {
// don't deploy services that are not requested by the user
// project and storage are required entries!
if (["project", "storage"].includes(service) === false && requestedServices.includes(service) === false) {
(workspace as any)[service] = null;
}
});
}

if (workspace.storage && workspace.storage.connectionString) {
process.env.AZURE_STORAGE_CONNECTION_STRING = workspace.storage.connectionString;
debug(`set env variable AZURE_STORAGE_CONNECTION_STRING`);
}

let deployStatus = false;
let hostingUrl = "";
let hostingUrl: { message: string } = { message: "" };
let functionUrls: { name: string; url: string }[] = [];
let registryPath = "";
let serviceUrl = "";

if (requestedServices.length) {
console.log(`Deploying services: ${chalk.green(requestedServices.join(","))}`);
}

// Deploy hosting config
if (workspace.hosting) {
deployStatus = true;
Expand All @@ -35,20 +54,20 @@ module.exports = async function() {
// https://docs.microsoft.com/en-us/cli/azure/storage/blob?view=azure-cli-latest#az-storage-blob-upload-batch
await az(
`storage blob upload-batch --source "${workspace.hosting.folder}" --destination "\\$web" --account-name "${workspace.storage.name}" --no-progress`,
`Deploying hosting ${chalk.cyan(workspace.project.name)}...`
`Deploying hosting ${chalk.cyan(workspace.storage.name)}...`
);

// https://docs.microsoft.com/en-us/cli/azure/storage/account?view=azure-cli-latest#az-storage-account-show
hostingUrl = await az(`storage account show --name ${workspace.storage.name} --query "primaryEndpoints.web"`, `Fetching URL for ${chalk.cyan(workspace.project.name)}...`);
}

// Deploy functions config
if (workspace.functionApp) {
if (workspace.functions) {
deployStatus = true;

debug(`deploying functions`);

const functionApp = workspace.functionApp;
const functionApp = workspace.functions;

await npm<void>(`run build:production`, joinPath(process.cwd(), functionApp.folder as string, functionApp.name), `Building Function app ${chalk.cyan(functionApp.name)}...`);
const functionAppPublishResult = await func<void>(
Expand Down Expand Up @@ -82,18 +101,17 @@ module.exports = async function() {
registryPath = image;

debug(`deploying cluster`);
await kubectl(`apply -f k8s.yaml -o json`, `Deploying cluster ${chalk.cyan(workspace.k8s.name)}...`) as any;

serviceUrl = await kubectl(`get service ${workspace.k8s.name} -o jsonpath='{.status.loadBalancer.ingress[].ip}{":"}{.spec.ports[].targetPort}'`, `Fetching service adrress...`);
(await kubectl(`apply -f k8s.yaml -o json`, `Deploying cluster ${chalk.cyan(workspace.k8s.name)}...`)) as any;

// k8s FQDN
serviceUrl = workspace.k8s.hostname;
debug(`fetching service address=${chalk.green(serviceUrl)}`);
}

/////


if (hostingUrl) {
console.log(`${chalk.yellow("➜")} Hosting: ${chalk.green(hostingUrl)}`);
if (hostingUrl.message) {
console.log(`${chalk.yellow("➜")} Hosting: ${chalk.green(hostingUrl.message.replace(/"/g, ''))}`);
}

if (workspace.database) {
Expand All @@ -109,7 +127,9 @@ module.exports = async function() {

if (registryPath) {
console.log(`${chalk.yellow("➜")} Kubernetes:`);
console.log(` - URL: ${chalk.green(serviceUrl)}`);
if (serviceUrl) {
console.log(` - URL: ${chalk.green(serviceUrl)}`);
}
console.log(` - Container: ${chalk.green(registryPath)}`);
}

Expand All @@ -118,7 +138,5 @@ module.exports = async function() {
} else {
console.log(chalk.yellow(`✗ No resources deployed. Run hexa init and try again!`));
}

console.log(`\n`);
return true;
};
27 changes: 2 additions & 25 deletions src/commands/init.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import chalk from "chalk";
import { askForFeatures, askIfOverrideProjectFile } from "../core/prompt";
import { absolutePath, Config, deleteFile, isProjectFileExists, pluralize } from "../core/utils";
import { absolutePath, Config, deleteFile, isProjectFileExists, pluralize, FEATURES } from "../core/utils";
const debug = require("debug")("init");

module.exports = async function(options?: HexaInitOptions) {
Expand All @@ -9,31 +9,8 @@ module.exports = async function(options?: HexaInitOptions) {
debug(chalk.bold(chalk.yellow(`Warning: Flag --force has been set. Hexa won't ask for any confirmation!`)));
}

const FEATURES = [
{
name: "Hosting: Configure and deploy to Azure Static Website",
value: "hosting",
short: "Hosting"
},
{
name: "Functions: Configure and deploy an Azure Functions",
value: "functions",
short: "Functions"
},
{
name: "Database: Configure and deploy a database on Azure",
value: "database",
short: "Database"
},
{
name: "Kubernetes: Configure a Kubernetes cluster (preview)",
value: "kubernetes",
short: "Kubernetes"
}
];

let selectedFeatures: any[] = [];
const requetedServices = (options && options.requetedServices) || [];
const requetedServices = (options && options.requestedServices) || [];

// if the user requested a subset of services, use that choice...
if (requetedServices.length) {
Expand Down
27 changes: 24 additions & 3 deletions src/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const Configstore = require("configstore");
const dotenv = require("dotenv");
const packageJson = require("../../package.json");
const debug = require("debug")(`hexa`);

const crypto = require("crypto");

// generate a Global UUID per execution.
Expand Down Expand Up @@ -36,6 +35,28 @@ export const Config = new Configstore(packageJson.name, {

debug(`Cached config stored at ${chalk.green(Config.path)}`);

export const FEATURES = [
{
name: "Hosting: Configure and deploy to Azure Static Website",
value: "hosting",
short: "Hosting"
},
{
name: "Functions: Configure and deploy an Azure Functions",
value: "functions",
short: "Functions"
},
{
name: "Database: Configure and deploy a database on Azure",
value: "database",
short: "Database"
},
{
name: "Kubernetes: Configure a Kubernetes cluster (preview)",
value: "kubernetes",
short: "Kubernetes"
}
];
export const WORKSPACE_FILENAME = "hexa.json";
export const ENV_FILENAME = ".env";

Expand Down Expand Up @@ -181,7 +202,7 @@ export function saveWorkspace(config: Partial<HexaWorkspace>) {

// we don't want to store IDs in the workspace file
for (var key in config) {
delete config[key].id;
delete (config as any)[key].id;
}

let oldConfig = {};
Expand Down Expand Up @@ -250,7 +271,7 @@ export function copyTemplate(src: string, destination: string, context?: { [key:

context = {
...context,
date: (new Date()).toISOString()
date: new Date().toISOString()
};

let srcContent = readFileFromDisk(src) || "";
Expand Down

0 comments on commit e8908fd

Please sign in to comment.