diff --git a/.github/workflows/_build.yml b/.github/workflows/_build.yml new file mode 100644 index 0000000..b07ebac --- /dev/null +++ b/.github/workflows/_build.yml @@ -0,0 +1,26 @@ +name: Go + +on: + workflow_call: + inputs: + go_versions: + type: string + description: Go versions to run workflow on + required: true + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + go_version: ${{ fromJSON(inputs.go_versions) }} + steps: + - uses: actions/checkout@v3 + + - name: Set up go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go_version }} + + - name: Build + run: make build diff --git a/.github/workflows/_go-versions.yml b/.github/workflows/_go-versions.yml new file mode 100644 index 0000000..d07ee74 --- /dev/null +++ b/.github/workflows/_go-versions.yml @@ -0,0 +1,19 @@ +name: Go + +on: + workflow_call: + outputs: + go_versions: + description: "The golang version matrix" + value: ${{ jobs.go-versions.outputs.matrix }} + +jobs: + go-versions: + name: Lookup go versions + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.versions.outputs.matrix }} + steps: + - uses: actions/checkout@v3 + - uses: arnested/go-version-action@v1 + id: versions diff --git a/.github/workflows/_golangci-lint.yml b/.github/workflows/_golangci-lint.yml new file mode 100644 index 0000000..066c8d7 --- /dev/null +++ b/.github/workflows/_golangci-lint.yml @@ -0,0 +1,17 @@ +name: "golangci-lint" + +on: workflow_call + +permissions: + contents: read + pull-requests: read +jobs: + golangci: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: golangci-lint + uses: golangci/golangci-lint-action@v2 + with: + version: latest + only-new-issues: true diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml new file mode 100644 index 0000000..33c3993 --- /dev/null +++ b/.github/workflows/_test.yml @@ -0,0 +1,26 @@ +name: "Unit Tests" + +on: + workflow_call: + inputs: + go_versions: + type: string + description: Go versions to run workflow on + required: true + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + go_version: ${{ fromJSON(inputs.go_versions) }} + name: Go ${{ matrix.go_version }} unit tests + steps: + - uses: actions/checkout@v2 + + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go_version }} + + - run: make test diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index de8cb53..0000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Go - -on: - push: - branches: ["latest"] - pull_request: - branches: ["latest"] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: 1.18 - - - name: Build - run: go build -v ./... - - - name: Test and coverage - run: go test -cover -v ./... diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..307794f --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,26 @@ +name: "Pull Request" + +on: + pull_request: + branches: + - latest + +concurrency: + group: ci-tests-${{ github.ref }}-1 + cancel-in-progress: true + +jobs: + go-versions: + uses: ./.github/workflows/_go-versions.yml + call-lint: + uses: ./.github/workflows/_golangci-lint.yml + call-build: + uses: ./.github/workflows/_build.yml + needs: go-versions + with: + go_versions: ${{ needs.go-versions.outputs.go_versions }} + call-test: + uses: ./.github/workflows/_test.yml + needs: go-versions + with: + go_versions: ${{ needs.go-versions.outputs.go_versions }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..bf56245 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,31 @@ +name: goreleaser + +on: + push: + tags: + - "v*" # Versioning tags + +permissions: + contents: write # Required to upload dist files + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.19 + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v2 + with: + version: latest + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 66fd13c..f70e817 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,15 @@ # Test binary, built with `go test -c` *.test -# Output of the go coverage tool, specifically when used with LiteIDE -*.out +# Output of the go coverage tool +coverage.* # Dependency directories (remove the comment below to include it) # vendor/ + +# CI +build/ + +# Editors +*~ +.vscode diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..3b47548 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,32 @@ +before: + hooks: + - go mod tidy +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + main: ./cmd/server +archives: + - replacements: + darwin: macos + linux: linux + windows: windows + 386: i386 + amd64: x86_64 +source: + enabled: true + name_template: "{{ .ProjectName }}-{{ .Version }}-sources" + format: "tar.gz" +checksum: + name_template: "checksums.txt" +snapshot: + name_template: "{{ .Tag }}-dev" +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" diff --git a/Containerfile b/Containerfile new file mode 100644 index 0000000..90e402d --- /dev/null +++ b/Containerfile @@ -0,0 +1,22 @@ +# Build stage +ARG GOLANG_VERSION +ARG ALPINE_VERSION + +FROM docker.io/library/golang:${GOLANG_VERSION}-alpine${ALPINE_VERSION} AS builder +WORKDIR /src +COPY . . +RUN apk add --no-cache ca-certificates tzdata make && \ + make build + +# Server image +FROM scratch + +ENV PORT 8080 +LABEL org.opencontainers.image.source="https://github.com/fmartingr/bazaar" +LABEL maintainer="Felipe Martin " + +COPY --from=builder /src/build/bazaar /usr/bin/ +COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt + +ENTRYPOINT ["/usr/bin/bazaar"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..92e752f --- /dev/null +++ b/Makefile @@ -0,0 +1,99 @@ +PROJECT_NAME := bazaar + +GOLANG_VERSION=1.19 + +VERSION_COMMIT := $git rev-parse --short HEAD) +SOURCE_FILES ?=./internal/... ./cmd/... ./pkg/... + +TEST_OPTIONS ?= -v -failfast -race -bench=. -benchtime=100000x -cover -coverprofile=coverage.out +TEST_TIMEOUT ?=1m + +CLEAN_OPTIONS ?=-modcache -testcache + +LD_FLAGS := -X main.version=$(VERSION) -s -w +CGO_ENABLED := 0 + +BUILDS_PATH := ./build +FROM_MAKEFILE := y + +CONTAINER_RUNTIME := podman +CONTAINERFILE_NAME := Containerfile +CONTAINER_GOLANG_VERSION := ${GOLANG_VERSION} +CONTAINER_ALPINE_VERSION := 3.16 +CONTAINER_IMAGE_NAME := fmartingr/${PROJECT_NAME} +CONTAINER_IMAGE_TAG := dev + +# Common exports +export FROM_MAKEFILE +export VERSION_COMMIT + +export LD_FLAGS +export CGO_ENABLED + +export SOURCE_FILES +export TEST_OPTIONS +export TEST_TIMEOUT +export BUILDS_PATH + +export CONTAINER_RUNTIME +export CONTAINERFILE_NAME +export CONTAINER_GOLANG_VERSION +export CONTAINER_ALPINE_VERSION +export CONTAINER_IMAGE_NAME +export CONTAINER_IMAGE_TAG + +.PHONY: all +all: help + +# this is godly +# https://news.ycombinator.com/item?id=11939200 +.PHONY: help +help: ### this screen. Keep it first target to be default +ifeq ($(UNAME), Linux) + @grep -P '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \ + awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' +else + @# this is not tested, but prepared in advance for you, Mac drivers + @awk -F ':.*###' '$$0 ~ FS {printf "%15s%s\n", $$1 ":", $$2}' \ + $(MAKEFILE_LIST) | grep -v '@awk' | sort +endif + +.PHONY: clean +clean: ### clean test cache, build files + $(info: Make: Clean) + @rm -rf ${BUILDS_PATH} + @go clean ${CLEAN_OPTIONS} + +.PHONY: build +build: clean ### builds the project for the setup os/arch combinations + $(info: Make: Build) + @go build -a -v -ldflags "${LD_FLAGS}" -o ${BUILDS_PATH}/bazaar ./cmd/bazaar/*.go + @chmod +x ${BUILDS_PATH}/bazaar + +.PHONY: build-container-image +build-container: + $(info: Make: Container image) + @bash scripts/build-container-image.sh + +.PHONY: quick-run +quick-run: ### Executes the project using golang + @go run ./cmd/bazaar/*.go + +.PHONY: run +run: ### Executes the project build locally + @make build + ${BUILDS_PATH}/bazaar + +.PHONY: format +format: ### Executes the formatting pipeline on the project + $(info: Make: Format) + @bash scripts/format.sh + +.PHONY: lint +lint: ### Check the project for errors + $(info: Make: Lint) + @bash scripts/lint.sh + +.PHONY: test +test: ### Runs the test suite + @bash scripts/test.sh diff --git a/cmd/server/main.go b/cmd/bazaar/main.go similarity index 100% rename from cmd/server/main.go rename to cmd/bazaar/main.go diff --git a/go.mod b/go.mod index 5937287..1057ca1 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/fmartingr/bazaar -go 1.18 +go 1.19 require ( github.com/PuerkitoBio/goquery v1.8.0 @@ -12,6 +12,6 @@ require ( github.com/andybalholm/cascadia v1.3.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 // indirect + golang.org/x/net v0.0.0-20220809012201-f428fae20770 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c3f1a97..ebb0aa3 100644 --- a/go.sum +++ b/go.sum @@ -15,8 +15,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 h1:N9Vc/rorQUDes6B9CNdIxAn5jODGj2wzfrei2x4wNj4= -golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220809012201-f428fae20770 h1:dIi4qVdvjZEjiMDv7vhokAZNGnz3kepwuXqFKYDdDMs= +golang.org/x/net v0.0.0-20220809012201-f428fae20770/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/scripts/build-container-image.sh b/scripts/build-container-image.sh new file mode 100644 index 0000000..23421d3 --- /dev/null +++ b/scripts/build-container-image.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e + +if [ -z "$FROM_MAKEFILE" ]; then + echo "Do not call this file directly - use the make command" + exit 1 +fi + +${CONTAINER_RUNTIME} build --build-arg "GOLANG_VERSION=${CONTAINER_GOLANG_VERSION}" --build-arg="ALPINE_VERSION=${CONTAINER_ALPINE_VERSION}" -t ${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG} -f ${CONTAINERFILE_NAME} . diff --git a/scripts/format.sh b/scripts/format.sh new file mode 100644 index 0000000..ffcea17 --- /dev/null +++ b/scripts/format.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -e + +if [ -z "$FROM_MAKEFILE" ]; then + echo "Do not call this file directly - use the make command" + exit 1 +fi + +# Enable/Disable formatters +GOFMT_ENABLED=${GOFMT_ENABLED:-y} + +# Add go binaries path to current $PATH +PATH=$PATH:$(go env GOPATH)/bin + +files=$(find . -name '*.go') + +for file in $files +do + if [ "$GOFMT_ENABLED" == "y" ]; then + gofmt -w -s $file + fi +done diff --git a/scripts/lint.sh b/scripts/lint.sh new file mode 100644 index 0000000..e3d81d7 --- /dev/null +++ b/scripts/lint.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e + +if [ -z "$FROM_MAKEFILE" ]; then + echo "Do not call this file directly - use the make command" + exit 1 +fi + +golangci-lint run --tests=false diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100644 index 0000000..35fe703 --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e + +if [ -z "$FROM_MAKEFILE" ]; then + echo "Do not call this file directly - use the make command" + exit 1 +fi + +COVERAGE_PATH=coverage.out +COVERAGE_HTML_PATH=coverage.html +CGO_ENABLED=1 # Used for -race + +go test ${TEST_OPTIONS} ${SOURCE_FILES} -timeout=${TEST_TIMEOUT} + +echo +echo "== Coverage report ==" +echo + +go tool cover -html=${COVERAGE_PATH} -o ${COVERAGE_HTML_PATH} +go tool cover -func=${COVERAGE_PATH}