Skip to content

Latest commit

 

History

History
267 lines (187 loc) · 10.1 KB

README.md

File metadata and controls

267 lines (187 loc) · 10.1 KB

DEPRECATED: As there's now a binary version, godev, I have stopped support/maintenance for this section of code. Feel free to dissect it for your own needs. The instructions for the binary version can be found here

Go Develop 🤓

A set of scripts/tools packaged in a Docker image to quickly get up-and-writing with Golang.

If you're looking for a binary, check out that version at this directory.

Scope of Work

  • ✅ Use Docker to provision an environment for a Golang 1.x application
  • ✅ Live-reload of application using go build
  • ✅ Live-updating of application's dependenices (go mod used here)
  • ✅ Live-reload of tests using go test
  • ✅ Statically link production binary using go build
  • ✅ Docker image building using the scratch image
  • ✅ Still be able to run things like go (mod|build|run|test) on the host system

System Requirements

For Windows auto-update does not work out of the box (because of #56). Use docker-windows-volume-watcher to activate it.

You don't need Go installed or a GOPATH for this 🥂

Usage

TL;DR

The quickest way to try this out is to copy the following into a Makefile in your target directory and run make init:

GOLANG_DEV_VERSION=latest

# initialises this directory - use once only
init:
	@$(MAKE) _dev ARG="init"
# builds the application - outputs an `app` binary
build:
	@$(MAKE) _dev ARG="build"
# runs tests in watch-mode
test: build
	@$(MAKE) _dev ARG="test"
# runs tests once
test.once: build
	@$(MAKE) _dev ARG="test -coverprofile c.out"
# runs the application on the host network
start: build
	@$(MAKE) _dev ARG="start" ARGS="${ARGS}"
# creates a shell in a fresh container generated from the image, usable for development on non-linux machines
shell:
	$(MAKE) _dev ARG="shell"
# retrieves the latest version we are at
version.get:
	@docker run -v "$(CURDIR):/app" zephinzer/vtscripts:latest get-latest -q
# bumps the version by 1: specify VERSION as "patch", "minor", or "major", to be specific about things
version.bump:
	@docker run -v "$(CURDIR):/app" zephinzer/vtscripts:latest iterate ${VERSION} -i
# base command to run other scripts (do not use alone)
_dev:
	@docker run \
    -it \
    --network host \
    -u $$(id -u) \
    -v "$(CURDIR)/.cache/pkg:/go/pkg" \
    -v "$(CURDIR):/go/src/app" \
    zephinzer/golang-dev:$(GOLANG_DEV_VERSION) ${ARG} ${ARGS}

Check out the documentation below on how to bundle your application into a scratch Docker image.

Getting Started With Just The golang-dev Image

If you already have a Makefile/don't want a Makefile (but why?), running the following in any directory should get you up and running:

docker run -it \
  -u ${UID} \
  -v "$(pwd)/.cache/pkg:/go/pkg" \
  -v "$(pwd):/go/src/app" \
  zephinzer/golang-dev:latest init;

The script should ask a series of questions which if you agree to all, will create a Git repository, add an appropriate .gitignore file, initialise go mod, and provision a Dockerfile you can use to build your own image.

Notes:

  • The -u parameter sets the guest user to use your host user ID so that new files aren't created as root, causing problems on your host machine when you attempt to delete them.
  • The mapping of the .cache directory allows for faster subsequent dependency processing by go mod.

Live-Reload, Live-Dependency-Update, Live-Testing Development

Assuming you've completed the above step, create a main.go if there isn't already one, and run the following to start development:

docker run -it \
  -u ${UID} \
  --network host \
  -v "$(pwd)/.cache/pkg:/go/pkg" \
  -v "$(pwd):/go/src/app" \
  zephinzer/golang-dev:latest start;

To start the tests, create a new terminal in the same directory and run:

docker run -it \
  -u ${UID} \
  --network host \
  -v "$(pwd)/.cache/pkg:/go/pkg" \
  -v "$(pwd):/go/src/app" \
  zephinzer/golang-dev:latest test;

Notes

  • Making changes to *.go will result in a live-reload
  • Add a new import will cause the script to start downloading the new dependency
  • Removing that import will simply cause the dependency to be removed - simple stuff
  • If you need a port open without using --network host, specify the flag -p "HOSTPORT":"CONTAINERPORT" in the docker run command
  • If a new file is created, you'll need to send an interrupt to the process and start it again to begin watching it. I have no idea how to automatically watch new files but if you do, please submit a pull request. Thanks in advance!

Building a Binary

Assuming you have a main.go, building a binary is as simple as running:

docker run -it \
  -u ${UID} \
  -v "$(pwd)/.cache/pkg:/go/pkg" \
  -v "$(pwd):/go/src/app" \
  zephinzer/golang-dev:latest build;

The binary will appear in your current directory and be named app.$GOOS.$GOARCH. It will be postfixd with a .exe if $GOOS specifies a Windows build.

Notes:

Building Into a Docker Image

If you denied the init script from creating a Dockerfile, you can run it again to get it. Otherwise, the Dockerfile script should be:

FROM zephinzer/golang-dev:latest as development
COPY . /go/src/app
ENTRYPOINT [ "start" ]
FROM development as build
RUN build
ENTRYPOINT [ "/go/src/app/app" ]
FROM scratch as production
COPY --from=build /go/src/app/app /
ENTRYPOINT [ "/app" ]

Copy the above and paste it in a file named Dockerfile in your root directory. After that, you can build your image by running:

docker build -t yourname/yourimage:yourtag .;

Advanced Usage

Usage in a docker-compose.yml

Add the following in your Docker Compose to use this as part of a Docker provisioned environment:

version: "3.5" # or anything you're using
services:
  # ...
  app:
    image: zephinzer/golang-dev:latest
    environment: # if needed
      PORT: "3000"
    ports: # if needed
      - "3000:3000"
    user: "${USER_ID}"
    entrypoint: ["start"]
    volumes:
      - "./:/go/src/app" # for mapping source files
      - "./.cache/pkg:/go/pkg" # for mapping go cache
    # ...
  # ...

Technical Footnotes

Why golang-dev Came About

  • Golang requirements. Go's infamous $GOPATH is a pain-in-the-filesystem. Developing via a Docker environment abstracts this away. Also, you no longer have to have Go installed on your system since managing different Go versions is another pain-in-the-filesystem.
  • Live-reload tooling. Realize works for applications but does not run tests. Same for Gin which seems . Only GoConvey does it well, but it uses a browser interface instead of a CLI. Go Convey also only outputs a PASS or FAIL. I wanted to see error logs on FAIL which it didn't provide me.
  • Auto-download dependencies. None of Realize, Gin and GoConvey automatically downloads dependencies either. While this is super useful, it also requires context of which package manager to use. This project enforces the use of go mod which accomodates previous package managers such as glide and go dep.

Where golang-dev Fits In

I use this for development of information-systems type of software - basically, CRUD services. It might work for your own development, it might not. Drop me a pull request if there's something you can and are willing to fix/add, drop me an issue otherwise and I'll see if I can get it done!


Development/Hacking

If you're interested in working on this, read on!

The contribution mechanism is roughly the same as other open-source projects:

  1. Fork this repository
  2. Make your changes on master
  3. Make a pull request

Code

The main logic of how this works is written as shell scripts in the /scripts directory.

The Dockerfile simply copies the /scripts in and adds it to the $PATH.

Testing

Tests are contained in the ./test directory but you can run it from the root using make test.

Building

To build the Docker image, run make build.

Versioning

To bump a patch version, run make version.bump.

To bump a minor versoin, run make version.bump VERSION=minor.

To bump a major versoin, run make version.bump VERSION=major.

Publishing

To publish the Docker image, run make publish.

This publishes two images - one with the version as recorded by the Git tags, another with the version of Golang, and a last one with the latest tag.

Other Things

Licensing

This project is licensed under the MIT license. See the LICENSE file for the full text.

All Relevant Links

Support/Work Hours

This is a side-project of mine meant to support my own development needs. I have a day job, so unless I have an urgent need while using this in my professional work, most of my code-level work on this repository will be done during weekends. Pull requests are supported throughout the week!(:

Thanks for understanding!

Projects Using This

Cheers 😎

Leave me a 🌟 or watch this repository to indicate your interest in my sustained development on this. It'll help me decide whether or not I should deprecate this once my own use case for this is over.