Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZeger-Jan van de Weg <zegerjan@gitlab.com>2018-10-18 14:04:47 +0300
committerZeger-Jan van de Weg <zegerjan@gitlab.com>2018-10-18 14:04:47 +0300
commit6e813b1b03c89db750c17ab77afe84eba4d13339 (patch)
tree905b5bb540ad8898a82f1ee6b1e3370c4a5d3426
parent536ead1b2ac80de4eacc16c3916d5188e527bc38 (diff)
parentc1aa5d38391d8092ca852bc3486397b3181a8741 (diff)
Merge branch 'makefile-bootstrap' into 'master'
Make Makefile more predictable by bootstrapping See merge request gitlab-org/gitaly!913
-rw-r--r--Makefile267
-rw-r--r--_support/makegen.go404
-rw-r--r--changelogs/unreleased/makefile-bootstrap.yml5
3 files changed, 475 insertions, 201 deletions
diff --git a/Makefile b/Makefile
index ffb51d0f8..68954ed90 100644
--- a/Makefile
+++ b/Makefile
@@ -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