Skip to content

Add CI workflow to lint and check formatting of Go code #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .github/workflows/check-go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Check Go

# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/check-go.yml"
- "Taskfile.yml"
- "**.go"
pull_request:
paths:
- ".github/workflows/check-go.yml"
- "Taskfile.yml"
- "**.go"
schedule:
# Run every Tuesday at 8 AM UTC to catch breakage caused by changes to tools.
- cron: "0 8 * * TUE"
workflow_dispatch:
repository_dispatch:

jobs:
check-errors:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Install Task
uses: arduino/actions/setup-taskfile@master
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
version: 3.x

- name: Check for errors
run: task go:vet

check-style:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Install Task
uses: arduino/actions/setup-taskfile@master
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
version: 3.x

- name: Check style
run: task --silent go:lint

check-formatting:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Install Task
uses: arduino/actions/setup-taskfile@master
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
version: 3.x

- name: Format code
run: task go:format

- name: Check formatting
run: git diff --color --exit-code
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![Check Go status](https://github.com/arduino/libraries-repository-engine/actions/workflows/check-go.yml/badge.svg)](https://github.com/arduino/libraries-repository-engine/actions/workflows/check-go.yml)

BUILD
----------------------------

Expand Down
33 changes: 32 additions & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# See: https://taskfile.dev/#/usage
version: "3"

env:
vars:
DEFAULT_GO_PACKAGES:
sh: echo $(go list ./... | tr '\n' ' ')

Expand All @@ -15,3 +15,34 @@ tasks:
desc: Run unit tests
cmds:
- go test -v -short -run '{{default ".*" .GO_TEST_REGEX}}' {{default "-timeout 10m -coverpkg=./... -covermode=atomic" .GO_TEST_FLAGS}} -coverprofile=coverage_unit.txt {{default .DEFAULT_GO_PACKAGES .GO_PACKAGES}}

go:check:
desc: Check for problems with Go code
deps:
- task: go:vet
- task: go:lint

go:vet:
desc: Check for errors in Go code
cmds:
- go vet {{default .DEFAULT_GO_PACKAGES .GO_PACKAGES}}

go:lint:
desc: Lint Go code
cmds:
- |
PROJECT_PATH="$PWD"
# `go get` and `go list` commands must be run from a temporary folder to avoid polluting go.mod
cd "$(mktemp -d "${TMPDIR-${TMP-/tmp}}/task-temporary-XXXXX")"
go get golang.org/x/lint/golint
GOLINT_PATH="$(go list -f '{{"{{"}}.Target{{"}}"}}' golang.org/x/lint/golint || echo "false")"
# `golint` must be run from the module folder
cd "$PROJECT_PATH"
"$GOLINT_PATH" \
{{default "-min_confidence 0.8 -set_exit_status" .GO_LINT_FLAGS}} \
{{default .DEFAULT_GO_PACKAGES .GO_PACKAGES}}

go:format:
desc: Format Go code
cmds:
- go fmt {{default .DEFAULT_GO_PACKAGES .GO_PACKAGES}}
11 changes: 7 additions & 4 deletions libraries/bad_file_cleaner.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path/filepath"
)

