Skip to content

Commit

Permalink
feat: generate Bazel config for Functions
Browse files Browse the repository at this point in the history
  • Loading branch information
manekinekko committed Oct 20, 2019
1 parent 3320996 commit 1033470
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 8 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -80,9 +80,9 @@ Options:
login connect to your Azure
init initialize a new workspace
deploy deploy to Azure
-f, --force override all confirmations (default: false)
-y, --yes answer yes to all confirmations (default: false)
-r, --relogin force login (default: false)
-c, --create enable resource creation (default: true)
-c, --create enable resource creation (default: false)
-m, --manual enable Manual mode (default: false)
-d, --debug enable debug mode (default: false)
-s, --sas use SAS token (only: storage and database) (default: false)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -10,7 +10,7 @@
"homepage": "https://github.com/manekinekko/hexa#readme",
"private": false,
"scripts": {
"start": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts",
"start": "npm run build -- --watch",
"build": "rm -fr build/ && mkdir build && npm run copy && tsc",
"copy": "cp -r src/templates build",
"prepare": "npm run build",
Expand Down
24 changes: 23 additions & 1 deletion src/core/utils.ts
Expand Up @@ -228,10 +228,18 @@ export function isProjectFileExists() {
return isFound;
}

export function copyTemplate(src: string, destination: string) {
export function copyTemplate(src: string, destination: string, context?: {[key: string]: string}) {
const templateDir = getTemplateFullPath();
src = templateDir + "/" + src;

if (context) {
let srcContent = readFileFromDisk(src) || "";
for (let key in context) {
srcContent = srcContent.replace(new RegExp(`{{(${key})}}`, 'g'), context[key]);
}
debug(`copying template file src=${chalk.green(src)}, destination=${chalk.green(destination)}, context=${chalk.green(JSON.stringify(context))}`);
return fs.writeFileSync(destination, srcContent);
}
debug(`copying template file src=${chalk.green(src)}, destination=${chalk.green(destination)}`);
return fs.copyFileSync(src, destination);
}
Expand All @@ -247,3 +255,17 @@ export function getFullPath(folder: string) {
export function joinPath(...args: string[]) {
return path.join(...args);
}

export function updateFile({filepath, replace, search}: {filepath: string, replace: string, search?: string}) {
let srcContent = readFileFromDisk(filepath) || "";

if (search) {
srcContent = srcContent.replace(search, replace);
}
else {
srcContent = [srcContent, replace].join(`\n`);
}

debug(`updating file src=${chalk.green(filepath)}`);
return fs.writeFileSync(filepath, srcContent);
}
59 changes: 58 additions & 1 deletion src/features/functions/init.ts
@@ -1,6 +1,6 @@
import chalk from "chalk";
import { askForFunctionsAppFolder } from "../../core/prompt";
import { Config, createDirectoryIfNotExists, directoryExists, func, npm, saveWorkspace, uuid } from "../../core/utils";
import { Config, createDirectoryIfNotExists, directoryExists, func, npm, saveWorkspace, uuid, copyTemplate, sanitize, updateFile } from "../../core/utils";
const debug = require("debug")("functions:init");

module.exports = async function() {
Expand Down Expand Up @@ -54,7 +54,64 @@ module.exports = async function() {
`${functionAppPath}`,
`Scaffolding function ${chalk.cyan(functionHttpName)}...`
);

// override the function index.ts with a simpler example
copyTemplate(`init/functions/index.ts.tpl`, `${functionAppPath}/${functionHttpName}/index.ts`, {functionHttpName: sanitize(functionHttpName)});

await npm<void>(`install`, functionAppPath, `Installing dependencies for ${chalk.cyan(functionAppPath)}...`);

// should be setup Bazel config?
if (process.env.HEXA_USE_BAZEL) {
await npm<void>(`install -D @bazel/ibazel@latest @bazel/bazel@latest @bazel/typescript@latest`, functionAppPath, `Adding Bazel configuration for ${chalk.cyan(functionAppPath)}...`);

// create the WORKSPACE
copyTemplate(`init/functions/WORKSPACE.tpl`, `${functionAppPath}/WORKSPACE`, {functionAppName: sanitize(functionAppName)});

// create the root BUILD.bazel file
copyTemplate(`init/functions/BUILD.root.bazel.tpl`, `${functionAppPath}/BUILD.bazel`);

// create the BUILD.bazel file for the function
copyTemplate(`init/functions/BUILD.bazel.tpl`, `${functionAppPath}/${functionHttpName}/BUILD.bazel`, {functionHttpName: sanitize(functionHttpName)});

// update function.json to use Bazel's ${bazel-bin} file
updateFile({
filepath: `${functionAppPath}/${functionHttpName}/function.json`,
replace: `../bazel-bin/${functionHttpName}/index.js`,
search: `../dist/${functionHttpName}/index.js`,
});

updateFile({
filepath: `${functionAppPath}/${functionHttpName}/index.ts`,
replace: `../bazel-bin/${functionHttpName}/index.js`,
search: `.body: "Hello from Bazel"`,
});

updateFile({
filepath: `${functionAppPath}/package.json`,
replace: `"build": "bazel build //..."`,
search: `"build": "tsc"`,
});

updateFile({
filepath: `${functionAppPath}/package.json`,
replace: `"watch": "ibazel build //..."`,
search: `"watch": "tsc --w"`,
});

updateFile({
filepath: `${functionAppPath}/.funcignore`,
replace: `
## Bazel ignored files
node_modules/@bazel/*
BUILD.bazel
# ignore all bazel output folder except the bazel-bin folder
# where the transpiled code lives
bazel-*
!bazel-bin
`
});
}

return true;
};
6 changes: 3 additions & 3 deletions src/features/hosting/index.ts
Expand Up @@ -22,15 +22,15 @@ module.exports = async function() {

if (overrideHtml || typeof overrideHtml === "undefined") {
// copy index.html
copyTemplate(`init/index.html`, `${folder}/index.html`);
copyTemplate(`init/hosting/index.html.tpl`, `${folder}/index.html`);
}
if (override404 || typeof override404 === "undefined") {
// copy 404.html
copyTemplate(`init/404.html`, `${folder}/404.html`);
copyTemplate(`init/hosting/404.html.tpl`, `${folder}/404.html`);
}
if (overrideError || typeof overrideError === "undefined") {
// copy errro.html
copyTemplate(`init/error.html`, `${folder}/error.html`);
copyTemplate(`init/hosting/error.html.tpl`, `${folder}/error.html`);
}

const storage: AzureStorage = Config.get("storage");
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Expand Up @@ -47,6 +47,7 @@ console.log(prettyFont.string);
.option("-t, --token", "generate a Storage token into a .env file", false)
.option("-j, --just <services>", "setup or deploy only the selected services (e.g. --just functions,hosting)", false)
.option("--yolo", "enable all modes and all services", false)
.option("--use <builder>", "use a specific build system (e.g. tsc,bazel)", 'tsc')
.parse(process.argv);

// set confiuration
Expand Down Expand Up @@ -80,6 +81,9 @@ console.log(prettyFont.string);
if (program.token) {
process.env.HEXA_STORAGE_GENERATE_TOKEN = "1";
}
if (program.use === 'bazel') {
process.env.HEXA_USE_BAZEL = "1";
}

// use process.argv not program.argv
const commandName = process.argv[2];
Expand Down
9 changes: 9 additions & 0 deletions src/templates/init/functions/BUILD.bazel.tpl
@@ -0,0 +1,9 @@
load("@npm_bazel_typescript//:index.bzl", "ts_library")

package(default_visibility = ["//visibility:public"])

ts_library(
name = "{{functionHttpName}}",
srcs = ["index.ts"],
deps = ["@npm//@azure/functions"]
)
1 change: 1 addition & 0 deletions src/templates/init/functions/BUILD.root.bazel.tpl
@@ -0,0 +1 @@
exports_files(["tsconfig.json"], visibility = ["//:__subpackages__"])
24 changes: 24 additions & 0 deletions src/templates/init/functions/WORKSPACE.tpl
@@ -0,0 +1,24 @@
workspace(
name = "{{functionAppName}}",
managed_directories = {"@npm": ["node_modules"]},
)

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "1447312c8570e8916da0f5f415186e7098cdd4ce48e04b8e864f793c766959c3",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.38.2/rules_nodejs-0.38.2.tar.gz"],
)

load("@build_bazel_rules_nodejs//:index.bzl", "npm_install")
npm_install(
name = "npm",
package_json = "//:package.json",
package_lock_json = "//:package-lock.json",
)

load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
install_bazel_dependencies()

load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
ts_setup_workspace()
9 changes: 9 additions & 0 deletions src/templates/init/functions/index.ts.tpl
@@ -0,0 +1,9 @@
import { AzureFunction, Context, HttpRequest } from "@azure/functions";

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
context.res = {
body: "Hello {{functionHttpName}}"
};
};

export default httpTrigger;
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 1033470

Please sign in to comment.