Skip to content

Commit

Permalink
chore: whole project refactoring
Browse files Browse the repository at this point in the history
fix: tests and moving components

fix:
- CI: removed circleci as it is duplicated with gh actions
- GH action: fixed
- Dockerfile handle new paths
- GoReleaser fixed path

fix: errors handling and utility funcs
- error handling when payload is empty
- better error handling for some utility functions
- validation error parser rewritten

refactor: some improvements on error handling and code organization:
- URL for validateURL are strictly checked
- Request are checked for their response http code
- Common routine for validate requests
  • Loading branch information
sebbalex committed Oct 28, 2020
1 parent 5fe7b05 commit ed951a3
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 106 deletions.
15 changes: 0 additions & 15 deletions .circleci/config.yml

This file was deleted.

6 changes: 3 additions & 3 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.13
go-version: ^1.15
id: go

- name: Check out code into the Go module directory
uses: actions/checkout@v2

- name: Build
run: go build -o publiccode-validator -v ./src
run: go build -o publiccode-validator

- name: Test
run: go test -v ./src
run: go test -race
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
app.log
publiccode-validator
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ builds:
-
id: publiccode-validator
binary: publiccode-validator
main: ./src
main: main.go
ldflags:
- -s -w -X main.version={{.Version}} -X main.date={{.Date}}
env:
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ENV BIN /usr/local/bin/publiccode-validator

WORKDIR /go/src

COPY ./src/ .
COPY ./ .
COPY .git/ .

RUN apk add git
Expand Down
118 changes: 52 additions & 66 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,19 @@ import (
"github.com/ghodss/yaml"
"github.com/gorilla/mux"
publiccode "github.com/italia/publiccode-parser-go"
"github.com/italia/publiccode-validator/apiv1"
"github.com/italia/publiccode-validator/utils"
)

//Message json type mapping, for test purpose
type Message struct {
Status int `json:"status"`
Message string `json:"message"`
Publiccode *publiccode.PublicCode `json:"pc,omitempty"`
Error string `json:"error,omitempty"`
ValidationError []ErrorInvalidValue `json:"validationErrors,omitempty"`
}

// App application main settings and export for tests
type App struct {
Router *mux.Router
Port string
Debug bool
DisableNetwork bool
}

var (
version string
date string
)

// main server start
func main() {
app := App{}
app.init()
app.Run()
}
// App localize type
type App utils.App

