From 930d5af42914e5979626ff572174e3342aa623d6 Mon Sep 17 00:00:00 2001 From: Egor Tarasov Date: Thu, 31 Oct 2024 01:21:31 +0100 Subject: [PATCH] Release pipeline with changelog.md only (#38) - also fixed golangci-lint hanging --- .github/workflows/go.yml | 34 ------- .github/workflows/publish-release.yml | 48 +++++++++ .github/workflows/run-tests.yml | 13 ++- .golangci.yml | 125 +++++++++++------------- CHANGELOG.md | 4 + Makefile | 22 +++-- README.md | 37 +++---- build.sh | 8 -- cicd/version.sh | 16 +-- cmd/root.go | 9 +- cmd/version/version.go | 43 ++++++++ pkg/client/auth/credentials/provider.go | 4 +- tests/run_e2e_test.go | 2 +- 13 files changed, 198 insertions(+), 167 deletions(-) delete mode 100644 .github/workflows/go.yml create mode 100644 .github/workflows/publish-release.yml delete mode 100755 build.sh create mode 100644 cmd/version/version.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index 7613eea..0000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,34 +0,0 @@ -# This workflow will build a golang project -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go - -name: Go - -on: - push: - tags: - - 'v*' - -jobs: - - build: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@master - - - name: Build - run: | - make build-in-docker - - - name: Generate Changelog - run: | - VERSION=$(cicd/version.sh) - cicd/changelog.sh $VERSION > bin/CHANGELOG.md - - - name: Create GitHub Release - uses: softprops/action-gh-release@v1 - with: - body_path: bin/CHANGELOG.md - files: bin/ydbops* - env: - GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 0000000..7dde000 --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -0,0 +1,48 @@ +name: check-for-new-release + +on: + push: + branches: + - 'master' + +jobs: + tag: + runs-on: ubuntu-latest + outputs: + tagcreated: ${{steps.tag-step.outputs.tagcreated}} + tagname: ${{steps.tag-step.outputs.tagname}} + steps: + - uses: actions/checkout@v4 + - id: extract-version-step + run: | + echo "version=$(./cicd/version.sh)" >> $GITHUB_ENV + - id: tag-step + uses: butlerlogic/action-autotag@1.1.2 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + root: "./CHANGELOG.md" + tag_prefix: "v" + regex_pattern: '##[\s]*([0-9\.]{3,})' + + publish-release: + runs-on: ubuntu-latest + needs: tag + if: ${{ needs.tag.outputs.tagcreated == 'yes' }} + steps: + - uses: actions/checkout@v4 + - name: Build + run: | + make build-in-docker + - name: Generate Changelog + run: | + VERSION=$(cicd/version.sh) + cicd/changelog.sh $VERSION > bin/CHANGELOG.md + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + body_path: bin/CHANGELOG.md + files: bin/ydbops* + tag_name: ${{ needs.tag.outputs.tagname }} + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 0c6d753..9eadee8 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -16,10 +16,17 @@ jobs: steps: - name: checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 # because we use new-from-rev in golangci-lint - name: golangci-lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v6 + with: + version: v1.61.0 + - name: golangci-lint-new-code-much-stricter + uses: golangci/golangci-lint-action@v6 with: - version: v1.58.1 + version: v1.61.0 + args: --verbose --disable-all --new-from-rev=origin/master --enable wrapcheck,stylecheck,funlen,mnd,cyclop autoformatter: name: autoformat check concurrency: @@ -63,6 +70,6 @@ jobs: go mod download echo "$HOME/go/bin" >> $GITHUB_PATH - name: build ydbops - run: go build + run: make build - name: run tests run: go test -v -p 1 ./... -args -ginkgo.v diff --git a/.golangci.yml b/.golangci.yml index f76d93e..1ecc9e4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -4,7 +4,7 @@ run: concurrency: 4 # timeout for analysis, e.g. 30s, 5m, default is 1m - deadline: 5m + timeout: 5m # exit code when at least one issue was found, default is 1 issues-exit-code: 1 @@ -12,10 +12,6 @@ run: # include test files or not, default is true tests: false - # list of build tags, all linters use it. Default is empty list. - #build-tags: - # - mytag - # which files to skip: they will be analyzed, but issues from them # won't be reported. Default value is empty list, but there is # no need to include all autogenerated files, we confidently recognize @@ -36,7 +32,6 @@ output: # print linter name in the end of issue text, default is true print-linter-name: true - # all available settings of specific linters linters-settings: errcheck: @@ -58,11 +53,11 @@ linters-settings: # simplify code: gofmt with `-s` option, true by default simplify: true gofumpt: - module-path: github.com/ydb-platform/ydb-go-sdk/v3 + module-path: github.com/ydb-platform/ydbops goimports: # put imports beginning with prefix after 3rd-party packages; # it's a comma-separated list of prefixes - local-prefixes: github.com/ydb-platform/ydb-go-sdk/v3 + local-prefixes: github.com/ydb-platform/ydbops goconst: # minimal length of string constant, 3 by default min-len: 2 @@ -213,65 +208,62 @@ linters-settings: # Whether to check exported functions. # Default: false checkExported: true + linters: disable-all: true enable: -# - cyclop - - dogsled -# - dupl - - errcheck - - errorlint -# - exhaustive -# - exhaustivestruct -# - forbidigo -# - funlen -# - gci -# - gocognit - - goconst - - gocritic - - gocyclo -# - godot -# - godox - - gofmt # On why gofmt when goimports is enabled - https://github.com/golang/go/issues/21476 - - gofumpt - - goheader -# - goimports -# - gomnd -# - gomoddirectives -# - gomodguard - - gosec - - gosimple - - govet -# - depguard -# - ifshort -# - ireturn -# - lll - - makezero - - misspell - - ineffassign - - misspell - - nakedret - - nestif -# - nilnil -# - nlreturn - - nolintlint - - prealloc - - predeclared - - rowserrcheck - - revive -# - stylecheck -# - tagliatelle -# - testpackage -# - thelper -# - tenv - # - typecheck - - unconvert - - unparam - - unused -# - varnamelen - - whitespace -# - wrapcheck -# - wsl + - dogsled + - dupl + - errcheck + - errorlint + - exhaustive + - gocognit + - goconst + - gocritic + - gocyclo + - gofmt # On why gofmt when goimports is enabled - https://github.com/golang/go/issues/21476 + - gofumpt + - goheader + - goimports + - gomoddirectives + - gomodguard + - gosimple + - govet + - makezero + - misspell + - ineffassign + - misspell + - nakedret + - nestif + - nilnil + - nolintlint + - prealloc + - predeclared + - rowserrcheck + - revive + - tagliatelle + - testpackage + - thelper + - tenv + - typecheck + - unconvert + - unparam + - unused + - whitespace + + # impossible to refactor now, these are launched on all new code: + # - wrapcheck - too many unwrapped errors + # - stylecheck - abbreviations capitalization + # - funlen + # - mnd + # - cyclop + + # Disabled forever: + # - varnamelen - short variable names are more normal than this linter thinks + # - godox - TODOs in the code are normal + # - depguard - we don't really have a policy of forbidding stuff + # - lll - virtually impossible to create logs \ help otherwise + # - gosec G115, we use too many uint32 for Node identifiers and false positives are very common issues: # List of regexps of issue texts to exclude, empty list by default. @@ -318,13 +310,8 @@ issues: # Show only new issues created in git patch with set file path. # new-from-patch: path/to/patch/file exclude-rules: - - path: internal/xatomic/type.go - linters: - - predeclared - path: _test\.go linters: - unused - unparam - gocritic - - path: _test\.go - text: "ydb.Connection is deprecated" diff --git a/CHANGELOG.md b/CHANGELOG.md index e978046..a300ec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.0.10 ++ `version` command ++ new release pipeline - modify CHANGELOG.md only, rest is automatic + ## 0.0.9 + Information about version in help output + Scripts for build release diff --git a/Makefile b/Makefile index 84b98cd..f0a8966 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,11 @@ -APP_VERSION=$(shell cicd/version.sh) BINARY_NAME=ydbops BUILD_DIR=bin + +APP_VERSION=$(shell cicd/version.sh) TODAY=$(shell date --iso=minutes) +GIT_COMMIT=$(shell git rev-parse HEAD) + +LDFLAGS="-X github.com/ydb-platform/ydbops/cmd/version.BuildVersion=${APP_VERSION} -X github.com/ydb-platform/ydbops/cmd/version.BuildTimestamp=${TODAY} -X github.com/ydb-platform/ydbops/cmd/version.BuildCommit=${GIT_COMMIT}" all: build build-macos @@ -13,11 +17,11 @@ pre-build: @mkdir -p $(BUILD_DIR) build-macos: lint pre-build - GOOS=darwin GOARCH=amd64 go build -ldflags='-X github.com/ydb-platform/ydbops/cmd.buildVersion=${APP_VERSION}' -o ${BUILD_DIR}/${BINARY_NAME}_darwin_amd64 main.go - GOOS=darwin GOARCH=arm64 go build -ldflags='-X github.com/ydb-platform/ydbops/cmd.buildVersion=${APP_VERSION}' -o ${BUILD_DIR}/${BINARY_NAME}_darwin_arm64 main.go + GOOS=darwin GOARCH=amd64 go build -ldflags=${LDFLAGS} -o ${BUILD_DIR}/${BINARY_NAME}_darwin_amd64 main.go + GOOS=darwin GOARCH=arm64 go build -ldflags=${LDFLAGS} -o ${BUILD_DIR}/${BINARY_NAME}_darwin_arm64 main.go build: lint pre-build - CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -ldflags='-X github.com/ydb-platform/ydbops/cmd.buildVersion=${APP_VERSION}' -o ${BUILD_DIR}/${BINARY_NAME} main.go + CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -ldflags=${LDFLAGS} -o ${BUILD_DIR}/${BINARY_NAME} main.go strip bin/${BINARY_NAME} clear: @@ -29,12 +33,12 @@ dep: docker: docker build --force-rm -t $(BINARY_NAME) . -build-in-docker: docker +test: + if [ "$(shell uname)" = "Linux" ]; then make build; else make build-macos; fi + ginkgo test ./... + +build-in-docker: clear docker docker rm -f $(BINARY_NAME) || true docker create --name $(BINARY_NAME) $(BINARY_NAME) docker cp '$(BINARY_NAME):/app/bin/' $(BUILD_DIR) docker rm -f $(BINARY_NAME) - -clean: - @echo "Cleaning..." - @rm -Rf $(BUILD_DIR) diff --git a/README.md b/README.md index 232c3c9..3f7637a 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,7 @@ `ydbops` utility is used to perform various ad-hoc and maintenance operations on YDB clusters. -## On the up-to-date'ness of this readme - -Soon an official documentation on [ydb.tech](https://ydb.tech) will be available. - -For now, please use the below info for reference only, it might be slightly outdated. +For comprehensive documentation, refer to [ydb.tech](https://ydb.tech/docs/en/reference/ydbops/) ## Prerequisites: @@ -14,8 +10,7 @@ For now, please use the below info for reference only, it might be slightly outd ## How to build -Execute build.sh -Also Dockerfile can be used as a part of other multi-stage dockerfiles. +Execute `make build-in-docker`, you will get binaries for Linux and MacOS, both amd and arm. ## How to run tests @@ -25,13 +20,9 @@ Ginkgo testing library is used. Do: ginkgo test -vvv ./tests ``` -## Current limitations: - -1. [NON-CRITICAL FEATURE] Yandex IAM authorization with SA account key file is currently unsupported. However, you can always issue the token yourself and put it inside the `YDB_TOKEN` variable: `export YDB_TOKEN=$(ycp --profile iam create-token)` - ## How to use: -Please browse the `ydbops --help` first. Then read along for examples (substitute your own values, of course). +Please browse the `ydbops --help` first. Then read along for examples (substitute your own values). #### Restart baremetal storage hosts @@ -83,15 +74,13 @@ ydbops restart --storage \ ## How to create a new version ### In Github -1. Define new version number, like 1.1.0 -2. Update CHANGELOG.md with proper information about new version -3. Push changes into the repository (git push) -4. Add tag v{VERSION}, like v1.1.0 (git tag v1.1.0) -5. Push tag into the repository (git push --tags) -6. Github will create a new release - -## Localy -1. Define new version number, like 1.1.0 -2. Update CHANGELOG.md with proper information about new version -4. Add tag v{VERSION}, like v1.1.0 (git tag v1.1.0) -5. make build-in-docker \ No newline at end of file +1. Define new semver version number (e.g. 1.1.0) +2. Update CHANGELOG.md with proper information about new version. Add the following to the beginning of the file, before previous entries: +``` +## + +- change 1 +- change 2 +``` +3. Create a pull request, wait for it to be merged +4. Github actions will create both the tag and the release with binaries for all platforms diff --git a/build.sh b/build.sh deleted file mode 100755 index d5425d1..0000000 --- a/build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -docker run --name ydbops-build \ - -v $(pwd):/usr/local/go/src/ydbops \ - -w /usr/local/go/src/ydbops golang:1.22 make build -docker rm -f ydbops-build - -exit 0 \ No newline at end of file diff --git a/cicd/version.sh b/cicd/version.sh index 2a80c61..ea4cddb 100755 --- a/cicd/version.sh +++ b/cicd/version.sh @@ -1,14 +1,2 @@ -LATEST_TAG_REV=$(git rev-list --tags --max-count=1) -LATEST_COMMIT_REV=$(git rev-list HEAD --max-count=1) - -if [ -n "$LATEST_TAG_REV" ]; then - LATEST_TAG=$(git describe --tags "$(git rev-list --tags --max-count=1)") - else - LATEST_TAG="v0.0.0" -fi - -if [ "$LATEST_TAG_REV" != "$LATEST_COMMIT_REV" ]; then - echo "$LATEST_TAG+$(git rev-list HEAD --max-count=1 --abbrev-commit)" - else - echo "$LATEST_TAG" -fi +APP_VERSION=$(cat ./CHANGELOG.md | grep "##" | head -n 1 | cut -d ' ' -f 2) +echo "v$APP_VERSION" diff --git a/cmd/root.go b/cmd/root.go index dbf3177..1e9e248 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,6 +1,8 @@ package cmd import ( + "fmt" + "github.com/fatih/color" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -10,6 +12,7 @@ import ( "github.com/ydb-platform/ydbops/cmd/maintenance" "github.com/ydb-platform/ydbops/cmd/restart" "github.com/ydb-platform/ydbops/cmd/run" + "github.com/ydb-platform/ydbops/cmd/version" iCli "github.com/ydb-platform/ydbops/internal/cli" "github.com/ydb-platform/ydbops/pkg/cli" "github.com/ydb-platform/ydbops/pkg/cmdutil" @@ -17,8 +20,6 @@ import ( "github.com/ydb-platform/ydbops/pkg/options" ) -var buildVersion = "v0.0.0" - var RootCommandDescription = command.NewDescription( "ydbops", "ydbops: a CLI tool for performing YDB cluster maintenance operations", @@ -45,10 +46,11 @@ func NewRootCommand( roptions := &RootOptions{ BaseOptions: boptions, } + cmd := &cobra.Command{ Use: RootCommandDescription.GetUse(), Short: RootCommandDescription.GetShortDescription(), - Long: RootCommandDescription.GetLongDescription() + " (" + buildVersion + ")", + Long: fmt.Sprintf("%s (%s)", RootCommandDescription.GetLongDescription(), version.BuildVersion), // hide --completion for more compact --help CompletionOptions: cobra.CompletionOptions{ DisableDefaultCmd: true, @@ -95,5 +97,6 @@ func InitRootCommandTree(root *cobra.Command, f cmdutil.Factory) { restart.New(f), maintenance.New(f), run.New(f), + version.New(), ) } diff --git a/cmd/version/version.go b/cmd/version/version.go new file mode 100644 index 0000000..4432137 --- /dev/null +++ b/cmd/version/version.go @@ -0,0 +1,43 @@ +package version + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/ydb-platform/ydbops/pkg/command" +) + +var ( // These variables are populated during build time using ldflags + BuildTimestamp string + BuildVersion string + BuildCommit string +) + +var VersionCommandDescription = command.NewDescription( + "version", + "Print ydbops version", + "Print ydbops version and other build info: git commit and date", +) + +func New() *cobra.Command { + cmd := &cobra.Command{ + Use: VersionCommandDescription.GetUse(), + Short: VersionCommandDescription.GetShortDescription(), + Long: VersionCommandDescription.GetLongDescription(), + RunE: func(_ *cobra.Command, args []string) error { + if len(args) > 0 { + return fmt.Errorf("free args not expected: %v", args) + } + fmt.Printf( + "Git commit: %s\nTag: %s\nBuild date: %s", + BuildCommit, + BuildVersion, + BuildTimestamp, + ) + return nil + }, + } + + return cmd +} diff --git a/pkg/client/auth/credentials/provider.go b/pkg/client/auth/credentials/provider.go index f665800..69ff3a5 100644 --- a/pkg/client/auth/credentials/provider.go +++ b/pkg/client/auth/credentials/provider.go @@ -80,9 +80,9 @@ func (b *baseProvider) Init() error { b.impl = NewMetadata(b.logger) case options.None: b.initErr = fmt.Errorf("determined credentials to be anonymous. Anonymous credentials are currently unsupported") - default: + case options.Unset, options.MultipleAtOnce: b.initErr = fmt.Errorf( - "internal error: authorization type not recognized after options validation, this should never happen", + "internal error: these values should have not passed the CLI validation, this should never happen", ) } if b.initErr == nil { diff --git a/tests/run_e2e_test.go b/tests/run_e2e_test.go index 6cb7251..a70c6b2 100644 --- a/tests/run_e2e_test.go +++ b/tests/run_e2e_test.go @@ -101,7 +101,7 @@ func RunTestCase(tc TestCase) { } } - cmd := exec.Command(filepath.Join("..", "ydbops"), commandArgs...) + cmd := exec.Command(filepath.Join("..", "bin", "ydbops"), commandArgs...) outputBytes, _ := cmd.CombinedOutput() // TODO some tests return with an error. Maybe tune this test a bit // so it includes checking the error code as well