From bec3d281849309c0d6030b35190ab14b67944ff0 Mon Sep 17 00:00:00 2001 From: Emad Mokhtar Date: Sun, 21 Apr 2024 11:12:00 +0200 Subject: [PATCH] V2/docker image (#107) * Add the docker image --- .env | 0 .github/workflows/docker-hub-push.yml | 34 +++ .github/workflows/go-test.yaml | 1 + .github/workflows/golangci-lint.yml | 1 + .github/workflows/semver-lable.yml | 24 ++ .gitignore | 5 +- .idea/.gitignore | 10 - .idea/.name | 1 - .idea/ChatGPTCopilotChannelManager.xml | 10 - .idea/dataSources.xml | 17 -- .idea/dbnavigator.xml | 403 ------------------------- .idea/modules.xml | 8 - .idea/sqldialects.xml | 6 - .idea/tafseer_api.iml | 9 +- .idea/vcs.xml | 2 +- Dockerfile | 33 ++ README.md | 18 +- config.yaml.example | 13 - config/config.go | 11 +- config/database.go | 12 +- config/logger.go | 35 ++- config/service.go | 6 +- go.mod | 7 +- go.sum | 15 +- main.go | 2 +- 25 files changed, 164 insertions(+), 519 deletions(-) create mode 100644 .env create mode 100644 .github/workflows/docker-hub-push.yml create mode 100644 .github/workflows/semver-lable.yml delete mode 100644 .idea/.gitignore delete mode 100644 .idea/.name delete mode 100644 .idea/ChatGPTCopilotChannelManager.xml delete mode 100644 .idea/dataSources.xml delete mode 100644 .idea/dbnavigator.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/sqldialects.xml create mode 100644 Dockerfile delete mode 100644 config.yaml.example diff --git a/.env b/.env new file mode 100644 index 0000000..e69de29 diff --git a/.github/workflows/docker-hub-push.yml b/.github/workflows/docker-hub-push.yml new file mode 100644 index 0000000..3e117dc --- /dev/null +++ b/.github/workflows/docker-hub-push.yml @@ -0,0 +1,34 @@ +name: Docker + +on: + push: + tags: + - 'v*' + +env: + IMAGE_NAME: tafseer_api + +jobs: + push_to_registry: + name: Push Docker image to Docker Hub + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Get the version + id: get_version + run: echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/} + + - name: Log in to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v2 + with: + context: . + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ steps.get_version.outputs.VERSION }} \ No newline at end of file diff --git a/.github/workflows/go-test.yaml b/.github/workflows/go-test.yaml index e2bb70c..b318094 100644 --- a/.github/workflows/go-test.yaml +++ b/.github/workflows/go-test.yaml @@ -5,6 +5,7 @@ on: branches: - master - main + - v2/master pull_request: jobs: diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 4a4e43b..54ea66b 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -4,6 +4,7 @@ on: branches: - master - main + - v2/master pull_request: permissions: diff --git a/.github/workflows/semver-lable.yml b/.github/workflows/semver-lable.yml new file mode 100644 index 0000000..a50ca97 --- /dev/null +++ b/.github/workflows/semver-lable.yml @@ -0,0 +1,24 @@ +name: Semantic Versioning Label + +on: + push: + branches: + - v2/master + +jobs: + semver_tag_from_pr: + # permissions required to find PR for last commit and push the new tag + permissions: + contents: write + pull-requests: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: "0" # we need full git-history to determine the last semVer tag + ssh-key: ${{ secrets.semver_github_action }} + - name: bump semVer + uses: simontheleg/semver-tag-from-pr-action@v1 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + repo_ssh_key: ${{ secrets.SEMVER_GITHUB_ACTION_PRIVATE }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index aaf9a70..3cc83a1 100644 --- a/.gitignore +++ b/.gitignore @@ -172,6 +172,5 @@ Temporary Items # End of https://www.toptal.com/developers/gitignore/api/goland,go,macos -### Project ### - -config.yaml \ No newline at end of file +# Project +.env \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index a9d7db9..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml -# GitHub Copilot persisted chat sessions -/copilot/chatSessions diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 1d9f371..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -tafseer_api \ No newline at end of file diff --git a/.idea/ChatGPTCopilotChannelManager.xml b/.idea/ChatGPTCopilotChannelManager.xml deleted file mode 100644 index 50a522f..0000000 --- a/.idea/ChatGPTCopilotChannelManager.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml deleted file mode 100644 index 92ea493..0000000 --- a/.idea/dataSources.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - postgresql - true - org.postgresql.Driver - jdbc:postgresql://localhost:5432/postgres - - - - - - $ProjectFileDir$ - - - \ No newline at end of file diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml deleted file mode 100644 index c362f6e..0000000 --- a/.idea/dbnavigator.xml +++ /dev/null @@ -1,403 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 5206b52..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml deleted file mode 100644 index 6df4889..0000000 --- a/.idea/sqldialects.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/tafseer_api.iml b/.idea/tafseer_api.iml index 5d81a31..7ee078d 100644 --- a/.idea/tafseer_api.iml +++ b/.idea/tafseer_api.iml @@ -1,11 +1,4 @@ - + - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 35eb1dd..94a25f7 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8c50c8b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +FROM golang:latest as builder + +LABEL maintainer="Emad Mokhtar " + +# Set the Current Working Directory inside the container +WORKDIR /app + +# Copy go mod and sum files +COPY go.mod go.sum ./ + +# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed +RUN go mod download + +# Copy the source from the current directory to the Working Directory inside the container +COPY . . + +# Build the Go app +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/service + +FROM alpine:latest + +RUN apk --no-cache add ca-certificates + +WORKDIR /root/ + +# Copy the Pre-built binary file from the previous stage +COPY --from=builder /app/main . + +# Expose port 8080 to the outside +EXPOSE 8080 + +# Command to run the executable +CMD ["./main"] \ No newline at end of file diff --git a/README.md b/README.md index 51835a9..13b0de7 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ -# Golang RESTful service template +# Quran REST API Service -Golang REST web service template. This template used Cookiecuttter template to generate new services. +Quran REST API Service. This service is written with Golang. ## Packages used -| Name | Purpose | -|-----------|--------------------------| -| [Echo][2] | Web Requests | -| [Zap][4] | Logging | -| [Gorm][3] | ORM & Database access | -| [Fig][1] | Configuration Management | +| Name | Purpose | +|----------------|--------------------------| +| [Echo][2] | Web Requests | +| [Zap][4] | Logging | +| [Gorm][3] | ORM & Database access | +| [Clean Env][1] | Configuration Management | -[1]: [https://github.com/kkyr/fig] +[1]: [https://github.com/ilyakaznacheev/cleanenv] [2]: [https://echo.labstack.com] [3]: [https://gorm.io] [4]: [https://github.com/uber-go/zap] \ No newline at end of file diff --git a/config.yaml.example b/config.yaml.example deleted file mode 100644 index 020efa7..0000000 --- a/config.yaml.example +++ /dev/null @@ -1,13 +0,0 @@ -database: - host: "localhost" - port: "5432" - dbname: "golang_rest_service_template" - username: "root" - password: "" - sslmode: "disable" -logger: - level: "debug" -service: - addr: "localhost" - port: "1323" - env: "dev" \ No newline at end of file diff --git a/config/config.go b/config/config.go index fe87cc7..d5a55f3 100644 --- a/config/config.go +++ b/config/config.go @@ -1,22 +1,27 @@ package config import ( - "github.com/kkyr/fig" + "github.com/ilyakaznacheev/cleanenv" "go.uber.org/zap" ) type Config struct { Service - Logger zap.Logger + Logger zap.Logger + LogLevel string `yaml:"log_level" env:"LOG_LEVEL" env-default:"info"` Database } func LoadConfig() (*Config, error) { var cfg Config - if err := fig.Load(&cfg, fig.File("config.yaml"), fig.UseEnv("svc")); err != nil { + if err := cleanenv.ReadEnv(&cfg); err != nil { return nil, err } return &cfg, nil } + +func (c Config) ConfigLogger() *zap.Logger { + return NewLogger(c.Env, c.LogLevel) +} diff --git a/config/database.go b/config/database.go index e4301ae..2cf8b1a 100644 --- a/config/database.go +++ b/config/database.go @@ -7,12 +7,12 @@ import ( ) type Database struct { - Host string `fig:"host" default:"localhost"` - Port string `fig:"port" default:"3306"` - User string `fig:"user" default:"root"` - Password string `fig:"password" default:""` - DBName string `fig:"dbname" default:"golang_rest_service_template"` - SSLMode string `fig:"sslmode" default:"disable"` + Host string `yaml:"host" env:"DB_HOST" env-default:"localhost"` + Port string `yaml:"port" env:"DB_PORT" env-default:"3306"` + User string `yaml:"user" env:"DB_USER" env-default:"root"` + Password string `yaml:"password" env:"DB_PASS" env-default:""` + DBName string `yaml:"dbname" env:"DB_NAME" env-default:"golang_rest_service_template"` + SSLMode string `yaml:"sslmode" env:"DB_SSL_MODE" env-default:"disable"` } func (db *Database) GetDSN() string { diff --git a/config/logger.go b/config/logger.go index eb2c5d1..d0e6c0d 100644 --- a/config/logger.go +++ b/config/logger.go @@ -1,17 +1,36 @@ package config -import "go.uber.org/zap" +import ( + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +func NewLogger(env string, logLevel string) *zap.Logger { + var config zap.Config -func NewLogger(env string) *zap.Logger { switch env { case "dev": - logger, _ := zap.NewDevelopment() - return logger + config = zap.NewDevelopmentConfig() case "prod": - logger, _ := zap.NewProduction() - return logger + config = zap.NewProductionConfig() default: - logger, _ := zap.NewDevelopment() - return logger + config = zap.NewDevelopmentConfig() } + + // Set the log level + switch logLevel { + case "debug": + config.Level = zap.NewAtomicLevelAt(zapcore.DebugLevel) + case "info": + config.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel) + case "warn": + config.Level = zap.NewAtomicLevelAt(zapcore.WarnLevel) + case "error": + config.Level = zap.NewAtomicLevelAt(zapcore.ErrorLevel) + default: + config.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel) + } + + logger, _ := config.Build() + return logger } diff --git a/config/service.go b/config/service.go index e434cba..a9eeb19 100644 --- a/config/service.go +++ b/config/service.go @@ -3,9 +3,9 @@ package config import "fmt" type Service struct { - Addr string `fig:"addr" default:"localhost"` - Port string `fig:"port" default:"1323"` - Env string `fig:"env" default:"dev"` + Addr string `yaml:"addr" env:"ADDR" env-default:"localhost"` + Port string `yaml:"port" env:"PORT" env-default:"8080"` + Env string `yaml:"env" env:"ENV" env-default:"dev"` } func (svc Service) FullAddress() string { diff --git a/go.mod b/go.mod index c025e82..40e7279 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module tafseer_api go 1.19 require ( - github.com/kkyr/fig v0.3.1 + github.com/ilyakaznacheev/cleanenv v1.5.0 github.com/labstack/echo/v4 v4.11.4 github.com/labstack/gommon v0.4.2 github.com/stretchr/testify v1.8.4 @@ -13,6 +13,7 @@ require ( ) require ( + github.com/BurntSushi/toml v1.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -20,11 +21,10 @@ require ( github.com/jackc/pgx/v5 v5.4.3 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/mapstructure v1.4.1 // indirect - github.com/pelletier/go-toml v1.9.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect @@ -38,4 +38,5 @@ require ( golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect ) diff --git a/go.sum b/go.sum index 73d02cf..d6a2f39 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,6 @@ +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -5,6 +8,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/ilyakaznacheev/cleanenv v1.5.0 h1:0VNZXggJE2OYdXE87bfSSwGxeiGt9moSR2lOrsHHvr4= +github.com/ilyakaznacheev/cleanenv v1.5.0/go.mod h1:a5aDzaJrLCQZsazHol1w8InnDcOX0OColm64SlIi6gk= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= @@ -15,8 +20,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/kkyr/fig v0.3.1 h1:GqsamO9dwY05t2xh6ubzjPPYw2It4hoWbKZEWmDxM0o= -github.com/kkyr/fig v0.3.1/go.mod h1:ItUILF8IIzgZOMhx5xpJ1W/bviQsWRKOwKXfE/tqUoA= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -29,10 +34,6 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 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= @@ -76,3 +77,5 @@ gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM= gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= gorm.io/gorm v1.25.8 h1:WAGEZ/aEcznN4D03laj8DKnehe1e9gYQAjW8xyPRdeo= gorm.io/gorm v1.25.8/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 h1:slmdOY3vp8a7KQbHkL+FLbvbkgMqmXojpFUO/jENuqQ= +olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3/go.mod h1:oVgVk4OWVDi43qWBEyGhXgYxt7+ED4iYNpTngSLX2Iw= diff --git a/main.go b/main.go index 259d29d..c8368c2 100644 --- a/main.go +++ b/main.go @@ -22,7 +22,7 @@ func Run() error { } // Setup logger - logger := config.NewLogger(cfg.Env) + logger := cfg.ConfigLogger() // Echo middlewares config.SetupMiddlewares(echoSvc, logger)