-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2f50944
commit 0056295
Showing
8 changed files
with
361 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
globals: | ||
onFailure: | ||
# This failure handler will be called failed of any step in the pipeline | ||
# comment this out if you do not want to integrate pipeline with slack | ||
- handlerName: slack-notify-error | ||
|
||
failureHandlers: | ||
- name: debug-env | ||
image: busybox | ||
script: | | ||
echo "### PWD" | ||
pwd | ||
echo "### ENV" | ||
env | ||
echo "ls -la" | ||
ls -la | ||
- name: slack-notify-error | ||
image: iceci/utils | ||
script: | | ||
cat <<EOF > slacknotify.json | ||
{ | ||
"text" : "Build $ICE_BUILD_NUMBER on branch $ICE_GIT_BRANCH_NAME failed on step $ICE_FAILED_STEP_NAME commited by $ICE_GIT_AUTHOR_NAME" | ||
} | ||
EOF | ||
curl -X POST -H 'Content-type: application/json' --data "@slacknotify.json" $SLACK_WEBHOOK | ||
environment: | ||
- name: SLACK_WEBHOOK | ||
fromSecret: slack-webhook | ||
|
||
# Service with postgres will run during whole pipeline | ||
services: | ||
- name: db | ||
image: postgres:11 | ||
environment: | ||
- name: POSTGRES_DB | ||
value: testdb | ||
- name: POSTGRES_PASSWORD | ||
value: dbpass | ||
- name: POSTGRES_USER | ||
value: dbuser | ||
|
||
steps: | ||
- name: test-and-build | ||
containerRun: | ||
image: golang:1.14 | ||
script: | | ||
go test ./cmd | ||
go build -o example-go-app cmd/main.go | ||
environment: | ||
- name: CGO_ENABLED | ||
value: 0 | ||
- name: APP_PORT | ||
value: 8000 | ||
- name: DB_HOST | ||
value: db | ||
- name: DB_PORT | ||
value: 5432 | ||
- name: DB_USER | ||
value: dbuser | ||
- name: DB_PASS | ||
value: dbpass | ||
- name: DB_NAME | ||
value: testdb | ||
- name: DB_DIALECT | ||
value: postgres | ||
|
||
- name: build-docker-image | ||
containerBuild: | ||
dockerSecret: dockerhub | ||
user: iceci | ||
imageName: example-go-webapp | ||
tags: | ||
- "{{ ICE_BUILD_NUMBER }}" | ||
- latest | ||
|
||
# comment this step out if you do not want to integrate this pipeline with slack | ||
- name: slack-notify | ||
containerRun: | ||
image: iceci/utils | ||
script: | | ||
cat <<EOF > slacknotify.json | ||
{ | ||
"text" : "Build $ICE_BUILD_NUMBER on branch $ICE_GIT_BRANCH_NAME finished successfully!" | ||
} | ||
EOF | ||
curl -X POST -H 'Content-type: application/json' --data "@slacknotify.json" $SLACK_WEBHOOK | ||
environment: | ||
- name: SLACK_WEBHOOK | ||
fromSecret: slack-webhook |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
FROM scratch | ||
|
||
ADD example-go-app /example-go-app | ||
|
||
CMD ["/example-go-app"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,23 @@ | ||
# example-go-gin-api | ||
# IceCI Go example - Gin API | ||
|
||
This repository is a small example to help you get started building **IceCI** pipelines for Go applications. | ||
|
||
The application itself is a very simplified example of a web API with tests. It's not by any means a guideline on building Go applications - its only purpose is showcasing how to build IceCI pipelines for Go applications. | ||
|
||
This repository is a *GitHub template repository*, so please feel free to create new repositories based on it and mess around with the code and the pipeline config. Please also check the information below for a list of prerequisites needed to run the pipeline in IceCI. | ||
|
||
# Setting up IceCI | ||
|
||
|
||
To launch the pipeline in IceCI you have to create 2 secrets - both of which are explicitly referenced in the `.iceci.yaml` file. | ||
|
||
* `dockerhub` - docker hub credentials with `docker.io` set as registry. | ||
|
||
* `slack-webhook` - a generic secret with hook for Slack notifications - it can be ignored by commenting out the `slack-notify` step as well as the `slack-notify-error` failure handler in the pipeline definition file. | ||
|
||
You can also find some additional info in the comments of the `.iceci.yaml` file itself. | ||
|
||
|
||
--- | ||
|
||
Kept cool 🧊 by [Icetek](https://icetek.io/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"github.com/gin-gonic/gin" | ||
"github.com/jinzhu/gorm" | ||
_ "github.com/jinzhu/gorm/dialects/postgres" | ||
"github.com/kelseyhightower/envconfig" | ||
"net/http" | ||
) | ||
|
||
type AppConfig struct { | ||
Port string `required:"true"` | ||
} | ||
|
||
type DbConfig struct { | ||
Host string `required:"true"` | ||
Port string `required:"true"` | ||
User string `required:"true"` | ||
Pass string `required:"true"` | ||
Name string `required:"true"` | ||
Dialect string `required:"true"` | ||
SSLMode string `default:"disable"` | ||
} | ||
|
||
type Quote struct { | ||
Id uint | ||
Quote string | ||
Author string | ||
} | ||
|
||
func loadDbConfig() (*DbConfig, error) { | ||
config := &DbConfig{} | ||
err := envconfig.Process("DB", config) | ||
if err != nil { | ||
return nil, errors.New(fmt.Sprintf("cannot load db config, %s", err)) | ||
} | ||
|
||
return config, nil | ||
} | ||
|
||
func loadAppConfig() (*AppConfig, error) { | ||
config := &AppConfig{} | ||
err := envconfig.Process("APP", config) | ||
if err != nil { | ||
return nil, errors.New(fmt.Sprintf("cannot load app config, %s", err)) | ||
} | ||
|
||
return config, nil | ||
} | ||
|
||
func setupDb(dbConfig *DbConfig) (*gorm.DB, error) { | ||
connString := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=%s", | ||
dbConfig.Host, dbConfig.Port, dbConfig.User, dbConfig.Name, dbConfig.Pass, dbConfig.SSLMode) | ||
|
||
db, err := gorm.Open(dbConfig.Dialect, connString) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
db.AutoMigrate(Quote{}) | ||
|
||
return db, nil | ||
} | ||
|
||
func setupRouter(db *gorm.DB) (*gin.Engine, error) { | ||
ginEngine := gin.Default() | ||
ginEngine.GET("/health", func(c *gin.Context) { | ||
c.String(http.StatusOK, "ok") | ||
}) | ||
|
||
ginEngine.GET("/quote", func(c *gin.Context) { | ||
var quotes []Quote | ||
query := db.Find("es) | ||
|
||
if query.Error != nil { | ||
c.JSON(http.StatusInternalServerError, gin.H{"message": "Error fetching rows"}) | ||
return | ||
} | ||
|
||
c.JSON(http.StatusOK, quotes) | ||
}) | ||
|
||
return ginEngine, nil | ||
} | ||
|
||
func main() { | ||
appConfig, err := loadAppConfig() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
dbConfig, err := loadDbConfig() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
db, err := setupDb(dbConfig) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
ginEngine, err := setupRouter(db) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
err = ginEngine.Run(fmt.Sprintf(":%s", appConfig.Port)) | ||
|
||
if err != nil { | ||
panic(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/jinzhu/gorm" | ||
"github.com/stretchr/testify/assert" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
) | ||
|
||
func TestWebEndpoints(t *testing.T) { | ||
a := assert.New(t) | ||
|
||
dbConfig, err := loadDbConfig() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
db, err := setupDb(dbConfig) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
router, err := setupRouter(db) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
setupFixtures(db) | ||
|
||
t.Run("health endpoint should return status 200", func(t *testing.T) { | ||
req, _ := http.NewRequest("GET", "/health", nil) | ||
w := httptest.NewRecorder() | ||
router.ServeHTTP(w, req) | ||
|
||
a.Equal(200, w.Code) | ||
a.Equal("ok", w.Body.String()) | ||
}) | ||
|
||
t.Run("quotes endpoint should return an element", func(t *testing.T) { | ||
var result []map[string]interface{} | ||
|
||
req, _ := http.NewRequest("GET", "/quote", nil) | ||
w := httptest.NewRecorder() | ||
router.ServeHTTP(w, req) | ||
err := json.Unmarshal(w.Body.Bytes(), &result) | ||
if err != nil { | ||
t.Fatal(fmt.Sprintf("failed parsing endpoint response, %s", err)) | ||
} | ||
|
||
a.Equal(200, w.Code) | ||
a.Equal(1, len(result)) | ||
}) | ||
|
||
teardownFixtures(db) | ||
} | ||
|
||
func setupFixtures(db *gorm.DB) { | ||
quote := Quote{ | ||
Quote: "A day without sunshine is like, you know, night", | ||
Author: "Steve Martin", | ||
} | ||
|
||
db.Create("e) | ||
} | ||
|
||
func teardownFixtures(db *gorm.DB) { | ||
db.Delete(Quote{}, "author = ?", "Steve Martin") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module github.com/iceCI/example-go-gin-api | ||
|
||
go 1.13 | ||
|
||
require ( | ||
github.com/gin-gonic/gin v1.6.2 | ||
github.com/jinzhu/gorm v1.9.12 | ||
github.com/kelseyhightower/envconfig v1.4.0 | ||
github.com/stretchr/testify v1.4.0 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= | ||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= | ||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= | ||
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= | ||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= | ||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= | ||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= | ||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= | ||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | ||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= | ||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= | ||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= | ||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= | ||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= | ||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= | ||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= | ||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | ||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= | ||
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | ||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= | ||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | ||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |