diff options
author | Zeger-Jan van de Weg <zegerjan@gitlab.com> | 2018-10-18 14:04:47 +0300 |
---|---|---|
committer | Zeger-Jan van de Weg <zegerjan@gitlab.com> | 2018-10-18 14:04:47 +0300 |
commit | 6e813b1b03c89db750c17ab77afe84eba4d13339 (patch) | |
tree | 905b5bb540ad8898a82f1ee6b1e3370c4a5d3426 | |
parent | 536ead1b2ac80de4eacc16c3916d5188e527bc38 (diff) | |
parent | c1aa5d38391d8092ca852bc3486397b3181a8741 (diff) |
Merge branch 'makefile-bootstrap' into 'master'
Make Makefile more predictable by bootstrapping
See merge request gitlab-org/gitaly!913
-rw-r--r-- | Makefile | 267 | ||||
-rw-r--r-- | _support/makegen.go | 404 | ||||
-rw-r--r-- | changelogs/unreleased/makefile-bootstrap.yml | 5 |
3 files changed, 475 insertions, 201 deletions
@@ -1,221 +1,86 @@ -PREFIX := /usr/local -PKG := gitlab.com/gitlab-org/gitaly -BUILD_DIR := $(CURDIR) -TARGET_DIR := $(BUILD_DIR)/_build -TARGET_SETUP := $(TARGET_DIR)/.ok -BIN_BUILD_DIR := $(TARGET_DIR)/bin -PKG_BUILD_DIR := $(TARGET_DIR)/src/$(PKG) -export TEST_REPO_STORAGE_PATH := $(BUILD_DIR)/internal/testhelper/testdata/data -TEST_REPO := $(TEST_REPO_STORAGE_PATH)/gitlab-test.git -GIT_TEST_REPO := $(TEST_REPO_STORAGE_PATH)/gitlab-git-test.git -INSTALL_DEST_DIR := $(DESTDIR)$(PREFIX)/bin/ -COVERAGE_DIR := $(TARGET_DIR)/cover -ASSEMBLY_ROOT := $(TARGET_DIR)/assembly -export GITALY_TEST_RUBY_DIR := $(BUILD_DIR)/ruby -BUNDLE_FLAGS ?= --deployment - -BUILDTIME = $(shell date -u +%Y%m%d.%H%M%S) -VERSION_PREFIXED = $(shell git describe) -VERSION = $(VERSION_PREFIXED:v%=%) -GO_LDFLAGS = -ldflags '-X $(PKG)/internal/version.version=$(VERSION) -X $(PKG)/internal/version.buildtime=$(BUILDTIME)' - -unexport GOROOT -unexport GOBIN - -export GOPATH := $(TARGET_DIR) -export PATH := $(GOPATH)/bin:$(PATH) - -# Returns a list of all non-vendored (local packages) -LOCAL_PACKAGES = $(shell cd "$(PKG_BUILD_DIR)" && GOPATH=$(GOPATH) go list ./... | grep -v '^$(PKG)/vendor/' | grep -v '^$(PKG)/ruby/') -LOCAL_GO_FILES = $(shell find -L $(PKG_BUILD_DIR) -name "*.go" -not -path "$(PKG_BUILD_DIR)/vendor/*" -not -path "$(PKG_BUILD_DIR)/_build/*") -CHANGED_LOCAL_GO_FILES = $(shell git status --porcelain --short | awk '{ print $$2 }' | grep -v '^$(PKG)/vendor/' | grep .go$) -CHANGED_LOCAL_GO_PACKAGES = $(foreach file,$(CHANGED_LOCAL_GO_FILES),./$(dir $(file))/...) -COMMAND_PACKAGES = $(shell cd "$(PKG_BUILD_DIR)" && GOPATH=$(GOPATH) go list ./cmd/...) -COMMANDS = $(subst $(PKG)/cmd/,,$(COMMAND_PACKAGES)) - -# Developer Tools -GOVENDOR = $(BIN_BUILD_DIR)/govendor -GOLINT = $(BIN_BUILD_DIR)/golint -GOCOVMERGE = $(BIN_BUILD_DIR)/gocovmerge -GOIMPORTS = $(BIN_BUILD_DIR)/goimports -MEGACHECK = $(BIN_BUILD_DIR)/megacheck - -.NOTPARALLEL: - -.PHONY: all +# Top-level Makefile for Gitaly +# +# Responsibilities of this file: +# - create GOPATH in _build with symlink to current dir +# - re-generate _build/Makefile from makegen.go on each run +# - dispatch commands to _build/Makefile +# +# "Magic" should happen in the makegen.go dynamic template. We want +# _build/Makefile to be as static as possible. + +BUILD_DIR = _build +PKG = gitlab.com/gitlab-org/gitaly +MAKEGEN = $(BUILD_DIR)/makegen + +# These variables are handed down to make in _build +export GOPATH := $(CURDIR)/$(BUILD_DIR) +export PATH := $(PATH):$(GOPATH)/bin +export TEST_REPO_STORAGE_PATH := $(CURDIR)/internal/testhelper/testdata/data + all: build -$(TARGET_SETUP): - rm -rf $(TARGET_DIR) - mkdir -p "$(dir $(PKG_BUILD_DIR))" - ln -sf ../../../.. "$(PKG_BUILD_DIR)" - mkdir -p "$(BIN_BUILD_DIR)" - touch "$(TARGET_SETUP)" - -build: .ruby-bundle $(TARGET_SETUP) - go install $(GO_LDFLAGS) $(COMMAND_PACKAGES) - cp $(foreach cmd,$(COMMANDS),$(BIN_BUILD_DIR)/$(cmd)) $(BUILD_DIR)/ - -.ruby-bundle: ruby/Gemfile.lock ruby/Gemfile - cd ruby && bundle config # for debugging - cd ruby && bundle install $(BUNDLE_FLAGS) - cd ruby && bundle show gitaly-proto # sanity check - touch $@ +.PHONY: build +build: prepare-build + cd $(BUILD_DIR) && make install INSTALL_DEST_DIR=$(CURDIR) -# TODO: confirm what references this target? Omnibus? Source installs? .PHONY: install -install: build - mkdir -p $(INSTALL_DEST_DIR) - cd $(BIN_BUILD_DIR) && install $(COMMANDS) $(INSTALL_DEST_DIR) - -.PHONY: force-ruby-bundle -force-ruby-bundle: - rm -f .ruby-bundle +install: prepare-build + cd $(BUILD_DIR) && make $@ -# Assembles all runtime components into a directory -# Used by the GDK: run `make assemble ASSEMBLY_ROOT=.../gitaly` .PHONY: assemble -assemble: force-ruby-bundle build assemble-internal - -# assemble-internal does not force 'bundle install' to run again -.PHONY: assemble-internal -assemble-internal: build - rm -rf $(ASSEMBLY_ROOT)/bin $(ASSEMBLY_ROOT)/ruby - mkdir -p $(ASSEMBLY_ROOT)/bin - rm -rf ruby/tmp - cp -r ruby $(ASSEMBLY_ROOT)/ruby - rm -rf $(ASSEMBLY_ROOT)/ruby/spec - install $(foreach cmd,$(COMMANDS),$(BIN_BUILD_DIR)/$(cmd)) $(ASSEMBLY_ROOT)/bin - -binaries: assemble - @if [ $$(uname -m) != 'x86_64' ]; then echo Incorrect architecture for build: $(uname -m); exit 1; fi - @cd $(ASSEMBLY_ROOT) && shasum -a 256 bin/* | tee checksums.sha256.txt - -docker: $(TARGET_SETUP) - rm -rf $(TARGET_DIR)/docker/ - mkdir -p $(TARGET_DIR)/docker/bin/ - cp -r ruby $(TARGET_DIR)/docker/ruby/ - rm -rf $(TARGET_DIR)/docker/ruby/vendor/bundle - - for cmd in $(COMMAND_PACKAGES); do \ - GOOS=linux GOARCH=amd64 go build $(GO_LDFLAGS) -o "$(TARGET_DIR)/docker/bin/$$(basename $$cmd)" $$cmd; \ - done - - cp Dockerfile $(TARGET_DIR)/docker/ - docker build -t gitlab/gitaly:$(VERSION_PREFIXED) -t gitlab/gitaly:latest $(TARGET_DIR)/docker/ - -.PHONY: verify -verify: lint check-formatting megacheck govendor-status notice-up-to-date govendor-tagged rubocop - -.PHONY: govendor-status -govendor-status: $(TARGET_SETUP) $(GOVENDOR) - cd $(PKG_BUILD_DIR) && govendor status +assemble: prepare-build + cd $(BUILD_DIR) && make $@ -.PHONY: govendor-tagged -govendor-tagged: $(TARGET_SETUP) $(GOVENDOR) - cd $(PKG_BUILD_DIR) && _support/gitaly-proto-tagged - -$(TEST_REPO): - git clone --bare https://gitlab.com/gitlab-org/gitlab-test.git $@ - # Git notes aren't fetched by default with git clone - git -C $@ fetch origin refs/notes/*:refs/notes/* - -$(GIT_TEST_REPO): - git clone --bare https://gitlab.com/gitlab-org/gitlab-git-test.git $@ - -.PHONY: prepare-tests -prepare-tests: $(TARGET_SETUP) $(TEST_REPO) $(GIT_TEST_REPO) .ruby-bundle +.PHONY: binaries +binaries: prepare-build + cd $(BUILD_DIR) && make $@ .PHONY: test -test: test-go rspec - -.PHONY: test-go -test-go: prepare-tests - @go test -count=1 $(LOCAL_PACKAGES) # count=1 bypasses go 1.10 test caching - -.PHONY: race-go -race-go: prepare-tests - @go test -race $(LOCAL_PACKAGES) - +test: prepare-build + cd $(BUILD_DIR) && make $@ + .PHONY: rspec -rspec: assemble-internal prepare-tests - cd ruby && bundle exec rspec - -.PHONY: rubocop -rubocop: .ruby-bundle $(TARGET_SETUP) - cd ruby && bundle exec rubocop --parallel - -.PHONY: test-changes -test-changes: prepare-tests - cd $(PKG_BUILD_DIR) && go test $(CHANGED_LOCAL_GO_PACKAGES) +rspec: prepare-build + cd $(BUILD_DIR) && make $@ -.PHONY: lint -lint: $(GOLINT) - go run _support/lint.go - -.PHONY: megacheck -megacheck: $(MEGACHECK) - @$(MEGACHECK) $(LOCAL_PACKAGES) - -.PHONY: check-formatting -check-formatting: $(TARGET_SETUP) $(GOIMPORTS) - @test -z "$$($(GOIMPORTS) -e -l $(LOCAL_GO_FILES))" || (echo >&2 "Formatting or imports need fixing: 'make format'" && $(GOIMPORTS) -e -l $(LOCAL_GO_FILES) && false) +.PHONY: verify +verify: prepare-build + cd $(BUILD_DIR) && make $@ .PHONY: format -format: $(TARGET_SETUP) $(GOIMPORTS) - # In addition to fixing imports, goimports also formats your code in the same style as gofmt - # so it can be used as a replacement. - @$(GOIMPORTS) -w -l $(LOCAL_GO_FILES) +format: prepare-build + cd $(BUILD_DIR) && make $@ -.PHONY: package -package: build - ./_support/package/package $(COMMANDS) +.PHONY: cover +cover: prepare-build + cd $(BUILD_DIR) && make $@ .PHONY: notice -notice: $(TARGET_SETUP) $(GOVENDOR) - cd $(PKG_BUILD_DIR) && govendor license -template _support/notice.template -o $(BUILD_DIR)/NOTICE +notice: prepare-build + cd $(BUILD_DIR) && make $@ + +.PHONY: race-go +race-go: prepare-build + cd $(BUILD_DIR) && make $@ + +.PHONY: docker +docker: prepare-build + cd $(BUILD_DIR) && make $@ + +.PHONY: prepare-build +prepare-build: $(BUILD_DIR)/.ok update-makefile +$(BUILD_DIR)/.ok: + mkdir -p $(BUILD_DIR)/src/$(shell dirname $(PKG)) + cd $(BUILD_DIR)/src/$(shell dirname $(PKG)) && rm -f $(shell basename $(PKG)) && \ + ln -sf ../../../.. $(shell basename $(PKG)) + touch $@ -.PHONY: notice-up-to-date -notice-up-to-date: $(TARGET_SETUP) $(GOVENDOR) - @(cd $(PKG_BUILD_DIR) && govendor license -template _support/notice.template | cmp - NOTICE) || (echo >&2 "NOTICE requires update: 'make notice'" && false) +.PHONY: update-makefile +update-makefile: _build/makegen $(BUILD_DIR)/.ok + cd $(BUILD_DIR) && ./makegen > Makefile -.PHONY: codeclimate-report -codeclimate-report: - docker run --env CODECLIMATE_CODE="$(BUILD_DIR)" --volume "$(BUILD_DIR)":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f text +_build/makegen: _support/makegen.go $(BUILD_DIR)/.ok + go build -o $@ _support/makegen.go -.PHONY: clean clean: - rm -rf $(TARGET_DIR) $(TEST_REPO_STORAGE_PATH) ./ruby/tmp/repositories ./internal/service/ssh/gitaly-*-pack .ruby-bundle - -.PHONY: cover -cover: prepare-tests $(GOCOVMERGE) - @echo "NOTE: make cover does not exit 1 on failure, don't use it to check for tests success!" - mkdir -p "$(COVERAGE_DIR)" - rm -f $(COVERAGE_DIR)/*.out "$(COVERAGE_DIR)/all.merged" "$(COVERAGE_DIR)/all.html" - go run _support/test-cover-parallel.go $(COVERAGE_DIR) $(LOCAL_PACKAGES) - $(GOCOVMERGE) $(COVERAGE_DIR)/*.out > "$(COVERAGE_DIR)/all.merged" - go tool cover -html "$(COVERAGE_DIR)/all.merged" -o "$(COVERAGE_DIR)/all.html" - @echo "" - @echo "=====> Total test coverage: <=====" - @echo "" - @go tool cover -func "$(COVERAGE_DIR)/all.merged" - -# Install govendor -$(GOVENDOR): $(TARGET_SETUP) - go get -v github.com/kardianos/govendor - -# Install golint -$(GOLINT): $(TARGET_SETUP) - go get -v golang.org/x/lint/golint - -# Install gocovmerge -$(GOCOVMERGE): $(TARGET_SETUP) - go get -v github.com/wadey/gocovmerge - -# Install goimports -$(GOIMPORTS): $(TARGET_SETUP) - go get -v golang.org/x/tools/cmd/goimports - -# Install megacheck -$(MEGACHECK): $(TARGET_SETUP) - go get -v honnef.co/go/tools/cmd/megacheck + rm -rf $(BUILD_DIR) .ruby-bundle $(TEST_REPO_STORAGE_PATH) diff --git a/_support/makegen.go b/_support/makegen.go new file mode 100644 index 000000000..e5f8b5ca0 --- /dev/null +++ b/_support/makegen.go @@ -0,0 +1,404 @@ +/* + makegen.go -- Makefile generator for Gitaly + +This file is used to generate _build/Makefile. In _build/Makefile we +can assume that we are in a GOPATH (rooted at _build) and that +$GOPATH/bin is in PATH. The generator runs in the root of the Gitaly +tree. The goal of the generator is to use as little dynamic behaviors +in _build/Makefile (e.g. shelling out to find a list of files), and do +these things as much as possible in Go and then pass them into the +template. + +The working directory of makegen.go and the Makefile it generates is +_build. +*/ + +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "sort" + "strings" + "text/template" + "time" +) + +func main() { + gm := &gitalyMake{} + + tmpl := template.New("Makefile") + tmpl.Funcs(map[string]interface{}{ + "join": strings.Join, + }) + tmpl = template.Must(tmpl.Parse(templateText)) + + err := tmpl.Execute(os.Stdout, gm) + if err != nil { + log.Fatalf("execution failed: %s", err) + } +} + +type gitalyMake struct { + commandPackages []string + cwd string + versionPrefixed string + goFiles []string + buildTime string +} + +// BuildDir is the GOPATH root. It is also the working directory of the Makefile we are generating. +func (gm *gitalyMake) BuildDir() string { + if len(gm.cwd) > 0 { + return gm.cwd + } + + cwd, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + gm.cwd, err = filepath.EvalSymlinks(cwd) + if err != nil { + log.Fatal(err) + } + + return gm.cwd +} + +func (gm *gitalyMake) Pkg() string { return "gitlab.com/gitlab-org/gitaly" } +func (gm *gitalyMake) GoImports() string { return "bin/goimports" } +func (gm *gitalyMake) GoCovMerge() string { return "bin/gocovmerge" } +func (gm *gitalyMake) GoLint() string { return "bin/golint" } +func (gm *gitalyMake) GoVendor() string { return "bin/govendor" } +func (gm *gitalyMake) MegaCheck() string { return "bin/megacheck" } +func (gm *gitalyMake) CoverageDir() string { return filepath.Join(gm.BuildDir(), "cover") } + +// SourceDir is the location of gitaly's files, inside the _build GOPATH. +func (gm *gitalyMake) SourceDir() string { return filepath.Join(gm.BuildDir(), "src", gm.Pkg()) } + +func (gm *gitalyMake) TestRepoStoragePath() string { + path := os.Getenv("TEST_REPO_STORAGE_PATH") + if len(path) == 0 { + log.Fatal("TEST_REPO_STORAGE_PATH is not set") + } + + return path +} + +func (gm *gitalyMake) TestRepo() string { + return filepath.Join(gm.TestRepoStoragePath(), "gitlab-test.git") +} + +func (gm *gitalyMake) GitTestRepo() string { + return filepath.Join(gm.TestRepoStoragePath(), "gitlab-git-test.git") +} + +func (gm *gitalyMake) CommandPackages() []string { + if len(gm.commandPackages) > 0 { + return gm.commandPackages + } + + entries, err := ioutil.ReadDir(filepath.Join(gm.SourceDir(), "cmd")) + if err != nil { + log.Fatal(err) + } + + for _, dir := range entries { + if !dir.IsDir() { + continue + } + + gm.commandPackages = append(gm.commandPackages, filepath.Join(gm.Pkg(), "cmd", dir.Name())) + } + + return gm.commandPackages +} + +func (gm *gitalyMake) Commands() []string { + var out []string + for _, pkg := range gm.CommandPackages() { + out = append(out, filepath.Base(pkg)) + } + return out +} + +func (gm *gitalyMake) BuildTime() string { + if len(gm.buildTime) > 0 { + return gm.buildTime + } + + now := time.Now().UTC() + gm.buildTime = fmt.Sprintf("%d%02d%02d.%02d%02d%02d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()) + return gm.buildTime +} + +func (gm *gitalyMake) GoLdFlags() string { + return fmt.Sprintf("-ldflags '-X %s/internal/version.version=%s -X %s/internal/version.buildtime=%s'", gm.Pkg(), gm.Version(), gm.Pkg(), gm.BuildTime()) +} + +func (gm *gitalyMake) VersionPrefixed() string { + if len(gm.versionPrefixed) > 0 { + return gm.versionPrefixed + } + + cmd := exec.Command("git", "describe") + cmd.Stderr = os.Stderr + out, err := cmd.Output() + if err != nil { + log.Printf("%s: %v", strings.Join(cmd.Args, " "), err) + gm.versionPrefixed = "unknown" + return gm.versionPrefixed + } + gm.versionPrefixed = strings.TrimSpace(string(out)) + + return gm.versionPrefixed +} + +func (gm *gitalyMake) Version() string { return strings.TrimPrefix(gm.VersionPrefixed(), "v") } + +func (gm *gitalyMake) GoFiles() []string { + if len(gm.goFiles) > 0 { + return gm.goFiles + } + + root := gm.SourceDir() + "/." // Add "/." to traverse symlink + + filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() && path != root { + if path == filepath.Join(root, "ruby") || path == filepath.Join(root, "vendor") { + return filepath.SkipDir + } + + if name := info.Name(); name == "testdata" || strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") { + return filepath.SkipDir + } + } + + if !info.IsDir() && strings.HasSuffix(path, ".go") { + rel, err := filepath.Rel(root, path) + if err != nil { + return err + } + gm.goFiles = append(gm.goFiles, rel) + } + + return nil + }) + + sort.Strings(gm.goFiles) + + return gm.goFiles +} + +func (gm *gitalyMake) AllPackages() []string { + pkgMap := make(map[string]struct{}) + for _, f := range gm.GoFiles() { + pkgMap[filepath.Dir(filepath.Join(gm.Pkg(), f))] = struct{}{} + } + + var pkgs []string + for k := range pkgMap { + pkgs = append(pkgs, k) + } + + sort.Strings(pkgs) + + return pkgs +} + +var templateText = ` +# _build/Makefile +# +# This is an auto-generated Makefile. Do not edit. Do not invoke +# directly, use ../Makefile instead. This file is generated using +# makegen.go. +# + +# These variables may be overriden at runtime by top-level make +PREFIX ?= /usr/local +INSTALL_DEST_DIR := $(DESTDIR)$(PREFIX)/bin/ +BUNDLE_FLAGS ?= --deployment +ASSEMBLY_ROOT ?= {{ .BuildDir }}/assembly + +unexport GOROOT +unexport GOBIN + +.NOTPARALLEL: + +.PHONY: all +all: build + +.PHONY: build +build: ../.ruby-bundle + go install {{ .GoLdFlags }} {{ join .CommandPackages " " }} + +# This file is used by Omnibus and CNG to skip the "bundle install" +# step. Both Omnibus and CNG assume it is in the Gitaly root, not in +# _build. Hence the '../' in front. +../.ruby-bundle: {{ .SourceDir }}/ruby/Gemfile.lock {{ .SourceDir }}/ruby/Gemfile + cd {{ .SourceDir }}/ruby && bundle config # for debugging + cd {{ .SourceDir }}/ruby && bundle install $(BUNDLE_FLAGS) + cd {{ .SourceDir }}/ruby && bundle show gitaly-proto # sanity check + touch $@ + +.PHONY: install +install: build + mkdir -p $(INSTALL_DEST_DIR) + cd bin && install {{ join .Commands " " }} $(INSTALL_DEST_DIR) + +.PHONY: force-ruby-bundle +force-ruby-bundle: + rm -f ../.ruby-bundle + +# Assembles all runtime components into a directory +# Used by the GDK: run 'make assemble ASSEMBLY_ROOT=.../gitaly' +.PHONY: assemble +assemble: force-ruby-bundle build assemble-internal + +# assemble-internal does not force 'bundle install' to run again +.PHONY: assemble-internal +assemble-internal: assemble-ruby assemble-go + +.PHONY: assemble-go +assemble-go: build + rm -rf $(ASSEMBLY_ROOT)/bin + mkdir -p $(ASSEMBLY_ROOT)/bin + cd bin && install {{ join .Commands " " }} $(ASSEMBLY_ROOT)/bin + +.PHONY: assemble-ruby +assemble-ruby: + rm -rf $(ASSEMBLY_ROOT)/ruby + mkdir -p $(ASSEMBLY_ROOT) + rm -rf {{ .SourceDir }}/ruby/tmp + cp -r {{ .SourceDir }}/ruby $(ASSEMBLY_ROOT)/ruby + rm -rf $(ASSEMBLY_ROOT)/ruby/spec + +binaries: assemble + @if [ $$(uname -m) != 'x86_64' ]; then echo Incorrect architecture for build: $(uname -m); exit 1; fi + @cd $(ASSEMBLY_ROOT) && shasum -a 256 bin/* | tee checksums.sha256.txt + +{{ .TestRepo }}: + git clone --bare --quiet https://gitlab.com/gitlab-org/gitlab-test.git $@ + # Git notes aren't fetched by default with git clone + git -C $@ fetch origin refs/notes/*:refs/notes/* + +{{ .GitTestRepo }}: + git clone --bare --quiet https://gitlab.com/gitlab-org/gitlab-git-test.git $@ + +.PHONY: prepare-tests +prepare-tests: {{ .TestRepo }} {{ .GitTestRepo }} ../.ruby-bundle + +.PHONY: test +test: test-go rspec + +.PHONY: test-go +test-go: prepare-tests + @go test -count=1 {{ join .AllPackages " " }} # count=1 bypasses go 1.10 test caching + +.PHONY: race-go +race-go: prepare-tests + @go test -race {{ join .AllPackages " " }} + +.PHONY: rspec +rspec: assemble-go prepare-tests + cd {{ .SourceDir }}/ruby && bundle exec rspec + +.PHONY: verify +verify: lint check-formatting megacheck govendor-status notice-up-to-date govendor-tagged rubocop + +.PHONY: lint +lint: {{ .GoLint }} + # golint + @cd {{ .SourceDir }} && go run _support/lint.go + +{{ .GoLint }}: + go get golang.org/x/lint/golint + +.PHONY: check-formatting +check-formatting: {{ .GoImports }} + # goimports + @cd {{ .SourceDir }} && goimports -e -l {{ join .GoFiles " " }} | awk '{ print } END { if(NR>0) { print "Formatting error, run make format"; exit(1) } }' + +{{ .GoImports }}: + go get golang.org/x/tools/cmd/goimports + +.PHONY: format +format: {{ .GoImports }} + # In addition to fixing imports, goimports also formats your code in the same style as gofmt + # so it can be used as a replacement. + @cd {{ .SourceDir }} && goimports -w -l {{ join .GoFiles " " }} + +.PHONY: megacheck +megacheck: {{ .MegaCheck }} + # megacheck + @{{ .MegaCheck }} {{ join .AllPackages " " }} + +# Install megacheck +{{ .MegaCheck }}: + go get honnef.co/go/tools/cmd/megacheck + +.PHONY: govendor-status +govendor-status: {{ .GoVendor }} + # govendor status + @cd {{ .SourceDir }} && govendor status + +{{ .GoVendor }}: + go get github.com/kardianos/govendor + +.PHONY: notice-up-to-date +notice-up-to-date: {{ .GoVendor }} + # notice-up-to-date + @(cd {{ .SourceDir }} && govendor license -template _support/notice.template | cmp - NOTICE) || (echo >&2 "NOTICE requires update: 'make notice'" && false) + +.PHONY: notice +notice: {{ .GoVendor }} + cd {{ .SourceDir }} && govendor license -template _support/notice.template -o NOTICE + +.PHONY: govendor-tagged +govendor-tagged: {{ .GoVendor }} + # govendor-tagged + @cd {{ .SourceDir }} && _support/gitaly-proto-tagged + +.PHONY: rubocop +rubocop: ../.ruby-bundle + cd {{ .SourceDir }}/ruby && bundle exec rubocop --parallel + +.PHONY: cover +cover: prepare-tests {{ .GoCovMerge }} + @echo "NOTE: make cover does not exit 1 on failure, don't use it to check for tests success!" + mkdir -p "{{ .CoverageDir }}" + rm -f {{ .CoverageDir }}/*.out "{{ .CoverageDir }}/all.merged" "{{ .CoverageDir }}/all.html" + @cd {{ .SourceDir }} && go run _support/test-cover-parallel.go {{ .CoverageDir }} {{ join .AllPackages " " }} + {{ .GoCovMerge }} {{ .CoverageDir }}/*.out > "{{ .CoverageDir }}/all.merged" + go tool cover -html "{{ .CoverageDir }}/all.merged" -o "{{ .CoverageDir }}/all.html" + @echo "" + @echo "=====> Total test coverage: <=====" + @echo "" + @go tool cover -func "{{ .CoverageDir }}/all.merged" + +{{ .GoCovMerge }}: + go get github.com/wadey/gocovmerge + +.PHONY: docker +docker: + rm -rf docker/ + mkdir -p docker/bin/ + rm -rf {{ .SourceDir }}/ruby/tmp + cp -r {{ .SourceDir }}/ruby docker/ruby + rm -rf docker/ruby/vendor/bundle +{{ $pkg := .Pkg }} +{{ $goLdFlags := .GoLdFlags }} +{{ range $cmd := .Commands }} + GOOS=linux GOARCH=amd64 go build {{ $goLdFlags }} -o "docker/bin/{{ $cmd }}" {{ $pkg }}/cmd/{{ $cmd }} +{{ end }} + cp {{ .SourceDir }}/Dockerfile docker/ + docker build -t gitlab/gitaly:{{ .VersionPrefixed }} -t gitlab/gitaly:latest docker/ +` diff --git a/changelogs/unreleased/makefile-bootstrap.yml b/changelogs/unreleased/makefile-bootstrap.yml new file mode 100644 index 000000000..e1f6a730f --- /dev/null +++ b/changelogs/unreleased/makefile-bootstrap.yml @@ -0,0 +1,5 @@ +--- +title: Make Makefile more predictable by bootstrapping +merge_request: 913 +author: +type: other |