Initial commit
This commit is contained in:
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
bin/*
|
||||
21
.github/workflows/ci.yaml
vendored
Normal file
21
.github/workflows/ci.yaml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: Continuous Integration
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
name: CI
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Run linter
|
||||
run: make lint
|
||||
- name: Run unit tests
|
||||
run: make unit-test
|
||||
- name: Build Linux binary
|
||||
run: make PLATFORM=linux/amd64
|
||||
- name: Build Windows binary
|
||||
run: make PLATFORM=windows/amd64
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
bin/
|
||||
40
Dockerfile
Normal file
40
Dockerfile
Normal file
@@ -0,0 +1,40 @@
|
||||
# syntax = docker/dockerfile:1-experimental
|
||||
|
||||
FROM --platform=${BUILDPLATFORM} golang:1.14.3-alpine AS base
|
||||
WORKDIR /src
|
||||
ENV CGO_ENABLED=0
|
||||
COPY go.* .
|
||||
RUN go mod download
|
||||
|
||||
FROM base AS build
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /out/example .
|
||||
|
||||
FROM base AS unit-test
|
||||
RUN --mount=target=. \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
go test -v .
|
||||
|
||||
FROM golangci/golangci-lint:v1.27-alpine AS lint-base
|
||||
|
||||
FROM base AS lint
|
||||
RUN --mount=target=. \
|
||||
--mount=from=lint-base,src=/usr/bin/golangci-lint,target=/usr/bin/golangci-lint \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/root/.cache/golangci-lint \
|
||||
golangci-lint run --timeout 10m0s ./...
|
||||
|
||||
FROM scratch AS bin-unix
|
||||
COPY --from=build /out/example /
|
||||
|
||||
FROM bin-unix AS bin-linux
|
||||
FROM bin-unix AS bin-darwin
|
||||
|
||||
FROM scratch AS bin-windows
|
||||
COPY --from=build /out/example /example.exe
|
||||
|
||||
FROM bin-${TARGETOS} as bin
|
||||
|
||||
24
LICENSE
Normal file
24
LICENSE
Normal file
@@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
||||
18
Makefile
Normal file
18
Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
all: bin/example
|
||||
test: lint unit-test
|
||||
|
||||
PLATFORM=local
|
||||
|
||||
.PHONY: bin/example
|
||||
bin/example:
|
||||
@docker build . --target bin \
|
||||
--output bin/ \
|
||||
--platform ${PLATFORM}
|
||||
|
||||
.PHONY: unit-test
|
||||
unit-test:
|
||||
@docker build . --target unit-test
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@docker build . --target lint
|
||||
106
README.md
Normal file
106
README.md
Normal file
@@ -0,0 +1,106 @@
|
||||

|
||||
|
||||
Example Containerized Go Development Environment
|
||||
------------------------------------------------
|
||||
|
||||
This repository contains an example Go project with a containerized development
|
||||
environment. The example project is a simple CLI tool that echos back its
|
||||
inputs.
|
||||
|
||||
## Why should I containerize my development environment?
|
||||
|
||||
There are several advantages to containerizing your development environment:
|
||||
* You make explicit the tools and versions of tools required to develop your
|
||||
project
|
||||
* Your builds will be more deterministic and reproducible
|
||||
|
||||
These will both make it easier for people to collaborate on your project, as
|
||||
everyone will have the same environment, and make it easier to debug things like
|
||||
CI failures.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The only requirements to build and use this project are Docker and `make`. The
|
||||
latter can easily be substituted with your scripting tool of choice.
|
||||
|
||||
You will also need to enable the BuildKit builder in the Docker CLI. This can be
|
||||
done by setting `DOCKER_BUILDKIT=1` in your environment.
|
||||
|
||||
### macOS
|
||||
|
||||
* Install [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
||||
* Ensure that you have `make` (included with Xcode)
|
||||
* Run `export DOCKER_BUILDKIT=1` in your terminal or add to your shell
|
||||
initialization scripts
|
||||
|
||||
### Windows
|
||||
|
||||
* Install [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
||||
* Ensure that you have `make`
|
||||
* If using PowerShell, run `$env:DOCKER_BUILDKIT=1`
|
||||
* If using command prompt, run `set DOCKER_BUILDKIT=1`
|
||||
|
||||
### Linux
|
||||
|
||||
* Install [Docker](https://docs.docker.com/engine/install/)
|
||||
* Ensure that you have `make`
|
||||
* Run `export DOCKER_BUILDKIT=1` in your terminal or add to your shell
|
||||
initialization scripts
|
||||
|
||||
## Getting started
|
||||
|
||||
Building the project will output a static binary in the bin/ folder. The
|
||||
default platform is for macOS but this can be changed using the `PLATFORM` variable:
|
||||
```console
|
||||
$ make # build for your host OS
|
||||
$ make PLATFORM=darwin/amd64 # build for macOS
|
||||
$ make PLATFORM=windows/amd64 # build for Windows x86_64
|
||||
$ make PLATFORM=linux/amd64 # build for Linux x86_64
|
||||
$ make PLATFORM=linux/arm # build for Linux ARM
|
||||
```
|
||||
|
||||
You can then run the binary, which is a simple echo binary, as follows:
|
||||
```console
|
||||
$ ./bin/example hello world!
|
||||
hello world!
|
||||
```
|
||||
|
||||
To run the unit tests run:
|
||||
```console
|
||||
$ make unit-test
|
||||
```
|
||||
|
||||
To run the linter:
|
||||
```console
|
||||
$ make lint
|
||||
```
|
||||
|
||||
There's then a helpful `test` alias for running both the linter and the unit
|
||||
tests:
|
||||
```console
|
||||
$ make test
|
||||
```
|
||||
|
||||
## Structure of project
|
||||
|
||||
### Dockerfile
|
||||
|
||||
The [Dockerfile](./Dockerfile) codifies all the tools needed for the project
|
||||
and the commands that need to be run for building and testing it.
|
||||
|
||||
### Makefile
|
||||
|
||||
The [Makefile](./Makefile) is purely used to script the required `docker build`
|
||||
commands as these can get quite long. You can replace this file with a scripting
|
||||
language of your choice.
|
||||
|
||||
### CI
|
||||
|
||||
The CI is configured in the [ci.yaml file](./github/workflows/ci.yaml). By
|
||||
containerizing the toolchain, the CI relies on the toolchain we defined in the
|
||||
Dockerfile and doesn't require any custom setup.
|
||||
|
||||
## Read more
|
||||
|
||||
* [Docker build reference documentation](https://docs.docker.com/engine/reference/commandline/build/)
|
||||
* [Experimental Dockerfile syntax](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md)
|
||||
0
bin/.placeholder
Normal file
0
bin/.placeholder
Normal file
8
go.mod
Normal file
8
go.mod
Normal file
@@ -0,0 +1,8 @@
|
||||
module github.com/chris-crone/containerized-go
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.5.1
|
||||
)
|
||||
13
go.sum
Normal file
13
go.sum
Normal file
@@ -0,0 +1,13 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
24
main.go
Normal file
24
main.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func echo(args []string) error {
|
||||
if len(args) < 2 {
|
||||
return errors.New("no message to echo")
|
||||
}
|
||||
_, err := fmt.Println(strings.Join(args[1:], " "))
|
||||
return err
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := echo(os.Args); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%+v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
19
main_test.go
Normal file
19
main_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEcho(t *testing.T) {
|
||||
// Test happy path
|
||||
err := echo([]string{"bin-name", "hello", "world!"})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestEchoErrorNoArgs(t *testing.T) {
|
||||
// Test empty arguments
|
||||
err := echo([]string{})
|
||||
require.Error(t, err)
|
||||
}
|
||||
Reference in New Issue
Block a user