// FailIfHasUndesiredFiles returns an error if the folder contains any undesired files.
func FailIfHasUndesiredFiles(folder string) error {
err := failIfContainsForbiddenFileInRoot(folder)
if err != nil {
Expand All @@ -15,10 +16,11 @@ func FailIfHasUndesiredFiles(folder string) error {
return failIfContainsExes(folder)
}

var FORBIDDEN_FILES = []string{".development"}
// ForbiddenFiles is the names of the forbidden files.
var ForbiddenFiles = []string{".development"}

func failIfContainsForbiddenFileInRoot(folder string) error {
for _, file := range FORBIDDEN_FILES {
for _, file := range ForbiddenFiles {
if _, err := os.Stat(filepath.Join(folder, file)); err == nil {
return errors.New(file + " file found, skipping")
}
Expand All @@ -27,10 +29,11 @@ func failIfContainsForbiddenFileInRoot(folder string) error {
return nil
}

var PATTERNS = []string{"*.exe"}
// Patterns is the file patterns of executables.
var Patterns = []string{"*.exe"}

func failIfContainsExes(folder string) error {
for _, pattern := range PATTERNS {
for _, pattern := range Patterns {
cmd := exec.Command("find", folder, "-type", "f", "-name", pattern)
output, err := cmd.CombinedOutput()
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion libraries/clamav.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func modifyEnv(env []string, key, value string) []string {
return envMapToSlice(envMap)
}

// RunAntiVirus scans the folder for viruses.
func RunAntiVirus(folder string) ([]byte, error) {
cmd := exec.Command("clamdscan", "-i", folder)
cmd.Env = modifyEnv(os.Environ(), "LANG", "en")
Expand All @@ -42,7 +43,7 @@ func RunAntiVirus(folder string) ([]byte, error) {

output := string(out)
if strings.Index(output, "Infected files: 0") == -1 {
return out, errors.New("Infected files found!")
return out, errors.New("Infected files found")
}

return out, nil
Expand Down
7 changes: 4 additions & 3 deletions libraries/cron/fill_missing_checksums.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package cron

import (
"arduino.cc/repository/libraries/hash"
"io"
"net/http"
"os"

"arduino.cc/repository/libraries/hash"
)

/*
Check for missing size and checksum field and fills them
by downloading a copy of the file.
FillMissingChecksumsForDownloadArchives checks for missing size and checksum field and fills them
by downloading a copy of the file.
*/
func FillMissingChecksumsForDownloadArchives(URL string, filename string) (int64, string, error) {
size, err := download(URL, filename)
Expand Down
15 changes: 15 additions & 0 deletions libraries/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,12 @@ type Dependency struct {
Version string
}

// New returns a new DB object.
func New(libraryFile string) *DB {
return &DB{libraryFile: libraryFile}
}

// AddLibrary adds a library to the database.
func (db *DB) AddLibrary(library *Library) error {
db.mutex.Lock()
defer db.mutex.Unlock()
Expand All @@ -70,6 +72,7 @@ func (db *DB) AddLibrary(library *Library) error {
return nil
}

// HasLibrary returns whether the database already contains the given library.
func (db *DB) HasLibrary(libraryName string) bool {
db.mutex.Lock()
defer db.mutex.Unlock()
Expand All @@ -81,6 +84,7 @@ func (db *DB) hasLibrary(libraryName string) bool {
return found != nil
}

// FindLibrary returns the Library object for the given name.
func (db *DB) FindLibrary(libraryName string) (*Library, error) {
db.mutex.Lock()
defer db.mutex.Unlock()
Expand All @@ -96,6 +100,7 @@ func (db *DB) findLibrary(libraryName string) (*Library, error) {
return nil, errors.New("library not found")
}

// AddRelease adds a library release to the database.
func (db *DB) AddRelease(release *Release, repoURL string) error {
db.mutex.Lock()
defer db.mutex.Unlock()
Expand All @@ -120,6 +125,7 @@ func (db *DB) AddRelease(release *Release, repoURL string) error {
return nil
}

// HasReleaseByNameVersion returns whether the database contains a release for the given library and version number.
func (db *DB) HasReleaseByNameVersion(libraryName string, libraryVersion string) bool {
db.mutex.Lock()
defer db.mutex.Unlock()
Expand All @@ -131,6 +137,7 @@ func (db *DB) hasReleaseByNameVersion(libraryName string, libraryVersion string)
return found != nil
}

// HasRelease returns whether the database already contains the given Release object.
func (db *DB) HasRelease(release *Release) bool {
db.mutex.Lock()
defer db.mutex.Unlock()
Expand All @@ -141,6 +148,7 @@ func (db *DB) hasRelease(release *Release) bool {
return db.hasReleaseByNameVersion(release.LibraryName, release.Version.String())
}

// FindRelease returns the Release object from the database that matches the given object.
func (db *DB) FindRelease(release *Release) (*Release, error) {
db.mutex.Lock()
defer db.mutex.Unlock()
Expand All @@ -156,6 +164,7 @@ func (db *DB) findReleaseByNameVersion(libraryName string, libraryVersion string
return nil, errors.New("library not found")
}

// LoadFromFile returns a DB object loaded from the given filename.
func LoadFromFile(filename string) (*DB, error) {
file, err := os.Open(filename)
if err != nil {
Expand All @@ -170,6 +179,7 @@ func LoadFromFile(filename string) (*DB, error) {
return db, nil
}

// Load returns a DB object loaded from the given reader.
func Load(r io.Reader) (*DB, error) {
decoder := json.NewDecoder(r)
db := new(DB)
Expand All @@ -180,6 +190,7 @@ func Load(r io.Reader) (*DB, error) {
return db, nil
}

// SaveToFile saves the database to a file.
func (db *DB) SaveToFile() error {
db.mutex.Lock()
defer db.mutex.Unlock()
Expand All @@ -191,6 +202,7 @@ func (db *DB) SaveToFile() error {
return db.save(file)
}

// Save writes the database via the given writer.
func (db *DB) Save(r io.Writer) error {
db.mutex.Lock()
defer db.mutex.Unlock()
Expand Down Expand Up @@ -222,6 +234,7 @@ func (db *DB) findLatestReleaseOfLibrary(lib *Library) (*Release, error) {
return found, nil
}

// FindReleasesOfLibrary returns the database's releases for the given Library object.
func (db *DB) FindReleasesOfLibrary(lib *Library) []*Release {
db.mutex.Lock()
defer db.mutex.Unlock()
Expand All @@ -239,10 +252,12 @@ func (db *DB) findReleasesOfLibrary(lib *Library) []*Release {
return releases
}

// Commit saves the database to disk.
func (db *DB) Commit() error {
return db.SaveToFile()
}

// Init loads a database from file and returns it.
func Init(libraryFile string) *DB {
libs, err := LoadFromFile(libraryFile)
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions libraries/db/versioning.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,34 @@ package db

import "encoding/json"

// Version is the type for library versions.
type Version struct {
version string
}

// Less returns whether the receiver version is lower than the argument.
func (version *Version) Less(other Version) (bool, error) {
// TODO: apply semantic versioning
return version.version < other.version, nil
}

// String returns the version in string form.
func (version *Version) String() string {
return version.version
}

// UnmarshalJSON parses the JSON-encoded argument and stores the result in the receiver.
func (version *Version) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &version.version)
}

// MarshalJSON returns the JSON encoding of the receiver.
func (version *Version) MarshalJSON() ([]byte, error) {
// Encode version as a string
return json.Marshal(version.version)
}

// VersionFromString parses a string to a Version object.
func VersionFromString(str string) Version {
return Version{version: str}
}
2 changes: 2 additions & 0 deletions libraries/file/SCCS.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package file

// SCCSFiles is a map of folder names used internally by source code control systems.
var SCCSFiles = map[string]bool{
"CVS": true,
"RCS": true,
Expand All @@ -8,6 +9,7 @@ var SCCSFiles = map[string]bool{
".hg": true,
".bzr": true}

// IsSCCS returns whether the given string is a folder name used internally by source code control systems.
func IsSCCS(name string) bool {
return SCCSFiles[name]
}
Loading