From 9df541ff0d01025713ef009c0f9885e6a6f4ddd8 Mon Sep 17 00:00:00 2001 From: KEINOS Date: Sun, 14 Feb 2021 12:22:05 +0900 Subject: [PATCH] Speed up workflow testing by getting away from Docker (PR #21) ## Feature * feat: requirement checker for merge testing * feat: use `golangci-lint` v1.36.0 -> latest * feat: coverage action w/out docker * feat: merge-tests.yaml w/out docker * feat: use pre-installed shellcheck * feat: ".shellceckrc" - For older version compatibility. (CI uses old version) ## Fixes * fix: shell check errors * fix: golangci-lint.yaml as dispatch workflow only - Since merge-tests.yaml does the same thing limit it to `workflow_dispatch` as an individual test --- .devcontainer/Dockerfile | 6 +-- .devcontainer/README.md | 33 ++++++------ .github/check-requirements.sh | 77 +++++++++++++++++++++++++++ .github/mergify.yml | 4 +- .github/workflows/coverage-tests.yaml | 54 +++++++++++++------ .github/workflows/golangci-lint.yaml | 1 - .github/workflows/merge-tests.yaml | 56 ++++++++++++++----- .shellcheckrc | 8 +++ bin/.gitignore | 6 ++- build-app.sh | 14 ++--- conf/README.md | 51 +++++++++++++++++- 11 files changed, 251 insertions(+), 59 deletions(-) create mode 100755 .github/check-requirements.sh create mode 100644 .shellcheckrc diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 2352ad1..5ee90bc 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -75,9 +75,9 @@ RUN url_download="https://github.com/koalaman/shellcheck/releases/download/lates && shellcheck --version \ && rm -r "$path_tmp_dir" -# golangci-lint - The fast Go linters runner. -# binary will be $(go env GOPATH)/bin/golangci-lint -RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.36.0 \ +# golangci-lint - The fast Go linters runner. Version=latest +# binary will be installed under: $(go env GOPATH)/bin/golangci-lint +RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin \ # Smoke test && golangci-lint --version diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 568071c..7e8d9ff 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -1,25 +1,26 @@ -# Dockerfile for CIs and Development +# Dockerfile for GitHub and VSCode Users To Develop -## For CIs +This directory is for [GitHub Codespaces](https://github.com/features/codespaces) and/or [VS Code + Docker](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) users for development. -The [CI](https://en.wikipedia.org/wiki/Continuous_integration) will run the [Dockerfile](Dockerfile) to build the image and then run the tests in a container. +It includes most of the necessary packages and tools for developing Golang app. Aiming to provide the same environment to develop the app. -- Current CI - - [GitHub Actions](https://docs.github.com/en/free-pro-team@latest/actions): [../.github/workflows/](https://github.com/KEINOS/Hello-Cobra/tree/main/.github/workflows) +## Developing Online -## For DEVs +If GitHub detects this directory (`.devcontainer`) in the repo, then you will be able to develop online via [GitHub Codespaces](https://github.com/features/codespaces). -This directory is for [GitHub Codespaces](https://github.com/features/codespaces) and [VS Code + Docker](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) users to develop the cloned/forked repo. +## VS Code + Docker User -### VS Code + Docker User +The container contains VS Code Server as well. If you already have installed the "[Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)" extension, then press "F1" and select "`Remote-Containers: Open in Container`". -If you already have installed the "[Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)" extension, press "F1" and select "`Remote-Containers: Open in Container`". After a while, you'll get most of the environment needed to develop and debug. +After a while, you'll get most of the environment needed to develop and debug. -- File Description - - [cobra.yaml](cobra.yaml): Default `cobra` command Settings. - - [devcontainer.json](devcontainer.json): VSCode Extensions to be installed. - - [Dockerfile](Dockerfile): Alpine based Golang development container. - - [postCreateCommand.sh](postCreateCommand.sh): Initialization script that runs after the container and the VSCode server is up and before connection from VSCode. - - [settings.vscode.json](settings.vscode.json): Additional VSCode Settings. - - [welcome.sh](welcome.sh): Bash script to display the welcome message in the terminal when first login. It will display the basic info and TIPs to use. +## File Description + +- [cobra.yaml](cobra.yaml): Default `cobra` command Settings. Used for `$ cobra add ..` +- [devcontainer.env](devcontainer.env): ENV variables to be loaded once when the container's created. +- [devcontainer.json](devcontainer.json): VSCode Extensions to be installed and env settings. +- [Dockerfile](Dockerfile): Debian 10 (buster) based Golang development container. +- [postCreateCommand.sh](postCreateCommand.sh): Initialization script that runs after the container and the VSCode server is up. +- [README.md](README.md): This file. ;-) +- [welcome.sh](welcome.sh): Bash script to display the basic info and TIPs to use in the first shell login. diff --git a/.github/check-requirements.sh b/.github/check-requirements.sh new file mode 100755 index 0000000..6a275f4 --- /dev/null +++ b/.github/check-requirements.sh @@ -0,0 +1,77 @@ +#!/bin/sh +# ============================================================================= +# This script checks if the commands and packages required for merge testing +# are installed. +# ============================================================================= + +# ----------------------------------------------------------------------------- +# Constants +# ----------------------------------------------------------------------------- +SUCCESS=0 +FAILURE=1 +TRUE=0 +FALSE=1 + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +isAvailable() { + command_tmp="${1:?Command name missing}" + msg_error="${2:?Error message missing}" + url_reference="${3:?'URL for reference missing'}" + + printf -- ' %s ... ' "$command_tmp" + if ! which "$command_tmp" 1>/dev/null 2>/dev/null; then + flag_covered_all=$FALSE + echo 'NG' + echo >&2 " - ABOUT : ${msg_error}" + echo >&2 " - DETAILS: ${url_reference}" + return $FALSE + fi + echo 'OK' +} + +# ----------------------------------------------------------------------------- +# Main +# ----------------------------------------------------------------------------- +flag_covered_all=$TRUE + +echo 'Checking requirements for:' + +echo +echo 'Shell scripts:' +isAvailable \ + shellcheck \ + '"shellcheck" is a static analysis tool for shell scripts.' \ + 'https://github.com/koalaman/shellcheck' + +isAvailable shfmt \ + '"shfmt" is a linter for shell scripts to support POSIX Shell, Bash, and mksh.' \ + 'https://github.com/mvdan/sh' + +echo +echo 'Go programs:' +isAvailable \ + go \ + '"go" is required as a matter of course.' \ + 'https://golang.org/' + +isAvailable \ + gofmt \ + '"gofmt" is a formatter for golang.' \ + 'https://golang.org/cmd/gofmt/' + +isAvailable \ + golangci-lint \ + '"golangci-lint" is is a Go linters aggregator.' \ + 'https://golangci-lint.run/' + +if [ $flag_covered_all -ne 0 ]; then + echo + echo >&2 "Some requirements missing." + exit $FAILURE +fi + +echo +echo 'OK - All requirements were installed! You are good to Go testing!' +exit $SUCCESS diff --git a/.github/mergify.yml b/.github/mergify.yml index c7564f4..9abc51e 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -2,7 +2,7 @@ pull_request_rules: - name: automatic merge on CI success and 2 approved reviews conditions: - "#approved-reviews-by>=2" - - "check-success=docker_test" + - "check-success=merge_tests" - base=main - -draft actions: @@ -11,7 +11,7 @@ pull_request_rules: strict: smart+fasttrack - name: automatic merge on CI success if only markdown and/or Golang files were changed conditions: - - "check-success=docker_test" + - "check-success=merge_tests" - files~=.\.(?i)(md|go)$ - base=main - -draft diff --git a/.github/workflows/coverage-tests.yaml b/.github/workflows/coverage-tests.yaml index 842ae1d..a043b49 100644 --- a/.github/workflows/coverage-tests.yaml +++ b/.github/workflows/coverage-tests.yaml @@ -5,21 +5,45 @@ on: pull_request: jobs: - docker_test: - runs-on: ubuntu-latest + coverage: + name: Unit test and coverage + + strategy: + matrix: + platform: [ubuntu-latest, macos-latest, windows-latest] + + runs-on: ${{ matrix.platform }} + steps: - - name: Checkout the code - uses: actions/checkout@v2 - - name: Build the test image + - uses: actions/checkout@v2 + + - uses: actions/setup-go@v2 + with: + go-version: 1.15.x + + - name: Use Cache + uses: actions/cache@v2 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Download Modules + if: steps.cache.outputs.cache-hit != 'true' + run: go mod download + + - name: Run coverage (Windows) + if: runner.os == 'Windows' run: | - pwd && \ - cd ./.devcontainer && \ - docker build -t test:ci . - - name: Run the tests on the container + go install + go mod tidy + go vet -v ./... + go test -cover -v ./... + + - name: Run coverage (Linux/macOS) + if: runner.os != 'Windows' run: | - pwd && \ - docker run \ - -v $(pwd):/workspaces/Hello-Cobra \ - -w /workspaces/Hello-Cobra \ - test:ci \ - /bin/bash ./.github/run-tests-coverage.sh --verbose + go install + go mod tidy + /bin/bash ./.github/run-tests-coverage.sh --verbose diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index 67585d9..fcbd352 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -3,7 +3,6 @@ name: golangci-lint on: workflow_dispatch: - pull_request: jobs: golangci: diff --git a/.github/workflows/merge-tests.yaml b/.github/workflows/merge-tests.yaml index 9c8c1c3..4a55940 100644 --- a/.github/workflows/merge-tests.yaml +++ b/.github/workflows/merge-tests.yaml @@ -5,21 +5,53 @@ on: pull_request: jobs: - docker_test: + merge_tests: runs-on: ubuntu-latest steps: - name: Checkout the code uses: actions/checkout@v2 - - name: Build the test image + + - uses: actions/setup-go@v2 + with: + go-version: 1.15.x + + - name: Use Cache + uses: actions/cache@v2 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Download Modules + if: steps.cache.outputs.cache-hit != 'true' + run: go mod download + + - name: Run shellcheck (pre-installed) run: | - pwd && \ - cd ./.devcontainer && \ - docker build -t test:ci . - - name: Run full-tests on the container + find . -name '*.sh' -type f -print0 | xargs -0 shellcheck + + - name: Install and run shfmt + run: | + GO111MODULE=on go get mvdan.cc/sh/v3/cmd/shfmt + find . -name '*.sh' -type f -print0 | xargs -0 shfmt -d + + - name: Run gofmt + uses: Jerome1337/gofmt-action@v1.0.4 + with: + gofmt-path: '.' + gofmt-flags: '-d -e' # display diffs and report all errors + + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v2 + with: + version: v1.36 + args: --config ./.github/golangci.yml + # use pre-installed Go + skip-go-installation: true + + - name: Run requirement check run: | - pwd && \ - docker run \ - -v $(pwd):/workspaces/Hello-Cobra \ - -w /workspaces/Hello-Cobra \ - test:ci \ - /bin/bash ./.github/run-tests-merge.sh + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin + ./.github/check-requirements.sh + ./.github/run-tests-merge.sh diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000..e5fff0c --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,8 @@ +# ============================================================================= +# ShellCheck Configuration +# ============================================================================= +# See: https://github.com/koalaman/shellcheck/wiki/ + +# Disable +# SC2230: https://github.com/koalaman/shellcheck/wiki/SC2230 +disable=SC2230 diff --git a/bin/.gitignore b/bin/.gitignore index 3d40bee..6a50c0e 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -1,4 +1,6 @@ -# We do not want to version control the built binary. -# Though we need this directory for access control purposes. +# Output directory of built/compiled application via "../build-app.sh" +# +# We do not want to version control the built binary. Though we need +# this directory for access control purposes. * !.gitignore diff --git a/build-app.sh b/build-app.sh index 155f5cc..5e120f2 100755 --- a/build-app.sh +++ b/build-app.sh @@ -53,7 +53,7 @@ GOARCH: For supported architectures specify '--list' option. GOARM: - The 3rd argument is the ARM version. Such as: + The 3rd argument is the ARM variant/version. Such as: "5", "6", "7".(Default: empty) @@ -69,20 +69,20 @@ Sample usage: ./build-app.sh --list ./build-app.sh -l - # Linux (Intel) + # Build Linux (Intel) binary ./build-app.sh linux - # macOS + # Build macOS binary ./build-app.sh darwin #Equivalent to: ./build-app.sh darwin amd64 ./build-app.sh darwin arm64 - # Windows10 + # Build Windows10 binary ./build-app.sh windows - # Raspberry Pi 3 + # Build Raspberry Pi 3 binary ./build-app.sh linux arm 7 - # QNAP ARM5 + # Build QNAP ARM5 binary ./build-app linux arm 5 HEREDOC @@ -104,7 +104,7 @@ listPlatforms() { echo "$list" | indentSTDIN 1>&2 exit $FAILURE } - echo 'List of available platforms. (OS/Architecture)' + echo 'List of available platforms to build. (GOOS/GOARCH)' echo "$list" | indentSTDIN exit $SUCCESS } diff --git a/conf/README.md b/conf/README.md index 1b58029..7884fcb 100644 --- a/conf/README.md +++ b/conf/README.md @@ -1,3 +1,52 @@ # Package conf -Directory of file configuration for the app using Viper. +Directory of file-configuration package using [Viper](https://github.com/spf13/viper). + +- Note that this package may be used as JSON/YAML file reader but it's not designed to load MEGA sized file. + +## Sample usage in other package + +Pretend the user config file (`userConfig.json`) was as below: + +```json +{ + "my_value": "Cobra" +} +``` + +Then the Go sample to load it would be as below: + +```go +package cmd + +import "github.com/KEINOS/Hello-Cobra/conf" + +// TDataUser defines the data structure to be stored from the conf file read. +type TDataUser struct { + // MyValue is the variable to store the value of "my_value" key in the conf file. + MyValue string `mapstructure:"my_value"` +} + +var ( + configFile = conf.TConfigApp{ + PathDirConf: ".", + NameFileConf: "userConfig", + NameTypeConf: "json", + } + + userValues = TDataUser{ + MyValue: "default value", + } +) + +// Load value from "./userConfig.json" to `userValues` +if err := conf.LoadConfig(*configFile, &userValues); err != nil { + // do something with the error +} + +// Use loaded value from the conf file +myValue := userValues.MyValue + +// `myValue` expects to be "Cobra" + +```