From fa91354cf2d54b7671d5167e8eece1239503b19a Mon Sep 17 00:00:00 2001 From: Manuel Vogel <8409778+mavogel@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:54:29 +0200 Subject: [PATCH] feat: add semantic release (#12) * fix: build and linting Signed-off-by: Manuel Vogel <8409778+mavogel@users.noreply.github.com> * feat: add semantic release Signed-off-by: Manuel Vogel <8409778+mavogel@users.noreply.github.com> * chore: remove deprecated tools Signed-off-by: Manuel Vogel <8409778+mavogel@users.noreply.github.com> * feat: add renovate Signed-off-by: Manuel Vogel <8409778+mavogel@users.noreply.github.com> * fix: back from main to tmp master Signed-off-by: Manuel Vogel <8409778+mavogel@users.noreply.github.com> * fix: run test and lint on PR Signed-off-by: Manuel Vogel <8409778+mavogel@users.noreply.github.com> * fix(ci): use also GH token for semantic release Signed-off-by: Manuel Vogel <8409778+mavogel@users.noreply.github.com> --------- Signed-off-by: Manuel Vogel <8409778+mavogel@users.noreply.github.com> --- .chglog/CHANGELOG.tpl.md | 40 --------------- .chglog/config.yml | 33 ------------ .github/renovate.json | 6 +++ .github/workflows/lint.yml | 20 ++++---- .github/workflows/release.yml | 26 ---------- .github/workflows/semantic-lint.yml | 20 ++++++++ .github/workflows/semantic.yml | 37 ++++++++++++++ .github/workflows/test.yml | 27 ++++++---- .golangci.yml | 78 ++++++++++++++++++++++++++--- .releaserc.yml | 16 ++++++ Makefile | 39 ++------------- forward.go | 24 ++++----- forward_test.go | 6 +-- validators.go | 4 +- 14 files changed, 194 insertions(+), 182 deletions(-) delete mode 100755 .chglog/CHANGELOG.tpl.md delete mode 100755 .chglog/config.yml create mode 100644 .github/renovate.json delete mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/semantic-lint.yml create mode 100644 .github/workflows/semantic.yml create mode 100644 .releaserc.yml diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md deleted file mode 100755 index 7a662d2..0000000 --- a/.chglog/CHANGELOG.tpl.md +++ /dev/null @@ -1,40 +0,0 @@ -{{ range .Versions }} - -## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} - -> {{ datetime "2006-01-02" .Tag.Date }} - -{{ range .CommitGroups -}} -### {{ .Title }} - -{{ range .Commits -}} -* {{ .Subject }} ([{{ .Hash.Short }}]({{ $.Info.RepositoryURL }}/commit/{{ .Hash.Long }})) -{{ end }} -{{ end -}} - -{{- if .RevertCommits -}} -### Reverts - -{{ range .RevertCommits -}} -* {{ .Revert.Header }} -{{ end }} -{{ end -}} - -{{- if .MergeCommits -}} -### Pull Requests - -{{ range .MergeCommits -}} -* {{ .Header }} -{{ end }} -{{ end -}} - -{{- if .NoteGroups -}} -{{ range .NoteGroups -}} -### {{ .Title }} - -{{ range .Notes }} -{{ .Body }} -{{ end }} -{{ end -}} -{{ end -}} -{{ end -}} diff --git a/.chglog/config.yml b/.chglog/config.yml deleted file mode 100755 index ddcf2af..0000000 --- a/.chglog/config.yml +++ /dev/null @@ -1,33 +0,0 @@ -style: github -template: CHANGELOG.tpl.md -info: - title: CHANGELOG - repository_url: https://github.com/mavogel/go-ssh-forward -options: - commits: - filters: - Type: - - feat - - fix - - perf - - refactor - - docs - - build - - chore - commit_groups: - title_maps: - feat: Features - fix: Bug Fixes - perf: Performance Improvements - refactor: Code Refactoring - docs: Documentation - build: Build Environment - chore: General - header: - pattern: "^(\\w*)\\:\\s(.*)$" - pattern_maps: - - Type - - Subject - notes: - keywords: - - BREAKING CHANGE diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..55043df --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ] + } \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 159000d..7e4df02 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,19 +8,19 @@ on: push: branches: - master - paths-ignore: - - 'README.md' + +permissions: + contents: read jobs: - golangci: + lint: name: lint - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: - fetch-depth: 0 + go-version: '1.21.x' + cache: false - name: golangci-lint - uses: golangci/golangci-lint-action@v2 - with: - version: v1.40.0 \ No newline at end of file + uses: golangci/golangci-lint-action@v6 \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 2cc15f7..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: goreleaser - -on: - push: - tags: - - '*' - -jobs: - goreleaser: - runs-on: ubuntu-20.04 - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: 1.16 - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v2 - with: - version: latest - args: release --rm-dist - env: - GITHUB_TOKEN: ${{ secrets.GORELEASER_TOKEN }} diff --git a/.github/workflows/semantic-lint.yml b/.github/workflows/semantic-lint.yml new file mode 100644 index 0000000..450b22f --- /dev/null +++ b/.github/workflows/semantic-lint.yml @@ -0,0 +1,20 @@ +name: semantic-lint + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +permissions: + contents: read + pull-requests: read + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/semantic.yml b/.github/workflows/semantic.yml new file mode 100644 index 0000000..f94d981 --- /dev/null +++ b/.github/workflows/semantic.yml @@ -0,0 +1,37 @@ +name: semantic +on: + push: + branches: + - master + - next + +permissions: + contents: read # for checkout + +jobs: + release: + name: release + runs-on: ubuntu-latest + permissions: + contents: write # to be able to publish a GitHub release + issues: write # to be able to comment on released issues + pull-requests: write # to be able to comment on released pull requests + id-token: write # to enable use of OIDC for npm provenance + steps: + - name: checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: setup node.js + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + - name: release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npx \ + -p @semantic-release/commit-analyzer \ + -p @semantic-release/release-notes-generator \ + -p @semantic-release/github \ + semantic-release --debug \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 810896b..424ad6e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,22 +12,27 @@ on: - 'README.md' jobs: unit: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v5 with: - go-version: 1.16 + go-version: 1.21.x - name: Run tests run: make test - - name: Convert coverage - uses: jandelgado/gcov2lcov-action@v1.0.5 - - name: Upload coverage - uses: coverallsapp/github-action@master - with: - github-token: ${{ secrets.github_token }} - path-to-lcov: coverage.lcov + #- name: Upload coverage reports to Codecov + # uses: codecov/codecov-action@v4 + # env: + # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + #- name: Upload coverage reports to Codeclimate + # if: github.event_name != 'pull_request' + # uses: paambaati/codeclimate-action@v9.0.0 + # env: + # CC_TEST_REPORTER_ID: ${{ secrets.CODECLIMATE_TEST_REPORTER_ID }} + # with: + # prefix: "github.com/mavogel/go-ssh-forward" + # coverageLocations: coverage.txt:gocov diff --git a/.golangci.yml b/.golangci.yml index 018010f..3207cfd 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,11 +1,73 @@ -run: - tests: false +linters-settings: + dupl: + threshold: 100 + funlen: + lines: 100 + statements: 50 + goconst: + min-len: 2 + min-occurrences: 3 + gocritic: + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + disabled-checks: + - dupImport # https://github.com/go-critic/go-critic/issues/845 + - ifElseChain + - octalLiteral + - whyNoLint + gocyclo: + min-complexity: 15 + golint: + min-confidence: 0 + lll: + line-length: 140 + maligned: + suggest-new: true + misspell: + locale: US linters: - enable-all: true - disable: + # please, do not use `enable-all`: it's deprecated and will be removed soon. + # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint + disable-all: true + enable: + - bodyclose + - dogsled + - errcheck + - funlen + - goconst + - gocritic + - gocyclo + - gofmt + - goimports + - goprintffuncname + - gosec + - gosimple + - govet + - ineffassign - lll - - exhaustivestruct - - interfacer - - maligned - - scopelint \ No newline at end of file + - misspell + - nakedret + - nilnil + - noctx + - nolintlint + - staticcheck + - stylecheck + - typecheck + - unconvert + - unparam + - unused + - whitespace + +issues: + exclude-rules: + - path: _test\.go + linters: + - funlen + +run: + timeout: 2m \ No newline at end of file diff --git a/.releaserc.yml b/.releaserc.yml new file mode 100644 index 0000000..65259a7 --- /dev/null +++ b/.releaserc.yml @@ -0,0 +1,16 @@ +plugins: + - "@semantic-release/commit-analyzer" + - "@semantic-release/release-notes-generator" + - - "@semantic-release/github" + - successComment: | + :tada: This ${issue.pull_request ? 'pull request is included' : 'issue has been resolved'} in version ${nextRelease.version} :tada: + + The release is available on [GitHub release](https://github.com/mavogel/go-ssh-forward/releases/tag/${nextRelease.gitTag}) :rocket: + +branches: + - name: +([0-9])?(.{+([0-9]),x}).x + - name: master + - name: next + prerelease: true + - name: pre/rc + prerelease: '${name.replace(/^pre\\//g, "")}' \ No newline at end of file diff --git a/Makefile b/Makefile index 429a58c..db78b00 100644 --- a/Makefile +++ b/Makefile @@ -7,10 +7,6 @@ GOOS ?= $(shell $(GO) env GOOS) GOARCH ?= $(shell $(GO) env GOARCH) GOHOST ?= GOOS=$(GOOS) GOARCH=$(GOARCH) $(GO) -# Tool versions -GOLANGCI_VERSION = 1.39.0 -GITCHGLOG_VERSION = 0.14.2 - .PHONY: all all: help @@ -20,41 +16,12 @@ all: help .PHONY: test test: ## Run tests @ $(MAKE) --no-print-directory log-$@ - $(GOHOST) test -race -covermode atomic -coverprofile coverage.out -v ./... - -bin/golangci-lint: bin/golangci-lint-${GOLANGCI_VERSION} - @ln -sf golangci-lint-${GOLANGCI_VERSION} bin/golangci-lint -bin/golangci-lint-${GOLANGCI_VERSION}: - @mkdir -p bin - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | BINARY=golangci-lint bash -s -- v${GOLANGCI_VERSION} - @mv bin/golangci-lint $@ + $(GOHOST) test -timeout 60s -race -covermode atomic -coverprofile coverage.txt -v ./... .PHONY: lint -lint: bin/golangci-lint ## Run linters - @ $(MAKE) --no-print-directory log-$@ - bin/golangci-lint run - -########### -##@ Release - -bin/git-chglog: bin/git-chglog-${GITCHGLOG_VERSION} - @ln -sf git-chglog-${GITCHGLOG_VERSION} bin/git-chglog -bin/git-chglog-${GITCHGLOG_VERSION}: - @mkdir -p bin - curl -L https://github.com/git-chglog/git-chglog/releases/download/v${GITCHGLOG_VERSION}/git-chglog_${GITCHGLOG_VERSION}_${OS}_amd64.tar.gz | tar -zOxf - git-chglog > ./bin/git-chglog-${GITCHGLOG_VERSION} && chmod +x ./bin/git-chglog-${GITCHGLOG_VERSION} - -.PHONY: changelog -changelog: bin/git-chglog ## Generate changelog - @ $(MAKE) --no-print-directory log-$@ - bin/git-chglog --next-tag $(VERSION) -o CHANGELOG.md - -.PHONY: release -release: changelog ## Release a new tag +lint: ## Run linters @ $(MAKE) --no-print-directory log-$@ - git add CHANGELOG.md - git commit -m "chore: update changelog for $(VERSION)" - git tag $(VERSION) - git push origin master $(VERSION) + golangci-lint run ######## ##@ Help diff --git a/forward.go b/forward.go index bb4d54a..5ffa679 100644 --- a/forward.go +++ b/forward.go @@ -3,16 +3,15 @@ package forward import ( "fmt" "io" - "io/ioutil" "log" "net" + "os" "time" "golang.org/x/crypto/ssh" ) -// nolint: gochecknoglobals -var ( +var ( //nolint: gochecknoglobals readDeadline = 30 writeDeadline = 30 connectionTimeout = 8 * time.Second @@ -67,8 +66,7 @@ func NewForward(config *Config) (*Forward, chan error, error) { return t, forwardErrors, nil } -// nolint: cyclop -func (f *Forward) run(sshClient *ssh.Client, localListener net.Listener) { +func (f *Forward) run(sshClient *ssh.Client, localListener net.Listener) { //nolint: cyclop defer func() { localListener.Close() sshClient.Close() @@ -77,11 +75,11 @@ func (f *Forward) run(sshClient *ssh.Client, localListener net.Listener) { jumpCount := 1 for { - // nolint: godox + //nolint: godox endHostConn, err := sshClient.Dial("tcp", f.config.RemoteAddress) // TODO timeout here? if err != nil { f.forwardErrors <- fmt.Errorf("failed to connect on end host to docker daemon at '%s': %w", f.config.RemoteAddress, err) - return // nolint: nlreturn + return //nolint: nlreturn } if err = endHostConn.SetReadDeadline(time.Now().Add(time.Duration(readDeadline) * time.Second)); err != nil { @@ -91,12 +89,12 @@ func (f *Forward) run(sshClient *ssh.Client, localListener net.Listener) { if err = endHostConn.SetWriteDeadline(time.Now().Add(time.Duration(writeDeadline) * time.Second)); err != nil { f.forwardErrors <- fmt.Errorf("failed to set write deadline on end host connection: %w", err) } - defer endHostConn.Close() + defer endHostConn.Close() //nolint: gocritic localConn, err := f.buildLocalConnection(localListener) if err != nil { f.forwardErrors <- fmt.Errorf("failed to build the local connection: %w", err) - return // nolint: nlreturn + return //nolint: nlreturn } if err = localConn.SetReadDeadline(time.Now().Add(time.Duration(readDeadline) * time.Second)); err != nil { @@ -106,7 +104,7 @@ func (f *Forward) run(sshClient *ssh.Client, localListener net.Listener) { if err = localConn.SetWriteDeadline(time.Now().Add(time.Duration(writeDeadline) * time.Second)); err != nil { f.forwardErrors <- fmt.Errorf("failed to set write deadline on local connection: %w", err) } - defer localConn.Close() + defer localConn.Close() //nolint: gocritic if err != nil { select { @@ -135,7 +133,7 @@ func (f *Forward) Stop() { func convertToSSHConfig(toConvert *SSHConfig) (*ssh.ClientConfig, error) { config := &ssh.ClientConfig{ User: toConvert.User, - HostKeyCallback: ssh.InsecureIgnoreHostKey(), // nolint: gosec + HostKeyCallback: ssh.InsecureIgnoreHostKey(), //nolint: gosec Timeout: connectionTimeout, } @@ -155,7 +153,7 @@ func convertToSSHConfig(toConvert *SSHConfig) (*ssh.ClientConfig, error) { // publicKeyFile helper to read the key files. func publicKeyFile(file string) (ssh.AuthMethod, error) { - buffer, err := ioutil.ReadFile(file) + buffer, err := os.ReadFile(file) if err != nil { return nil, fmt.Errorf("failed to read file '%s': %w", file, err) } @@ -239,7 +237,7 @@ func (f *Forward) dialNextJump(jumpHostClient *ssh.Client, nextJumpAddress strin jumpHostConn, err := jumpHostClient.Dial("tcp", nextJumpAddress) if err != nil { f.forwardErrors <- fmt.Errorf("ssh.Dial from jump host to end server failed: %w", err) - return // nolint: nlreturn + return //nolint: nlreturn } connChan <- jumpHostConn }() diff --git a/forward_test.go b/forward_test.go index 7ae4885..522cfbb 100644 --- a/forward_test.go +++ b/forward_test.go @@ -129,9 +129,9 @@ func TestForwardUnreachableEndHostWithoutJump(t *testing.T) { checkErrorContains(t, err, "ssh.Dial directly to end host failed") } -////////////// +// //////////// // Helpers -////////////// +// //////////// func checkErrorContains(t *testing.T, err error, errorMsgtoContain string) { if !strings.Contains(err.Error(), errorMsgtoContain) { t.Errorf("Expected error to contain \n'%s' but got \n'%s'", errorMsgtoContain, err.Error()) @@ -142,7 +142,7 @@ func createConfig(jumpHostAddress, jumpHostUser, jumpHostPrivateKeyFile, jumpHos return createConfigBase(jumpHostAddress, jumpHostUser, jumpHostPrivateKeyFile, jumpHostPassword, "localhost:2376", "localhost:2376") } -func createConfigWithAddresses(jumpHostAddress, jumpHostUser, jumpHostPrivateKeyFile, jumpHostPassword, localAddress, remoteAddress string) *Config { +func createConfigWithAddresses(jumpHostAddress, jumpHostUser, jumpHostPrivateKeyFile, jumpHostPassword, localAddress, remoteAddress string) *Config { //nolint: lll return createConfigBase(jumpHostAddress, jumpHostUser, jumpHostPrivateKeyFile, jumpHostPassword, localAddress, remoteAddress) } diff --git a/validators.go b/validators.go index 6bc57b2..0c04ce9 100644 --- a/validators.go +++ b/validators.go @@ -5,8 +5,8 @@ import ( ) var ( - ErrJumpHostsNotSupportd = errors.New("only 1 jump host is supported atm") // nolint: revive - ErrLocalAndRemoteAddressUnset = errors.New("localAddress and RemoteAddress have to be set") // nolint: revive + ErrJumpHostsNotSupportd = errors.New("only 1 jump host is supported atm") //nolint: revive + ErrLocalAndRemoteAddressUnset = errors.New("localAddress and RemoteAddress have to be set") //nolint: revive ErrSSHConfigUnset = errors.New("SSHConfig cannot be nil") ErrUserEmpty = errors.New("user cannot be empty") ErrAddressEmpty = errors.New("address cannot be empty")