diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 000000000..061e7cf92 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,37 @@ +#!/usr/bin/env sh + +echo Running pre-commit hook + +# Check for required binaries, otherwise don't run +if ! command -v grep &> /dev/null +then + echo "grep could not be found - skipping pre-commit" + exit 0 +fi + +if ! command -v sed &> /dev/null +then + echo "sed could not be found - skipping pre-commit" + exit 0 +fi + +if ! command -v xargs &> /dev/null +then + echo "xargs could not be found - skipping pre-commit" + exit 0 +fi + +# Run pre-commit, this checks if we changed any golang files and runs the checks. +# The files are then git-added +FILES=$(git diff --cached --name-only --diff-filter=ACMR | grep .go | sed 's| |\\ |g') +if [ -n "$FILES" ]; then + make check + if [ $? -ne 0 ]; then + echo "Error running make check - please fix before committing" + echo "if this is a mistake you can skip the checks with 'git commit --no-verify'" + exit 1 + fi + echo "$FILES" | xargs git add +fi + +exit 0 diff --git a/.gitignore b/.gitignore index 55001d6b4..290180e0e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ web/node_modules web/dist/files release gitness +.idea +coverage.out diff --git a/.local.env b/.local.env new file mode 100644 index 000000000..e69de29bb diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..052d6f7fd --- /dev/null +++ b/Makefile @@ -0,0 +1,159 @@ +ifndef GOPATH + GOPATH := $(shell go env GOPATH) +endif +ifndef GOBIN + GOBIN := $(shell go env GOPATH)/bin +endif +ifndef DOCKER_BUILD_OPTS + DOCKER_BUILD_OPTS := +endif + +tools = $(addprefix $(GOBIN)/, golangci-lint goimports govulncheck) +deps = $(addprefix $(GOBIN)/, wire dbmate mockgen) + +ifneq (,$(wildcard ./.local.env)) + include ./.local.env + export +endif + +.DEFAULT_GOAL := all + +init: ## Install git hooks to perform pre-commit checks + git config core.hooksPath .githooks + git config commit.template .gitmessage + +all: dep tools generate lint build test ## Build and run the test for gitness + @echo "Run `make start` to start the services" + +dep: $(deps) ## Install the deps required to generate code and build gitness + @echo "Installing dependencies" + @go mod download + +tools: $(tools) ## Install tools required for the build + @echo "Installed tools" + +mocks: $(mocks) + @echo "Generating Test Mocks" + +generate: $(mocks) wire_gen.go mocks/mock_client.go + @echo "Generating Code" + +build: generate ## Build the gitness service binary + @echo "Building Gitness Server" + CGO_ENABLED=0 go build -ldflags="-X github.com/harness/gitness/version.GitCommit=${GIT_COMMIT} -X github.com/harness/gitness/version.Version=${GITNESS_VERSION}" -o ./gitness . + +test: generate ## Run the go tests + @echo "Running tests" + go test -v -coverprofile=coverage.out ./internal/... + go tool cover -html=coverage.out + +run: dep ## Run the gitness binary from source + @go run -race -ldflags="-X github.com/harness/gitness/version.Version=1.0.0" . + +clean-db: ## delete all data from local database + psql postgresql://gitness:gitness@localhost:5432/gitness -f scripts/db/cleanup.sql + +populate-db: ## inject sample data into local database + psql postgresql://gitness:gitness@localhost:5432/gitness -f scripts/db/sample_data.sql + +update-tools: delete-tools $(tools) ## Update the tools by deleting and re-installing + +delete-tools: ## Delete the tools + @rm $(tools) || true + + +######################################### +# Docker environment commands +# The following targets relate to running gitness and its dependent services +######################################### +start: ## Run all dependent services and start the gitness server locally - the service will listen on :3000 by default + docker-compose -f ./docker/docker-compose.yml up ${DOCKER_BUILD_OPTS} --remove-orphans + +stop: ## Stop all services + docker-compose -f ./docker/docker-compose.yml down --remove-orphans + +dev: ## Run local dev environment this starts the services which gitness depends on + docker-compose -f ./docker/docker-compose.yml up ${DOCKER_BUILD_OPTS} --remove-orphans db redis + +test-env: stop ## Run test environment - this runs all services and the gitness in test mode. + docker-compose -f ./docker/docker-compose.yml -f ./docker/docker-compose.test.yml up -d ${DOCKER_BUILD_OPTS} --remove-orphans + +image: ## Build the gitness docker image + @echo "Building Gitness Image" + @docker build --build-arg GITNESS_VERSION=latest \ + --build-arg GIT_COMMIT=${GIT_COMMIT} \ + --build-arg GITHUB_ACCESS_TOKEN=${GITHUB_ACCESS_TOKEN} \ + -t gitness:latest \ + -f ./docker/Dockerfile . + +e2e: generate test-env ## Run e2e tests + chmod +x wait-for-gitness.sh && ./wait-for-gitness.sh + go test -p 1 -v -coverprofile=e2e_cov.out ./tests/... -env=".env.local" + + +########################################### +# Code Formatting and linting +########################################### + +format: tools # Format go code and error if any changes are made + @echo "Formating ..." + @goimports -w . + @echo "Formatting complete" + +sec: + @echo "Vulnerability detection $(1)" + @govulncheck ./... + +lint: tools generate # lint the golang code + @echo "Linting $(1)" + @golangci-lint run + +########################################### +# Code Generation +# +# Some code generation can be slow, so we only run it if +# the source file has changed. +########################################### +wire_gen.go: cli/server/wire.go ## Update the wire dependency injection if wire.go has changed. + @echo "Updating wire_gen.go" + go generate ./cli/server/wire_gen.go + +mocks/mock_client.go: internal/store/store.go client/client.go + go generate mocks/mock.go + +########################################### +# Install Tools and deps +# +# These targets specify the full path to where the tool is installed +# If the tool already exists it wont be re-installed. +########################################### + +# Install golangci-lint +$(GOBIN)/golangci-lint: + @echo "🔘 Installing golangci-lint... (`date '+%H:%M:%S'`)" + @curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin + +# Install goimports to format code +$(GOBIN)/goimports: + @echo "🔘 Installing goimports ... (`date '+%H:%M:%S'`)" + @go install golang.org/x/tools/cmd/goimports + +# Install wire to generate dependency injection +$(GOBIN)/wire: + go install github.com/google/wire/cmd/wire@latest + +# Install dbmate to perform db migrations +$(GOBIN)/dbmate: + go install github.com/amacneil/dbmate@v1.15.0 + +# Install mockgen to generate mocks +$(GOBIN)/mockgen: + go install github.com/golang/mock/mockgen@latest + +$(GOBIN)/govulncheck: + go install golang.org/x/vuln/cmd/govulncheck@latest + +help: ## show help message + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[$$()% 0-9a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +.PHONY: delete-tools update-tools help format lint \ No newline at end of file diff --git a/README.md b/README.md index 04d6fcbdd..99f48adb6 100644 --- a/README.md +++ b/README.md @@ -2,25 +2,24 @@ Install the latest stable version of Node and Go version 1.17 or higher, and then install the below Go programs. Ensure the GOPATH [bin directory](https://go.dev/doc/gopath_code#GOPATH) is added to your PATH. -```text -$ go install github.com/golang/mock/mockgen@latest -$ go install github.com/google/wire/cmd/wire@latest +```bash +$ make all ``` # Build Build the user interface: -```text +```bash $ pushd web -$ npm install -$ npm run build +$ yarn install +$ yarn run build $ popd ``` Build the server and command line tools: -```text +```bash $ go generate ./... $ go build -o release/gitness ``` @@ -29,9 +28,8 @@ $ go build -o release/gitness Execute the unit tests: -```text -$ go generate ./... -$ go test -v -cover ./... +```bash +$ make test ``` # Run @@ -40,7 +38,7 @@ This project supports all operating systems and architectures supported by Go. Start the server at `localhost:3000` -```text +```bash $ release/gitness server ``` @@ -58,54 +56,54 @@ This project includes simple command line tools for interacting with the system. Register a new user: -```text +```bash $ release/gitness register ``` Login to the application: -```text +```bash $ release/gitness login ``` Logout from the application: -```text +```bash $ release/gitness logout ``` View your account details: -```text +```bash $ release/gitness account ``` -Generate a peronsal access token: +Generate a personal access token: -```text +```bash $ release/gitness token ``` Create a pipeline: -```text +```bash $ release/gitness pipeline create ``` List pipelines: -```text +```bash $ release/gitness pipeline ls ``` Debug and output http responses from the server: -```text +```bash $ DEBUG=true release/gitness pipeline ls ``` View all commands: -```text +```bash $ release/gitness --help ``` diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml new file mode 100644 index 000000000..0f61f2f6d --- /dev/null +++ b/docker/docker-compose.yaml @@ -0,0 +1,39 @@ +version: "3.9" + +services: + db: + image: postgres + restart: always + environment: + POSTGRES_DB: gitness + POSTGRES_USER: gitness + POSTGRES_PASSWORD: gitness + PGDATA: /var/lib/postgresql/data/pgdata + ports: + - "5432:5432" + expose: + - 5432 + volumes: + - ./init-user-db.sh:/docker-entrypoint-initdb.d/init-user-db.sh + - gitness_data:/var/lib/postgresql/data + + migration: + build: + context: ../db + dockerfile: ./Dockerfile + environment: + DATABASE_URL: postgres://gitness:gitness@db:5432/gitness?sslmode=disable + depends_on: + - db + + redis: + image: redis:6.0 + container_name: cache + ports: + - "6379:6379" + expose: + - 6379 + +volumes: + gitness_data: + driver: local \ No newline at end of file diff --git a/docker/init-user-db.sh b/docker/init-user-db.sh new file mode 100644 index 000000000..ec9f80a03 --- /dev/null +++ b/docker/init-user-db.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -e + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL + CREATE DATABASE gitness_test; + GRANT ALL PRIVILEGES ON DATABASE gitness_test TO "$POSTGRES_USER"; +EOSQL \ No newline at end of file diff --git a/scripts/db/cleanup.sql b/scripts/db/cleanup.sql new file mode 100644 index 000000000..e69de29bb diff --git a/scripts/db/sample_data.sql b/scripts/db/sample_data.sql new file mode 100644 index 000000000..e69de29bb diff --git a/version/version.go b/version/version.go index 8f3656bb6..c94699a5c 100644 --- a/version/version.go +++ b/version/version.go @@ -12,23 +12,23 @@ var ( GitRepository string // GitCommit is the git commit that was compiled GitCommit string - // VersionMajor is for an API incompatible changes. - VersionMajor int64 = 1 - // VersionMinor is for functionality in a backwards-compatible manner. - VersionMinor int64 - // VersionPatch is for backwards-compatible bug fixes. - VersionPatch int64 - // VersionPre indicates prerelease. - VersionPre = "" - // VersionDev indicates development branch. Releases will be empty string. - VersionDev string + // Major is for an API incompatible changes. + Major int64 = 1 + // Minor is for functionality in a backwards-compatible manner. + Minor int64 + // Patch is for backwards-compatible bug fixes. + Patch int64 + // Pre indicates prerelease. + Pre = "" + // Dev indicates development branch. Releases will be empty string. + Dev string ) // Version is the specification version that the package types support. var Version = semver.Version{ - Major: VersionMajor, - Minor: VersionMinor, - Patch: VersionPatch, - PreRelease: semver.PreRelease(VersionPre), - Metadata: VersionDev, + Major: Major, + Minor: Minor, + Patch: Patch, + PreRelease: semver.PreRelease(Pre), + Metadata: Dev, } diff --git a/wait-for-gitness.sh b/wait-for-gitness.sh new file mode 100644 index 000000000..359c78a8f --- /dev/null +++ b/wait-for-gitness.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -eux + +declare -r HOST="localhost:3000/health" + +wait-for-url() { + echo "Testing $1" + timeout -s TERM 180 bash -c \ + 'while [[ "$(curl -s -o /dev/null -L -w ''%{http_code}'' ${0})" != "200" ]];\ + do echo "Waiting for ${0}" && sleep 2;\ + done' ${1} + echo "OK!" + curl $1 +} +wait-for-url http://${HOST}