From af564e4ff77013ee742ee74b55205afd07e22872 Mon Sep 17 00:00:00 2001 From: Robert Lin Date: Sat, 14 Apr 2018 14:46:43 -0700 Subject: [PATCH 1/4] Migrate dev tips to CONTRIBUTING, add CODEOWNERS --- .github/CODEOWNERS | 1 + .github/CONTRIBUTING.md | 159 ++++++++++++++++++++++++++++++++++++++++ README.md | 151 +++----------------------------------- 3 files changed, 170 insertions(+), 141 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/CONTRIBUTING.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..f5189a89 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @bobheadxi diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..74cec18e --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,159 @@ +# Contributing + +This document outlines key considerations and tips for anyone contributing to Inertia. + +- [Opening an Issue](#opening-an-issue) +- [Submitting a Pull Request](#submitting-a-pull-request) +- [Development Tips](#development-tips) + +------ + +# Opening an Issue + +Please do a quick search of past issues before opening a ticket. If working on a ticket, please assign it to yourself or leave a comment saying you are working on it. If you have decide to stop working on a ticket before it gets resolved, please un-assign yourself. + +# Submitting a Pull Request + +All pull requests should be connected to one or more issues. Please try to fill out the pull request template to the best of your ability and use a clear, descriptive title. + +At the very least, all pull requests need to pass our Travis builds and receive an approval from a reviewer. Please include tests whenever possible. + +# Development Tips + +This section outlines the various tools available to help you get started developing Inertia. Run `make ls` to list all the Makefile shortcuts available. + +If you would like to contribute, feel free to comment on an issue or make one and open up a pull request! + +## Setup + +First, [install Go](https://golang.org/doc/install#install) and grab Inertia's source code: + +```bash +$> go get -u github.com/ubclaunchpad/inertia +``` + +We use [dep](https://github.com/golang/dep) for managing Golang dependencies, and [npm](https://www.npmjs.com) to manage dependencies for Inertia's React web app. Make sure both are installed before running the following commands. + +```bash +$> dep ensure # Inertia CLI and daemon dependencies +$> make web-deps # Inertia Web dependencies +$> make RELEASE=test # installs Inertia build tagged as "test" +$> inertia --version # check what version you have installed +``` + +A build tagged as `test` allows you to use `make testdaemon` for local development. See the next section for more details. + +Alternatively, you can manually edit `.inertia.toml` to use your desired daemon version - see the [Release Streams](#release-streams) documentation for more details. + +Note that if you install Inertia using these commands or any variation of `go install`, you may have to remove the binary using `go clean -i github.com/ubclaunchpad/inertia` to go back to using an Inertia CLI installed using Homebrew. To go back to a `go install`ed version of Inertia, you need to run `brew uninstall inertia`. + +## Repository Structure + +The codebase for the CLI is in the root directory. This code should only include the user interface - all client-based logic and functionality should go into the client. + +### Client + +The Inertia client manages all clientside functionality. The client codebase is in `client/`. + +### Daemon + +The Inertia daemon manages all serverside functionality. The daemon codebase is in `daemon/inertia`. + +### Inertia Web + +The Inertia Web application provides a web interface to manage an Inertia deployment. The web application codebase is in `daemon/web`. + +## Testing and Locally Deploying + +You will need Docker installed and running to run the Inertia test suite, which includes a number of integration tests. + +```bash +$> make test-all # test against ubuntu:latest +$> make test-all VPS_OS=ubuntu VERSION=14.04 # test against ubuntu:14.04 +``` + +You can also manually start a container that sets up a mock VPS for testing: + +```bash +$> make testenv VPS_OS=ubuntu VERSION=16.04 +# This defaults to ubuntu:lastest without args. +# Note the location of the key that is printed and use that when +# adding your local remote. +``` + +You can [SSH into this testvps container](https://bobheadxi.github.io/dockerception/#ssh-services-in-docker) and otherwise treat it just as you would treat a real VPS: + +```bash +$> cd /path/to/my/dockercompose/project +$> inertia init +$> inertia remote add local +# PEM file: inertia/test/keys/id_rsa, User: 'root', Address: 0.0.0.0 +$> inertia local init +$> inertia local status +``` + +The above steps will pull and use a daemon image from Docker Hub based on the version in your `.inertia.toml`. + +### Daemon + +To use a daemon compiled from source, set your Inertia version in `.inertia.toml` to `test` and run: + +```bash +$> make testdaemon +$> inertia local init +``` + +This will build a daemon image and `scp` it over to the test VPS, and use that image for the daemon when setting up `testvps` using `inertia local init` + +If you run into this error when deploying onto the `testvps`: + +```bash +docker: Error response from daemon: error creating aufs mount to /var/lib/docker/aufs/mnt/fed036790dfcc73da5f7c74a7264e617a2889ccf06f61dc4d426cf606de2f374-init: invalid argument. +``` + +You probably need to go into your Docker settings and add this line to the Docker daemon configuration file: + +```js +{ + ... + "storage-driver" : "aufs" +} +``` + +This sneaky configuration file can be found under `Docker -> Preferences -> Daemon -> Advanced -> Edit File`. + +### Web App + +Inertia Web is a React application. To run a local instance of Inertia Web: + +```bash +$> make web-run +``` + +Make sure you have a local daemon set up for this web app to work - see the previous section for more details. + +## Compiling Bash Scripts + +To bootstrap servers, some bash scripting is often involved, but we'd like to avoid shipping bash scripts with our go binary. So we use [go-bindata](https://github.com/jteeuwen/go-bindata) to compile shell scripts into our go executables. + +```bash +$> go get -u github.com/jteeuwen/go-bindata/... +``` + +If you make changes to the bootstrapping shell scripts in `client/bootstrap/`, convert them to `Assets` by running: + +```bash +$> make bootstrap +``` + +Then use your asset! + +```go +shellScriptData, err := Asset("cmd/bootstrap/myshellscript.sh") +if err != nil { + log.Fatal("No asset with that name") +} + +// Optionally run shell script over SSH. +result, _ := remote.RunSSHCommand(string(shellScriptData)) +``` diff --git a/README.md b/README.md index a2aba80c..02e88936 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,15 @@

