From c7968c4901c76feac91720d598faf8688e733e7f Mon Sep 17 00:00:00 2001 From: Siddhartha Basu Date: Fri, 15 May 2026 20:01:52 +0000 Subject: [PATCH 1/7] chore: upgrade Go from 1.22 to 1.25 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upgrade go.mod, Dockerfile, and all CI workflow files to use Go 1.25. Docker image updated to golang:1.25-trixie (bullseye not available for 1.25). πŸ’˜ Generated with Crush Assisted-by: Crush:deepseek/deepseek-v4-pro --- .github/workflows/ci.yaml | 2 +- .github/workflows/lint.yaml | 2 +- .github/workflows/release.yaml | 2 +- .github/workflows/testcov.yaml | 2 +- build/package/Dockerfile | 2 +- go.mod | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 850b861..5c5fffd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ jobs: - name: set up golang uses: actions/setup-go@v5 with: - go-version: 1.22 + go-version: 1.25 - name: unit test run: go test -parallel 4 -covermode=atomic -coverprofile=profile.cov -v ./... - name: upload coverage to codecov diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 4bf830b..645705c 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -8,7 +8,7 @@ jobs: uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: 1.22 + go-version: 1.25 cache: false - name: run linter uses: golangci/golangci-lint-action@v6 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 77bc98e..183be6d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -12,7 +12,7 @@ jobs: - name: setup golang uses: actions/setup-go@v5 with: - go-version: 1.22 + go-version: 1.25 - name: generate and publish binary if: startsWith(github.ref, 'refs/tags/') uses: goreleaser/goreleaser-action@v6 diff --git a/.github/workflows/testcov.yaml b/.github/workflows/testcov.yaml index 625170a..4d942e2 100644 --- a/.github/workflows/testcov.yaml +++ b/.github/workflows/testcov.yaml @@ -7,7 +7,7 @@ jobs: - name: set up golang uses: actions/setup-go@v5 with: - go-version: 1.22 + go-version: 1.25 - name: check out code uses: actions/checkout@v4 - name: unit test diff --git a/build/package/Dockerfile b/build/package/Dockerfile index 44f7113..805d375 100644 --- a/build/package/Dockerfile +++ b/build/package/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22-bullseye AS builder +FROM golang:1.25-trixie AS builder LABEL maintainer="Siddhartha Basu " ENV GOPROXY https://proxy.golang.org ENV GO111MODULE=on \ diff --git a/go.mod b/go.mod index 304a978..5c6e077 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/dictyBase-docker/github-actions -go 1.22 +go 1.25 require ( github.com/Jeffail/gabs/v2 v2.7.0 From 332f28efbc7d06cfdec8aae3e4e678dcda22bfb3 Mon Sep 17 00:00:00 2001 From: Siddhartha Basu Date: Fri, 15 May 2026 15:02:10 -0500 Subject: [PATCH 2/7] docs: add AGENTS.md with essential development commands Create a documentation file to centralize common CLI commands for testing, linting, and formatting. This provides a quick reference for developers to ensure consistent execution of project tasks using gotestsum and golangci-lint. --- AGENTS.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..3beb554 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,22 @@ +# AGENTS.md + + +## Essential Commands + +```bash +# Test +gotestsum --format pkgname-and-test-fails --format-hide-empty-pkg -- ./... + +# Test (verbose) +gotestsum --format testdox --format-hide-empty-pkg -- ./... + +# Watch mode +gotestsum --watch --format pkgname-and-test-fails --format-hide-empty-pkg -- ./... + +# Lint +golangci-lint run ./... + +# Format +golangci-lint fmt + + From 7186f65b2e8b4df0b436f9cc9baaf37f2ff9f629 Mon Sep 17 00:00:00 2001 From: Siddhartha Basu Date: Fri, 15 May 2026 15:02:18 -0500 Subject: [PATCH 3/7] refactor(.golangci.yml): update linter configuration and enable new checks Update the golangci-lint configuration to version 2, enable parallel runners, and refresh the list of enabled linters to align with modern Go best practices. Add specific formatters and refine exclusion rules to reduce noise from generated code and third-party dependencies. --- .golangci.yml | 87 +++++++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index aa482e6..a42b0d5 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,61 +1,74 @@ -linters-settings: - lll: - line-length: 2380 - funlen: - lines: 75 - errcheck: - ignore : "" +version: "2" +run: + allow-parallel-runners: true linters: - # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint - disable-all: true + default: none enable: - asciicheck + - bidichk - bodyclose - - cyclop + - copyloopvar + - cyclop - decorder - dogsled - - dupl - - errcheck - - errname - funlen - - gochecknoinits + - funcorder - goconst - - gocritic - gocyclo - - godot - - gofmt - - goimports - gosec - - gosimple - govet - gocognit + - godoclint + - intrange - ineffassign + - importas + - inamedparam + - interfacebloat - lll + - loggercheck - maintidx - misspell + - mnd + - modernize - nakedret - nestif - - nilerr - - nolintlint - - prealloc - - paralleltest + - protogetter - revive - - rowserrcheck + - recvcheck - staticcheck - - stylecheck - - typecheck + - testifylint + - modernize - unconvert - - thelper - - tparallel + - usestdlibvars - unparam - unused - - unconvert - - unparam - - varnamelen - - wastedassign - whitespace - - wrapcheck - - # don't enable: - # - godox - maligned,prealloc - # - gochecknoglobals + - wsl_v5 + settings: + funlen: + lines: 120 + statements: 50 + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ + - internal/baserow/ + - internal/k8s/ +formatters: + enable: + - gofumpt + - goimports + - golines + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ From b4b521aadf53be2360e882cbafe239a2d5ae2c86 Mon Sep 17 00:00:00 2001 From: Siddhartha Basu Date: Fri, 15 May 2026 20:04:31 +0000 Subject: [PATCH 4/7] chore(deps): upgrade all golang.org/x and google.golang.org packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - golang.org/x/{oauth2,sync,text,net,crypto,sys,exp} to latest - google.golang.org/{api,grpc,protobuf,genproto} to latest - Transitive deps (cloud.google.com, otel) updated accordingly πŸ’˜ Generated with Crush Assisted-by: Crush:deepseek/deepseek-v4-pro --- go.mod | 51 ++++++++++++----------- go.sum | 125 ++++++++++++++++++++++++++++++--------------------------- 2 files changed, 91 insertions(+), 85 deletions(-) diff --git a/go.mod b/go.mod index 5c6e077..c24de0f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/dictyBase-docker/github-actions -go 1.25 +go 1.25.0 require ( github.com/Jeffail/gabs/v2 v2.7.0 @@ -10,45 +10,44 @@ require ( github.com/repeale/fp-go v0.11.1 github.com/sethvargo/go-githubactions v1.3.0 github.com/sirupsen/logrus v1.9.3 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 github.com/urfave/cli v1.22.16 - golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d - golang.org/x/oauth2 v0.26.0 - golang.org/x/sync v0.11.0 - golang.org/x/text v0.22.0 - google.golang.org/api v0.219.0 + golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a + golang.org/x/oauth2 v0.36.0 + golang.org/x/sync v0.20.0 + golang.org/x/text v0.37.0 + google.golang.org/api v0.279.0 ) require ( - cloud.google.com/go/auth v0.14.0 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect - cloud.google.com/go/compute/metadata v0.6.0 // indirect + cloud.google.com/go/auth v0.20.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-ini/ini v1.66.6 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect - github.com/googleapis/gax-go/v2 v2.14.1 // indirect - github.com/kr/text v0.2.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.15 // indirect + github.com/googleapis/gax-go/v2 v2.22.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect - go.opentelemetry.io/otel v1.32.0 // indirect - go.opentelemetry.io/otel/metric v1.32.0 // indirect - go.opentelemetry.io/otel/trace v1.32.0 // indirect - golang.org/x/crypto v0.32.0 // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/sys v0.29.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47 // indirect - google.golang.org/grpc v1.70.0 // indirect - google.golang.org/protobuf v1.36.4 // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/sys v0.44.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/grpc v1.81.1 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 41202d3..0aa9f1f 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,16 @@ -cloud.google.com/go/auth v0.14.0 h1:A5C4dKV/Spdvxcl0ggWwWEzzP7AZMJSEIgrkngwhGYM= -cloud.google.com/go/auth v0.14.0/go.mod h1:CYsoRL1PdiDuqeQpZE0bP2pnPrGqFcOkI0nldEQis+A= -cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= -cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= -cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= -cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA= +cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -18,16 +19,16 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/go-ini/ini v1.66.6 h1:h6k2Bb0HWS/BXXHCXj4QHjxPmlIU4NK+7MuLp9SD+4k= github.com/go-ini/ini v1.66.6/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwMmHdhl4= @@ -39,24 +40,24 @@ github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= -github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= -github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= -github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/googleapis/enterprise-certificate-proxy v0.3.15 h1:xolVQTEXusUcAA5UgtyRLjelpFFHWlPQ4XfWGc7MBas= +github.com/googleapis/enterprise-certificate-proxy v0.3.15/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= +github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4= +github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o= github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/repeale/fp-go v0.11.1 h1:Q/e+gNyyHaxKAyfdbBqvip3DxhVWH453R+kthvSr9Mk= github.com/repeale/fp-go v0.11.1/go.mod h1:4KrwQJB1VRY+06CA+jTc4baZetr6o2PeuqnKr5ybQUc= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sethvargo/go-githubactions v1.3.0 h1:Kg633LIUV2IrJsqy2MfveiED/Ouo+H2P0itWS0eLh8A= @@ -72,57 +73,63 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= -go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d h1:vtUKgx8dahOomfFzLREU8nSv25YHnTgLBn4rDnWZdU0= -golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= -golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.219.0 h1:nnKIvxKs/06jWawp2liznTBnMRQBEPpGo7I+oEypTX0= -google.golang.org/api v0.219.0/go.mod h1:K6OmjGm+NtLrIkHxv1U3a0qIf/0JOvAHd5O/6AoyKYE= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/api v0.279.0 h1:hsx2M2OaRcaKtVYK6vXEUnQvdjnend7ZYES+lYaot74= +google.golang.org/api v0.279.0/go.mod h1:B9TqLBwJqVjp1mtt7WeoQwWRwvu/400y5lETOql+giQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47 h1:91mG8dNTpkC0uChJUQ9zCiRqx3GEEFOWaRZ0mI6Oj2I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= -google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= -google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0= +google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I= +google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 h1:41r6JMbpzBMen0R/4TZeeAmGXSJC7DftGINUodzTkPI= +google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 h1:seT2EwLWM78plQ7wcDfuWBc/4FAEAXDDiaSol4ku4qo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 2ba83226e15207a97863eb98f74f31723949c79b Mon Sep 17 00:00:00 2001 From: Siddhartha Basu Date: Fri, 15 May 2026 20:42:48 +0000 Subject: [PATCH 5/7] style: fix all golangci-lint warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace magic numbers with named constants across all files - Fix testifylint expected-actual ordering and assert.Contains - Modernize interface{}β†’any and SplitSeq usage - Fix line length, whitespace, and formatting (wsl_v5, gofumpt, golines) - Replace deprecated option.WithCredentialsFile with WithAuthCredentialsFile πŸ’˜ Generated with Crush Assisted-by: Crush:deepseek/deepseek-v4-pro --- cmd/github-actions/main.go | 1 + internal/app/analytics/analytics.go | 15 ++++++- internal/app/chart/chart.go | 14 ++++--- internal/app/chatops/deploy.go | 20 ++++++++- internal/app/chatops/deploy_test.go | 30 +++++++------- internal/app/comment/ontology.go | 27 ++++++++++--- internal/app/comment/ontology_test.go | 27 +++++++++---- internal/app/dagger/dagger.go | 54 +++++++++++++++++++++---- internal/app/deploy/deploy.go | 10 ++++- internal/app/deploy/share.go | 6 +++ internal/app/gcloud/gcloud.go | 7 +++- internal/app/issue/issue.go | 43 ++++++++++++++++---- internal/app/repository/commit.go | 17 ++++++-- internal/app/repository/file.go | 15 +++++-- internal/app/repository/migrate.go | 23 ++++++++++- internal/app/repository/migrate_test.go | 4 ++ internal/app/storage/s3.go | 11 ++++- internal/cmd/migrate.go | 9 ++++- internal/fake/github.go | 4 ++ internal/fake/http.go | 8 ++++ internal/fake/payload.go | 6 +++ internal/file/io.go | 10 ++++- internal/github/builder.go | 7 ++++ internal/github/builder_test.go | 8 +++- internal/github/manager.go | 14 ++++++- internal/github/manager_test.go | 4 ++ internal/logger/logger.go | 2 + internal/ontology/report.go | 8 ++++ internal/ontology/report_test.go | 1 + internal/runner/helm.go | 4 ++ 30 files changed, 336 insertions(+), 73 deletions(-) diff --git a/cmd/github-actions/main.go b/cmd/github-actions/main.go index 307cc04..e9b6d6e 100644 --- a/cmd/github-actions/main.go +++ b/cmd/github-actions/main.go @@ -39,6 +39,7 @@ func main() { Value: "dictyBase", }, } + app.Commands = []cli.Command{ cmd.IssueCommentCmds(), cmd.CommentsCountByDateCmds(), diff --git a/internal/app/analytics/analytics.go b/internal/app/analytics/analytics.go index c1810c5..76a86d6 100644 --- a/internal/app/analytics/analytics.go +++ b/internal/app/analytics/analytics.go @@ -40,11 +40,16 @@ func generateReportRequest(clt *cli.Context) *ga.ReportRequest { } func Report(clt *cli.Context) error { - srv, err := ga.NewService(context.Background(), option.WithCredentialsFile(clt.String("credential-file"))) + srv, err := ga.NewService( + context.Background(), + option.WithAuthCredentialsFile(option.ServiceAccount, clt.String("credential-file")), + ) if err != nil { return fmt.Errorf("error in creating service client %s", err) } + rq := &ga.GetReportsRequest{ReportRequests: []*ga.ReportRequest{generateReportRequest(clt)}} + res, err := ga.NewReportsService(srv).BatchGet(rq).Do() if err != nil { return fmt.Errorf("error in running the query %s", err) @@ -55,19 +60,25 @@ func Report(clt *cli.Context) error { func writeOutput(clt *cli.Context, res *ga.GetReportsResponse) error { fhr := os.Stdout + if len(clt.String("output")) > 1 { ch, err := os.Create(clt.String("output")) if err != nil { return fmt.Errorf("error in creating file %s %s", clt.String("output"), err) } + fhr = ch } + defer fhr.Close() + wrt := csv.NewWriter(fhr) + err := wrt.Write(processReportHeader(res)) if err != nil { return fmt.Errorf("error in writing header %s", err) } + for _, row := range res.Reports[0].Data.Rows { for _, metric := range row.Metrics { dataRow := slices.Insert(metric.Values, 0, fmtDate(row.Dimensions[0])) @@ -76,7 +87,9 @@ func writeOutput(clt *cli.Context, res *ga.GetReportsResponse) error { } } } + wrt.Flush() + if err := wrt.Error(); err != nil { return fmt.Errorf("error in finishing csv output %s", err) } diff --git a/internal/app/chart/chart.go b/internal/app/chart/chart.go index 55e4d7c..f6edc0c 100644 --- a/internal/app/chart/chart.go +++ b/internal/app/chart/chart.go @@ -5,13 +5,16 @@ import ( "github.com/urfave/cli" ) +const exitFailure = 2 + func DeployChart(clt *cli.Context) error { helm, err := runner.NewHelm() if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + if err := helm.IsConnected(); err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } return installOrUpgrade(clt, helm) @@ -20,8 +23,9 @@ func DeployChart(clt *cli.Context) error { func installOrUpgrade(clt *cli.Context, helm *runner.Helm) error { isok, err := helm.IsChartDeployed(clt.String("name")) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + prc := &runner.ChartParams{ Name: clt.String("name"), Namespace: clt.String("namespace"), @@ -30,11 +34,11 @@ func installOrUpgrade(clt *cli.Context, helm *runner.Helm) error { } if isok { if err := helm.UpgradeChart(prc); err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } } else { if err := helm.InstallChart(prc); err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } } diff --git a/internal/app/chatops/deploy.go b/internal/app/chatops/deploy.go index e0981eb..a6b6f5b 100644 --- a/internal/app/chatops/deploy.go +++ b/internal/app/chatops/deploy.go @@ -56,7 +56,8 @@ type Inputs struct { // WorkflowDispatchEvent is triggered when someone triggers a workflow run on GitHub or // sends a POST request to the create a workflow dispatch event endpoint. // -// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#workflow_dispatch +// GitHub API docs: +// https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#workflow_dispatch type WorkflowDispatchEvent struct { Inputs json.RawMessage `json:"inputs,omitempty"` Ref *string `json:"ref,omitempty"` @@ -75,10 +76,12 @@ type Output struct { func getWorkflowInputsFromJSON(r io.Reader) (*Inputs, error) { inp := &Inputs{} + w := &WorkflowDispatchEvent{} if err := json.NewDecoder(r).Decode(w); err != nil { return inp, fmt.Errorf("error in decoding json %s", err) } + if err := json.Unmarshal(w.Inputs, &inp); err != nil { return inp, fmt.Errorf("error in decoding json data to struct %s", err) } @@ -92,24 +95,30 @@ func ParseDeployCommand(clt *cli.Context) error { return fmt.Errorf("error in reading content from file %s", err) } defer r.Close() + pjson, err := getWorkflowInputsFromJSON(r) if err != nil { return err } + act := githubactions.New() log := logger.GetLogger(clt) + oinput, err := parseWorkflowInputs(pjson) if err != nil { return fmt.Errorf("error in parsing workflow inputs %s", err) } + imageTag := oinput.ImageTag // add image tag prefixes for developers if clt.Bool("frontend") && pjson.Cluster == "erickube" { imageTag = fmt.Sprintf("ericdev-%s", oinput.ImageTag) } + if clt.Bool("frontend") && pjson.Cluster == "siddkube" { imageTag = fmt.Sprintf("devsidd-%s", oinput.ImageTag) } + act.SetOutput("image_tag", imageTag) act.SetOutput("ref", oinput.Ref) log.Info("added all keys to the output") @@ -128,6 +137,7 @@ func parseWorkflowInputs(param *Inputs) (*Output, error) { ctx: context.Background(), branchClient: client.Repositories, } + if strings.Contains(param.URL, "pull") { o, err := parsePR(prc, param) if err != nil { @@ -136,6 +146,7 @@ func parseWorkflowInputs(param *Inputs) (*Output, error) { return o, nil } + o, err := parseIssue(bclient, param) if err != nil { return out, err @@ -146,6 +157,7 @@ func parseWorkflowInputs(param *Inputs) (*Output, error) { func parsePR(prc *pullRequestClient, param *Inputs) (*Output, error) { out := &Output{} + if param.Commit == "" { ref, err := prc.getHeadCommitFromPR( param.RepositoryName, @@ -155,11 +167,13 @@ func parsePR(prc *pullRequestClient, param *Inputs) (*Output, error) { if err != nil { return out, err } + out.ImageTag = fmt.Sprintf("pr-%s-%s", param.IssueNumber, ref[0:7]) out.Ref = ref return out, nil } + out.ImageTag = fmt.Sprintf("pr-%s-%s", param.IssueNumber, param.Commit[0:7]) out.Ref = param.Commit @@ -173,6 +187,7 @@ func (prc *pullRequestClient) getHeadCommitFromPR( if err != nil { return "", fmt.Errorf("error converting string to int %s", err) } + pgr, _, err := prc.pullRequestClient.Get( context.Background(), owner, @@ -188,6 +203,7 @@ func (prc *pullRequestClient) getHeadCommitFromPR( func parseIssue(bc *branchClient, param *Inputs) (*Output, error) { out := &Output{} + if param.Branch != "" { ref, err := bc.getHeadCommitFromBranch( param.RepositoryName, @@ -197,12 +213,14 @@ func parseIssue(bc *branchClient, param *Inputs) (*Output, error) { if err != nil { return out, err } + cb := strings.ReplaceAll(param.Branch, "/", "-") out.ImageTag = fmt.Sprintf("%s-%s", cb, ref[0:7]) out.Ref = ref return out, nil } + if param.Commit != "" { out.ImageTag = param.Commit[0:7] out.Ref = param.Commit diff --git a/internal/app/chatops/deploy_test.go b/internal/app/chatops/deploy_test.go index 5b24630..5d0bd54 100644 --- a/internal/app/chatops/deploy_test.go +++ b/internal/app/chatops/deploy_test.go @@ -39,13 +39,16 @@ func (m *mockBranchClient) GetBranch( func openTestJSON(filename string) (*os.File, error) { file := &os.File{} + dir, err := os.Getwd() if err != nil { return file, fmt.Errorf("unable to get current dir %s", err) } + path := filepath.Join( filepath.Dir(dir), "../../testdata", filename, ) + r, err := os.Open(path) if err != nil { return file, fmt.Errorf("error in reading content from file %s", err) @@ -65,21 +68,19 @@ func TestGetWorkflowInputsFromJSON(t *testing.T) { err, "should not receive error from extracting workflow inputs", ) - assert.Equal(input.Cluster, "erickube", "should match cluster") + assert.Equal("erickube", input.Cluster, "should match cluster") assert.Equal( - input.URL, "https://github.com/dictybase-playground/github-actions-experiments/pull/18#issuecomment-690700284", + input.URL, "should match html-url", ) - assert.Equal(input.IssueNumber, "18", "should match issue number") + assert.Equal("18", input.IssueNumber, "should match issue number") assert.Equal( - input.RepositoryName, - "github-actions-experiments", + "github-actions-experiments", input.RepositoryName, "should match repository name", ) assert.Equal( - input.RepositoryOwner, - "dictybase-playground", + "dictybase-playground", input.RepositoryOwner, "should match repository owner", ) assert.Empty(input.Commit, "should have empty commit value") @@ -94,8 +95,7 @@ func TestGetWorkflowInputsFromJSON(t *testing.T) { ) assert.Empty(ijson.Commit, "should have empty commit value") assert.Equal( - ijson.Branch, - "feature/new-command", + "feature/new-command", ijson.Branch, "should have empty branch value", ) // check json payload for commits @@ -108,8 +108,7 @@ func TestGetWorkflowInputsFromJSON(t *testing.T) { ) assert.Empty(ijson3.Branch, "should have empty branch value") assert.Equal( - ijson3.Commit, - "f85f132b3a986c12eb0c2a61d60a5c3dd8347bf3", + "f85f132b3a986c12eb0c2a61d60a5c3dd8347bf3", ijson3.Commit, "should match commit value", ) } @@ -136,7 +135,7 @@ func TestParsePR(t *testing.T) { } o, err := parsePR(prc, inp) assert.NoError(err, "should not have error from parsing pr") - assert.Equal(o.ImageTag, "pr-9-f85f132", "should match pr image tag") + assert.Equal("pr-9-f85f132", o.ImageTag, "should match pr image tag") assert.Equal(o.Ref, inp.Commit, "should match ref value") // test output when not given a commit @@ -145,7 +144,7 @@ func TestParsePR(t *testing.T) { } iss2, err := parsePR(prc, i2) assert.NoError(err, "should not have error from parsing pr") - assert.Equal(iss2.ImageTag, "pr-9-17f9184", "should match pr image tag") + assert.Equal("pr-9-17f9184", iss2.ImageTag, "should match pr image tag") assert.Equal(iss2.Ref, mockSHA, "should match ref value") } @@ -171,7 +170,7 @@ func TestParseIssue(t *testing.T) { } o, err := parseIssue(bcl, inp) assert.NoError(err, "should not have error from parsing issue") - assert.Equal(o.ImageTag, "f85f132", "should match commit image tag") + assert.Equal("f85f132", o.ImageTag, "should match commit image tag") assert.Equal(o.Ref, inp.Commit, "should match ref value") // test when given a branch i2 := &Inputs{ @@ -181,8 +180,7 @@ func TestParseIssue(t *testing.T) { iss2, err := parseIssue(bcl, i2) assert.NoError(err, "should not have error from parsing issue") assert.Equal( - iss2.ImageTag, - "feature-new-command-17f9184", + "feature-new-command-17f9184", iss2.ImageTag, "should match branch image tag", ) assert.Equal(iss2.Ref, mockSHA, "should match ref value") diff --git a/internal/app/comment/ontology.go b/internal/app/comment/ontology.go index 986b556..7eb8cbc 100644 --- a/internal/app/comment/ontology.go +++ b/internal/app/comment/ontology.go @@ -63,15 +63,19 @@ type reportContent struct { Violations []string } +const exitFailure = 2 + func OntoReportOnPullComment(clt *cli.Context) error { cf, err := listCommittedFiles(clt.String("commit-list-file")) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + rps, err := ontoReport(clt, cf) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + err = createCommentFromReport(&reportParams{ prid: clt.Int("pull-request-id"), repository: clt.GlobalString("repository"), @@ -81,7 +85,7 @@ func OntoReportOnPullComment(clt *cli.Context) error { data: rps, }) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } return reportStatusError(rps) @@ -92,6 +96,7 @@ func ontoReport( cf []string, ) (map[string][]*reportContent, error) { rcs := make(map[string][]*reportContent) + for _, folder := range cf { html, err := readHTMLContent( fmt.Sprintf( @@ -102,6 +107,7 @@ func ontoReport( if err != nil { return rcs, err } + viol, err := ontology.ParseViolations( fmt.Sprintf("%s/%s.json", clt.String("report-dir"), folder), "ERROR", @@ -110,6 +116,7 @@ func ontoReport( if !ontology.IsViolationNotFound(err) { return rcs, fmt.Errorf("ontology not found %s", err) } + if _, ok := rcs["pass"]; ok { rcs["pass"] = append(rcs["pass"], &reportContent{ Name: fmt.Sprintf("%s.obo", folder), @@ -121,6 +128,7 @@ func ontoReport( continue } + if _, ok := rcs["fail"]; ok { rcs["fail"] = append(rcs["fail"], &reportContent{ Name: fmt.Sprintf("%s.obo", folder), @@ -130,6 +138,7 @@ func ontoReport( continue } + rcs["fail"] = []*reportContent{{ Name: fmt.Sprintf("%s.obo", folder), Violations: viol, @@ -144,6 +153,7 @@ func readHTMLContent(file string) (string, error) { if _, err := os.Stat(file); os.IsNotExist(err) { return "", nil } + ct, err := os.ReadFile(file) if err != nil { return "", fmt.Errorf("error in reading file %s", err) @@ -156,7 +166,7 @@ func reportStatusError(rs map[string][]*reportContent) error { if _, ok := rs["fail"]; ok { return cli.NewExitError( fmt.Sprintf("failed report count %d", len(rs["fail"])), - 2, + exitFailure, ) } @@ -168,10 +178,12 @@ func createCommentFromReport(args *reportParams) error { if err != nil { return fmt.Errorf("error in getting github client %s", err) } + mkd, err := mkdownOutput(args.data) if err != nil { return err } + _, _, err = gclient.Issues.CreateComment( context.Background(), args.owner, @@ -187,12 +199,14 @@ func createCommentFromReport(args *reportParams) error { return nil } -func mkdownOutput(data interface{}) (*bytes.Buffer, error) { +func mkdownOutput(data any) (*bytes.Buffer, error) { out := bytes.NewBufferString("") + t, err := template.New("onto-report").Parse(tmpl) if err != nil { return out, fmt.Errorf("error in parsing template %s", err) } + if err := t.Execute(out, data); err != nil { return out, fmt.Errorf("error in executing template %s", err) } @@ -202,15 +216,18 @@ func mkdownOutput(data interface{}) (*bytes.Buffer, error) { func listCommittedFiles(path string) ([]string, error) { var afiles []string + r, err := os.Open(path) if err != nil { return afiles, fmt.Errorf("unable to open file %s", err) } defer r.Close() + scanner := bufio.NewScanner(r) for scanner.Scan() { afiles = append(afiles, baseNoSuffix(scanner.Text())) } + if err := scanner.Err(); err != nil { return afiles, fmt.Errorf("error from scanning %s", err) } diff --git a/internal/app/comment/ontology_test.go b/internal/app/comment/ontology_test.go index f8b09bc..45628f3 100644 --- a/internal/app/comment/ontology_test.go +++ b/internal/app/comment/ontology_test.go @@ -3,7 +3,6 @@ package comment import ( "fmt" "os" - "strings" "testing" "github.com/stretchr/testify/require" @@ -116,6 +115,7 @@ func failAndPassData() map[string][]*reportContent { func TestMkdownOutput(t *testing.T) { t.Parallel() + htmlStr := []string{ "Full report", "bootstrap", @@ -127,6 +127,7 @@ func TestMkdownOutput(t *testing.T) { assert := require.New(t) bout, err := mkdownOutput(failAndPassData()) assert.NoError(err, "should not produce any error from template execution") + subslice := []string{ "dicty_env", "dicty_pheno", @@ -135,13 +136,16 @@ func TestMkdownOutput(t *testing.T) { "green is good", } for _, n := range subslice { - assert.True(strings.Contains(bout.String(), n)) + assert.Contains(bout.String(), n) } + for _, s := range htmlStr { assert.Containsf(bout.String(), s, "should have the string %s", s) } + bout, err = mkdownOutput(failData()) assert.NoError(err, "should not produce any error from template execution") + subslice = []string{ "dicty_env", "dicty_pheno", @@ -149,23 +153,29 @@ func TestMkdownOutput(t *testing.T) { "green is good", } for _, n := range subslice { - assert.True(strings.Contains(bout.String(), n)) + assert.Contains(bout.String(), n) } - assert.False(strings.Contains(bout.String(), "dicty_assay")) + + assert.NotContains(bout.String(), "dicty_assay") + for _, s := range htmlStr { assert.Containsf(bout.String(), s, "should have the string %s", s) } + bout, err = mkdownOutput(passData()) assert.NoError(err, "should not produce any error from template execution") + subslice = []string{ "dicty_assay", "dicty_flower", } for _, n := range subslice { - assert.True(strings.Contains(bout.String(), n)) + assert.Contains(bout.String(), n) } - assert.False(strings.Contains(bout.String(), "dicty_pheno")) - assert.False(strings.Contains(bout.String(), "best of the best")) + + assert.NotContains(bout.String(), "dicty_pheno") + assert.NotContains(bout.String(), "best of the best") + for _, s := range htmlStr { assert.Containsf(bout.String(), s, "should have the string %s", s) } @@ -179,7 +189,9 @@ func TestListCommittedFiles(t *testing.T) { err, "should not throw error from creating a temp file", ) + defer os.Remove(tmpf.Name()) + content := []string{"/onto/dicty_assay.obo", "/pronto/dicty_flower.obo"} for _, line := range content { if _, err := fmt.Fprintf(tmpf, "%s\n", line); err != nil { @@ -189,6 +201,7 @@ func TestListCommittedFiles(t *testing.T) { ) } } + files, err := listCommittedFiles(tmpf.Name()) assert.NoError(err, "should not throw error from getting the list") assert.ElementsMatch( diff --git a/internal/app/dagger/dagger.go b/internal/app/dagger/dagger.go index 1c09849..7985b47 100644 --- a/internal/app/dagger/dagger.go +++ b/internal/app/dagger/dagger.go @@ -22,25 +22,38 @@ import ( const ( owner = "dagger" repo = "dagger" + + // chunkSize represents the chunk size (1KB) for copying the dagger binary. + chunkSize = 1024 + + // execFileMode represents the file mode for the dagger binary. + execFileMode = 0o755 + + exitFailure = 2 ) // SetupDaggerCheckSum sets up the Dagger checksum and outputs it to GitHub Actions. func SetupDaggerCheckSum(clt *cli.Context) error { var dver string + if len(clt.String("version")) == 0 { ver, err := fetchDaggerVersion() if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + dver = ver } else { dver = fmt.Sprintf("v%s", clt.String("version")) } + gclient := github.NewClient(nil) + rel, err := fetchDaggerRelease(gclient, dver) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + checksum, err := fetchDaggerCheckSum( clt.String("checksum-file"), clt.String("dagger-file"), @@ -48,11 +61,13 @@ func SetupDaggerCheckSum(clt *cli.Context) error { rel, ) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + gha := githubactions.New() gha.SetOutput("dagger_version", dver) gha.SetOutput("dagger_bin_checksum", checksum) + return nil } @@ -61,10 +76,12 @@ func SetupDaggerBin(clt *cli.Context) error { dver := clt.String("dagger-version") binDir := clt.String("dagger-bin-dir") gclient := github.NewClient(nil) + rel, err := fetchDaggerRelease(gclient, dver) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + err = fetchDaggerBinary( clt.String("dagger-file"), dver, @@ -73,8 +90,9 @@ func SetupDaggerBin(clt *cli.Context) error { rel, ) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + return nil } @@ -89,6 +107,7 @@ func fetchDaggerRelease( if err != nil { return nil, handleError("error in fetching release %s", err) } + return rel, nil } @@ -98,15 +117,18 @@ func fetchDaggerBinary( rel *github.RepositoryRelease, ) error { tarballName := fmt.Sprintf("dagger_%s_%s", ver, fileSuffix) + idx, err := findTarballIndex(rel, tarballName) if err != nil { return err } + reader, err := downloadReleaseAsset(gclient, rel.Assets[idx].GetID()) if err != nil { return err } defer reader.Close() + return extractTarball(reader, filepath.Join(binDir, "dagger")) } @@ -123,6 +145,7 @@ func findTarballIndex( errors.New("could not find dagger tarball file"), ) } + return idx, nil } @@ -139,6 +162,7 @@ func downloadReleaseAsset( if err != nil { return nil, handleError("error in downloading asset %s", err) } + return reader, nil } @@ -148,6 +172,7 @@ func extractTarball(reader io.ReadCloser, binFileName string) error { return handleError("extractTarGz: NewReader failed: %w", err) } defer uncompressedStream.Close() + tarReader := tar.NewReader(uncompressedStream) for { header, err := tarReader.Next() @@ -155,15 +180,18 @@ func extractTarball(reader io.ReadCloser, binFileName string) error { if err == io.EOF { break } + return handleError("extractTarGz: Next() failed: %w", err) } + if header.Name != "dagger" { continue } + writer, err := os.OpenFile( binFileName, os.O_CREATE|os.O_RDWR, - os.FileMode(0755), + os.FileMode(execFileMode), ) if err != nil { return handleError( @@ -171,20 +199,24 @@ func extractTarball(reader io.ReadCloser, binFileName string) error { err, ) } + for { - _, err := io.CopyN(writer, tarReader, 1024) + _, err := io.CopyN(writer, tarReader, chunkSize) if err != nil { if err == io.EOF { break } + return handleError( "error in writing dagger bin file in temp dir %s", err, ) } } + defer writer.Close() } + return nil } @@ -194,6 +226,7 @@ func fetchDaggerCheckSum( rel *github.RepositoryRelease, ) (string, error) { var empty string + idx := slices.IndexFunc(rel.Assets, func(ast *github.ReleaseAsset) bool { return ast.GetName() == checksumFileName }) @@ -203,6 +236,7 @@ func fetchDaggerCheckSum( errors.New("could not find checksum file"), ) } + reader, _, err := gclient.Repositories.DownloadReleaseAsset( context.Background(), owner, repo, @@ -212,7 +246,9 @@ func fetchDaggerCheckSum( if err != nil { return empty, handleError("error in downloading asset %s", err) } + var line string + scanner := bufio.NewScanner(reader) for scanner.Scan() { if strings.Contains(scanner.Text(), daggerFileName) { @@ -220,6 +256,7 @@ func fetchDaggerCheckSum( break } } + if err := scanner.Err(); err != nil { return empty, handleError("error in reading checksum file %s", err) } @@ -229,11 +266,13 @@ func fetchDaggerCheckSum( func fetchDaggerVersion() (string, error) { var empty string + resp, err := http.Get("https://dl.dagger.io/dagger/latest_version") if err != nil { return empty, handleError("error in fetching dagger version %s", err) } defer resp.Body.Close() + bcont, err := io.ReadAll(resp.Body) if err != nil { return empty, handleError("error in reading response body", err) @@ -253,6 +292,7 @@ func handleError(msg string, err error) error { func RemoveInvalidControlChars(strc string) string { var builder strings.Builder + for _, rtc := range strc { if rtc >= 32 && rtc != 127 { builder.WriteRune(rtc) diff --git a/internal/app/deploy/deploy.go b/internal/app/deploy/deploy.go index 48204b9..e80c315 100644 --- a/internal/app/deploy/deploy.go +++ b/internal/app/deploy/deploy.go @@ -10,18 +10,23 @@ import ( "github.com/urfave/cli" ) +const exitFailure = 2 + func Status(clt *cli.Context) error { logger := logger.GetLogger(clt) + gclient, err := client.GetGithubClient(clt.GlobalString("token")) if err != nil { return cli.NewExitError( fmt.Sprintf("error in getting github client %s", err), - 2, + exitFailure, ) } + state := clt.String("state") url := clt.String("url") desc := fmt.Sprintf("setting deployment status %s", clt.String("state")) + dsp, _, err := gclient.Repositories.CreateDeploymentStatus( context.Background(), clt.GlobalString("owner"), @@ -39,9 +44,10 @@ func Status(clt *cli.Context) error { state, err, ), - 2, + exitFailure, ) } + logger.Infof( "created deployment status %s with id %d", dsp.GetState(), diff --git a/internal/app/deploy/share.go b/internal/app/deploy/share.go index 7dff7be..3147312 100644 --- a/internal/app/deploy/share.go +++ b/internal/app/deploy/share.go @@ -23,10 +23,12 @@ type Payload struct { func GetPayload(data []byte) (*Payload, error) { var s string + pld := new(Payload) if err := json.Unmarshal(data, &s); err != nil { return pld, fmt.Errorf("error in decoding json data to string %s", err) } + if err := json.Unmarshal([]byte(s), pld); err != nil { return pld, fmt.Errorf("error in decoding string to structure %s", err) } @@ -40,16 +42,20 @@ func ShareDeployPayload(clt *cli.Context) error { return fmt.Errorf("error in reading content from file %s", err) } defer pld.Close() + gdl := &github.Deployment{} if err := json.NewDecoder(pld).Decode(gdl); err != nil { return fmt.Errorf("error in decoding json %s", err) } + pgdl, err := GetPayload(gdl.Payload) if err != nil { return err } + act := githubactions.New() log := logger.GetLogger(clt) + act.SetOutput("id", strconv.Itoa(int(gdl.GetID()))) act.SetOutput("url", gdl.GetURL()) act.SetOutput("cluster", pgdl.Cluster) diff --git a/internal/app/gcloud/gcloud.go b/internal/app/gcloud/gcloud.go index 01be960..9709fc6 100644 --- a/internal/app/gcloud/gcloud.go +++ b/internal/app/gcloud/gcloud.go @@ -5,18 +5,21 @@ import ( "github.com/urfave/cli" ) +const exitFailure = 2 + func K8sClusterCredentials(clt *cli.Context) error { gcloud, err := runner.NewGcloud() if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + err = gcloud.GetClusterCredentials( clt.String("project"), clt.String("zone"), clt.String("cluster"), ) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } return nil diff --git a/internal/app/issue/issue.go b/internal/app/issue/issue.go index 1ddd577..4848c91 100644 --- a/internal/app/issue/issue.go +++ b/internal/app/issue/issue.go @@ -15,6 +15,12 @@ import ( "github.com/urfave/cli" ) +const ( + issuesPerPage = 15 + commentsPerPage = 30 + exitFailure = 2 +) + const ( layout = "01/02/2006" dateFilterlayout = "2006-01-02" @@ -26,13 +32,16 @@ func CommentsCountByDate(clt *cli.Context) error { if err != nil { return cli.NewExitError( fmt.Sprintf("error in getting github client %s", err), - 2, + exitFailure, ) } + opt := &github.SearchOptions{ - ListOptions: github.ListOptions{PerPage: 15}, + ListOptions: github.ListOptions{PerPage: issuesPerPage}, } + var totalComments, totalIssues int + query := fmt.Sprintf( "repo:%s/%s created:>=%s", clt.GlobalString("owner"), @@ -48,20 +57,25 @@ func CommentsCountByDate(clt *cli.Context) error { if err != nil { return cli.NewExitError( fmt.Sprintf("error in fetching issues %s", err), - 2, + exitFailure, ) } + totalIssues += len(result.Issues) for _, iss := range result.Issues { totalComments += *iss.Comments } + if resp.NextPage == 0 { break } + opt.Page = resp.NextPage } + fmt.Printf("total no of issues %d\n", totalIssues) fmt.Printf("total no of comments %d\n", totalComments) + return nil } @@ -72,6 +86,7 @@ func CommentsReport(clt *cli.Context) error { } else { fname = fmt.Sprintf("%s-%s.csv", clt.String("output"), time.Now().Format(fileLayout)) } + output, err := os.Create(fname) if err != nil { return cli.NewExitError( @@ -80,22 +95,26 @@ func CommentsReport(clt *cli.Context) error { clt.String("output"), err, ), - 2, + exitFailure, ) } defer output.Close() + writer := csv.NewWriter(output) + gclient, err := client.GetGithubClient(clt.GlobalString("token")) if err != nil { return cli.NewExitError( fmt.Sprintf("error in getting github client %s", err), - 2, + exitFailure, ) } + count, err := writeIssues(clt, gclient, writer) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + logger.GetLogger(clt).Infof("wrote %d records in the report", count) return nil @@ -107,6 +126,7 @@ func writeIssues( writer *csv.Writer, ) (int, error) { count := 0 + err := writer.Write([]string{ "Issue ID", "Title", "Total Comments", "Status", "Created On", "Closed On", @@ -114,6 +134,7 @@ func writeIssues( if err != nil { return count, fmt.Errorf("error in writing file header %s", err) } + opt := issueOpts(clt) for { issues, resp, err := gclient.Issues.ListByRepo( @@ -125,14 +146,17 @@ func writeIssues( if err != nil { return count, fmt.Errorf("error in fetching issues %s", err) } + for _, iss := range issues { if iss.IsPullRequest() { continue } + var closedStr string if iss.GetState() == "closed" { closedStr = iss.GetClosedAt().Format(layout) } + err := writer.Write([]string{ strconv.Itoa(iss.GetNumber()), iss.GetTitle(), @@ -147,14 +171,19 @@ func writeIssues( err, ) } + count++ } + if resp.NextPage == 0 { break } + opt.Page = resp.NextPage } + writer.Flush() + if err := writer.Error(); err != nil { return count, fmt.Errorf("error in writing %s", err) } @@ -166,6 +195,6 @@ func issueOpts(c *cli.Context) *github.IssueListByRepoOptions { return &github.IssueListByRepoOptions{ State: c.String("state"), Sort: "comments", - ListOptions: github.ListOptions{PerPage: 30}, + ListOptions: github.ListOptions{PerPage: commentsPerPage}, } } diff --git a/internal/app/repository/commit.go b/internal/app/repository/commit.go index ec86635..7205a1b 100644 --- a/internal/app/repository/commit.go +++ b/internal/app/repository/commit.go @@ -11,22 +11,26 @@ import ( "github.com/urfave/cli" ) +const exitFailure = 2 + func FilesCommited(clt *cli.Context) error { gclient, err := client.GetLegacyGithubClient(clt.GlobalString("token")) if err != nil { return cli.NewExitError( fmt.Sprintf("error in getting github client %s", err), - 2, + exitFailure, ) } + inp, err := os.Open(clt.String("payload-file")) if err != nil { return cli.NewExitError( fmt.Sprintf("error in reading content from file %s", err), - 2, + exitFailure, ) } defer inp.Close() + files, err := gh.FilterCommittedFiles(&gh.CommittedFilesParams{ Client: gclient, Input: inp, @@ -35,15 +39,18 @@ func FilesCommited(clt *cli.Context) error { SkipDeleted: clt.BoolT("skip-deleted"), }) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + log := logger.GetLogger(clt) if len(files) == 0 { log.Warn("no committed file found matching the criteria") return nil } + out := os.Stdout + if len(clt.String("output")) > 0 { wout, err := os.Create(clt.String("output")) if err != nil { @@ -51,10 +58,12 @@ func FilesCommited(clt *cli.Context) error { fmt.Errorf( "error in creating file %s %s", clt.String("output"), - err), 2) + err), exitFailure) } + out = wout } + fmt.Fprint(out, strings.Join(files, "\n")) log.Infof("%d files has changed in the push", len(files)) diff --git a/internal/app/repository/file.go b/internal/app/repository/file.go index d897262..f87bc05 100644 --- a/internal/app/repository/file.go +++ b/internal/app/repository/file.go @@ -21,16 +21,19 @@ func BatchMultiRepo(clt *cli.Context) error { gclient, err := client.GetGithubClient(clt.GlobalString("token")) if err != nil { return cli.NewExitError( - fmt.Sprintf("error in getting github client %s", err), 2) + fmt.Sprintf("error in getting github client %s", err), exitFailure) } + rfl, wbc, err := readFiles(clt) if err != nil { - return cli.NewExitError(err.Error(), 2) + return cli.NewExitError(err.Error(), exitFailure) } + path := fmt.Sprintf( "%s/%s", clt.String("repository-path"), filepath.Base(clt.String("input-file")), ) + msg := github.String( fmt.Sprintf("adding %s file", filepath.Base(clt.String("input-file")), @@ -51,9 +54,10 @@ func BatchMultiRepo(clt *cli.Context) error { fmt.Sprintf("error in adding file %s to repository %s %s", path, fmt.Sprintf("%s/%s", rpo.owner, rpo.name), err, ), - 2, + exitFailure, ) } + logger.GetLogger(clt).Debugf( "uploaded file %s to repository %s", path, fmt.Sprintf("%s/%s", rpo.owner, rpo.name), @@ -65,6 +69,7 @@ func BatchMultiRepo(clt *cli.Context) error { func readFiles(clt *cli.Context) ([]byte, []byte, error) { var byr []byte + rpl, err := os.ReadFile(clt.String("repository-list")) if err != nil { return rpl, byr, fmt.Errorf( @@ -73,6 +78,7 @@ func readFiles(clt *cli.Context) ([]byte, []byte, error) { err, ) } + wnc, err := os.ReadFile(clt.String("input-file")) if err != nil { return rpl, wnc, fmt.Errorf( @@ -87,7 +93,8 @@ func readFiles(clt *cli.Context) ([]byte, []byte, error) { func parseOwnerRepo(str string) []*repo { rpo := make([]*repo, 0) - for _, f := range strings.Split(str, "\n") { + + for f := range strings.SplitSeq(str, "\n") { v := strings.Split(f, "/") rpo = append(rpo, &repo{owner: v[0], name: v[1]}) } diff --git a/internal/app/repository/migrate.go b/internal/app/repository/migrate.go index 771243d..1bf5a05 100644 --- a/internal/app/repository/migrate.go +++ b/internal/app/repository/migrate.go @@ -27,6 +27,7 @@ type poll struct { func (p *poll) forRepo() error { ticker := time.NewTicker(p.pollInterval) defer ticker.Stop() + OUTER: for { select { @@ -38,6 +39,7 @@ OUTER: ) if err == nil { p.repoShare <- rpg + p.log.Debugf( "polling finished for repo %s/%s", rpg.GetName(), rpg.GetOwner().GetLogin(), @@ -45,10 +47,12 @@ OUTER: break OUTER } + errResp, ok := err.(*gh.ErrorResponse) if !ok { return fmt.Errorf("unexpected github error %s", err) } + if errResp.Response.StatusCode != http.StatusNotFound { return fmt.Errorf("unexpected github error %s", err) } @@ -74,7 +78,9 @@ type migration struct { func (m *migration) createFork() error { defer close(m.repoShare) + rgr := new(errgroup.Group) + for _, repo := range m.repositories { rfc, _, err := m.client.Repositories.CreateFork( context.Background(), @@ -90,6 +96,7 @@ func (m *migration) createFork() error { repo, ) } + if _, ok := err.(*gh.AcceptedError); !ok { return fmt.Errorf( "error in creating fork for repo %s %v", @@ -97,6 +104,7 @@ func (m *migration) createFork() error { err, ) } + m.log.Debugf( "created fork for repo %s on organization %s\n", repo, rfc.GetOwner().GetLogin(), @@ -111,6 +119,7 @@ func (m *migration) createFork() error { } rgr.Go(pol.forRepo) } + if err := rgr.Wait(); err != nil { return fmt.Errorf("error after waiting %s", err) } @@ -120,8 +129,10 @@ func (m *migration) createFork() error { func (m *migration) makeArchive() error { defer close(m.repoNameShare) + for repo := range m.repoShare { repo.Archived = gh.Bool(true) + _, _, err := m.client.Repositories.Edit( context.Background(), repo.GetOwner().GetLogin(), @@ -131,7 +142,9 @@ func (m *migration) makeArchive() error { if err != nil { return fmt.Errorf("error in setting archive status %s", err) } + m.repoNameShare <- repo.GetName() + m.log.Debugf( "created archive for repo %s/%s", repo.GetName(), repo.GetOwner().GetLogin(), @@ -151,6 +164,7 @@ func (m *migration) delRepo() error { if err != nil { return fmt.Errorf("error in deleting repo %s %s", repo, err) } + m.log.Debugf("deleted repo %s", repo) } @@ -162,14 +176,17 @@ func MigrateRepositories(clt *cli.Context) error { if err != nil { return cli.NewExitError( fmt.Sprintf("error in getting github client %s", err), - 2, + exitFailure, ) } + log := logger.GetLogger(clt) deadline := time.Now(). Add(time.Duration(clt.Int64("poll-for")) * time.Second) + ctx, cancelFn := context.WithDeadline(context.Background(), deadline) defer cancelFn() + mgn := &migration{ repositories: clt.StringSlice("repo-to-move"), from: clt.GlobalString("owner"), @@ -185,12 +202,14 @@ func MigrateRepositories(clt *cli.Context) error { fgr.Go(mgn.createFork) fgr.Go(mgn.makeArchive) fgr.Go(mgn.delRepo) + if err := fgr.Wait(); err != nil { return cli.NewExitError( fmt.Sprintf("error in migrating repository %s", err), - 2, + exitFailure, ) } + log.Infof("migrated %d repositories", len(clt.StringSlice("repo-to-move"))) return nil diff --git a/internal/app/repository/migrate_test.go b/internal/app/repository/migrate_test.go index 8d934cc..aea60aa 100644 --- a/internal/app/repository/migrate_test.go +++ b/internal/app/repository/migrate_test.go @@ -16,12 +16,16 @@ import ( func TestMigrateRepositories(t *testing.T) { t.Parallel() assert := require.New(t) + server, client := fake.GhServerClient() defer server.Close() + grp := new(errgroup.Group) deadline := time.Now().Add(4 * time.Second) + ctx, cancelFn := context.WithDeadline(context.Background(), deadline) defer cancelFn() + mgn := &migration{ repositories: []string{"abc", "cde", "efg"}, from: "vandeley", diff --git a/internal/app/storage/s3.go b/internal/app/storage/s3.go index 8215b27..f25645a 100644 --- a/internal/app/storage/s3.go +++ b/internal/app/storage/s3.go @@ -8,6 +8,8 @@ import ( "github.com/urfave/cli" ) +const exitFailure = 2 + func getS3Host(clt *cli.Context) string { if len(clt.String("s3-server-port")) > 0 { return fmt.Sprintf( @@ -30,15 +32,19 @@ func SaveInS3(clt *cli.Context) error { if err != nil { return cli.NewExitError( fmt.Sprintf("error in getting minio client %s", err), - 2, + exitFailure, ) } + log := logger.GetLogger(clt) + path := clt.String("upload-path") if len(path) == 0 { path = clt.String("input") } + log.Debugf("upload path %s", path) + _, err = s3Client.FPutObject( clt.String("s3-bucket"), path, @@ -48,9 +54,10 @@ func SaveInS3(clt *cli.Context) error { if err != nil { return cli.NewExitError( fmt.Sprintf("unable to upload file %s", err), - 2, + exitFailure, ) } + log.Infof("save file %s to s3 storage", clt.String("input")) return nil diff --git a/internal/cmd/migrate.go b/internal/cmd/migrate.go index c3dda38..8ba8cf0 100644 --- a/internal/cmd/migrate.go +++ b/internal/cmd/migrate.go @@ -5,6 +5,11 @@ import ( "github.com/urfave/cli" ) +const ( + defaultPollFor = 60 + defaultPollInterval = 2 +) + func MigrateRepositories() cli.Command { return cli.Command{ Name: "migrate-repos", @@ -25,12 +30,12 @@ func MigrateRepositories() cli.Command { cli.Int64Flag{ Name: "poll-for", Usage: "threshold for polling forked repository(in seconds)", - Value: 60, + Value: defaultPollFor, }, cli.Int64Flag{ Name: "poll-interval", Usage: "polling interval for forked repository(in seconds)", - Value: 2, + Value: defaultPollInterval, }, }, } diff --git a/internal/fake/github.go b/internal/fake/github.go index 9dbbc3f..eb9454f 100644 --- a/internal/fake/github.go +++ b/internal/fake/github.go @@ -12,17 +12,21 @@ import ( func GithubCommitComparison() (*gh.CommitsComparison, error) { ccg := &gh.CommitsComparison{} + dir, err := os.Getwd() if err != nil { return ccg, fmt.Errorf("unable to get current dir %s", err) } + path := filepath.Join( filepath.Dir(dir), "../testdata", "commit-diff.json", ) + b, err := os.ReadFile(path) if err != nil { return ccg, errors.New("unable to read test file") } + if err := json.Unmarshal(b, ccg); err != nil { return ccg, fmt.Errorf("error in decoding json %s", err) } diff --git a/internal/fake/http.go b/internal/fake/http.go index 26f526e..e07b913 100644 --- a/internal/fake/http.go +++ b/internal/fake/http.go @@ -97,6 +97,7 @@ func delRoute() []*route { func routeTable() []*route { var route []*route + route = append(route, fetchRoute()...) route = append(route, postRoute()...) @@ -105,6 +106,7 @@ func routeTable() []*route { func handleNoContent(file string, w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) + if _, err := fmt.Fprint(w, file); err != nil { http.Error( w, @@ -125,6 +127,7 @@ func handleAccepted(file string, wrt http.ResponseWriter, _ *http.Request) { return } + wrt.WriteHeader(http.StatusAccepted) fmt.Fprint(wrt, string(bfl)) } @@ -140,6 +143,7 @@ func handleSuccess(file string, wrt http.ResponseWriter, _ *http.Request) { return } + if _, err := wrt.Write(bfl); err != nil { http.Error( wrt, @@ -154,13 +158,16 @@ func router(wrt http.ResponseWriter, req *http.Request) { if req.Method != rtbl.method { continue } + if !rtbl.regexp.MatchString(req.URL.Path) { continue } + rtbl.fn(rtbl.file, wrt, req) return } + http.NotFound(wrt, req) } @@ -169,6 +176,7 @@ func payloadFile(file string) ([]byte, error) { if err != nil { return []byte(""), fmt.Errorf("unable to get current file %s", err) } + b, err := os.ReadFile(path) if err != nil { return []byte(""), fmt.Errorf("unable to read test file %s", path) diff --git a/internal/fake/payload.go b/internal/fake/payload.go index 4455bdf..806c0b9 100644 --- a/internal/fake/payload.go +++ b/internal/fake/payload.go @@ -35,15 +35,18 @@ func OntoErrorFile() (string, error) { func PullReqPayload(name string) (io.Reader, error) { var r io.Reader + dir, err := os.Getwd() if err != nil { return r, fmt.Errorf("unable to get current dir %s", err) } + path := filepath.Join( filepath.Dir(dir), "../testdata", name, ) + fhd, err := os.Open(path) if err != nil { return fhd, fmt.Errorf("error in opening file %s", err) @@ -54,11 +57,14 @@ func PullReqPayload(name string) (io.Reader, error) { func PushPayload() (io.Reader, error) { var r io.Reader + dir, err := os.Getwd() if err != nil { return r, fmt.Errorf("unable to get current dir %s", err) } + path := filepath.Join(filepath.Dir(dir), "../testdata", "push.json") + fhd, err := os.Open(path) if err != nil { return fhd, fmt.Errorf("error in opening file %s", err) diff --git a/internal/file/io.go b/internal/file/io.go index ef7a378..b6f0845 100644 --- a/internal/file/io.go +++ b/internal/file/io.go @@ -8,18 +8,24 @@ import ( ) func InputOutput(clt *cli.Context) (*os.File, *os.File, error) { - var inp *os.File - var out *os.File + var ( + inp *os.File + out *os.File + ) + r, err := os.Open(clt.String("payload-file")) if err != nil { return inp, out, fmt.Errorf("error in reading content from file %s", err) } + inp = r + if len(clt.String("output")) > 0 { w, err := os.Create(clt.String("output")) if err != nil { return inp, out, fmt.Errorf("error in creating file %s %s", clt.String("output"), err) } + out = w } else { out = os.Stdout diff --git a/internal/github/builder.go b/internal/github/builder.go index 3df1150..bc4980c 100644 --- a/internal/github/builder.go +++ b/internal/github/builder.go @@ -18,7 +18,9 @@ func (b *ChangedFilesBuilder) FilterSuffix(suffix string) *ChangedFilesBuilder { if len(b.files) == 0 { return b } + var afl []*ChangedFiles + for _, v := range b.files { if strings.HasSuffix(v.Name, suffix) { afl = append(afl, v) @@ -36,11 +38,14 @@ func (b *ChangedFilesBuilder) FilterDeleted( if len(b.files) == 0 { return b } + afl := make([]*ChangedFiles, 0) + for _, vfl := range b.files { if vfl.Change == "deleted" { continue } + afl = append(afl, vfl) } @@ -51,8 +56,10 @@ func (b *ChangedFilesBuilder) FilterUniqueByName() *ChangedFilesBuilder { if len(b.files) <= 1 { return b } + mnt := make(map[string]int) afl := make([]*ChangedFiles, 0) + for _, v := range b.files { n := path.Base(v.Name) if _, ok := mnt[n]; !ok { diff --git a/internal/github/builder_test.go b/internal/github/builder_test.go index b7fcaad..ec7ac22 100644 --- a/internal/github/builder_test.go +++ b/internal/github/builder_test.go @@ -15,6 +15,7 @@ func TestFilterUnique(t *testing.T) { err, "should not receive any error for parsing push event data", ) + files := CommittedFiles(cc).FilterUniqueByName().List() assert.Len(files, 11, "should have committed 11 unique files") assert.Contains( @@ -32,6 +33,7 @@ func TestFilterDeleted(t *testing.T) { err, "should not receive any error for parsing push event data", ) + files := CommittedFiles(cc).FilterDeleted(true).List() assert.Len(files, 14, "should have committed 14 unique files") assert.Contains( @@ -49,6 +51,7 @@ func TestFilterSuffix(t *testing.T) { err, "should not receive any error for parsing push event data", ) + files := CommittedFiles(cc).FilterSuffix("obo").List() assert.Len(files, 3, "should have committed 3 unique files") assert.Contains( @@ -66,8 +69,8 @@ func TestCommitedFiles(t *testing.T) { err, "should not receive any error for parsing push event data", ) - assert.Equal(ccg.GetStatus(), "ahead", "should match the status") - assert.Equal(ccg.GetAheadBy(), 31, "should match ahead by value") + assert.Equal("ahead", ccg.GetStatus(), "should match the status") + assert.Equal(31, ccg.GetAheadBy(), "should match ahead by value") assert.Equal( ccg.GetTotalCommits(), ccg.GetAheadBy(), @@ -90,6 +93,7 @@ func TestFilterChain(t *testing.T) { err, "should not receive any error for parsing push event data", ) + files := CommittedFiles( ccg, ).FilterSuffix("txt"). diff --git a/internal/github/manager.go b/internal/github/manager.go index d393145..17434b5 100644 --- a/internal/github/manager.go +++ b/internal/github/manager.go @@ -29,11 +29,14 @@ func (g *Manager) CommittedFilesInPull( r io.Reader, ) (*ChangedFilesBuilder, error) { var bcf *ChangedFilesBuilder + pev := &gh.PullRequestEvent{} if err := json.NewDecoder(r).Decode(pev); err != nil { return bcf, fmt.Errorf("error in decoding json %s", err) } + var after, before string + switch pev.GetAction() { case "synchronize": before = pev.GetBefore() @@ -42,6 +45,7 @@ func (g *Manager) CommittedFilesInPull( before = pev.GetPullRequest().GetBase().GetSHA() after = pev.GetPullRequest().GetHead().GetSHA() } + comc, _, err := g.client.Repositories.CompareCommits( context.Background(), pev.GetRepo().GetOwner().GetLogin(), @@ -60,10 +64,12 @@ func (g *Manager) CommittedFilesInPush( r io.Reader, ) (*ChangedFilesBuilder, error) { var bfl *ChangedFilesBuilder + pev := &gh.PushEvent{} if err := json.NewDecoder(r).Decode(pev); err != nil { return bfl, fmt.Errorf("error in decoding json %s", err) } + comc, _, err := g.client.Repositories.CompareCommits( context.Background(), pev.GetRepo().GetOwner().GetLogin(), @@ -91,8 +97,11 @@ func CommittedFiles(event *gh.CommitsComparison) *ChangedFilesBuilder { } func FilterCommittedFiles(args *CommittedFilesParams) ([]string, error) { - var fbl *ChangedFilesBuilder - var err error + var ( + fbl *ChangedFilesBuilder + err error + ) + switch args.Event { case "push": fbl, err = NewGithubManager( @@ -105,6 +114,7 @@ func FilterCommittedFiles(args *CommittedFilesParams) ([]string, error) { default: err = fmt.Errorf("event type %s not supported", args.Event) } + if err != nil { return []string{}, err } diff --git a/internal/github/manager_test.go b/internal/github/manager_test.go index 57e46b9..8b74d57 100644 --- a/internal/github/manager_test.go +++ b/internal/github/manager_test.go @@ -23,8 +23,10 @@ func TestCommittedFilesInpush(t *testing.T) { assert := require.New(t) r, err := fake.PushPayload() assert.NoError(err, "should not receive any error from reading push payload") + server, client := fake.GhServerClient() defer server.Close() + b, err := NewGithubManager(client).CommittedFilesInPush(r) assert.NoError( err, @@ -78,8 +80,10 @@ func testPull(t *testing.T, name string) { err, "should not receive any error from reading payload for push", ) + server, client := fake.GhServerClient() defer server.Close() + b, err := NewGithubManager(client).CommittedFilesInPull(reqp) assert.NoError( err, diff --git a/internal/logger/logger.go b/internal/logger/logger.go index e6cfbd0..ba31027 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -10,6 +10,7 @@ import ( func GetLogger(clt *cli.Context) *logrus.Entry { log := logrus.New() log.Out = os.Stderr + switch clt.GlobalString("log-format") { case "text": log.Formatter = &logrus.TextFormatter{ @@ -20,6 +21,7 @@ func GetLogger(clt *cli.Context) *logrus.Entry { TimestampFormat: "02/Jan/2006:15:04:05", } } + l := clt.GlobalString("log-level") switch l { case "debug": diff --git a/internal/ontology/report.go b/internal/ontology/report.go index 4c81e5e..b8269cc 100644 --- a/internal/ontology/report.go +++ b/internal/ontology/report.go @@ -13,26 +13,34 @@ func ParseViolations(path string, level string) ([]string, error) { if err != nil { return []string{}, fmt.Errorf("error in parsing json file %s", err) } + hasLevel := false + var violCont *gabs.Container + for _, child := range cont.Children() { v, ok := child.Search("level").Data().(string) if !ok { return []string{""}, errors.New("incompatible report format, level key not found") } + if v != level { continue } + violCont = child hasLevel = true break } + children := violCont.S("violations").Children() if !hasLevel || len(children) == 0 { return []string{}, &ViolationNotFoundError{Level: level} } + var slc []string + for _, child := range children { for k := range child.ChildrenMap() { slc = append(slc, strings.ReplaceAll(k, "_", " ")) diff --git a/internal/ontology/report_test.go b/internal/ontology/report_test.go index ec0a811..ae006b8 100644 --- a/internal/ontology/report_test.go +++ b/internal/ontology/report_test.go @@ -43,6 +43,7 @@ func TestParseViolations(t *testing.T) { "missing ontology title", "should have missing ontology title violation", ) + _, err = ParseViolations(fhd, "FATAL") assert.True(IsViolationNotFound(err), "should be violation not found error") } diff --git a/internal/runner/helm.go b/internal/runner/helm.go index a992d9b..4d265f8 100644 --- a/internal/runner/helm.go +++ b/internal/runner/helm.go @@ -84,11 +84,13 @@ func (h *Helm) IsChartDeployed(name string) (bool, error) { fmt.Sprintf("^%s$", name), "--short", ) + output, err := cmd.Output() if err != nil { return false, fmt.Errorf("error %s in running command %s", err, cmd.String()) } + trimmed := bytes.TrimSpace(output) if name == string(trimmed) { return true, nil @@ -111,7 +113,9 @@ func (h *Helm) ServerVersion() (string, error) { "--server", "--short", ) + var out bytes.Buffer + cmd.Stdout = &out if err := cmd.Run(); err != nil { return "", fmt.Errorf("error in getting helm version %s", err) From 0a8de79f724a2ef54f8b75de4e39d8241c1339e1 Mon Sep 17 00:00:00 2001 From: Siddhartha Basu Date: Fri, 15 May 2026 17:23:56 -0500 Subject: [PATCH 6/7] chore(ci): update GitHub token for pull request creation Replace the default github.token with a custom REPO_ACCESS_TOKEN secret. The default token often lacks the necessary permissions to trigger subsequent workflows or perform specific repository actions, requiring a personal access token with broader scope to ensure the pull request creation process succeeds. --- .github/workflows/create-pull-request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-pull-request.yml b/.github/workflows/create-pull-request.yml index a72d0d7..37e68ed 100644 --- a/.github/workflows/create-pull-request.yml +++ b/.github/workflows/create-pull-request.yml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v4 - name: Create Pull Request env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }} run: | # Get current branch name branch_name=$(git symbolic-ref --short HEAD) From 13e53ffdd7cabc33aa03d52895a1245f278f1b4a Mon Sep 17 00:00:00 2001 From: Siddhartha Basu Date: Fri, 15 May 2026 22:00:10 -0500 Subject: [PATCH 7/7] ci(lint.yaml): migrate to reusable workflow for golang linting Update the linting workflow to utilize the centralized golang-lint reusable workflow from the dictyBase/workflows repository. This change also restricts the workflow to ignore the master branch and ensures the linter runs against the specific pull request head commit. --- .github/workflows/lint.yaml | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 645705c..ccfe0be 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -1,16 +1,12 @@ name: Lint Golang code -on: [pull_request] +on: + pull_request: + branches-ignore: + - master jobs: - lint: - runs-on: ubuntu-latest - steps: - - name: check out code - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version: 1.25 - cache: false - - name: run linter - uses: golangci/golangci-lint-action@v6 - with: - version: v1.58.2 + call-lint: + uses: dictyBase/workflows/.github/workflows/golang-lint.yaml@develop + with: + repository: ${{ github.repository }} + ref: ${{ github.event.pull_request.head.sha }} + version: v2.8.0-alpine