From 72c4b4d73a0c5a3d0ce8ec9880bab7ae808e756c Mon Sep 17 00:00:00 2001 From: Jon Edvald Date: Thu, 14 Jun 2018 23:22:14 +0200 Subject: [PATCH] feat: generate homebrew formula on publish Note: This will not work until we cut another release, since the formula relies on a fix in a prior commit to work properly. --- .gitignore | 3 + README.md | 60 ++-------------- docs/guides/minikube.md | 8 ++- docs/introduction/getting-started.md | 95 ++++++++++++++----------- gulpfile.ts | 74 ++++++++++++++++++- package.json | 1 + support/homebrew-formula.rb | 22 ++++++ {static => support}/license-header.txt | 0 {static => support}/license-syntax.yaml | 0 support/support-util.ts | 24 +++++++ 10 files changed, 187 insertions(+), 100 deletions(-) create mode 100644 support/homebrew-formula.rb rename {static => support}/license-header.txt (100%) rename {static => support}/license-syntax.yaml (100%) create mode 100644 support/support-util.ts diff --git a/.gitignore b/.gitignore index d61ff652a6..2dd52cf78d 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,9 @@ src/**/*.js src/**/*.map src/**/*.d.ts static/bin/garden.js +support/**/*.js +support/**/*.map +support/**/*.d.ts test/**/*.js test/**/*.map *.tgz diff --git a/README.md b/README.md index 1510ef55d6..e1be6afc4c 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,7 @@ All that said, Garden can already be highly useful if the following applies to y * **You keep all your services in a single repository** _(multi-repo support coming soon!)._ * **You really don't want to spend your precious hours building your own developer tooling!** -If that sounds right for you, please give it a go and don't hesitate to report issues or come right over -to our [Gitter](https://gitter.im/garden-io/Lobby#) for a chat! +If that sounds right for you, please give it a go and don't hesitate to report issues. ## Features @@ -41,60 +40,15 @@ Garden is also designed to be pluggable and modular, with Kubernetes being just Over time we will add native support for a variety of platforms, including AWS (Lambda, ECS, Fargate and more), GCP, Heroku, OpenFaaS... and the list will continue growing. +Please read the [Motivation](https://docs.garden.io/introduction/motivation) section in our documentation +for a brief discussion on why we're building Garden. -## Setup -### Dependencies +## Usage -You need to set up the following on your local machine to use garden: -* Node.js >= 8.x -* Docker -* Git -* rsync -* [Watchman](https://facebook.github.io/watchman/docs/install.html) -* Local installation of Kubernetes - -To install Kubernetes, we recommend [Docker for Mac/Windows (edge version)](https://docs.docker.com/engine/installation/) -on Mac/Windows, and you can use [Minikube](https://github.com/kubernetes/minikube) on any supported platform. -You'll just need to configure a [kubectl context](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#kubectl-context-and-configuration) -to point to your local instance. - - - -On Mac, we recommend using Homebrew on Mac to install everything except Docker, but use whatever works for you! - -Note that you need to install the _edge version_ of Docker for Mac/Windows in -order to enable Kubernetes support. Once installed, you need to open the -Docker preferences, go to the Kubernetes section, tick `Enable Kubernetes` and -save. For more information, see [here for Mac](https://docs.docker.com/docker-for-mac/kubernetes/) -or [here for Windows](https://docs.docker.com/docker-for-windows/kubernetes/). - -### Installation - -Once you have the above dependencies set up, simply run - - npm install -g garden-cli - -Then go on to our [getting started guide](docs/introduction/getting-started.md), or try out the simple hello-world -example below to kick things off. - - -## Examples - -The `examples/` directory contains usage examples for the framework. You might want to start with -the `hello-world` example project, to see an example of basic build, deployment and interaction -flows. Take a look around the projects, taking special note of the `garden.yml` files - -it's pretty straightforward, we promise :) - -To spin it up, `cd` to any of the directories under `examples/` and run: - - garden deploy - -Once you've deployed the `hello-world` project, you can try querying the `/hello` endpoint: - - garden call hello-container/hello - -For more details, please head over to our [getting started guide](docs/introduction/getting-started.md). +Head over to our [Getting Started guide](https://docs.garden.io/introduction/getting-started) for details +on how to set up and use Garden, or look through our [Simple Project](https://docs.garden.io/examples/simple-project) +guide to get a quick sense of how it works. ## Contributing diff --git a/docs/guides/minikube.md b/docs/guides/minikube.md index cf6176cd64..1a2da3f5c0 100644 --- a/docs/guides/minikube.md +++ b/docs/guides/minikube.md @@ -6,9 +6,13 @@ Garden can be used with [Minikube](https://github.com/kubernetes/minikube) on su For Minikube installation instructions, please see the [official guide](https://github.com/kubernetes/minikube#installation). + You'll likely also need to install a driver to run the Minikube VM, please follow the -[instructions here](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver) -and note the name of the driver. +[instructions here](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md) +and note the name of the driver you use. The driver you choose will likely vary depending on your +OS/platform. We recommend [hyperkit](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver) +for macOS and [kvm2](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver) on most Linux +platforms. Once Minikube and the appropriate driver for your OS is installed, you can start it by running: diff --git a/docs/introduction/getting-started.md b/docs/introduction/getting-started.md index 5731e7a7e9..19c4e5b560 100644 --- a/docs/introduction/getting-started.md +++ b/docs/introduction/getting-started.md @@ -1,73 +1,82 @@ # Getting Started -This guide will walk you through setting up the Garden framework. +This guide will walk you through setting up the Garden framework. -## Install dependencies -You need the following dependencies on your local machine to use Garden: -* Node.js >= 8.x -* [Docker](https://docs.docker.com/) -* Git -* rsync -* [Watchman](https://facebook.github.io/watchman/docs/install.html) -* [Helm](https://github.com/kubernetes/helm) -* Local installation of Kubernetes +## Installation -### OSX +### macOS -#### Step 1: Docker and local Kubernetes -To install Docker and Kubernetes, we recommend [Docker for Mac (edge version)](https://docs.docker.com/engine/installation/). +For Mac, we recommend the following steps to install Garden. You can also follow the manual installation +steps below if you prefer. -_Note: you need to install the _edge version_ of Docker for Mac in -order to enable Kubernetes support._ +#### Step 1: Install homebrew -Once installed, open the -Docker preferences, go to the Kubernetes section, tick `Enable Kubernetes` and -save. +If you haven't already set up homebrew, please follow [their instructions](https://brew.sh/) to set it up. -Alternatively, you can use [Minikube](../guides/minikube.md) on any supported platform. +#### Step 2: Docker and local Kubernetes +To install Docker, Kubernetes and kubectl, we strongly recommend Docker for Mac (edge version). -#### Step 2: Other dependencies -For installing the other dependencies, we recommend using Homebrew. +_Note: you need to install the **edge version** of Docker for Mac in +order to enable Kubernetes support._ -### Linux +Once installed, open the Docker for Mac preferences, go to the Kubernetes section, +tick `Enable Kubernetes` and save. Please refer to their +[installation guide](https://docs.docker.com/engine/installation/) for details. -#### Step 1: Docker -To install Docker, please follow the instructions in the [official documentation](https://docs.docker.com/install/linux/docker-ce/ubuntu/). +Alternatively, you can use Minikube. We generally find it less stable and more hassle to +configure and use, but we do fully support it on Mac if you have it running. Please look at our +[Minikube guide](../guides/minikube.md) for details. -#### Step 2: Local Kubernetes -For local Kubernetes, you can use Minikube. Please see the -[official installation guide](https://github.com/kubernetes/minikube#installation) for instructions. - -You'll likely also need to install a driver to run the Minikube VM. Please follow the -[instructions here](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver), -and note the name of the driver. - -Once Minikube and the appropriate driver for your OS is installed, you can start it by running: +#### Step 3: Install `garden-cli` +We have a Homebrew tap and package that you can use to easily install `garden-cli` and all dependencies: ```sh -minikube start --vm-driver= # e.g. hyperkit on macOS +brew tap garden-io/garden +brew install garden-cli ``` -Finally, you will need to configure a [kubectl context](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#kubectl-context-and-configuration) -to point to your local instance. +To later upgrade to the newest version, simply run `brew update` and then `brew upgrade garden-cli` +(or `brew upgrade` to upgrade all your Homebrew packages). + + +### Linux / manual installation - +You need the following dependencies on your local machine to use Garden: + +* Node.js >= 8.x +* [Docker](https://docs.docker.com/) +* Git +* rsync +* [Watchman](https://facebook.github.io/watchman/docs/install.html) +* [Helm](https://github.com/kubernetes/helm) +* Local installation of Kubernetes and kubectl + +#### Step 1: Docker +To install Docker, please follow the instructions in the [official documentation](https://docs.docker.com/install/). -Check out our [Minikube guide](../guides/minikube.md) for further information on using Garden with Minikube. +#### Step 2: Local Kubernetes +For local Kubernetes, you can use [Minikube](https://github.com/kubernetes/minikube). Please see our +[Minikube guide](../guides/minikube.md) for instructions. -#### Step 3: Other dependencies -Other dependencies can be installed with the package manager of your choice +#### Step 3: Install other dependencies -## Install the Garden CLI +Use your preferred method or package manager to install `node` (version 8.x or higher), `git`, `rsync`, +[Watchman](https://facebook.github.io/watchman/docs/install.html) and +[Helm](https://github.com/kubernetes/helm). -Once you have the dependencies set up, simply run: +#### Step 4: Install `garden-cli` + +Once you have the dependencies set up, install the Garden CLI via `npm`: ```sh npm install -g garden-cli ``` +To later upgrade to the newest version, run `npm install -g -U garden-cli`. + + ## Using the CLI With the CLI installed, we can now try out a few commands using the [hello-world](https://github.com/garden-io/garden-examples/tree/master/hello-world) project from our Github [examples repository](https://github.com/garden-io/garden-examples). The example consists of a container service that runs an [Express](http://expressjs.com/) app, a serverless function, and an npm library package. @@ -99,4 +108,4 @@ And that's it! The services are now running on the Garden framework. You can see $ garden call hello-container/hello ``` -Check out our [Commands guide](../guides/commands.md) for other features like auto-reload, streaming service logs, running tests and lots more, or see how a Garden project is configured from scratch in our [Simple Project](../guides/simple-project.md) guide. \ No newline at end of file +Check out our [Commands guide](../guides/commands.md) for other features like auto-reload, streaming service logs, running tests and lots more, or see how a Garden project is configured from scratch in our [Simple Project](../guides/simple-project.md) guide. diff --git a/gulpfile.ts b/gulpfile.ts index 3e5b0d9539..3c8ff22273 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -2,18 +2,31 @@ import { spawn as _spawn, ChildProcess, } from "child_process" -import { writeFileSync } from "fs" +import { + writeFileSync, +} from "fs" +import { + ensureDir, + pathExists, + readFile, + remove, + writeFile, +} from "fs-extra" +import * as handlebars from "handlebars" import { join, relative, } from "path" import { generateDocs } from "./src/docs/generate" +import { getUrlChecksum } from "./support/support-util" +import execa = require("execa") const gulp = require("gulp") const cached = require("gulp-cached") const checkLicense = require("gulp-license-check") // const debug = require("gulp-debug") // const exec = require("gulp-exec") +const packageJson = require("./package.json") const pegjs = require("gulp-pegjs") const sourcemaps = require("gulp-sourcemaps") const gulpTslint = require("gulp-tslint") @@ -29,7 +42,8 @@ const tsSources = "src/**/*.ts" const testTsSources = "test/**/*.ts" const pegjsSources = "src/*.pegjs" -const licenseHeaderPath = "static/license-header.txt" +const tmpDir = join(__dirname, "tmp") +const licenseHeaderPath = "support/license-header.txt" const destDir = "build" @@ -180,6 +194,62 @@ gulp.task("tslint-tests", () => .pipe(gulpTslint.report()), ) +/** + * Updates our Homebrew tap with the current released package version. Should be run after relasing to NPM. + */ +gulp.task("update-brew", async () => { + // clone the homebrew-garden tap repo + const brewRepoDir = join(tmpDir, "homebrew-garden") + if (await pathExists(brewRepoDir)) { + await remove(brewRepoDir) + } + await execa("git", ["clone", "git@github.com:garden-io/homebrew-garden.git"], { cwd: tmpDir }) + + // read the existing formula + const formulaDir = join(brewRepoDir, "Formula") + await ensureDir(formulaDir) + const formulaPath = join(formulaDir, "garden-cli.rb") + const existingFormula = await pathExists(formulaPath) ? (await readFile(formulaPath)).toString() : "" + + // compile the formula handlebars template + const templatePath = join(__dirname, "support", "homebrew-formula.rb") + const templateString = (await readFile(templatePath)).toString() + const template = handlebars.compile(templateString) + + // get the metadata from npm + const metadataJson = await execa.stdout("npm", ["view", "garden-cli", "--json"]) + const metadata = JSON.parse(metadataJson) + const version = metadata["dist-tags"].latest + const tarballUrl = metadata.dist.tarball + const sha256 = metadata.dist.shasum.length === 64 ? metadata.dist.shasum : await getUrlChecksum(tarballUrl, "sha256") + + const formula = template({ + version, + homepage: metadata.homepage || packageJson.homepage, + description: metadata.description, + tarballUrl, + sha256, + }) + + if (formula === existingFormula) { + console.log("No changes to formula") + } else { + await writeFile(formulaPath, formula) + + // check if the formula is OK + await execa("brew", ["audit", formulaPath]) + + for (const args of [ + ["add", formulaPath], + ["commit", "-m", `update to ${version}`], + ["tag", version], + ["push", "--tags"], + ]) { + await execa("git", args, { cwd: brewRepoDir }) + } + } +}) + gulp.task("watch-code", () => { const verify = (path) => { try { diff --git a/package.json b/package.json index 27f5cfcd06..abab9bf2f2 100644 --- a/package.json +++ b/package.json @@ -131,6 +131,7 @@ "generate-docs": "gulp generate-docs", "integ": "./test/integ/run", "lint": "gulp lint", + "postpublish": "gulp update-brew", "prepare": "npm run snyk-protect", "prepublishOnly": "npm run dist", "preversion": "npm test", diff --git a/support/homebrew-formula.rb b/support/homebrew-formula.rb new file mode 100644 index 0000000000..7acecd598c --- /dev/null +++ b/support/homebrew-formula.rb @@ -0,0 +1,22 @@ +require "language/node" + +class GardenCli < Formula + desc "{{description}}" + homepage "{{{homepage}}}" + url "{{{tarballUrl}}}" + sha256 "{{sha256}}" + + depends_on "node" + depends_on "rsync" + depends_on "watchman" + depends_on "python" => :build + + def install + system "npm", "install", *Language::Node.std_npm_install_args(libexec) + bin.install_symlink Dir["#{libexec}/bin/*"] + end + + test do + # add a meaningful test here + end +end diff --git a/static/license-header.txt b/support/license-header.txt similarity index 100% rename from static/license-header.txt rename to support/license-header.txt diff --git a/static/license-syntax.yaml b/support/license-syntax.yaml similarity index 100% rename from static/license-syntax.yaml rename to support/license-syntax.yaml diff --git a/support/support-util.ts b/support/support-util.ts new file mode 100644 index 0000000000..f0ad308893 --- /dev/null +++ b/support/support-util.ts @@ -0,0 +1,24 @@ +import Axios from "axios" +import { createHash } from "crypto" + +export async function getUrlChecksum(url: string, algorithm = "sha256") { + const response = await Axios({ + method: "GET", + url, + responseType: "stream", + }) + + return new Promise((resolve, reject) => { + const hash = createHash(algorithm) + + response.data.on("data", (chunk) => { + hash.update(chunk) + }) + + response.data.on("end", () => { + resolve(hash.digest("hex")) + }) + + response.data.on("error", reject) + }) +}