Skip to content

Commit

Permalink
Adding golangci-lint Linter to CI (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
matheusgomes28 authored Feb 18, 2024
1 parent 0188d1c commit aed7699
Show file tree
Hide file tree
Showing 16 changed files with 161 additions and 75 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/actions/golangci-lint/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: golangci-lint step
description: golangci-lint step
inputs:
linters:
description: Linter to run
required: true
runs:
using: composite
steps:
- name: Generating templ files
run: |
templ generate
shell: bash

- name: prepping lint commands
id: set-command
run: |
export LINTERS="${{ inputs.linters }}"
export LINTER_CMD="golangci-lint run --disable-all -E ${LINTERS//;/ -E }"
echo "linter_cmd=${LINTER_CMD}" >> $GITHUB_OUTPUT
shell: bash

- name: running the linter command
run: eval ${{ steps.set-command.outputs.linter_cmd }}
shell: bash
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

runs-on: ubuntu-latest
container:
image: mattgomes28/urchin-golang:0.1
image: mattgomes28/urchin-golang:0.2
options: --user 1001

steps:
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/failfast.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Fail Fast

on: [workflow_call]

jobs:
linters:
name: Linters 🧑‍🔬

runs-on: ubuntu-latest
container:
image: mattgomes28/urchin-golang:0.2
options: --user 1001

steps:
- uses: actions/checkout@v3

- uses: ./.github/workflows/actions/golangci-lint
name: Running Linters 🧪
with:
linters: errcheck;staticcheck;unused;gosimple;gofmt
7 changes: 4 additions & 3 deletions .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ on:
branches: [ "main" ]

jobs:
# failfast:
# uses: ./.github/workflows/failfast.yml
failfast:
uses: ./.github/workflows/failfast.yml

build:
uses: ./.github/workflows/build.yml
# needs: failfast
needs: failfast
# tests:
# uses: ./.github/workflows/test.yml
# needs: build
Expand Down
29 changes: 17 additions & 12 deletions admin-app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func getPostHandler(database *database.Database) func(*gin.Context) {
if err := c.ShouldBindUri(&post_binding); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "could not get post id",
"msg": err.Error(),
"msg": err.Error(),
})
return
}
Expand All @@ -49,7 +49,7 @@ func getPostHandler(database *database.Database) func(*gin.Context) {
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "invalid post id type",
"msg": err.Error(),
"msg": err.Error(),
})
return
}
Expand All @@ -59,14 +59,14 @@ func getPostHandler(database *database.Database) func(*gin.Context) {
log.Warn().Msgf("could not get post from DB: %v", err)
c.JSON(http.StatusNotFound, gin.H{
"error": "post id not found",
"msg": err.Error(),
"msg": err.Error(),
})
return
}