func (app *App) init() {
app.Port = "5000"
app.DisableNetwork = false
func init() {
if version == "" {
version = "devel"
if info, ok := debug.ReadBuildInfo(); ok {
Expand All @@ -57,19 +36,28 @@ func (app *App) init() {
if date == "" {
date = "(latest)"
}
app.Router = mux.NewRouter()
app.initializeRouters()
log.Infof("version %s compiled %s\n", version, date)
}

// Run http server
func (app *App) Run() {
log.Infof("version %s compiled %s\n", version, date)
// main server start
func main() {
app := App{}
app.Port = "5000"
app.DisableNetwork = false
app.initializeRouters()

// server run here because of tests
// https://github.com/gorilla/mux#testing-handlers
log.Infof("server is starting at port %s", app.Port)
log.Fatal(http.ListenAndServe(":"+app.Port, app.Router))
}

func (app *App) initializeRouters() {
//init router
app.Router = mux.NewRouter()
var api = app.Router.PathPrefix("/api").Subrouter()
var api1 = api.PathPrefix("/v1").Subrouter()

// v0
app.Router.
HandleFunc("/pc/validate", app.validateParam).
Methods("POST", "OPTIONS").
Expand All @@ -84,30 +72,24 @@ func (app *App) initializeRouters() {
Methods("POST", "OPTIONS").
Queries("url", "{url}")

//v1
app.Router.
HandleFunc("/v1/validate", app.validatev1).
Methods("POST", "OPTIONS")

}

// setupResponse set CORS header
func setupResponse(w *http.ResponseWriter, req *http.Request) {
//cors mode
(*w).Header().Set("Access-Control-Allow-Origin", "*")
(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
// v1
api1.
HandleFunc("/validate", apiv1.Validate)
// Methods("POST", "OPTIONS", "GET")
}

// parse returns new parsed and validated buffer and errors if any
func (app *App) parse(b []byte) ([]byte, error, error) {
url := getURLFromYMLBuffer(b)
url, err := utils.GetURLFromYMLBuffer(b)
if err != nil {
return nil, nil, err
}
p := publiccode.NewParser()
p.DisableNetwork = app.DisableNetwork

if url != nil {
p.DisableNetwork = app.DisableNetwork
p.RemoteBaseURL = getRawURL(url)
p.RemoteBaseURL = utils.GetRawURL(url)
}
log.Debugf("parse() called with disableNetwork: %v, and remoteBaseUrl: %s", p.DisableNetwork, p.RemoteBaseURL)
errParse := p.Parse(b)
Expand All @@ -121,7 +103,11 @@ func (app *App) parse(b []byte) ([]byte, error, error) {
func (app *App) parseRemoteURL(urlString string) ([]byte, error, error) {
log.Infof("called parseRemoteURL() url: %s", urlString)
p := publiccode.NewParser()
errParse := p.ParseRemoteFile(getRawFile(urlString))
urlString, err := utils.GetRawFile(urlString)
if err != nil {
return nil, nil, err
}
errParse := p.ParseRemoteFile(urlString)
pc, err := p.ToYAML()

return pc, errParse, err
Expand All @@ -132,7 +118,7 @@ func promptError(err error, w http.ResponseWriter,

log.Errorf(mess+": %v", err)

message := Message{
message := utils.Message{
Status: httpStatus,
Message: mess,
Error: err.Error(),
Expand All @@ -148,10 +134,10 @@ func promptValidationErrors(err error, w http.ResponseWriter,

log.Errorf(mess+": %v", err)

message := Message{
message := utils.Message{
Status: httpStatus,
Message: mess,
ValidationError: errorsToSlice(err),
ValidationError: utils.ErrorsToSlice(err),
}

w.Header().Set("Content-type", "application/json")
Expand All @@ -162,7 +148,7 @@ func promptValidationErrors(err error, w http.ResponseWriter,

func (app *App) validateRemoteURL(w http.ResponseWriter, r *http.Request) {
log.Info("called validateFromURL()")
setupResponse(&w, r)
utils.SetupResponse(&w, r)
if (*r).Method == "OPTIONS" {
return
}
Expand All @@ -174,7 +160,7 @@ func (app *App) validateRemoteURL(w http.ResponseWriter, r *http.Request) {
return
}

//parsing
// parsing
pc, errParse, errConverting := app.parseRemoteURL(urlString)

if errConverting != nil {
Expand All @@ -187,14 +173,14 @@ func (app *App) validateRemoteURL(w http.ResponseWriter, r *http.Request) {
}
promptValidationErrors(errParse, w, http.StatusUnprocessableEntity, "Validation Errors")
} else {
//set response CT based on client accept header
//and return respectively content
// set response CT based on client accept header
// and return respectively content
if r.Header.Get("Accept") == "application/json" {
w.Header().Set("Content-type", "application/json")
w.Write(yaml2json(pc))
w.Write(utils.Yaml2json(pc))
return
}
//default choice
// default choice
w.Header().Set("Content-type", "application/x-yaml")
w.Write(pc)
}
Expand All @@ -205,7 +191,7 @@ func (app *App) validateRemoteURL(w http.ResponseWriter, r *http.Request) {
// and then call normal validation
func (app *App) validateParam(w http.ResponseWriter, r *http.Request) {
log.Info("called validateParam()")
setupResponse(&w, r)
utils.SetupResponse(&w, r)
if (*r).Method == "OPTIONS" {
return
}
Expand All @@ -227,7 +213,7 @@ func (app *App) validateParam(w http.ResponseWriter, r *http.Request) {
// It accepts both format as input YML|JSON
func (app *App) validate(w http.ResponseWriter, r *http.Request) {
log.Info("called validate()")
setupResponse(&w, r)
utils.SetupResponse(&w, r)
if (*r).Method == "OPTIONS" {
return
}
Expand All @@ -237,9 +223,9 @@ func (app *App) validate(w http.ResponseWriter, r *http.Request) {
return
}

//Closing body after operations
// Closing body after operations
defer r.Body.Close()
//reading request
// reading request
body, err := ioutil.ReadAll(r.Body)
if err != nil {
promptError(err, w, http.StatusBadRequest, "Error reading body")
Expand All @@ -263,7 +249,7 @@ func (app *App) validate(w http.ResponseWriter, r *http.Request) {
m = body
}

//parsing
// parsing
var pc []byte
var errParse, errConverting error
pc, errParse, errConverting = app.parse(m)
Expand All @@ -282,14 +268,14 @@ func (app *App) validate(w http.ResponseWriter, r *http.Request) {
w.Write(json)
// promptError(errParse, w, http.StatusUnprocessableEntity, "Error parsing")
} else {
//set response CT based on client accept header
//and return respectively content
// set response CT based on client accept header
// and return respectively content
if r.Header.Get("Accept") == "application/json" {
w.Header().Set("Content-type", "application/json")
w.Write(yaml2json(pc))
w.Write(utils.Yaml2json(pc))
return
}
//default choice
// default choice
w.Header().Set("Content-type", "application/x-yaml")
w.Write(pc)
}
Expand Down
Loading

0 comments on commit ed951a3

Please sign in to comment.