From 744e5efce7b13beb008ec23cc0760f2ba7b45872 Mon Sep 17 00:00:00 2001 From: Michael Dockter Date: Thu, 11 Jul 2024 19:38:43 -0400 Subject: [PATCH] 71 dockter 1 (#72) * #71 Savepoint * #71 Improve test coverage * #71 Prepare for versioned release * #71 Prepare for versioned release * #71 Prepare for versioned release * #71 Prepare for versioned release * #71 Update documentations * #71 Update documentations * #71 Update documentations * #71 Update documentations --- .dockerignore | 3 +- .github/coverage/README.md | 20 ++ .../coverage/testcoverage.yaml | 6 +- .github/linters/.checkov.yaml | 3 +- .../linters/{.golangci.yml => .golangci.yaml} | 3 +- .github/linters/.jscpd.json | 6 +- .github/linters/README.md | 54 +++++ .github/workflows/README.md | 205 ++++++++++++++++++ .../workflows/add-labels-standardized.yaml | 2 +- .../add-to-project-garage-dependabot.yaml | 2 +- .github/workflows/add-to-project-garage.yaml | 2 +- .../dependabot-approve-and-merge.yaml | 2 +- .github/workflows/go-proxy-pull.yaml | 6 +- .github/workflows/go-test-darwin.yaml | 36 ++- .github/workflows/go-test-linux.yaml | 36 ++- .github/workflows/go-test-windows.yaml | 37 +++- .github/workflows/golangci-lint.yaml | 59 +++++ .github/workflows/lint-workflows.yaml | 2 +- .github/workflows/make-go-tag.yaml | 8 +- .../workflows/move-pr-to-done-dependabot.yaml | 2 +- .gitignore | 2 + CHANGELOG.md | 17 +- Makefile | 47 ++-- README.md | 52 ++--- cmdhelper/cmdhelper_examples_test.go | 73 +++++++ cmdhelper/cmdhelper_test.go | 109 +++------- docs/development.md | 154 ++++++------- docs/examples.md | 10 - go.mod | 4 +- go.sum | 8 +- main.go | 22 +- main_test.go | 5 +- makefiles/darwin.mk | 12 +- makefiles/linux.mk | 11 +- makefiles/windows.mk | 14 +- option/option.go | 42 ++++ option/option_test.go | 39 +++- settings/settings.go | 2 +- 38 files changed, 833 insertions(+), 284 deletions(-) create mode 100644 .github/coverage/README.md rename .testcoverage.yml => .github/coverage/testcoverage.yaml (97%) rename .github/linters/{.golangci.yml => .golangci.yaml} (98%) create mode 100644 .github/linters/README.md create mode 100644 .github/workflows/README.md create mode 100644 .github/workflows/golangci-lint.yaml create mode 100644 cmdhelper/cmdhelper_examples_test.go diff --git a/.dockerignore b/.dockerignore index 4e2bf93..253d5ef 100644 --- a/.dockerignore +++ b/.dockerignore @@ -9,5 +9,4 @@ CODE_OF_CONDUCT.md CONTRIBUTING.md docker-compose.test.yml LICENSE -PULL_REQUEST_TEMPLATE.md -README.md \ No newline at end of file +README.md diff --git a/.github/coverage/README.md b/.github/coverage/README.md new file mode 100644 index 0000000..9ca939c --- /dev/null +++ b/.github/coverage/README.md @@ -0,0 +1,20 @@ +# Coverage + +## testcoverage.yaml + +- [testcoverage.yaml] +- Used by `coverage:` in + - [go-test-darwin.yaml] + - [go-test-linux.yaml] + - [go-test-windows.yaml] +- [go-test-coverage] + - [go-test-coverage configuration] + - [go-test-coverage badge] + +[go-test-darwin.yaml]: ../workflows/README.md#go-test-darwinyaml +[go-test-linux.yaml]: ../workflows/README.md#go-test-linuxyaml +[go-test-windows.yaml]: ../workflows/README.md#go-test-windowsyaml +[testcoverage.yaml]: testcoverage.yaml +[go-test-coverage]: https://github.com/vladopajic/go-test-coverage +[go-test-coverage configuration]: https://github.com/vladopajic/go-test-coverage?tab=readme-ov-file#config +[go-test-coverage badge]: https://github.com/vladopajic/go-test-coverage/blob/main/docs/badge.md diff --git a/.testcoverage.yml b/.github/coverage/testcoverage.yaml similarity index 97% rename from .testcoverage.yml rename to .github/coverage/testcoverage.yaml index 8a0dda3..948373a 100644 --- a/.testcoverage.yml +++ b/.github/coverage/testcoverage.yaml @@ -15,15 +15,15 @@ local-prefix: "github.com/org/project" threshold: # (optional; default 0) # The minimum coverage that each file should have - file: 80 + file: 90 # (optional; default 0) # The minimum coverage that each package should have - package: 80 + package: 90 # (optional; default 0) # The minimum total coverage project should have - total: 80 + total: 90 # Holds regexp rules which will override thresholds for matched files or packages # using their paths. # diff --git a/.github/linters/.checkov.yaml b/.github/linters/.checkov.yaml index e2d7c03..86c8083 100644 --- a/.github/linters/.checkov.yaml +++ b/.github/linters/.checkov.yaml @@ -1,2 +1,3 @@ quiet: true -skip-check: CKV_DOCKER_7 +skip-check: + - CKV_DOCKER_7 diff --git a/.github/linters/.golangci.yml b/.github/linters/.golangci.yaml similarity index 98% rename from .github/linters/.golangci.yml rename to .github/linters/.golangci.yaml index 389317d..8c22489 100644 --- a/.github/linters/.golangci.yml +++ b/.github/linters/.golangci.yaml @@ -1,9 +1,10 @@ run: modules-download-mode: readonly - show-stats: true + timeout: 10m output: print-linter-name: false + show-stats: true sort-results: true linters: diff --git a/.github/linters/.jscpd.json b/.github/linters/.jscpd.json index 3a60fa8..9e26dfe 100644 --- a/.github/linters/.jscpd.json +++ b/.github/linters/.jscpd.json @@ -1,5 +1 @@ -{ - "ignore": [ - "**/*.go,**/go-test*.yaml" - ] -} \ No newline at end of file +{} \ No newline at end of file diff --git a/.github/linters/README.md b/.github/linters/README.md new file mode 100644 index 0000000..7bc3d2e --- /dev/null +++ b/.github/linters/README.md @@ -0,0 +1,54 @@ +# Linters + +## .checkov.yaml + +- [.checkov.yaml] +- Used by [lint-workflows.yaml] +- [checkov] + - [checkov configuration] + +## .golangci.yaml + +- [.golangci.yaml] +- Used by [golangci-lint.yaml] +- [golangci-lint] + - [golangci-lint configuration] + +## .jscpd.json + +- [.jscpd.json] +- Used by [lint-workflows.yaml] +- [jscpd] + - [jscpd configuration] + - Example: + + ```json + { + "ignore": [ + "**/*.go,**/go-test*.yaml" + ], + "threshold": 10 + } + ``` + +## .yaml-lint.yml + +- [.yaml-lint.yml] +- Used by [lint-workflows.yaml] +- [yaml-lint] + - [yaml-lint configuration] + +[.checkov.yaml]: .checkov.yaml +[.golangci.yaml]: .golangci.yaml +[.jscpd.json]: .jscpd.json +[.yaml-lint.yml]: .yaml-lint.yml +[checkov configuration]: https://www.checkov.io/2.Basics/CLI%20Command%20Reference.html +[checkov]: https://www.checkov.io/ +[golangci-lint configuration]: https://golangci-lint.run/usage/configuration/ +[golangci-lint.yaml]: ../workflows/README.md#golangci-lintyaml +[golangci-lint]: https://golangci-lint.run/ +[jscpd configuration]: https://github.com/kucherenko/jscpd/tree/master/apps/jscpd#options +[jscpd]: https://github.com/kucherenko/jscpd +[lint-workflows.yaml]: ../workflows/README.md#lint-workflowsyaml +[yaml-lint configuration]: https://yamllint.readthedocs.io/en/stable/configuration.html +[yaml-lint]: https://github.com/adrienverge/yamllint diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..c690e31 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,205 @@ +# Workflows + +## add-labels-standardized.yaml + +When issues are opened, +this action adds appropriate labels to the issue. +(e.g. "triage", "customer-submission") + +- [Add Labels Standardized GitHub action] + - Uses: [senzing-factory/build-resources/.../add-labels-to-issue.yaml] + +## add-to-project-garage-dependabot.yaml + +When a Dependabot Pull Request (PR) is made against `main` branch, +this action adds the PR to the "Garage" project board as "In Progress". + +- [Add to Project Garage Dependabot GitHub action] + - Uses: [senzing-factory/build-resources/.../add-to-project-dependabot.yaml] + +## add-to-project-garage.yaml + +When an issue is created, +this action adds the issue to the "Garage" board as "Backlog". + +- [Add to Project Garage GitHub action] + - Uses: [senzing-factory/build-resources/.../add-to-project.yaml] + +## dependabot-approve-and-merge.yaml + +When a Dependabot Pull Request (PR) is made against the `main` branch, +this action determines if it should be automatically approved and merged into the `main` branch. +Once this action occurs [move-pr-to-done-dependabot.yaml] moves the PR on the "Garage" project board to "Done". + +- [Dependabot Approve and Merge GitHub action] + - Uses: [senzing-factory/build-resources/.../dependabot-approve-and-merge.yaml] + +## docker-build-container.yaml + +When a Pull Request is made against the `main` branch, +this action verifies that the `Dockerfile` can be successfully built. + +*Note:* The Docker image is **not** pushed to [DockerHub]. + +- [Docker Build Container GitHub action] + - Uses: [senzing-factory/github-action-docker-buildx-build] + +## docker-push-containers-to-dockerhub.yaml + +After a [Semantic Version] release is created, +this action builds Docker images on multiple architectures and pushes the Docker images to [DockerHub]. + +- [Docker Push Containers to DockerHub GitHub action] + - Uses: [senzing-factory/github-action-docker-buildx-build] + +## golangci-lint.yaml + +When a change is committed to GitHub or a Pull Request is made against the `main` branch, +this action runs [golangci-lint] to run multiple linters against the code. + +- [Golangci Lint GitHub action] + - Configuration: + - [.golangci.yaml] + - Uses: + - [actions/checkout] + - [senzing-factory/github-action-install-senzing-api] + - [actions/setup-go] + - [golangci/golangci-lint-action] + +## go-proxy-pull.yaml + +After a [Semantic Version] release is created, +this action expedites the Go publishing process. + +- [Go Proxy Pull GitHub action] + - Uses: [andrewslotin/go-proxy-pull-action] + +## go-test-darwin.yaml + +When a Pull Request is made against the `main` branch, +this action runs `go test` with coverage testing on macOS. + +- [Go Test Darwin GitHub action] + - Configuration: [testcoverage.yaml] + - Uses: + - [actions/checkout] + - [actions/setup-go] + - [gotesttools/gotestfmt-action] + - [senzing-factory/github-action-install-senzing-api] + - [actions/upload-artifact] + - [senzing-factory/build-resources/.../go-coverage.yaml] + +## go-test-linux.yaml + +When a change is committed to GitHub or a Pull Request is made against the `main` branch, +this action runs `go test` with coverage testing on Linux. + +- [Go Test Linux GitHub action] + - Configuration: [testcoverage.yaml] + - Uses: + - [actions/checkout] + - [actions/setup-go] + - [gotesttools/gotestfmt-action] + - [senzing-factory/github-action-install-senzing-api] + - [actions/upload-artifact] + - [senzing-factory/build-resources/.../go-coverage.yaml] + +## go-test-windows.yaml + +When a Pull Request is made against the `main` branch, +this action runs `go test` with coverage testing on Windows. + +- [Go Test Windows GitHub action] + - Configuration: [testcoverage.yaml] + - Uses: + - [actions/checkout] + - [actions/setup-go] + - [gotesttools/gotestfmt-action] + - [senzing-factory/github-action-install-senzing-api] + - [actions/upload-artifact] + - [senzing-factory/build-resources/.../go-coverage.yaml] + +## lint-workflows.yaml + +When a change is committed to GitHub or a Pull Request is made against the `main` branch, +this action runs [super-linter] to run multiple linters against the code. + +- [Lint Workflows GitHub action] + - Configuration: + - [.checkov.yaml] + - [.jscpd.json] + - [.yaml-lint.yml] + - Uses: [senzing-factory/build-resources/.../lint-workflows.yaml] + +## make-go-github-file.yaml + +After a [Semantic Version] release is created, +this action creates a Pull Request for an updated [github.go] file +for the **next** Semantic Version release by increasing the Semantic Version's Patch value. + +- [Make Go GitHub File GitHub action] + - Uses: [senzing-factory/build-resources/.../make-go-github-file.yaml] + +## make-go-tag.yaml + +After a [Semantic Version] release is created, +this action creates a tag in the form `vM.m.P` using the SHA of the `M.m.P` release. +The `v` prefix is standard usage in [Go]. + +- [Make Go Tag GitHub action] + - Uses: + - [actions/checkout] + - [senzing-factory/github-action-make-go-tag] + +## move-pr-to-done-dependabot.yaml + +When a Pull Request is merged into the `main` branch, +this action moves the PR on the "Garage" project board to "Done". + +- [Move PR to Done Dependabot GitHub action] + - Uses: [senzing-factory/build-resources/.../move-pr-to-done-dependabot.yaml] + +[.checkov.yaml]: ../linters/README.md#checkovyaml +[.golangci.yaml]: ../linters/README.md#golangciyaml +[.jscpd.json]: ../linters/README.md#jscpdjson +[.yaml-lint.yml]: ../linters/README.md#yaml-lintyml +[actions/checkout]: https://github.com/actions/checkout +[actions/setup-go]: https://github.com/actions/setup-go +[actions/upload-artifact]: https://github.com/actions/upload-artifact +[Add Labels Standardized GitHub action]: add-labels-standardized.yaml +[Add to Project Garage Dependabot GitHub action]: add-to-project-garage-dependabot.yaml +[Add to Project Garage GitHub action]: add-to-project-garage.yaml +[andrewslotin/go-proxy-pull-action]: https://github.com/andrewslotin/go-proxy-pull-action +[Dependabot Approve and Merge GitHub action]: dependabot-approve-and-merge.yaml +[Docker Build Container GitHub action]: docker-build-container.yaml +[Docker Push Containers to DockerHub GitHub action]: docker-push-containers-to-dockerhub.yaml +[DockerHub]: https://hub.docker.com/ +[github.go]: ../../cmd/github.go +[Go Proxy Pull GitHub action]: go-proxy-pull.yaml +[Go Test Darwin GitHub action]: go-test-darwin.yaml +[Go Test Linux GitHub action]: go-test-linux.yaml +[Go Test Windows GitHub action]: go-test-windows.yaml +[Go]: https://go.dev/ +[Golangci Lint GitHub action]: golangci-lint.yaml +[golangci-lint]: https://github.com/golangci/golangci-lint +[golangci/golangci-lint-action]: https://github.com/golangci/golangci-lint-action +[gotesttools/gotestfmt-action]: https://github.com/gotesttools/gotestfmt-action +[Lint Workflows GitHub action]: lint-workflows.yaml +[Make Go GitHub File GitHub action]: make-go-github-file.yaml +[Make Go Tag GitHub action]: make-go-tag.yaml +[Move PR to Done Dependabot GitHub action]: move-pr-to-done-dependabot.yaml +[move-pr-to-done-dependabot.yaml]: move-pr-to-done-dependabotyaml +[Semantic Version]: https://semver.org/ +[senzing-factory/build-resources/.../add-labels-to-issue.yaml]: https://github.com/senzing-factory/build-resources/blob/main/.github/workflows/add-labels-to-issue.yaml +[senzing-factory/build-resources/.../add-to-project-dependabot.yaml]: https://github.com/senzing-factory/build-resources/blob/main/.github/workflows/add-to-project-dependabot.yaml +[senzing-factory/build-resources/.../add-to-project.yaml]: https://github.com/senzing-factory/build-resources/blob/main/.github/workflows/add-to-project.yaml +[senzing-factory/build-resources/.../dependabot-approve-and-merge.yaml]: https://github.com/senzing-factory/build-resources/blob/main/.github/workflows/dependabot-approve-and-merge.yaml +[senzing-factory/build-resources/.../go-coverage.yaml]: https://github.com/senzing-factory/build-resources/blob/main/.github/workflows/go-coverage.yaml +[senzing-factory/build-resources/.../lint-workflows.yaml]: https://github.com/senzing-factory/build-resources/blob/main/.github/workflows/lint-workflows.yaml +[senzing-factory/build-resources/.../make-go-github-file.yaml]: https://github.com/senzing-factory/build-resources/blob/main/.github/workflows/make-go-github-file.yaml +[senzing-factory/build-resources/.../move-pr-to-done-dependabot.yaml]: https://github.com/senzing-factory/build-resources/blob/main/.github/workflows/move-pr-to-done-dependabot.yaml +[senzing-factory/github-action-docker-buildx-build]: https://github.com/senzing-factory/github-action-docker-buildx-build +[senzing-factory/github-action-install-senzing-api]: https://github.com/senzing-factory/github-action-install-senzing-api +[senzing-factory/github-action-make-go-tag]: https://github.com/senzing-factory/github-action-make-go-tag +[super-linter]: https://github.com/super-linter/super-linter +[testcoverage.yaml]: ../coverage/README.md#testcoverageyaml diff --git a/.github/workflows/add-labels-standardized.yaml b/.github/workflows/add-labels-standardized.yaml index 01aa8a1..59ca6b2 100644 --- a/.github/workflows/add-labels-standardized.yaml +++ b/.github/workflows/add-labels-standardized.yaml @@ -1,4 +1,4 @@ -name: add labels standardized +name: Add labels standardized on: issues: diff --git a/.github/workflows/add-to-project-garage-dependabot.yaml b/.github/workflows/add-to-project-garage-dependabot.yaml index 19cc672..125bc58 100644 --- a/.github/workflows/add-to-project-garage-dependabot.yaml +++ b/.github/workflows/add-to-project-garage-dependabot.yaml @@ -1,4 +1,4 @@ -name: add to project garage dependabot +name: Add to project garage dependabot on: pull_request: diff --git a/.github/workflows/add-to-project-garage.yaml b/.github/workflows/add-to-project-garage.yaml index 53c0744..8397880 100644 --- a/.github/workflows/add-to-project-garage.yaml +++ b/.github/workflows/add-to-project-garage.yaml @@ -1,4 +1,4 @@ -name: add to project garage +name: Add to project garage on: issues: diff --git a/.github/workflows/dependabot-approve-and-merge.yaml b/.github/workflows/dependabot-approve-and-merge.yaml index 0aad27e..326edea 100644 --- a/.github/workflows/dependabot-approve-and-merge.yaml +++ b/.github/workflows/dependabot-approve-and-merge.yaml @@ -1,4 +1,4 @@ -name: dependabot approve and merge +name: Dependabot approve and merge on: pull_request: diff --git a/.github/workflows/go-proxy-pull.yaml b/.github/workflows/go-proxy-pull.yaml index c865757..607520d 100644 --- a/.github/workflows/go-proxy-pull.yaml +++ b/.github/workflows/go-proxy-pull.yaml @@ -1,4 +1,4 @@ -name: go proxy pull +name: Go proxy pull on: push: @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - - name: pull new module version + - name: Pull new module version uses: andrewslotin/go-proxy-pull-action@v1.2.0 with: - import_path: github.com/senzing-garage/go-cmdhelping + import_path: github.com/${{ github.repository }} diff --git a/.github/workflows/go-test-darwin.yaml b/.github/workflows/go-test-darwin.yaml index 553f249..0f0eec7 100644 --- a/.github/workflows/go-test-darwin.yaml +++ b/.github/workflows/go-test-darwin.yaml @@ -1,13 +1,18 @@ -name: go test darwin +name: Go test darwin on: [pull_request, workflow_dispatch] +env: + DYLD_LIBRARY_PATH: /opt/senzing/g2/lib:/opt/senzing/g2/lib/macos + LD_LIBRARY_PATH: /opt/senzing/g2/lib:/opt/senzing/g2/lib/macos + SENZING_TOOLS_DATABASE_URL: "sqlite3://na:na@nowhere/tmp/sqlite/G2C.db" + permissions: contents: read jobs: go-test-darwin: - name: "go test with Senzing: ${{ matrix.senzingapi-version }}; OS: ${{ matrix.os }}; Go: ${{ matrix.go }}" + name: "Go test with Senzing: ${{ matrix.senzingapi-version }}; OS: ${{ matrix.os }}; Go: ${{ matrix.go }}" runs-on: ${{ matrix.os }} strategy: matrix: @@ -16,23 +21,28 @@ jobs: senzingapi-version: [staging-v4] steps: - - name: checkout repository + - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - - name: setup go + - name: Setup go uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} - - name: install Senzing API + - name: Set up gotestfmt + uses: gotesttools/gotestfmt-action@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Senzing API uses: senzing-factory/github-action-install-senzing-api@v3 with: senzingapi-version: ${{ matrix.senzingapi-version }} - - name: run go test - run: go test -v -p 1 -coverprofile=./cover.out -covermode=atomic -coverpkg=./... ./... + - name: Run go test + run: go test -json -v -p 1 -coverprofile=./cover.out -covermode=atomic -coverpkg=./... ./... 2>&1 | tee /tmp/gotest.log | gotestfmt - name: Store coverage file uses: actions/upload-artifact@v4 @@ -40,7 +50,17 @@ jobs: name: cover.out path: ./cover.out + - name: Upload test log + uses: actions/upload-artifact@v4 + if: always() + with: + name: test-log + path: /tmp/gotest.log + if-no-files-found: error + coverage: - name: coverage + name: Coverage needs: go-test-darwin uses: senzing-factory/build-resources/.github/workflows/go-coverage.yaml@v2 + with: + coverage-config: ./.github/coverage/testcoverage.yaml diff --git a/.github/workflows/go-test-linux.yaml b/.github/workflows/go-test-linux.yaml index df2d2c4..7afdc70 100644 --- a/.github/workflows/go-test-linux.yaml +++ b/.github/workflows/go-test-linux.yaml @@ -1,13 +1,18 @@ -name: go test linux +name: Go test linux on: [push] +env: + LD_LIBRARY_PATH: /opt/senzing/g2/lib + SENZING_LOG_LEVEL: TRACE + SENZING_TOOLS_DATABASE_URL: sqlite3://na:na@nowhere/tmp/sqlite/G2C.db + permissions: contents: read jobs: go-test-linux: - name: "go test with Senzing: ${{ matrix.senzingapi-version }}; OS: ${{ matrix.os }}; Go: ${{ matrix.go }}" + name: "Go test with Senzing: ${{ matrix.senzingapi-version }}; OS: ${{ matrix.os }}; Go: ${{ matrix.go }}" runs-on: ${{ matrix.os }} strategy: matrix: @@ -16,23 +21,28 @@ jobs: senzingapi-version: [staging-v4] steps: - - name: checkout repository + - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - - name: setup go + - name: Setup go uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} - - name: install Senzing API + - name: Set up gotestfmt + uses: gotesttools/gotestfmt-action@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Senzing API uses: senzing-factory/github-action-install-senzing-api@v3 with: senzingapi-runtime-version: ${{ matrix.senzingapi-version }} - - name: run go test - run: go test -v -p 1 -coverprofile=./cover.out -covermode=atomic -coverpkg=./... ./... + - name: Run go test + run: go test -json -v -p 1 -coverprofile=./cover.out -covermode=atomic -coverpkg=./... ./... 2>&1 | tee /tmp/gotest.log | gotestfmt - name: Store coverage file uses: actions/upload-artifact@v4 @@ -40,7 +50,17 @@ jobs: name: cover.out path: ./cover.out + - name: Upload test log + uses: actions/upload-artifact@v4 + if: always() + with: + name: test-log + path: /tmp/gotest.log + if-no-files-found: error + coverage: - name: coverage + name: Coverage needs: go-test-linux uses: senzing-factory/build-resources/.github/workflows/go-coverage.yaml@v2 + with: + coverage-config: ./.github/coverage/testcoverage.yaml diff --git a/.github/workflows/go-test-windows.yaml b/.github/workflows/go-test-windows.yaml index c39b4c5..82aa264 100644 --- a/.github/workflows/go-test-windows.yaml +++ b/.github/workflows/go-test-windows.yaml @@ -1,13 +1,16 @@ -name: go test windows +name: Go test windows on: [pull_request, workflow_dispatch] +env: + SENZING_TOOLS_DATABASE_URL: "sqlite3://na:na@nowhere/C:\\Temp\\sqlite\\G2C.db" + permissions: contents: read jobs: go-test-windows: - name: "go test with Senzing: ${{ matrix.senzingapi-version }}; OS: ${{ matrix.os }}; Go: ${{ matrix.go }}" + name: "Go test with Senzing: ${{ matrix.senzingapi-version }}; OS: ${{ matrix.os }}; Go: ${{ matrix.go }}" runs-on: ${{ matrix.os }} strategy: matrix: @@ -16,24 +19,32 @@ jobs: senzingapi-version: [staging-v4] steps: - - name: checkout repository + - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - - name: setup go + - name: Setup go uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} - - name: install Senzing API + - name: Set up gotestfmt + uses: gotesttools/gotestfmt-action@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Senzing API uses: senzing-factory/github-action-install-senzing-api@v3 with: senzingapi-version: ${{ matrix.senzingapi-version }} - - name: run go test + - name: Add to "Path" environment variable + run: echo "C:\Program Files\Senzing\g2\lib" | Out-File -FilePath "$env:GITHUB_PATH" -Encoding utf8 -Append + + - name: Run go test run: | - go test -v -p 1 -coverprofile=cover -covermode=atomic -coverpkg=./... ./... + go test -json -v -p 1 -coverprofile=cover -covermode=atomic -coverpkg=./... ./... 2>&1 | tee "C:\Temp\gotest.log" | gotestfmt cp cover cover.out - name: Store coverage file @@ -42,7 +53,17 @@ jobs: name: cover.out path: cover.out + - name: Upload test log + uses: actions/upload-artifact@v4 + if: always() + with: + name: test-log + path: "C:\\Temp\\gotest.log" + if-no-files-found: error + coverage: - name: coverage + name: Coverage needs: go-test-windows uses: senzing-factory/build-resources/.github/workflows/go-coverage.yaml@v2 + with: + coverage-config: ./.github/coverage/testcoverage.yaml diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml new file mode 100644 index 0000000..8c0f53a --- /dev/null +++ b/.github/workflows/golangci-lint.yaml @@ -0,0 +1,59 @@ +name: Golangci lint + +on: + push: + branches-ignore: [main] + pull_request: + branches: [main] + +permissions: + # Required: allow read access to the content for analysis. + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + pull-requests: read + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Senzing API + uses: senzing-factory/github-action-install-senzing-api@v3 + with: + senzingapi-runtime-version: staging-v4 + + - name: Copy Senzing headers + run: | + mkdir --parents ./szconfig/gohelpers + cp /opt/senzing/g2/sdk/c/*.h ./szconfig/ + cp /opt/senzing/g2/sdk/c/gohelpers/*.h ./szconfig/gohelpers + mkdir --parents ./szconfigmanager/gohelpers + cp /opt/senzing/g2/sdk/c/*.h ./szconfigmanager/ + cp /opt/senzing/g2/sdk/c/gohelpers/*.h ./szconfigmanager/gohelpers + mkdir --parents ./szdiagnostic/gohelpers + cp /opt/senzing/g2/sdk/c/*.h ./szdiagnostic/ + cp /opt/senzing/g2/sdk/c/gohelpers/*.h ./szdiagnostic/gohelpers + mkdir --parents ./szengine/gohelpers + cp /opt/senzing/g2/sdk/c/*.h ./szengine/ + cp /opt/senzing/g2/sdk/c/gohelpers/*.h ./szengine/gohelpers + mkdir --parents ./szproduct/gohelpers + cp /opt/senzing/g2/sdk/c/*.h ./szproduct/ + cp /opt/senzing/g2/sdk/c/gohelpers/*.h ./szproduct/gohelpers + + - name: Setup go + uses: actions/setup-go@v5 + with: + go-version: 1.21 + + - name: Perform linting + uses: golangci/golangci-lint-action@v6 + with: + args: --config=${{ github.workspace }}/.github/linters/.golangci.yaml + only-new-issues: false + version: latest diff --git a/.github/workflows/lint-workflows.yaml b/.github/workflows/lint-workflows.yaml index c471330..e19c3f8 100644 --- a/.github/workflows/lint-workflows.yaml +++ b/.github/workflows/lint-workflows.yaml @@ -1,4 +1,4 @@ -name: lint workflows +name: Lint workflows on: push: diff --git a/.github/workflows/make-go-tag.yaml b/.github/workflows/make-go-tag.yaml index 5a25899..a4e0646 100644 --- a/.github/workflows/make-go-tag.yaml +++ b/.github/workflows/make-go-tag.yaml @@ -1,4 +1,4 @@ -name: make go tag +name: Make go tag on: push: @@ -10,12 +10,12 @@ permissions: jobs: make-go-tag: - name: make a vM.m.P tag + name: Make a vM.m.P tag runs-on: ubuntu-latest steps: - - name: checkout repository + - name: Checkout repository uses: actions/checkout@v4 - - name: make go version tag + - name: Make go version tag uses: senzing-factory/github-action-make-go-tag@v1 diff --git a/.github/workflows/move-pr-to-done-dependabot.yaml b/.github/workflows/move-pr-to-done-dependabot.yaml index b59571b..c5e0e87 100644 --- a/.github/workflows/move-pr-to-done-dependabot.yaml +++ b/.github/workflows/move-pr-to-done-dependabot.yaml @@ -1,4 +1,4 @@ -name: move pr to done dependabot +name: Move pr to done dependabot on: pull_request: diff --git a/.gitignore b/.gitignore index a7bf099..ffdb6d4 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,6 @@ go.work # Makefile target/ + +cover.out coverage.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 60a6bd9..fe39226 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- +## [0.2.3] - 2024-07-11 + +### Added in 0.2.3 + +- New Options: + - AvoidServe + - EngineInstanceName + - EngineSettings + - LicenseDaysLeft + - LicenseRecordsPercent + +### Deprecated in 0.2.3 + +- Deprecated Options: + - EngineConfigurationJSON + - EngineModuleName ## [0.2.2] - 2024-06-11 diff --git a/Makefile b/Makefile index c62763f..6304837 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ BUILD_TAG := $(shell git describe --always --tags --abbrev=0 | sed 's/v//') BUILD_ITERATION := $(shell git log $(BUILD_TAG)..HEAD --oneline | wc -l | sed 's/^ *//') GIT_REMOTE_URL := $(shell git config --get remote.origin.url) GO_PACKAGE_NAME := $(shell echo $(GIT_REMOTE_URL) | sed -e 's|^git@github.com:|github.com/|' -e 's|\.git$$||' -e 's|Senzing|senzing|') +PATH := $(MAKEFILE_DIRECTORY)/bin:$(PATH) # Recursive assignment ('=') @@ -32,7 +33,6 @@ GO_ARCH = $(word 2, $(GO_OSARCH)) # Conditional assignment. ('?=') # Can be overridden with "export" -# Example: "export LD_LIBRARY_PATH=/path/to/my/senzing-garage/g2/lib" LD_LIBRARY_PATH ?= /opt/senzing/g2/lib GOBIN ?= $(shell go env GOPATH)/bin @@ -63,8 +63,9 @@ hello-world: hello-world-osarch-specific # Dependency management # ----------------------------------------------------------------------------- -.PHONY: make-dependencies -make-dependencies: +.PHONY: dependencies-for-make +dependencies-for-make: + @go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest @go install github.com/vladopajic/go-test-coverage/v2@latest @curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.58.1 @@ -75,9 +76,23 @@ dependencies: @go get -t -u ./... @go mod tidy +# ----------------------------------------------------------------------------- +# Setup +# ----------------------------------------------------------------------------- + +.PHONY: setup +setup: setup-osarch-specific + +# ----------------------------------------------------------------------------- +# Lint +# ----------------------------------------------------------------------------- + +.PHONY: lint +lint: + @${GOBIN}/golangci-lint run --config=.github/linters/.golangci.yaml + # ----------------------------------------------------------------------------- # Build -# - docker-build: https://docs.docker.com/engine/reference/commandline/build/ # ----------------------------------------------------------------------------- PLATFORMS := darwin/amd64 darwin/arm64 linux/amd64 linux/arm64 windows/amd64 windows/arm64 @@ -108,25 +123,24 @@ coverage: coverage-osarch-specific check-coverage: export SENZING_LOG_LEVEL=TRACE check-coverage: go test ./... -coverprofile=./cover.out -covermode=atomic -coverpkg=./... - ${GOBIN}/go-test-coverage --config=./.testcoverage.yml + ${GOBIN}/go-test-coverage --config=.github/coverage/.testcoverage.yaml # ----------------------------------------------------------------------------- -# Lint +# Run # ----------------------------------------------------------------------------- -.PHONY: run-golangci-lint -run-golangci-lint: - ${GOBIN}/golangci-lint run --config=.github/linters/.golangci.yml +.PHONY: run +run: run-osarch-specific # ----------------------------------------------------------------------------- -# Run +# Documentation # ----------------------------------------------------------------------------- -.PHONY: run -run: run-osarch-specific +.PHONY: documentation +documentation: documentation-osarch-specific # ----------------------------------------------------------------------------- -# Utility targets +# Clean # ----------------------------------------------------------------------------- .PHONY: clean @@ -134,6 +148,9 @@ clean: clean-osarch-specific @go clean -cache @go clean -testcache +# ----------------------------------------------------------------------------- +# Utility targets +# ----------------------------------------------------------------------------- .PHONY: help help: @@ -149,10 +166,6 @@ print-make-variables: $(origin $V)),$(warning $V=$($V) ($(value $V))))) -.PHONY: setup -setup: setup-osarch-specific - - .PHONY: update-pkg-cache update-pkg-cache: @GOPROXY=https://proxy.golang.org GO111MODULE=on \ diff --git a/README.md b/README.md index 094c04a..f26e90e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,9 @@ # go-cmdhelping -If you are beginning your journey with -[Senzing](https://senzing.com/), -please start with -[Senzing Quick Start guides](https://docs.senzing.com/quickstart/). - -You are in the -[Senzing Garage](https://github.com/senzing-garage) -where projects are "tinkered" on. +If you are beginning your journey with [Senzing], +please start with [Senzing Quick Start guides]. + +You are in the [Senzing Garage] where projects are "tinkered" on. Although this GitHub repository may help you understand an approach to using Senzing, it's not considered to be "production ready" and is not considered to be part of the Senzing product. Heck, it may not even be appropriate for your application of Senzing! @@ -20,39 +16,45 @@ the recommendation is not to use it yet. ## Synopsis -`go-cmdhelping` contains utility packages for working with -[viper](https://github.com/spf13/viper) and -[cobra](https://github.com/spf13/cobra) +`go-cmdhelping` contains utility packages for working with [viper] and [cobra]. [![Go Reference](https://pkg.go.dev/badge/github.com/senzing-garage/go-cmdhelping.svg)](https://pkg.go.dev/github.com/senzing-garage/go-cmdhelping) [![Go Report Card](https://goreportcard.com/badge/github.com/senzing-garage/go-cmdhelping)](https://goreportcard.com/report/github.com/senzing-garage/go-cmdhelping) [![License](https://img.shields.io/badge/License-Apache2-brightgreen.svg)](https://github.com/senzing-garage/go-cmdhelping/blob/main/LICENSE) -[![gosec.yaml](https://github.com/senzing-garage/go-cmdhelping/actions/workflows/gosec.yaml/badge.svg)](https://github.com/senzing-garage/go-cmdhelping/actions/workflows/gosec.yaml) [![go-test-linux.yaml](https://github.com/senzing-garage/go-cmdhelping/actions/workflows/go-test-linux.yaml/badge.svg)](https://github.com/senzing-garage/go-cmdhelping/actions/workflows/go-test-linux.yaml) [![go-test-darwin.yaml](https://github.com/senzing-garage/go-cmdhelping/actions/workflows/go-test-darwin.yaml/badge.svg)](https://github.com/senzing-garage/go-cmdhelping/actions/workflows/go-test-darwin.yaml) [![go-test-windows.yaml](https://github.com/senzing-garage/go-cmdhelping/actions/workflows/go-test-windows.yaml/badge.svg)](https://github.com/senzing-garage/go-cmdhelping/actions/workflows/go-test-windows.yaml) ## Overview -`go-cmdhelping` is an opinionated use of -[viper](https://github.com/spf13/viper) and -[cobra](https://github.com/spf13/cobra). +`go-cmdhelping` is an opinionated use of [viper] and [cobra]. -Context variables are specified in a list of -[option.ContextVariable](option/option.go). +Context variables are specified in a list of [option.ContextVariable]. -The `[]option.ContextVariable` list is processed by functions in the -[cmdhelper](cmdhelper) package. +The `[]option.ContextVariable` list is processed by functions +in the [cmdhelper] package. ## Use -See -[main.go](main.go) -for an example of use. +See [main.go] for an example of use. ## References -- [Development](docs/development.md) -- [Errors](docs/errors.md) -- [Examples](docs/examples.md) +1. [API documentation] +1. [Development] +1. [Errors] +1. [Examples] + +[API documentation]: https://pkg.go.dev/github.com/senzing-garage/go-cmdhelping +[cmdhelper]: cmdhelper +[cobra]: https://github.com/spf13/cobra +[Development]: docs/development.md +[Errors]: docs/errors.md +[Examples]: docs/examples.md +[main.go]: main.go +[option.ContextVariable]: option/option.go +[Senzing Garage]: https://github.com/senzing-garage-garage +[Senzing Quick Start guides]: https://docs.senzing.com/quickstart/ +[Senzing]: https://senzing.com/ +[viper]: https://github.com/spf13/viper diff --git a/cmdhelper/cmdhelper_examples_test.go b/cmdhelper/cmdhelper_examples_test.go new file mode 100644 index 0000000..5c588e7 --- /dev/null +++ b/cmdhelper/cmdhelper_examples_test.go @@ -0,0 +1,73 @@ +package cmdhelper + +import ( + "fmt" + + "github.com/senzing-garage/go-cmdhelping/option" + "github.com/senzing-garage/go-cmdhelping/option/optiontype" + "github.com/spf13/cobra" +) + +// ---------------------------------------------------------------------------- +// Examples for godoc documentation +// ---------------------------------------------------------------------------- + +func ExampleInit() { + cobraCommand := &cobra.Command{ + Use: "example-use", + Short: "example-short", + Long: `example-long`, + } + var contextVariables = []option.ContextVariable{ + { + Default: "", + Envar: "MY_VARIABLE", + Help: "Description of my variable [%s]", + Arg: "my-variable", + Type: optiontype.String, + }, + } + Init(cobraCommand, contextVariables) + // Output: +} + +func ExampleOsLookupEnvBool() { + fmt.Println(option.OsLookupEnvBool("NOT_AN_ENVIRONMENT_VARIABLE", true)) + // Output: true +} + +func ExampleOsLookupEnvInt() { + fmt.Println(option.OsLookupEnvInt("NOT_AN_ENVIRONMENT_VARIABLE", 10)) + // Output: 10 +} + +func ExampleOsLookupEnvString() { + fmt.Println(option.OsLookupEnvString("NOT_AN_ENVIRONMENT_VARIABLE", "default")) + // Output: default +} + +func ExamplePreRun() { + cobraCommand := &cobra.Command{ + Use: "example-use", + Short: "example-short", + Long: `example-long`, + } + var contextVariables = []option.ContextVariable{ + { + Default: "", + Envar: "MY_VARIABLE", + Help: "Description of my variable [%s]", + Arg: "my-variable", + Type: optiontype.String, + }, + } + Init(cobraCommand, contextVariables) + PreRun(cobraCommand, []string{}, "example-cmd", contextVariables) + // Output: +} + +func ExampleVersion() { + result := Version("1.2.3", "4") + fmt.Println(result) + // Output: 1.2.3-4 +} diff --git a/cmdhelper/cmdhelper_test.go b/cmdhelper/cmdhelper_test.go index a5db3e9..c376113 100644 --- a/cmdhelper/cmdhelper_test.go +++ b/cmdhelper/cmdhelper_test.go @@ -1,13 +1,14 @@ package cmdhelper import ( - "fmt" + "os" + "path/filepath" "testing" "github.com/senzing-garage/go-cmdhelping/option" - "github.com/senzing-garage/go-cmdhelping/option/optiontype" "github.com/spf13/cobra" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var contextVariables = []option.ContextVariable{ @@ -31,18 +32,6 @@ func TestInit(test *testing.T) { Init(cobraCommand, contextVariables) } -func TestOsLookupEnvBool(test *testing.T) { - assert.True(test, option.OsLookupEnvBool("NOT_AN_ENVIRONMENT_VARIABLE", true)) -} - -func TestOsLookupEnvInt(test *testing.T) { - assert.Equal(test, 10, option.OsLookupEnvInt("NOT_AN_ENVIRONMENT_VARIABLE", 10)) -} - -func TestOsLookupEnvString(test *testing.T) { - assert.Equal(test, "default", option.OsLookupEnvString("NOT_AN_ENVIRONMENT_VARIABLE", "default")) -} - func TestPreRun(test *testing.T) { _ = test cobraCommand := &cobra.Command{ @@ -54,74 +43,46 @@ func TestPreRun(test *testing.T) { PreRun(cobraCommand, []string{}, "test-cmd", contextVariables) } -func TestVersion(test *testing.T) { - assert.Equal(test, "1.2.3-4", Version("1.2.3", "4")) -} - -func TestVersion_noIteration(test *testing.T) { - assert.Equal(test, "1.2.3", Version("1.2.3", "0")) -} - -// ---------------------------------------------------------------------------- -// Examples for godoc documentation -// ---------------------------------------------------------------------------- - -func ExampleInit() { - cobraCommand := &cobra.Command{ - Use: "example-use", - Short: "example-short", - Long: `example-long`, +func TestPreRun_badConfigurationPath(test *testing.T) { + _ = test + configurationOption := option.Configuration + configurationOption.Default = "/tmp/senzing-tools" + contextVariables := []option.ContextVariable{ + configurationOption, } - var contextVariables = []option.ContextVariable{ - { - Default: "", - Envar: "MY_VARIABLE", - Help: "Description of my variable [%s]", - Arg: "my-variable", - Type: optiontype.String, - }, + cobraCommand := &cobra.Command{ + Use: "test-use", + Short: "test-short", + Long: `test-long`, } Init(cobraCommand, contextVariables) - // Output: -} - -func ExampleOsLookupEnvBool() { - fmt.Println(option.OsLookupEnvBool("NOT_AN_ENVIRONMENT_VARIABLE", true)) - // Output: true -} - -func ExampleOsLookupEnvInt() { - fmt.Println(option.OsLookupEnvInt("NOT_AN_ENVIRONMENT_VARIABLE", 10)) - // Output: 10 -} - -func ExampleOsLookupEnvString() { - fmt.Println(option.OsLookupEnvString("NOT_AN_ENVIRONMENT_VARIABLE", "default")) - // Output: default + PreRun(cobraCommand, []string{}, "test-cmd", contextVariables) } -func ExamplePreRun() { - cobraCommand := &cobra.Command{ - Use: "example-use", - Short: "example-short", - Long: `example-long`, +func TestPreRun_goodConfigurationPath(test *testing.T) { + _ = test + configurationFilePath := filepath.Join(test.TempDir(), "configuration.txt") + file, err := os.Create(configurationFilePath) + require.NoError(test, err) + defer file.Close() + configurationOption := option.Configuration + configurationOption.Default = configurationFilePath + contextVariables := []option.ContextVariable{ + configurationOption, } - var contextVariables = []option.ContextVariable{ - { - Default: "", - Envar: "MY_VARIABLE", - Help: "Description of my variable [%s]", - Arg: "my-variable", - Type: optiontype.String, - }, + cobraCommand := &cobra.Command{ + Use: "test-use", + Short: "test-short", + Long: `test-long`, } Init(cobraCommand, contextVariables) - PreRun(cobraCommand, []string{}, "example-cmd", contextVariables) - // Output: + PreRun(cobraCommand, []string{}, "test-cmd", contextVariables) +} + +func TestVersion(test *testing.T) { + assert.Equal(test, "1.2.3-4", Version("1.2.3", "4")) } -func ExampleVersion() { - result := Version("1.2.3", "4") - fmt.Println(result) - // Output: 1.2.3-4 +func TestVersion_noIteration(test *testing.T) { + assert.Equal(test, "1.2.3", Version("1.2.3", "0")) } diff --git a/docs/development.md b/docs/development.md index 84ad3ec..8d4b9d7 100644 --- a/docs/development.md +++ b/docs/development.md @@ -2,7 +2,7 @@ ## Install Go -1. See Go's [Download and install](https://go.dev/doc/install) +1. See Go's [Download and install]. ## Install Senzing C library @@ -13,163 +13,169 @@ Since the Senzing library is a prerequisite, it must be installed first. 1. `/opt/senzing/g2/sdk/c` 1. `/etc/opt/senzing` -1. If not installed, see - [How to Install Senzing for Go Development](https://github.com/senzing-garage/knowledge-base/blob/main/HOWTO/install-senzing-for-go-development.md). +1. If not installed, see [How to Install Senzing for Go Development]. ## Install Git repository 1. Identify git repository. ```console - export GIT_ACCOUNT=senzing + export GIT_ACCOUNT=senzing-garage export GIT_REPOSITORY=go-cmdhelping export GIT_ACCOUNT_DIR=~/${GIT_ACCOUNT}.git export GIT_REPOSITORY_DIR="${GIT_ACCOUNT_DIR}/${GIT_REPOSITORY}" ``` -1. Using the environment variables values just set, follow steps in - [clone-repository](https://github.com/senzing-garage/knowledge-base/blob/main/HOWTO/clone-repository.md) to install the Git repository. +1. Using the environment variables values just set, follow + steps in [clone-repository] to install the Git repository. -## Build +## Dependencies -1. Build the binaries. +1. A one-time command to install dependencies needed for `make` targets. Example: - ```console - cd ${GIT_REPOSITORY_DIR} - make build + ```console + cd ${GIT_REPOSITORY_DIR} + make dependencies-for-make - ``` + ``` -1. The binaries will be found in ${GIT_REPOSITORY_DIR}/target. +1. Install dependencies needed for [Go] code. Example: ```console - tree ${GIT_REPOSITORY_DIR}/target + cd ${GIT_REPOSITORY_DIR} + make dependencies ``` -1. Run the binary. +## Build + +1. Build the binaries. Example: ```console - ${GIT_REPOSITORY_DIR}/target/linux/go-cmdhelping + cd ${GIT_REPOSITORY_DIR} + make clean build ``` -1. Clean up. +1. The binaries will be found in the `${GIT_REPOSITORY_DIR}/target` directory. Example: - ```console - cd ${GIT_REPOSITORY_DIR} - make clean + ```console + tree ${GIT_REPOSITORY_DIR}/target - ``` + ``` -## Test +## Run -1. Run Go tests. - Example: +1. Run the binary. + Examples: - ```console - cd ${GIT_REPOSITORY_DIR} - make test + 1. linux - ``` + ```console + ${GIT_REPOSITORY_DIR}/target/linux-amd64/go-cmdhelping -## Documentation + ``` -1. Start `godoc` documentation server. - Example: + 1. macOS - ```console - cd ${GIT_REPOSITORY_DIR} - godoc + ```console + ${GIT_REPOSITORY_DIR}/target/darwin-amd64/go-cmdhelping - ``` + ``` -1. Visit [localhost:6060](http://localhost:6060) -1. Senzing documentation will be in the "Third party" section. - `github.com` > `senzing` > `go-cmdhelping` + 1. windows -1. When a versioned release is published with a `v0.0.0` format tag, -the reference can be found by clicking on the following badge at the top of the README.md page: -[![Go Reference](https://pkg.go.dev/badge/github.com/senzing-garage/go-cmdhelping.svg)](https://pkg.go.dev/github.com/senzing-garage/go-cmdhelping) + ```console + ${GIT_REPOSITORY_DIR}/target/windows-amd64/go-cmdhelping -## Docker + ``` -1. Use make target to run a docker images that builds RPM and DEB files. +1. Clean up. Example: ```console cd ${GIT_REPOSITORY_DIR} - make docker-build + make clean ``` -1. Run docker container. +## Lint + +1. Run Go tests. Example: ```console - docker run \ - --rm \ - senzing/go-cmdhelping + cd ${GIT_REPOSITORY_DIR} + make lint ``` -## Package - -### Package RPM and DEB files +## Test -1. Use make target to run a docker images that builds RPM and DEB files. +1. Run Go tests. Example: ```console cd ${GIT_REPOSITORY_DIR} - make package + make clean setup test ``` -1. The results will be in the `${GIT_REPOSITORY_DIR}/target` directory. - Example: +## Coverage - ```console - tree ${GIT_REPOSITORY_DIR}/target +Create a code coverage map. - ``` - -### Test DEB package on Ubuntu - -1. Determine if `go-cmdhelping` is installed. +1. Run Go tests. Example: ```console - apt list --installed | grep go-cmdhelping + cd ${GIT_REPOSITORY_DIR} + make clean setup coverage ``` -1. :pencil2: Install `go-cmdhelping`. + A web-browser will show the results of the coverage. + The goal is to have over 80% coverage. + Anything less needs to be reflected in [testcoverage.yaml]. + +## Documentation + +1. Start [godoc] documentation server. Example: ```console - cd ${GIT_REPOSITORY_DIR}/target - sudo apt install ./go-cmdhelping-0.0.0.deb + cd ${GIT_REPOSITORY_DIR} + make clean documentation ``` -1. Run command. - Example: +1. If a web page doesn't appear, visit [localhost:6060]. +1. Senzing documentation will be in the "Third party" section. + `github.com` > `senzing` > `go-cmdhelping` - ```console - go-cmdhelping +1. When a versioned release is published with a `v0.0.0` format tag, +the reference can be found by clicking on the following badge at the top of the README.md page. +Example: - ``` + [![Go Reference](https://pkg.go.dev/badge/github.com/senzing-garage/go-cmdhelping.svg)](https://pkg.go.dev/github.com/senzing-garage/go-cmdhelping-go) -1. Remove `go-cmdhelping` from system. - Example: +1. To stop the `godoc` server, run ```console - sudo apt-get remove go-cmdhelping + cd ${GIT_REPOSITORY_DIR} + make clean ``` + +[clone-repository]: https://github.com/senzing-garage/knowledge-base/blob/main/HOWTO/clone-repository.md +[Download and install]: https://go.dev/doc/install +[Go]: https://go.dev/ +[godoc]: https://pkg.go.dev/golang.org/x/tools/cmd/godoc +[How to Install Senzing for Go Development]: https://github.com/senzing-garage/knowledge-base/blob/main/HOWTO/install-senzing-for-go-development.md +[localhost:6060]: http://localhost:6060/pkg/github.com/senzing-garage/go-cmdhelping/ +[testcoverage.yaml]: ../.github/coverage/testcoverage.yaml diff --git a/docs/examples.md b/docs/examples.md index 3cb6b8d..438ce74 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -1,11 +1 @@ # go-cmdhelping examples - -## Examples of CLI - -The following examples require initialization described in -[Demonstrate using Command Line Interface](../README.md#demonstrate-using-command-line-interface). - -## Examples of Docker - -The following examples require initialization described in -[Demonstrate using Docker](../README.md#demonstrate-using-docker). \ No newline at end of file diff --git a/go.mod b/go.mod index 16146ce..9ee8388 100644 --- a/go.mod +++ b/go.mod @@ -27,8 +27,8 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect + golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 383d1c1..e8b1344 100644 --- a/go.sum +++ b/go.sum @@ -63,10 +63,10 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM= -golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= +golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/main.go b/main.go index 6d4cc1f..bf66d7e 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,14 @@ const ( Long string = "Long description of command." ) +func Run(cmd *cobra.Command, args []string) { + _ = cmd + _ = args + fmt.Printf("--%-12s %s: %s\n", option.DatabaseURL.Arg, fmt.Sprintf(option.DatabaseURL.Help, option.DatabaseURL.Envar), viper.GetString(option.DatabaseURL.Arg)) + fmt.Printf("--%-12s %s: %d\n", option.HTTPPort.Arg, fmt.Sprintf(option.HTTPPort.Help, option.HTTPPort.Envar), viper.GetInt(option.HTTPPort.Arg)) + fmt.Printf("--%-12s %s: %s\n", option.LogLevel.Arg, fmt.Sprintf(option.LogLevel.Help, option.LogLevel.Envar), viper.GetString(option.LogLevel.Arg)) +} + func main() { // Define the command-line options / environment variables used for context variables. @@ -39,16 +47,10 @@ func main() { // Initialize cobra. var cobraCommand = &cobra.Command{ - Use: Use, - Short: Short, - Long: Long, - Run: func(cmd *cobra.Command, args []string) { - _ = cmd - _ = args - fmt.Printf("--%-12s %s: %s\n", option.DatabaseURL.Arg, fmt.Sprintf(option.DatabaseURL.Help, option.DatabaseURL.Envar), viper.GetString(option.DatabaseURL.Arg)) - fmt.Printf("--%-12s %s: %d\n", option.HTTPPort.Arg, fmt.Sprintf(option.HTTPPort.Help, option.HTTPPort.Envar), viper.GetInt(option.HTTPPort.Arg)) - fmt.Printf("--%-12s %s: %s\n", option.LogLevel.Arg, fmt.Sprintf(option.LogLevel.Help, option.LogLevel.Envar), viper.GetString(option.LogLevel.Arg)) - }, + Use: Use, + Short: Short, + Long: Long, + Run: Run, Version: cmdhelper.Version("1234", "5"), } diff --git a/main_test.go b/main_test.go index fb35697..254dbb3 100644 --- a/main_test.go +++ b/main_test.go @@ -1,13 +1,12 @@ package main import ( + "os" "testing" ) -/* - * The unit tests in this file simulate command line invocation. - */ func TestMain(test *testing.T) { _ = test + os.Args = []string{"command-name"} main() } diff --git a/makefiles/darwin.mk b/makefiles/darwin.mk index 5c07ecc..5475be3 100644 --- a/makefiles/darwin.mk +++ b/makefiles/darwin.mk @@ -17,17 +17,25 @@ build-osarch-specific: darwin/amd64 clean-osarch-specific: @rm -f $(GOPATH)/bin/$(PROGRAM_NAME) || true @rm -f $(MAKEFILE_DIRECTORY)/coverage.html || true - @rm -f $(MAKEFILE_DIRECTORY)/coverage.out || true + @rm -f $(MAKEFILE_DIRECTORY)/cover.out || true @rm -fr $(TARGET_DIRECTORY) || true + @pkill godoc || true .PHONY: coverage-osarch-specific +coverage-osarch-specific: export SENZING_LOG_LEVEL=TRACE coverage-osarch-specific: @go test -v -coverprofile=coverage.out -p 1 ./... @go tool cover -html="coverage.out" -o coverage.html @open file://$(MAKEFILE_DIRECTORY)/coverage.html +.PHONY: documentation-osarch-specific +documentation-osarch-specific: + godoc & + @open http://localhost:6060 + + .PHONY: hello-world-osarch-specific hello-world-osarch-specific: @echo "Hello World, from darwin." @@ -45,7 +53,7 @@ setup-osarch-specific: .PHONY: test-osarch-specific test-osarch-specific: - @go test -exec macos_exec_dyld.sh -v -p 1 ./... + @go test -exec macos_exec_dyld.sh -json -v -p 1 ./... 2>&1 | tee /tmp/gotest.log | gotestfmt # ----------------------------------------------------------------------------- # Makefile targets supported only by this platform. diff --git a/makefiles/linux.mk b/makefiles/linux.mk index f216c7e..f1929c6 100644 --- a/makefiles/linux.mk +++ b/makefiles/linux.mk @@ -17,8 +17,9 @@ build-osarch-specific: linux/amd64 clean-osarch-specific: @rm -f $(GOPATH)/bin/$(PROGRAM_NAME) || true @rm -f $(MAKEFILE_DIRECTORY)/coverage.html || true - @rm -f $(MAKEFILE_DIRECTORY)/coverage.out || true + @rm -f $(MAKEFILE_DIRECTORY)/cover.out || true @rm -fr $(TARGET_DIRECTORY) || true + @pkill godoc || true .PHONY: coverage-osarch-specific @@ -29,6 +30,12 @@ coverage-osarch-specific: @xdg-open $(MAKEFILE_DIRECTORY)/coverage.html +.PHONY: documentation-osarch-specific +documentation-osarch-specific: + godoc & + xdg-open http://localhost:6060 + + .PHONY: hello-world-osarch-specific hello-world-osarch-specific: @echo "Hello World, from linux." @@ -47,7 +54,7 @@ setup-osarch-specific: .PHONY: test-osarch-specific test-osarch-specific: - @go test -v -p 1 ./... + @go test -json -v -p 1 ./... 2>&1 | tee /tmp/gotest.log | gotestfmt # ----------------------------------------------------------------------------- # Makefile targets supported only by this platform. diff --git a/makefiles/windows.mk b/makefiles/windows.mk index b92648d..9a65844 100644 --- a/makefiles/windows.mk +++ b/makefiles/windows.mk @@ -18,15 +18,22 @@ build-osarch-specific: windows/amd64 clean-osarch-specific: del /F /S /Q $(GOPATH)/bin/$(PROGRAM_NAME) del /F /S /Q $(MAKEFILE_DIRECTORY)/coverage.html - del /F /S /Q $(MAKEFILE_DIRECTORY)/coverage.out + del /F /S /Q $(MAKEFILE_DIRECTORY)/cover.out del /F /S /Q $(TARGET_DIRECTORY) + taskkill /f /t/im godoc .PHONY: coverage-osarch-specific coverage-osarch-specific: @go test -v -coverprofile=coverage.out -p 1 ./... @go tool cover -html="coverage.out" -o coverage.html - @xdg-open file://$(MAKEFILE_DIRECTORY)/coverage.html + @explorer file://$(MAKEFILE_DIRECTORY)/coverage.html + + +.PHONY: documentation-osarch-specific +documentation-osarch-specific: + @start /b godoc + @explorer http://localhost:6060 .PHONY: hello-world-osarch-specific @@ -34,7 +41,6 @@ hello-world-osarch-specific: @echo "Hello World, from windows." - .PHONY: run-osarch-specific run-osarch-specific: @go run main.go @@ -47,7 +53,7 @@ setup-osarch-specific: .PHONY: test-osarch-specific test-osarch-specific: - @go test -v -p 1 ./... + @go test -json -v -p 1 ./... 2>&1 | tee /tmp/gotest.log | gotestfmt # ----------------------------------------------------------------------------- # Makefile targets supported only by this platform. diff --git a/option/option.go b/option/option.go index f49e9c5..cd8eca7 100644 --- a/option/option.go +++ b/option/option.go @@ -14,6 +14,14 @@ func (v ContextVariable) SetDefault(newDefault any) ContextVariable { return v } +var AvoidServe = ContextVariable{ + Arg: "avoid-serving", + Default: OsLookupEnvBool("SENZING_TOOLS_AVOID_SERVING", false), + Envar: "SENZING_TOOLS_AVOID_SERVING", + Help: "Avoid serving. For testing only. [%s]", + Type: optiontype.Bool, +} + var ConfigPath = ContextVariable{ Arg: "config-path", Default: OsLookupEnvString("SENZING_TOOLS_CONFIG_PATH", ""), @@ -134,6 +142,7 @@ var EnableXterm = ContextVariable{ Type: optiontype.Bool, } +// Deprecated: Use EngineSettings instead. var EngineConfigurationJSON = ContextVariable{ Arg: "engine-configuration-json", Default: OsLookupEnvString("SENZING_TOOLS_ENGINE_CONFIGURATION_JSON", ""), @@ -142,6 +151,14 @@ var EngineConfigurationJSON = ContextVariable{ Type: optiontype.String, } +var EngineInstanceName = ContextVariable{ + Arg: "engine-instance-name", + Default: fmt.Sprintf("senzing-tools-%d", time.Now().Unix()), + Envar: "SENZING_TOOLS_ENGINE_INSTANCE_NAME", + Help: "Identifier given to the Senzing engine [%s]", + Type: optiontype.String, +} + var EngineLogLevel = ContextVariable{ Arg: "engine-log-level", Default: OsLookupEnvInt("SENZING_TOOLS_ENGINE_LOG_LEVEL", 0), @@ -150,6 +167,7 @@ var EngineLogLevel = ContextVariable{ Type: optiontype.Int, } +// Deprecated: Use EngineInstanceName instead. var EngineModuleName = ContextVariable{ Arg: "engine-module-name", Default: fmt.Sprintf("senzing-tools-%d", time.Now().Unix()), @@ -158,6 +176,14 @@ var EngineModuleName = ContextVariable{ Type: optiontype.String, } +var EngineSettings = ContextVariable{ + Arg: "engine-settings", + Default: OsLookupEnvString("SENZING_TOOLS_ENGINE_SETTINGS", ""), + Envar: "SENZING_TOOLS_ENGINE_SETTINGS", + Help: "JSON string sent to Senzing's init() function [%s]", + Type: optiontype.String, +} + var MessageID = ContextVariable{ Arg: "message-id", Default: OsLookupEnvString("SENZING_TOOLS_MESSAGE_ID", ""), @@ -214,6 +240,22 @@ var JSONOutput = ContextVariable{ Type: optiontype.Bool, } +var LicenseDaysLeft = ContextVariable{ + Arg: "license-days-left", + Default: OsLookupEnvString("SENZING_TOOLS_LICENSE_DAYS_LEFT", "30"), + Envar: "SENZING_TOOLS_LICENSE_DAYS_LEFT", + Help: "Number of days left in license before flagging as an error [%s]", + Type: optiontype.String, +} + +var LicenseRecordsPercent = ContextVariable{ + Arg: "license-records-percent", + Default: OsLookupEnvString("SENZING_TOOLS_LICENSE_RECORDS_PERCENT", "90"), + Envar: "SENZING_TOOLS_LICENSE_RECORDS_PERCENT", + Help: "Percent of records allowed by license [%s]", + Type: optiontype.String, +} + var LicenseStringBase64 = ContextVariable{ Arg: "license-string-base64", Default: OsLookupEnvString("SENZING_TOOLS_LICENSE_STRING_BASE64", ""), diff --git a/option/option_test.go b/option/option_test.go index 8b9794b..30a28ca 100644 --- a/option/option_test.go +++ b/option/option_test.go @@ -11,8 +11,19 @@ import ( // ---------------------------------------------------------------------------- func TestOsLookupEnvBool(test *testing.T) { - test.Setenv("AN_ENVIRONMENT_VARIABLE", "true") - assert.True(test, OsLookupEnvBool("AN_ENVIRONMENT_VARIABLE", false)) + environmentVariableName := "AN_ENVIRONMENT_VARIABLE" + test.Setenv(environmentVariableName, "true") + assert.True(test, OsLookupEnvBool(environmentVariableName, false)) +} + +func TestOsLookupEnvBool_badValue(test *testing.T) { + environmentVariableName := "BAD_BOOLEAN_ENVIRONMENT_VARIABLE" + test.Setenv(environmentVariableName, "not-a-boolean") + assert.Panics(test, func() { _ = OsLookupEnvBool(environmentVariableName, true) }) +} + +func TestOsLookupEnvBool_notEnvVar(test *testing.T) { + assert.True(test, OsLookupEnvBool("NOT_AN_ENVIRONMENT_VARIABLE", true)) } func TestOsLookupEnvBool_useDefault(test *testing.T) { @@ -20,8 +31,19 @@ func TestOsLookupEnvBool_useDefault(test *testing.T) { } func TestOsLookupEnvInt(test *testing.T) { - test.Setenv("AN_ENVIRONMENT_VARIABLE", "10") - assert.Equal(test, 10, OsLookupEnvInt("AN_ENVIRONMENT_VARIABLE", 99)) + environmentVariableName := "AN_ENVIRONMENT_VARIABLE" + test.Setenv(environmentVariableName, "10") + assert.Equal(test, 10, OsLookupEnvInt(environmentVariableName, 99)) +} + +func TestOsLookupEnvInt_badValue(test *testing.T) { + environmentVariableName := "BAD_INTEGER_ENVIRONMENT_VARIABLE" + test.Setenv(environmentVariableName, "not-an-integer") + assert.Panics(test, func() { _ = OsLookupEnvInt(environmentVariableName, 10) }) +} + +func TestOsLookupEnvInt_notEnvVar(test *testing.T) { + assert.Equal(test, 10, OsLookupEnvInt("NOT_AN_ENVIRONMENT_VARIABLE", 10)) } func TestOsLookupEnvInt_useDefault(test *testing.T) { @@ -29,8 +51,13 @@ func TestOsLookupEnvInt_useDefault(test *testing.T) { } func TestOsLookupEnvString(test *testing.T) { - test.Setenv("AN_ENVIRONMENT_VARIABLE", "default") - assert.Equal(test, "default", OsLookupEnvString("AN_ENVIRONMENT_VARIABLE", "not-default")) + environmentVariableName := "AN_ENVIRONMENT_VARIABLE" + test.Setenv(environmentVariableName, "default") + assert.Equal(test, "default", OsLookupEnvString(environmentVariableName, "not-default")) +} + +func TestOsLookupEnvString_notEnvVar(test *testing.T) { + assert.Equal(test, "default", OsLookupEnvString("NOT_AN_ENVIRONMENT_VARIABLE", "default")) } func TestOsLookupEnvString_useDefault(test *testing.T) { diff --git a/settings/settings.go b/settings/settings.go index 5093882..1f7a2af 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -12,7 +12,7 @@ import ( func BuildSettings(ctx context.Context, aViper *viper.Viper) (string, error) { _ = ctx var err error - result := aViper.GetString(option.EngineConfigurationJSON.Arg) + result := aViper.GetString(option.EngineSettings.Arg) if len(result) == 0 { optionsList := map[string]option.ContextVariable{ "configPath": option.ConfigPath,