Built Status + alt="Build Status" /> Clean code + + @@ -25,23 +27,22 @@ Inertia is a cross-platform command line tool that simplifies setup and management of automated project deployment on any virtual private server. It aims to provide the ease and flexibility of services like Heroku without the complexity of Kubernetes while still giving users full control over their projects. -- [Usage](#package-usage) +- [Getting Started](#package-getting-started) - [Setup](#setup) - [Continuous Deployment](#continuous-deployment) - [Deployment Management](#deployment-management) - [Release Streams](#release-streams) - [Motivation and Design](#bulb-motivation-and-design) -- [Development](#construction-development) -# :package: Usage +# :package: Getting Started -All you need to get started is a docker-compose project, the Inertia CLI, and access to a virtual private server. To install the CLI using [Homebrew](https://brew.sh): +All you need to get started is a [compatible project](https://github.com/ubclaunchpad/inertia/wiki/Project-Compatibility), the Inertia CLI, and access to a virtual private server. The CLI can be installed using [Homebrew](https://brew.sh): ```bash $> brew install ubclaunchpad/tap/inertia ``` -For other platforms, you can also [download the appropriate binary from the Releases page](https://github.com/ubclaunchpad/inertia/releases) or [install Inertia from source](#installing-from-source). +For other platforms, you can [download the appropriate binary from the Releases page](https://github.com/ubclaunchpad/inertia/releases). ## Setup @@ -117,7 +118,9 @@ Add some bling to your Inertia-deployed project :sunglasses: # :bulb: Motivation and Design -At [UBC Launch Pad](http://www.ubclaunchpad.com), we are frequently changing hosting providers based on available funding and sponsorship. Inertia is a project to develop an in-house continuous deployment system to make deploying applications simple and painless, regardless of the hosting provider. +[UBC Launch Pad](http://www.ubclaunchpad.com) is a software engineering club at the University of British Columbia that aims to provide students with a community where they can work together to build a all sorts of cool projects, ranging from mobile apps and web services to cryptocurrencies. + +Many of our projects rely on hosting providers for deployment. We are frequently changing hosting providers based on available funding and sponsorship. Inertia is a project to develop an in-house deployment system to make setting up continuously deployed applications simple and painless, regardless of the hosting provider. The primary design goals of Inertia are to: @@ -136,137 +139,3 @@ The deployment daemon runs persistently in the background on the server, receivi

Inertia is set up serverside by executing a script over SSH that installs Docker and starts an Inertia daemon image with [access to the host Docker socket](https://bobheadxi.github.io/dockerception/#docker-in-docker). This Docker-in-Docker configuration gives the daemon the ability to start up other containers *alongside* it, rather than *within* it, as required. Once the daemon is set up, we avoid using further SSH commands and execute Docker commands through Docker's Golang API. Instead of installing the docker-compose toolset, we [use a docker-compose image](https://bobheadxi.github.io/dockerception/#docker-compose-in-docker) to build and deploy user projects. - -# :construction: Development - -This section outlines the various tools available to help you get started developing Inertia. Run `make ls` to list all the Makefile shortcuts available. - -If you would like to contribute, feel free to comment on an issue or make one and open up a pull request! - -## Installing from Source - -First, [install Go](https://golang.org/doc/install#install) and grab Inertia's source code: - -```bash -$> go get -u github.com/ubclaunchpad/inertia -``` - -We use [dep](https://github.com/golang/dep) for managing Golang dependencies, and [npm](https://www.npmjs.com) to manage dependencies for Inertia's React web app. Make sure both are installed before running the following commands. - -```bash -$> dep ensure # Inertia CLI and daemon dependencies -$> make web-deps # Inertia Web dependencies -``` - -For usage, it is highly recommended that you use a [tagged build](https://github.com/ubclaunchpad/inertia/releases) to ensure compatibility between the CLI and your Inertia daemon. - -```bash -$> git checkout $VERSION -$> make inertia-tagged # installs a tagged version of Inertia -$> inertia --version # check what version you have installed -``` - -Alternatively, you can manually edit `.inertia.toml` to use your desired daemon version - see the [Release Streams](#release-streams) documentation for more details. - -Note that if you install Inertia using these commands or any variation of `go install`, you may have to remove the binary using `go clean -i github.com/ubclaunchpad/inertia` to go back to using an Inertia CLI installed using Homebrew. To go back to a `go install`ed version of Inertia, you need to run `brew uninstall inertia`. - -For development, you should install a build tagged as `test` so that you can make use `make testdaemon` for local development. See the next section for more details. - -```bash -$> make RELEASE=test # installs current Inertia build and mark as "test" -``` - -## Testing and Locally Deploying - -You will need Docker installed and running to run the Inertia test suite, which includes a number of integration tests. - -```bash -$> make test-all # test against ubuntu:latest -$> make test-all VPS_OS=ubuntu VERSION=14.04 # test against ubuntu:14.04 -``` - -You can also manually start a container that sets up a mock VPS for testing: - -```bash -$> make testenv VPS_OS=ubuntu VERSION=16.04 -# This defaults to ubuntu:lastest without args. -# Note the location of the key that is printed and use that when -# adding your local remote. -``` - -You can [SSH into this testvps container](https://bobheadxi.github.io/dockerception/#ssh-services-in-docker) and otherwise treat it just as you would treat a real VPS: - -```bash -$> cd /path/to/my/dockercompose/project -$> inertia init -$> inertia remote add local -# PEM file: inertia/test/keys/id_rsa, User: 'root', Address: 0.0.0.0 -$> inertia local init -$> inertia local status -``` - -The above steps will pull and use a daemon image from Docker Hub based on the version in your `.inertia.toml`. - -### Daemon - -To use a daemon compiled from source, set your Inertia version in `.inertia.toml` to `test` and run: - -```bash -$> make testdaemon -$> inertia local init -``` - -This will build a daemon image and `scp` it over to the test VPS, and use that image for the daemon when setting up `testvps` using `inertia local init` - -If you run into this error when deploying onto the `testvps`: - -```bash -docker: Error response from daemon: error creating aufs mount to /var/lib/docker/aufs/mnt/fed036790dfcc73da5f7c74a7264e617a2889ccf06f61dc4d426cf606de2f374-init: invalid argument. -``` - -You probably need to go into your Docker settings and add this line to the Docker daemon configuration file: - -```js -{ - ... - "storage-driver" : "aufs" -} -``` - -This sneaky configuration file can be found under `Docker -> Preferences -> Daemon -> Advanced -> Edit File`. - -### Web App - -Inertia Web is a React application. To run a local instance of Inertia Web: - -```bash -$> make web-run -``` - -Make sure you have a local daemon set up for this web app to work - see the previous section for more details. - -## Compiling Bash Scripts - -To bootstrap servers, some bash scripting is often involved, but we'd like to avoid shipping bash scripts with our go binary. So we use [go-bindata](https://github.com/jteeuwen/go-bindata) to compile shell scripts into our go executables. - -```bash -$> go get -u github.com/jteeuwen/go-bindata/... -``` - -If you make changes to the bootstrapping shell scripts in `client/bootstrap/`, convert them to `Assets` by running: - -```bash -$> make bootstrap -``` - -Then use your asset! - -```go -shellScriptData, err := Asset("cmd/bootstrap/myshellscript.sh") -if err != nil { - log.Fatal("No asset with that name") -} - -// Optionally run shell script over SSH. -result, _ := remote.RunSSHCommand(string(shellScriptData)) -``` From f2f82713ce00ac45e6a5571b3f294d5d8db97196 Mon Sep 17 00:00:00 2001 From: Robert Lin Date: Sat, 14 Apr 2018 16:10:27 -0700 Subject: [PATCH 2/4] Add Features section --- .static/inertia-init.png | Bin 0 -> 40948 bytes README.md | 24 ++++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .static/inertia-init.png diff --git a/.static/inertia-init.png b/.static/inertia-init.png new file mode 100644 index 0000000000000000000000000000000000000000..33d02ecbe38a8f62144da1b73222630c136c76f1 GIT binary patch literal 40948 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 - + + + @@ -25,7 +27,25 @@ ---------------- -Inertia is a cross-platform command line tool that simplifies setup and management of automated project deployment on any virtual private server. It aims to provide the ease and flexibility of services like Heroku without the complexity of Kubernetes while still giving users full control over their projects. +Inertia is a cross-platform command line tool that enables effortless setup and management of continuous, automated deployment on any virtual private server. + +

+ +

+ +| | Main Features | +----|----------------- +🚀 | Simple setup from your computer without ever having to manually SSH into your remote +🍰 | Use any remote virtual private server platform you want +⚒ | Deploy a wide range of supported projects (including docker-compose and Heroku buildpacks) +🚄 | Have your project automatically updated as soon as you `git push` +🛂 | Start up and shut down your deployment with ease +📚 | Monitor your deployed application's logs straight from your command line +🏷 | Configure deployment to your liking with branch settings and more + +Maintained with :heart: by [UBC Launch Pad](https://www.ubclaunchpad.com/) + +---------------- - [Getting Started](#package-getting-started) - [Setup](#setup) From de928fbb54e806af592339652632f6f92cb400be Mon Sep 17 00:00:00 2001 From: Robert Lin Date: Sat, 14 Apr 2018 16:58:40 -0700 Subject: [PATCH 3/4] Fix integration test script --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 744edb65..15e89a47 100644 --- a/Makefile +++ b/Makefile @@ -43,12 +43,12 @@ test-all: test-integration: make testenv VPS_OS=$(VPS_OS) VPS_VERSION=$(VPS_VERSION) make testdaemon - go test ./... -v -ldflags "-X main.Version=test" --cover + go test ./... -v -run 'Integration' -ldflags "-X main.Version=test" --cover # Run integration tests verbosely without recreating test VPS test-integration-fast: make testdaemon - go test ./... -run -v Integration -ldflags "-X main.Version=test" --cover + go test ./... -v -run 'Integration' -ldflags "-X main.Version=test" --cover # Create test VPS testenv: From 517daf343519439d50a875adde3a8865678c34bb Mon Sep 17 00:00:00 2001 From: Robert Lin Date: Sat, 14 Apr 2018 17:48:23 -0700 Subject: [PATCH 4/4] Add contributing section --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 25298863..805a39cf 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ ---------------- -Inertia is a cross-platform command line tool that enables effortless setup and management of continuous, automated deployment on any virtual private server. +Inertia is a simple cross-platform command line application that enables effortless setup and management of continuous, automated deployment on any virtual private server. It is built and maintained with :heart: by [UBC Launch Pad](https://www.ubclaunchpad.com/).

@@ -36,15 +36,13 @@ Inertia is a cross-platform command line tool that enables effortless setup and | | Main Features | ----|----------------- 🚀 | Simple setup from your computer without ever having to manually SSH into your remote -🍰 | Use any remote virtual private server platform you want -⚒ | Deploy a wide range of supported projects (including docker-compose and Heroku buildpacks) +🍰 | Use any Linux-based remote virtual private server platform you want +⚒ | Deploy a wide range of supported project types (including docker-compose and Heroku buildpacks) 🚄 | Have your project automatically updated as soon as you `git push` 🛂 | Start up and shut down your deployment with ease 📚 | Monitor your deployed application's logs straight from your command line 🏷 | Configure deployment to your liking with branch settings and more -Maintained with :heart: by [UBC Launch Pad](https://www.ubclaunchpad.com/) - ---------------- - [Getting Started](#package-getting-started) @@ -53,6 +51,7 @@ Maintained with :heart: by [UBC Launch Pad](https://www.ubclaunchpad.com/) - [Deployment Management](#deployment-management) - [Release Streams](#release-streams) - [Motivation and Design](#bulb-motivation-and-design) +- [Contributing](#books-contributing) # :package: Getting Started @@ -138,9 +137,9 @@ Add some bling to your Inertia-deployed project :sunglasses: # :bulb: Motivation and Design -[UBC Launch Pad](http://www.ubclaunchpad.com) is a software engineering club at the University of British Columbia that aims to provide students with a community where they can work together to build a all sorts of cool projects, ranging from mobile apps and web services to cryptocurrencies. +[UBC Launch Pad](http://www.ubclaunchpad.com) is a student-run software engineering club at the University of British Columbia that aims to provide students with a community where they can work together to build a all sorts of cool projects, ranging from mobile apps and web services to cryptocurrencies and machine learning applications. -Many of our projects rely on hosting providers for deployment. We are frequently changing hosting providers based on available funding and sponsorship. Inertia is a project to develop an in-house deployment system to make setting up continuously deployed applications simple and painless, regardless of the hosting provider. +Many of our projects rely on hosting providers for deployment. Unfortunately we frequently change hosting providers based on available funding and sponsorship, meaning our projects often need to be redeployed. Inertia is a project to develop an in-house deployment system to make setting up continuously deployed applications simple and painless, regardless of the hosting provider. The primary design goals of Inertia are to: @@ -159,3 +158,7 @@ The deployment daemon runs persistently in the background on the server, receivi

Inertia is set up serverside by executing a script over SSH that installs Docker and starts an Inertia daemon image with [access to the host Docker socket](https://bobheadxi.github.io/dockerception/#docker-in-docker). This Docker-in-Docker configuration gives the daemon the ability to start up other containers *alongside* it, rather than *within* it, as required. Once the daemon is set up, we avoid using further SSH commands and execute Docker commands through Docker's Golang API. Instead of installing the docker-compose toolset, we [use a docker-compose image](https://bobheadxi.github.io/dockerception/#docker-compose-in-docker) to build and deploy user projects. + +# :books: Contributing + +Any contribution (pull requests, feedback, bug reports, ideas, etc.) is welcome! Please see our [contribution guide](https://github.com/ubclaunchpad/inertia/blob/master/.github/CONTRIBUTING.md) for more details and development tips.