c.JSON(http.StatusOK, gin.H{
"id": post.Id,
"title": post.Title,
"id": post.Id,
"title": post.Title,
"excerpt": post.Excerpt,
"content": post.Content,
})
Expand All @@ -83,7 +83,7 @@ func postPostHandler(database *database.Database) func(*gin.Context) {
log.Warn().Msgf("could not get post from DB: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "invalid request body",
"msg": err.Error(),
"msg": err.Error(),
})
return
}
Expand All @@ -97,7 +97,7 @@ func postPostHandler(database *database.Database) func(*gin.Context) {
log.Error().Msgf("failed to add post: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "could not add post",
"msg": err.Error(),
"msg": err.Error(),
})
return
}
Expand All @@ -119,7 +119,7 @@ func putPostHandler(database *database.Database) func(*gin.Context) {
log.Warn().Msgf("could not get post from DB: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "invalid request body",
"msg": err.Error(),
"msg": err.Error(),
})
return
}
Expand All @@ -134,7 +134,7 @@ func putPostHandler(database *database.Database) func(*gin.Context) {
log.Error().Msgf("failed to change post: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "could not change post",
"msg": err.Error(),
"msg": err.Error(),
})
return
}
Expand All @@ -156,7 +156,7 @@ func deletePostHandler(database *database.Database) func(*gin.Context) {
log.Warn().Msgf("could not delete post: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "invalid request body",
"msg": err.Error(),
"msg": err.Error(),
})
return
}
Expand All @@ -166,7 +166,7 @@ func deletePostHandler(database *database.Database) func(*gin.Context) {
log.Error().Msgf("failed to delete post: %v", err)
c.JSON(http.StatusBadRequest, gin.H{
"error": "could not delete post",
"msg": err.Error(),
"msg": err.Error(),
})
return
}
Expand All @@ -186,7 +186,12 @@ func Run(app_settings common.AppSettings, database database.Database) error {
r.POST("/posts", postPostHandler(&database))
r.PUT("/posts", putPostHandler(&database))
r.DELETE("/posts", deletePostHandler(&database))
r.Run(fmt.Sprintf(":%s", app_settings.WebserverPort))

err := r.Run(fmt.Sprintf(":%s", app_settings.WebserverPort))
if err != nil {
log.Error().Msgf("could not run app: %v", err)
return err
}

return nil
}
27 changes: 18 additions & 9 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,22 @@ type Generator = func(*gin.Context, common.AppSettings, *database.Database) ([]b
func Run(app_settings common.AppSettings, database *database.Database) error {
r := gin.Default()
r.MaxMultipartMemory = 1

// All cache-able endpoints
cache := makeCache(4, time.Minute * 10)
cache := makeCache(4, time.Minute*10)
addCachableHandler(r, "GET", "/", homeHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/contact", contactHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/post/:id", postHandler, &cache, app_settings, database)

// DO not cache as it needs to handlenew form values
r.POST("/contact-send", makeContactFormHandler())


r.Static("/static", "./static")
r.Run(fmt.Sprintf(":%s", app_settings.WebserverPort))
err := r.Run(fmt.Sprintf(":%s", app_settings.WebserverPort))
if err != nil {
log.Error().Msgf("could not run app: %v", err)
return err
}

return nil
}
Expand All @@ -46,7 +49,7 @@ func addCachableHandler(e *gin.Engine, method string, endpoint string, generator
c.Data(http.StatusOK, "text/html; charset=utf-8", cached_endpoint.contents)
return
}

// Before handler call (retrieve from cache)
html_buffer, err := generator(c, app_settings, db)
if err != nil {
Expand Down Expand Up @@ -76,8 +79,8 @@ func addCachableHandler(e *gin.Engine, method string, endpoint string, generator
}
}

/// This function will act as the handler for
/// the home page
// / This function will act as the handler for
// / the home page
func homeHandler(c *gin.Context, settings common.AppSettings, db *database.Database) ([]byte, error) {
posts, err := db.GetPosts()
if err != nil {
Expand All @@ -87,6 +90,12 @@ func homeHandler(c *gin.Context, settings common.AppSettings, db *database.Datab
// if not cached, create the cache
index_view := views.MakeIndex(posts)
html_buffer := bytes.NewBuffer(nil)
index_view.Render(c, html_buffer)

err = index_view.Render(c, html_buffer)
if err != nil {
log.Error().Msgf("could not render index: %v", err)
return []byte{}, err
}

return html_buffer.Bytes(), nil
}
24 changes: 12 additions & 12 deletions app/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import (

// Do not store over this amount
// of MBs in the cache
const MAX_CACHE_SIZE_MB = 10;
const MAX_CACHE_SIZE_MB = 10

type EndpointCache struct {
name string
contents []byte
name string
contents []byte
validUntil time.Time
}

Expand All @@ -23,21 +23,21 @@ func emptyEndpointCache() EndpointCache {
}

type Cache struct {
cacheMap shardedmap.ShardMap
cacheTimeout time.Duration
cacheMap shardedmap.ShardMap
cacheTimeout time.Duration
estimatedSize atomic.Uint64 // in bytes
}

func (self *Cache) Store(name string, buffer []byte) error {
// Only store to the cache if we have enough space left
afterSizeMB := float64(self.estimatedSize.Load() + uint64(len(buffer))) / 1000000;
afterSizeMB := float64(self.estimatedSize.Load()+uint64(len(buffer))) / 1000000
if afterSizeMB > MAX_CACHE_SIZE_MB {
return fmt.Errorf("maximum size reached")
}

var cache_entry interface{} = EndpointCache{
name: name,
contents: buffer,
name: name,
contents: buffer,
validUntil: time.Now().Add(self.cacheTimeout),
}
self.cacheMap.Set(name, &cache_entry)
Expand All @@ -55,8 +55,8 @@ func (self *Cache) Get(name string) (EndpointCache, error) {
if cache_contents.validUntil.After(time.Now()) {
return cache_contents, nil
} else {
self.cacheMap.Delete(name)
return emptyEndpointCache(), fmt.Errorf("cached endpoint had expired")
self.cacheMap.Delete(name)
return emptyEndpointCache(), fmt.Errorf("cached endpoint had expired")
}
}

Expand All @@ -69,8 +69,8 @@ func (self *Cache) Size() uint64 {

func makeCache(n_shards int, expiry_duration time.Duration) Cache {
return Cache{
cacheMap: shardedmap.NewShardMap(n_shards),
cacheTimeout: expiry_duration,
cacheMap: shardedmap.NewShardMap(n_shards),
cacheTimeout: expiry_duration,
estimatedSize: atomic.Uint64{},
}
}
33 changes: 26 additions & 7 deletions app/contact.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,61 @@ import (
"github.com/matheusgomes28/urchin/common"
"github.com/matheusgomes28/urchin/database"
"github.com/matheusgomes28/urchin/views"
"github.com/rs/zerolog/log"
)

func makeContactFormHandler() func(*gin.Context) {
return func(c *gin.Context) {
c.Request.ParseForm()
if err := c.Request.ParseForm(); err != nil {
log.Error().Msgf("could not parse form %v", err)
if err = render(c, http.StatusOK, views.MakeContactFailure("unknown", err.Error())); err != nil {
log.Error().Msgf("could not render %v", err)
}
return
}

email := c.Request.FormValue("email")
name := c.Request.FormValue("name")
message := c.Request.FormValue("message")

// Parse email
_, err := mail.ParseAddress(email)
if err != nil {
render(c, http.StatusOK, views.MakeContactFailure(email, err.Error()))
log.Error().Msgf("could not parse email: %v", err)
if err = render(c, http.StatusOK, views.MakeContactFailure(email, err.Error())); err != nil {
log.Error().Msgf("could not render: %v", err)
}
return
}

// Make sure name and message is reasonable
if len(name) > 200 {
render(c, http.StatusOK, views.MakeContactFailure(email, "name too long (200 chars max)"))
if err = render(c, http.StatusOK, views.MakeContactFailure(email, "name too long (200 chars max)")); err != nil {
log.Error().Msgf("could not render: %v", err)
}
return
}
}

if len(message) > 10000 {
render(c, http.StatusOK, views.MakeContactFailure(email, "message too long (1000 chars max)"))
if err = render(c, http.StatusOK, views.MakeContactFailure(email, "message too long (1000 chars max)")); err != nil {
log.Error().Msgf("could not render: %v", err)
}
return
}

render(c, http.StatusOK, views.MakeContactSuccess(email, name))
if err = render(c, http.StatusOK, views.MakeContactSuccess(email, name)); err != nil {
log.Error().Msgf("could not render: %v", err)
}
}
}

// TODO : This is a duplicate of the index handler... abstract
func contactHandler(c *gin.Context, app_settings common.AppSettings, db *database.Database) ([]byte, error) {
index_view := views.MakeContactPage()
html_buffer := bytes.NewBuffer(nil)
index_view.Render(c, html_buffer)
if err := index_view.Render(c, html_buffer); err != nil {
log.Error().Msgf("could not render: %v", err)
}

return html_buffer.Bytes(), nil
}
Loading

0 comments on commit aed7699

Please sign in to comment.