Bump go and golangci-lint versions, fix lint
This commit is contained in:
parent
de11885271
commit
913a6be647
|
|
@ -19,7 +19,7 @@ jobs:
|
||||||
- name: Set up go
|
- name: Set up go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.22.4'
|
go-version: '1.24.1'
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -36,7 +36,7 @@ jobs:
|
||||||
- name: Set up go
|
- name: Set up go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.22.4'
|
go-version: '1.24.1'
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -61,7 +61,7 @@ jobs:
|
||||||
- name: Set up go
|
- name: Set up go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.22.4'
|
go-version: '1.24.1'
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -72,10 +72,10 @@ jobs:
|
||||||
# There is a risk of drift between the two, but this is only linting,
|
# There is a risk of drift between the two, but this is only linting,
|
||||||
# not runtime correctness!
|
# not runtime correctness!
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v6
|
uses: golangci/golangci-lint-action@v7
|
||||||
with:
|
with:
|
||||||
working-directory: git-sync
|
working-directory: git-sync
|
||||||
version: v1.59.0
|
version: v2.0.0
|
||||||
|
|
||||||
- name: make lint
|
- name: make lint
|
||||||
working-directory: git-sync
|
working-directory: git-sync
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,55 @@
|
||||||
# pass, in contrast to .golangci.yaml which defines checks that also the
|
# pass, in contrast to .golangci.yaml which defines checks that also the
|
||||||
# existing code passes.
|
# existing code passes.
|
||||||
|
|
||||||
|
version: "2"
|
||||||
|
|
||||||
run:
|
run:
|
||||||
timeout: 30m
|
timeout: 30m
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
disable-all: false
|
default: all
|
||||||
|
|
||||||
enable: # please keep this alphabetized
|
enable: # please keep this alphabetized
|
||||||
- ginkgolinter
|
|
||||||
- gocritic
|
|
||||||
- govet
|
- govet
|
||||||
- ineffassign
|
- ineffassign
|
||||||
# Should we add logcheck, for consistency with kubernetes/kubernetes?
|
|
||||||
# - logcheck
|
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- stylecheck
|
|
||||||
- unused
|
- unused
|
||||||
|
- gocritic
|
||||||
|
- asasalint
|
||||||
|
- copyloopvar
|
||||||
|
|
||||||
linters-settings: # please keep this alphabetized
|
disable:
|
||||||
gocritic:
|
- errcheck
|
||||||
|
- cyclop
|
||||||
|
- depguard
|
||||||
|
- dupl
|
||||||
|
- err113
|
||||||
|
- exhaustruct
|
||||||
|
- funlen
|
||||||
|
- gochecknoglobals
|
||||||
|
- gochecknoinits
|
||||||
|
- gocognit
|
||||||
|
- goconst # TODO: turn this one on
|
||||||
|
- gocyclo
|
||||||
|
- gosec # TODO: turn this one on
|
||||||
|
- lll
|
||||||
|
- maintidx
|
||||||
|
- mnd
|
||||||
|
- musttag
|
||||||
|
- nestif
|
||||||
|
- nlreturn
|
||||||
|
- paralleltest
|
||||||
|
- perfsprint
|
||||||
|
- promlinter
|
||||||
|
- recvcheck
|
||||||
|
- revive
|
||||||
|
- tagliatelle
|
||||||
|
- testpackage
|
||||||
|
- varnamelen
|
||||||
|
- wrapcheck
|
||||||
|
- wsl
|
||||||
|
|
||||||
|
settings: # please keep this alphabetized
|
||||||
staticcheck:
|
staticcheck:
|
||||||
checks:
|
checks:
|
||||||
- "all"
|
- "all"
|
||||||
stylecheck:
|
|
||||||
|
|
|
||||||
9
Makefile
9
Makefile
|
|
@ -51,7 +51,7 @@ IMAGE := $(REGISTRY)/$(BIN)
|
||||||
TAG := $(VERSION)
|
TAG := $(VERSION)
|
||||||
OS_ARCH_TAG := $(TAG)__$(OS)_$(ARCH)
|
OS_ARCH_TAG := $(TAG)__$(OS)_$(ARCH)
|
||||||
|
|
||||||
BUILD_IMAGE ?= golang:1.22
|
BUILD_IMAGE ?= golang:1.24
|
||||||
|
|
||||||
DBG_MAKEFILE ?=
|
DBG_MAKEFILE ?=
|
||||||
ifneq ($(DBG_MAKEFILE),1)
|
ifneq ($(DBG_MAKEFILE),1)
|
||||||
|
|
@ -277,11 +277,8 @@ container-clean:
|
||||||
bin-clean:
|
bin-clean:
|
||||||
rm -rf .go bin
|
rm -rf .go bin
|
||||||
|
|
||||||
lint-staticcheck:
|
|
||||||
go run honnef.co/go/tools/cmd/staticcheck@2023.1.3
|
|
||||||
|
|
||||||
lint-golangci-lint:
|
lint-golangci-lint:
|
||||||
go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.0 run
|
go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.0.0 run -v
|
||||||
|
|
||||||
lint-shellcheck:
|
lint-shellcheck:
|
||||||
docker run \
|
docker run \
|
||||||
|
|
@ -292,4 +289,4 @@ lint-shellcheck:
|
||||||
shellcheck \
|
shellcheck \
|
||||||
$$(git ls-files ':!:vendor' '*.sh')
|
$$(git ls-files ':!:vendor' '*.sh')
|
||||||
|
|
||||||
lint: lint-staticcheck lint-golangci-lint lint-shellcheck
|
lint: lint-golangci-lint lint-shellcheck
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ type credentialSliceValue struct {
|
||||||
var _ pflag.Value = &credentialSliceValue{}
|
var _ pflag.Value = &credentialSliceValue{}
|
||||||
var _ pflag.SliceValue = &credentialSliceValue{}
|
var _ pflag.SliceValue = &credentialSliceValue{}
|
||||||
|
|
||||||
// pflagCredentialSlice is like pflag.StringSlice()
|
// pflagCredentialSlice is like pflag.StringSlice().
|
||||||
func pflagCredentialSlice(name, def, usage string) *[]credential {
|
func pflagCredentialSlice(name, def, usage string) *[]credential {
|
||||||
p := &credentialSliceValue{}
|
p := &credentialSliceValue{}
|
||||||
_ = p.Set(def)
|
_ = p.Set(def)
|
||||||
|
|
|
||||||
2
env.go
2
env.go
|
|
@ -296,7 +296,7 @@ type explicitFlag[T comparable] struct {
|
||||||
flagPtr *T
|
flagPtr *T
|
||||||
}
|
}
|
||||||
|
|
||||||
// newExplicitFlag allocates an explicitFlag
|
// newExplicitFlag allocates an explicitFlag.
|
||||||
func newExplicitFlag[T comparable](ptr *T, name, usage string, fn func(name string, value T, usage string) *T) {
|
func newExplicitFlag[T comparable](ptr *T, name, usage string, fn func(name string, value T, usage string) *T) {
|
||||||
h := &explicitFlag[T]{
|
h := &explicitFlag[T]{
|
||||||
realPtr: ptr,
|
realPtr: ptr,
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -20,4 +20,4 @@ require (
|
||||||
google.golang.org/protobuf v1.33.0 // indirect
|
google.golang.org/protobuf v1.33.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.22
|
go 1.23
|
||||||
|
|
|
||||||
107
main.go
107
main.go
|
|
@ -378,7 +378,7 @@ func main() {
|
||||||
|
|
||||||
// Handle print-and-exit cases.
|
// Handle print-and-exit cases.
|
||||||
if *flVersion {
|
if *flVersion {
|
||||||
fmt.Println(version.VERSION)
|
fmt.Fprintln(os.Stdout, version.VERSION)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
if *flHelp {
|
if *flHelp {
|
||||||
|
|
@ -415,7 +415,7 @@ func main() {
|
||||||
cmdRunner := cmd.NewRunner(log)
|
cmdRunner := cmd.NewRunner(log)
|
||||||
|
|
||||||
if *flRepo == "" {
|
if *flRepo == "" {
|
||||||
fatalConfigError(log, true, "required flag: --repo must be specified")
|
fatalConfigErrorf(log, true, "required flag: --repo must be specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -428,27 +428,27 @@ func main() {
|
||||||
log.V(0).Info("setting --ref from deprecated --rev")
|
log.V(0).Info("setting --ref from deprecated --rev")
|
||||||
*flRef = *flDeprecatedRev
|
*flRef = *flDeprecatedRev
|
||||||
case *flDeprecatedBranch != "" && *flDeprecatedRev != "":
|
case *flDeprecatedBranch != "" && *flDeprecatedRev != "":
|
||||||
fatalConfigError(log, true, "deprecated flag combo: can't set --ref from deprecated --branch and --rev (one or the other is OK)")
|
fatalConfigErrorf(log, true, "deprecated flag combo: can't set --ref from deprecated --branch and --rev (one or the other is OK)")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flRef == "" {
|
if *flRef == "" {
|
||||||
fatalConfigError(log, true, "required flag: --ref must be specified")
|
fatalConfigErrorf(log, true, "required flag: --ref must be specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flDepth < 0 { // 0 means "no limit"
|
if *flDepth < 0 { // 0 means "no limit"
|
||||||
fatalConfigError(log, true, "invalid flag: --depth must be greater than or equal to 0")
|
fatalConfigErrorf(log, true, "invalid flag: --depth must be greater than or equal to 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch submodulesMode(*flSubmodules) {
|
switch submodulesMode(*flSubmodules) {
|
||||||
case submodulesRecursive, submodulesShallow, submodulesOff:
|
case submodulesRecursive, submodulesShallow, submodulesOff:
|
||||||
default:
|
default:
|
||||||
fatalConfigError(log, true, "invalid flag: --submodules must be one of %q, %q, or %q", submodulesRecursive, submodulesShallow, submodulesOff)
|
fatalConfigErrorf(log, true, "invalid flag: --submodules must be one of %q, %q, or %q", submodulesRecursive, submodulesShallow, submodulesOff)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch *flGitGC {
|
switch *flGitGC {
|
||||||
case gcAuto, gcAlways, gcAggressive, gcOff:
|
case gcAuto, gcAlways, gcAggressive, gcOff:
|
||||||
default:
|
default:
|
||||||
fatalConfigError(log, true, "invalid flag: --git-gc must be one of %q, %q, %q, or %q", gcAuto, gcAlways, gcAggressive, gcOff)
|
fatalConfigErrorf(log, true, "invalid flag: --git-gc must be one of %q, %q, %q, or %q", gcAuto, gcAlways, gcAggressive, gcOff)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flDeprecatedDest != "" {
|
if *flDeprecatedDest != "" {
|
||||||
|
|
@ -467,11 +467,11 @@ func main() {
|
||||||
*flPeriod = time.Duration(int(*flDeprecatedWait*1000)) * time.Millisecond
|
*flPeriod = time.Duration(int(*flDeprecatedWait*1000)) * time.Millisecond
|
||||||
}
|
}
|
||||||
if *flPeriod < 10*time.Millisecond {
|
if *flPeriod < 10*time.Millisecond {
|
||||||
fatalConfigError(log, true, "invalid flag: --period must be at least 10ms")
|
fatalConfigErrorf(log, true, "invalid flag: --period must be at least 10ms")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flDeprecatedChmod != 0 {
|
if *flDeprecatedChmod != 0 {
|
||||||
fatalConfigError(log, true, "deprecated flag: --change-permissions is no longer supported")
|
fatalConfigErrorf(log, true, "deprecated flag: --change-permissions is no longer supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
var syncSig syscall.Signal
|
var syncSig syscall.Signal
|
||||||
|
|
@ -488,7 +488,7 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if syncSig == 0 {
|
if syncSig == 0 {
|
||||||
fatalConfigError(log, true, "invalid flag: --sync-on-signal must be a valid signal name or number")
|
fatalConfigErrorf(log, true, "invalid flag: --sync-on-signal must be a valid signal name or number")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -498,7 +498,7 @@ func main() {
|
||||||
*flSyncTimeout = time.Duration(*flDeprecatedTimeout) * time.Second
|
*flSyncTimeout = time.Duration(*flDeprecatedTimeout) * time.Second
|
||||||
}
|
}
|
||||||
if *flSyncTimeout < 10*time.Millisecond {
|
if *flSyncTimeout < 10*time.Millisecond {
|
||||||
fatalConfigError(log, true, "invalid flag: --sync-timeout must be at least 10ms")
|
fatalConfigErrorf(log, true, "invalid flag: --sync-timeout must be at least 10ms")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flDeprecatedMaxSyncFailures != 0 {
|
if *flDeprecatedMaxSyncFailures != 0 {
|
||||||
|
|
@ -514,10 +514,10 @@ func main() {
|
||||||
}
|
}
|
||||||
if *flExechookCommand != "" {
|
if *flExechookCommand != "" {
|
||||||
if *flExechookTimeout < time.Second {
|
if *flExechookTimeout < time.Second {
|
||||||
fatalConfigError(log, true, "invalid flag: --exechook-timeout must be at least 1s")
|
fatalConfigErrorf(log, true, "invalid flag: --exechook-timeout must be at least 1s")
|
||||||
}
|
}
|
||||||
if *flExechookBackoff < time.Second {
|
if *flExechookBackoff < time.Second {
|
||||||
fatalConfigError(log, true, "invalid flag: --exechook-backoff must be at least 1s")
|
fatalConfigErrorf(log, true, "invalid flag: --exechook-backoff must be at least 1s")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -527,13 +527,13 @@ func main() {
|
||||||
*flWebhookStatusSuccess = 0
|
*flWebhookStatusSuccess = 0
|
||||||
}
|
}
|
||||||
if *flWebhookStatusSuccess < 0 {
|
if *flWebhookStatusSuccess < 0 {
|
||||||
fatalConfigError(log, true, "invalid flag: --webhook-success-status must be a valid HTTP code or 0")
|
fatalConfigErrorf(log, true, "invalid flag: --webhook-success-status must be a valid HTTP code or 0")
|
||||||
}
|
}
|
||||||
if *flWebhookTimeout < time.Second {
|
if *flWebhookTimeout < time.Second {
|
||||||
fatalConfigError(log, true, "invalid flag: --webhook-timeout must be at least 1s")
|
fatalConfigErrorf(log, true, "invalid flag: --webhook-timeout must be at least 1s")
|
||||||
}
|
}
|
||||||
if *flWebhookBackoff < time.Second {
|
if *flWebhookBackoff < time.Second {
|
||||||
fatalConfigError(log, true, "invalid flag: --webhook-backoff must be at least 1s")
|
fatalConfigErrorf(log, true, "invalid flag: --webhook-backoff must be at least 1s")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -543,79 +543,79 @@ func main() {
|
||||||
}
|
}
|
||||||
if *flUsername != "" {
|
if *flUsername != "" {
|
||||||
if *flPassword == "" && *flPasswordFile == "" {
|
if *flPassword == "" && *flPasswordFile == "" {
|
||||||
fatalConfigError(log, true, "required flag: $GITSYNC_PASSWORD or --password-file must be specified when --username is specified")
|
fatalConfigErrorf(log, true, "required flag: $GITSYNC_PASSWORD or --password-file must be specified when --username is specified")
|
||||||
}
|
}
|
||||||
if *flPassword != "" && *flPasswordFile != "" {
|
if *flPassword != "" && *flPasswordFile != "" {
|
||||||
fatalConfigError(log, true, "invalid flag: only one of $GITSYNC_PASSWORD and --password-file may be specified")
|
fatalConfigErrorf(log, true, "invalid flag: only one of $GITSYNC_PASSWORD and --password-file may be specified")
|
||||||
}
|
}
|
||||||
if u, err := url.Parse(*flRepo); err == nil { // it may not even parse as a URL, that's OK
|
if u, err := url.Parse(*flRepo); err == nil { // it may not even parse as a URL, that's OK
|
||||||
if u.User != nil {
|
if u.User != nil {
|
||||||
fatalConfigError(log, true, "invalid flag: credentials may not be specified in --repo when --username is specified")
|
fatalConfigErrorf(log, true, "invalid flag: credentials may not be specified in --repo when --username is specified")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if *flPassword != "" {
|
if *flPassword != "" {
|
||||||
fatalConfigError(log, true, "invalid flag: $GITSYNC_PASSWORD may only be specified when --username is specified")
|
fatalConfigErrorf(log, true, "invalid flag: $GITSYNC_PASSWORD may only be specified when --username is specified")
|
||||||
}
|
}
|
||||||
if *flPasswordFile != "" {
|
if *flPasswordFile != "" {
|
||||||
fatalConfigError(log, true, "invalid flag: --password-file may only be specified when --username is specified")
|
fatalConfigErrorf(log, true, "invalid flag: --password-file may only be specified when --username is specified")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flGithubAppApplicationID != 0 || *flGithubAppClientID != "" {
|
if *flGithubAppApplicationID != 0 || *flGithubAppClientID != "" {
|
||||||
if *flGithubAppApplicationID != 0 && *flGithubAppClientID != "" {
|
if *flGithubAppApplicationID != 0 && *flGithubAppClientID != "" {
|
||||||
fatalConfigError(log, true, "invalid flag: only one of --github-app-application-id or --github-app-client-id may be specified")
|
fatalConfigErrorf(log, true, "invalid flag: only one of --github-app-application-id or --github-app-client-id may be specified")
|
||||||
}
|
}
|
||||||
if *flGithubAppInstallationID == 0 {
|
if *flGithubAppInstallationID == 0 {
|
||||||
fatalConfigError(log, true, "invalid flag: --github-app-installation-id must be specified when --github-app-application-id or --github-app-client-id are specified")
|
fatalConfigErrorf(log, true, "invalid flag: --github-app-installation-id must be specified when --github-app-application-id or --github-app-client-id are specified")
|
||||||
}
|
}
|
||||||
if *flGithubAppPrivateKey == "" && *flGithubAppPrivateKeyFile == "" {
|
if *flGithubAppPrivateKey == "" && *flGithubAppPrivateKeyFile == "" {
|
||||||
fatalConfigError(log, true, "invalid flag: $GITSYNC_GITHUB_APP_PRIVATE_KEY or --github-app-private-key-file must be specified when --github-app-application-id or --github-app-client-id are specified")
|
fatalConfigErrorf(log, true, "invalid flag: $GITSYNC_GITHUB_APP_PRIVATE_KEY or --github-app-private-key-file must be specified when --github-app-application-id or --github-app-client-id are specified")
|
||||||
}
|
}
|
||||||
if *flGithubAppPrivateKey != "" && *flGithubAppPrivateKeyFile != "" {
|
if *flGithubAppPrivateKey != "" && *flGithubAppPrivateKeyFile != "" {
|
||||||
fatalConfigError(log, true, "invalid flag: only one of $GITSYNC_GITHUB_APP_PRIVATE_KEY or --github-app-private-key-file may be specified")
|
fatalConfigErrorf(log, true, "invalid flag: only one of $GITSYNC_GITHUB_APP_PRIVATE_KEY or --github-app-private-key-file may be specified")
|
||||||
}
|
}
|
||||||
if *flUsername != "" {
|
if *flUsername != "" {
|
||||||
fatalConfigError(log, true, "invalid flag: --username may not be specified when --github-app-private-key-file is specified")
|
fatalConfigErrorf(log, true, "invalid flag: --username may not be specified when --github-app-private-key-file is specified")
|
||||||
}
|
}
|
||||||
if *flPassword != "" {
|
if *flPassword != "" {
|
||||||
fatalConfigError(log, true, "invalid flag: --password may not be specified when --github-app-private-key-file is specified")
|
fatalConfigErrorf(log, true, "invalid flag: --password may not be specified when --github-app-private-key-file is specified")
|
||||||
}
|
}
|
||||||
if *flPasswordFile != "" {
|
if *flPasswordFile != "" {
|
||||||
fatalConfigError(log, true, "invalid flag: --password-file may not be specified when --github-app-private-key-file is specified")
|
fatalConfigErrorf(log, true, "invalid flag: --password-file may not be specified when --github-app-private-key-file is specified")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if *flGithubAppApplicationID != 0 {
|
if *flGithubAppApplicationID != 0 {
|
||||||
fatalConfigError(log, true, "invalid flag: --github-app-application-id may only be specified when --github-app-private-key-file is specified")
|
fatalConfigErrorf(log, true, "invalid flag: --github-app-application-id may only be specified when --github-app-private-key-file is specified")
|
||||||
}
|
}
|
||||||
if *flGithubAppInstallationID != 0 {
|
if *flGithubAppInstallationID != 0 {
|
||||||
fatalConfigError(log, true, "invalid flag: --github-app-installation-id may only be specified when --github-app-private-key-file is specified")
|
fatalConfigErrorf(log, true, "invalid flag: --github-app-installation-id may only be specified when --github-app-private-key-file is specified")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(*flCredentials) > 0 {
|
if len(*flCredentials) > 0 {
|
||||||
for _, cred := range *flCredentials {
|
for _, cred := range *flCredentials {
|
||||||
if cred.URL == "" {
|
if cred.URL == "" {
|
||||||
fatalConfigError(log, true, "invalid flag: --credential URL must be specified")
|
fatalConfigErrorf(log, true, "invalid flag: --credential URL must be specified")
|
||||||
}
|
}
|
||||||
if cred.Username == "" {
|
if cred.Username == "" {
|
||||||
fatalConfigError(log, true, "invalid flag: --credential username must be specified")
|
fatalConfigErrorf(log, true, "invalid flag: --credential username must be specified")
|
||||||
}
|
}
|
||||||
if cred.Password == "" && cred.PasswordFile == "" {
|
if cred.Password == "" && cred.PasswordFile == "" {
|
||||||
fatalConfigError(log, true, "invalid flag: --credential password or password-file must be specified")
|
fatalConfigErrorf(log, true, "invalid flag: --credential password or password-file must be specified")
|
||||||
}
|
}
|
||||||
if cred.Password != "" && cred.PasswordFile != "" {
|
if cred.Password != "" && cred.PasswordFile != "" {
|
||||||
fatalConfigError(log, true, "invalid flag: only one of --credential password and password-file may be specified")
|
fatalConfigErrorf(log, true, "invalid flag: only one of --credential password and password-file may be specified")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flHTTPBind == "" {
|
if *flHTTPBind == "" {
|
||||||
if *flHTTPMetrics {
|
if *flHTTPMetrics {
|
||||||
fatalConfigError(log, true, "required flag: --http-bind must be specified when --http-metrics is set")
|
fatalConfigErrorf(log, true, "required flag: --http-bind must be specified when --http-metrics is set")
|
||||||
}
|
}
|
||||||
if *flHTTPprof {
|
if *flHTTPprof {
|
||||||
fatalConfigError(log, true, "required flag: --http-bind must be specified when --http-pprof is set")
|
fatalConfigErrorf(log, true, "required flag: --http-bind must be specified when --http-pprof is set")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1105,7 +1105,7 @@ func logSafeFlags(v int) []string {
|
||||||
}
|
}
|
||||||
// Handle --credential
|
// Handle --credential
|
||||||
if arg == "credential" {
|
if arg == "credential" {
|
||||||
orig := fl.Value.(*credentialSliceValue)
|
orig := fl.Value.(*credentialSliceValue) //nolint:forcetypeassert
|
||||||
sl := []credential{} // make a copy of the slice so we can mutate it
|
sl := []credential{} // make a copy of the slice so we can mutate it
|
||||||
for _, cred := range orig.value {
|
for _, cred := range orig.value {
|
||||||
if cred.Password != "" {
|
if cred.Password != "" {
|
||||||
|
|
@ -1153,10 +1153,12 @@ func sleepForever() {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fatalConfigError prints the error to the standard error, prints the usage
|
// fatalConfigErrorf prints the error to the standard error, prints the usage
|
||||||
// if the `printUsage` flag is true, exports the error to the error file and
|
// if the `printUsage` flag is true, exports the error to the error file and
|
||||||
// exits the process with the exit code.
|
// exits the process with the exit code.
|
||||||
func fatalConfigError(log *logging.Logger, printUsage bool, format string, a ...interface{}) {
|
//
|
||||||
|
//nolint:unparam
|
||||||
|
func fatalConfigErrorf(log *logging.Logger, printUsage bool, format string, a ...interface{}) {
|
||||||
s := fmt.Sprintf(format, a...)
|
s := fmt.Sprintf(format, a...)
|
||||||
fmt.Fprintln(os.Stderr, s)
|
fmt.Fprintln(os.Stderr, s)
|
||||||
if printUsage {
|
if printUsage {
|
||||||
|
|
@ -1399,7 +1401,7 @@ func dirIsEmpty(dir absPath) (bool, error) {
|
||||||
return len(dirents) == 0, nil
|
return len(dirents) == 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeDirContents iterated the specified dir and removes all contents
|
// removeDirContents iterated the specified dir and removes all contents.
|
||||||
func removeDirContents(dir absPath, log *logging.Logger) error {
|
func removeDirContents(dir absPath, log *logging.Logger) error {
|
||||||
return removeDirContentsIf(dir, log, func(fi os.FileInfo) (bool, error) {
|
return removeDirContentsIf(dir, log, func(fi os.FileInfo) (bool, error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|
@ -1445,7 +1447,7 @@ func removeDirContentsIf(dir absPath, log *logging.Logger, fn func(fi os.FileInf
|
||||||
|
|
||||||
// publishSymlink atomically sets link to point at the specified target. If the
|
// publishSymlink atomically sets link to point at the specified target. If the
|
||||||
// link existed, this returns the previous target.
|
// link existed, this returns the previous target.
|
||||||
func (git *repoSync) publishSymlink(ctx context.Context, worktree worktree) error {
|
func (git *repoSync) publishSymlink(worktree worktree) error {
|
||||||
targetPath := worktree.Path()
|
targetPath := worktree.Path()
|
||||||
linkDir, linkFile := git.link.Split()
|
linkDir, linkFile := git.link.Split()
|
||||||
|
|
||||||
|
|
@ -1475,7 +1477,7 @@ func (git *repoSync) publishSymlink(ctx context.Context, worktree worktree) erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeWorktree is used to remove a worktree and its folder
|
// removeWorktree is used to remove a worktree and its folder.
|
||||||
func (git *repoSync) removeWorktree(ctx context.Context, worktree worktree) error {
|
func (git *repoSync) removeWorktree(ctx context.Context, worktree worktree) error {
|
||||||
// Clean up worktree, if needed.
|
// Clean up worktree, if needed.
|
||||||
_, err := os.Stat(worktree.Path().String())
|
_, err := os.Stat(worktree.Path().String())
|
||||||
|
|
@ -1527,7 +1529,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
|
||||||
// /git/.git/worktrees/<worktree-dir-name>. Replace it with a reference
|
// /git/.git/worktrees/<worktree-dir-name>. Replace it with a reference
|
||||||
// using relative paths, so that other containers can use a different volume
|
// using relative paths, so that other containers can use a different volume
|
||||||
// mount name.
|
// mount name.
|
||||||
rootDotGit := ""
|
var rootDotGit string
|
||||||
if rel, err := filepath.Rel(worktree.Path().String(), git.root.String()); err != nil {
|
if rel, err := filepath.Rel(worktree.Path().String(), git.root.String()); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1745,7 +1747,7 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
|
||||||
// Figure out what we got. The ^{} syntax "peels" annotated tags to
|
// Figure out what we got. The ^{} syntax "peels" annotated tags to
|
||||||
// their underlying commit hashes, but has no effect if we fetched a
|
// their underlying commit hashes, but has no effect if we fetched a
|
||||||
// branch, plain tag, or hash.
|
// branch, plain tag, or hash.
|
||||||
remoteHash := ""
|
var remoteHash string
|
||||||
if output, _, err := git.Run(ctx, git.root, "rev-parse", "FETCH_HEAD^{}"); err != nil {
|
if output, _, err := git.Run(ctx, git.root, "rev-parse", "FETCH_HEAD^{}"); err != nil {
|
||||||
return false, "", err
|
return false, "", err
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1802,7 +1804,7 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
|
||||||
|
|
||||||
// If we have a new hash, update the symlink to point to the new worktree.
|
// If we have a new hash, update the symlink to point to the new worktree.
|
||||||
if changed {
|
if changed {
|
||||||
err := git.publishSymlink(ctx, newWorktree)
|
err := git.publishSymlink(newWorktree)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "", err
|
return false, "", err
|
||||||
}
|
}
|
||||||
|
|
@ -1976,7 +1978,7 @@ func (git *repoSync) CallAskPassURL(ctx context.Context) error {
|
||||||
return http.ErrUseLastResponse
|
return http.ErrUseLastResponse
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
httpReq, err := http.NewRequestWithContext(ctx, "GET", git.authURL, nil)
|
httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, git.authURL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("can't create auth request: %w", err)
|
return fmt.Errorf("can't create auth request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1987,7 +1989,7 @@ func (git *repoSync) CallAskPassURL(ctx context.Context) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != http.StatusOK {
|
||||||
errMessage, err := io.ReadAll(resp.Body)
|
errMessage, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("auth URL returned status %d, failed to read body: %w", resp.StatusCode, err)
|
return fmt.Errorf("auth URL returned status %d, failed to read body: %w", resp.StatusCode, err)
|
||||||
|
|
@ -2021,7 +2023,8 @@ func (git *repoSync) CallAskPassURL(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshGitHubAppToken generates a new installation token for a GitHub app and stores it as a credential
|
// RefreshGitHubAppToken generates a new installation token for a GitHub app
|
||||||
|
// and stores it as a credential.
|
||||||
func (git *repoSync) RefreshGitHubAppToken(ctx context.Context, githubBaseURL, privateKey, privateKeyFile, clientID string, appID, installationID int) error {
|
func (git *repoSync) RefreshGitHubAppToken(ctx context.Context, githubBaseURL, privateKey, privateKeyFile, clientID string, appID, installationID int) error {
|
||||||
git.log.V(3).Info("refreshing GitHub app token")
|
git.log.V(3).Info("refreshing GitHub app token")
|
||||||
|
|
||||||
|
|
@ -2080,7 +2083,7 @@ func (git *repoSync) RefreshGitHubAppToken(ctx context.Context, githubBaseURL, p
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
if resp.StatusCode != 201 {
|
if resp.StatusCode != http.StatusCreated {
|
||||||
errMessage, err := io.ReadAll(resp.Body)
|
errMessage, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GitHub app installation endpoint returned status %d, failed to read body: %w", resp.StatusCode, err)
|
return fmt.Errorf("GitHub app installation endpoint returned status %d, failed to read body: %w", resp.StatusCode, err)
|
||||||
|
|
@ -2247,8 +2250,8 @@ func parseGitConfigKey(r rune, ch <-chan rune) (string, error) {
|
||||||
buf = append(buf, r)
|
buf = append(buf, r)
|
||||||
|
|
||||||
for r := range ch {
|
for r := range ch {
|
||||||
switch {
|
switch r {
|
||||||
case r == ':':
|
case ':':
|
||||||
return string(buf), nil
|
return string(buf), nil
|
||||||
default:
|
default:
|
||||||
buf = append(buf, r)
|
buf = append(buf, r)
|
||||||
|
|
@ -2777,5 +2780,5 @@ HOOKS
|
||||||
`
|
`
|
||||||
|
|
||||||
func printManPage() {
|
func printManPage() {
|
||||||
fmt.Print(manual)
|
fmt.Fprint(os.Stdout, manual)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package cmd provides an API to run commands and log them in a consistent
|
||||||
|
// way.
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -40,7 +42,7 @@ type logintf interface {
|
||||||
WithCallDepth(depth int) logr.Logger
|
WithCallDepth(depth int) logr.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRunner returns a new CommandRunner
|
// NewRunner returns a new CommandRunner.
|
||||||
func NewRunner(log logintf) Runner {
|
func NewRunner(log logintf) Runner {
|
||||||
return Runner{log: log}
|
return Runner{log: log}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"k8s.io/git-sync/pkg/cmd"
|
"k8s.io/git-sync/pkg/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Exechook structure, implements Hook
|
// Exechook implements Hook in terms of executing a command.
|
||||||
type Exechook struct {
|
type Exechook struct {
|
||||||
// Runner
|
// Runner
|
||||||
cmdrunner cmd.Runner
|
cmdrunner cmd.Runner
|
||||||
|
|
@ -41,7 +41,7 @@ type Exechook struct {
|
||||||
log logintf
|
log logintf
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewExechook returns a new Exechook
|
// NewExechook returns a new Exechook.
|
||||||
func NewExechook(cmdrunner cmd.Runner, command string, getWorktree func(string) string, args []string, timeout time.Duration, log logintf) *Exechook {
|
func NewExechook(cmdrunner cmd.Runner, command string, getWorktree func(string) string, args []string, timeout time.Duration, log logintf) *Exechook {
|
||||||
return &Exechook{
|
return &Exechook{
|
||||||
cmdrunner: cmdrunner,
|
cmdrunner: cmdrunner,
|
||||||
|
|
@ -53,12 +53,12 @@ func NewExechook(cmdrunner cmd.Runner, command string, getWorktree func(string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name describes hook, implements Hook.Name
|
// Name describes hook, implements Hook.Name.
|
||||||
func (h *Exechook) Name() string {
|
func (h *Exechook) Name() string {
|
||||||
return "exechook"
|
return "exechook"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do runs exechook.command, implements Hook.Do
|
// Do runs exechook.command, implements Hook.Do.
|
||||||
func (h *Exechook) Do(ctx context.Context, hash string) error {
|
func (h *Exechook) Do(ctx context.Context, hash string) error {
|
||||||
ctx, cancel := context.WithTimeout(ctx, h.timeout)
|
ctx, cancel := context.WithTimeout(ctx, h.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package hook provides a way to run hooks in a controlled way.
|
||||||
package hook
|
package hook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -38,7 +39,7 @@ func init() {
|
||||||
prometheus.MustRegister(hookRunCount)
|
prometheus.MustRegister(hookRunCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describes what a Hook needs to implement, run by HookRunner
|
// Hook describes a single hook of some sort, which can be run by HookRunner.
|
||||||
type Hook interface {
|
type Hook interface {
|
||||||
// Describes hook
|
// Describes hook
|
||||||
Name() string
|
Name() string
|
||||||
|
|
@ -52,7 +53,7 @@ type hookData struct {
|
||||||
hash string
|
hash string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHookData returns a new HookData
|
// NewHookData returns a new HookData.
|
||||||
func NewHookData() *hookData {
|
func NewHookData() *hookData {
|
||||||
return &hookData{
|
return &hookData{
|
||||||
ch: make(chan struct{}, 1),
|
ch: make(chan struct{}, 1),
|
||||||
|
|
@ -87,7 +88,7 @@ func (d *hookData) send(newHash string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHookRunner returns a new HookRunner
|
// NewHookRunner returns a new HookRunner.
|
||||||
func NewHookRunner(hook Hook, backoff time.Duration, data *hookData, log logintf, oneTime bool) *HookRunner {
|
func NewHookRunner(hook Hook, backoff time.Duration, data *hookData, log logintf, oneTime bool) *HookRunner {
|
||||||
hr := &HookRunner{hook: hook, backoff: backoff, data: data, log: log}
|
hr := &HookRunner{hook: hook, backoff: backoff, data: data, log: log}
|
||||||
if oneTime {
|
if oneTime {
|
||||||
|
|
@ -96,7 +97,7 @@ func NewHookRunner(hook Hook, backoff time.Duration, data *hookData, log logintf
|
||||||
return hr
|
return hr
|
||||||
}
|
}
|
||||||
|
|
||||||
// HookRunner struct
|
// HookRunner struct.
|
||||||
type HookRunner struct {
|
type HookRunner struct {
|
||||||
// Hook to run and check
|
// Hook to run and check
|
||||||
hook Hook
|
hook Hook
|
||||||
|
|
@ -118,12 +119,12 @@ type logintf interface {
|
||||||
V(level int) logr.Logger
|
V(level int) logr.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send sends hash to hookdata
|
// Send sends hash to hookdata.
|
||||||
func (r *HookRunner) Send(hash string) {
|
func (r *HookRunner) Send(hash string) {
|
||||||
r.data.send(hash)
|
r.data.send(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run waits for trigger events from the channel, and run hook when triggered
|
// Run waits for trigger events from the channel, and run hook when triggered.
|
||||||
func (r *HookRunner) Run(ctx context.Context) {
|
func (r *HookRunner) Run(ctx context.Context) {
|
||||||
var lastHash string
|
var lastHash string
|
||||||
|
|
||||||
|
|
@ -171,7 +172,7 @@ func (r *HookRunner) sendOneTimeResultAndTerminate(completedSuccessfully bool) {
|
||||||
// WaitForCompletion waits for HookRunner to send completion message to
|
// WaitForCompletion waits for HookRunner to send completion message to
|
||||||
// calling thread and returns either true if HookRunner executed successfully
|
// calling thread and returns either true if HookRunner executed successfully
|
||||||
// and some error otherwise.
|
// and some error otherwise.
|
||||||
// Assumes that r.oneTimeResult is not nil, but if it is, returns an error
|
// Assumes that r.oneTimeResult is not nil, but if it is, returns an error.
|
||||||
func (r *HookRunner) WaitForCompletion() error {
|
func (r *HookRunner) WaitForCompletion() error {
|
||||||
// Make sure function should be called
|
// Make sure function should be called
|
||||||
if r.oneTimeResult == nil {
|
if r.oneTimeResult == nil {
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ func TestHookData(t *testing.T) {
|
||||||
t.Run("last update wins when channel buffer is full", func(t *testing.T) {
|
t.Run("last update wins when channel buffer is full", func(t *testing.T) {
|
||||||
hd := NewHookData()
|
hd := NewHookData()
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
for i := range 10 {
|
||||||
h := fmt.Sprintf("111111111111111111111111111111111111111%d", i)
|
h := fmt.Sprintf("111111111111111111111111111111111111111%d", i)
|
||||||
hd.send(h)
|
hd.send(h)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WebHook structure, implements Hook
|
// Webhook implements Hook for HTTP requests.
|
||||||
type Webhook struct {
|
type Webhook struct {
|
||||||
// Url for the http/s request
|
// Url for the http/s request
|
||||||
url string
|
url string
|
||||||
|
|
@ -39,7 +39,7 @@ type Webhook struct {
|
||||||
log logintf
|
log logintf
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebhook returns a new WebHook
|
// NewWebhook returns a new WebHook.
|
||||||
func NewWebhook(url, method string, success int, timeout time.Duration, log logintf) *Webhook {
|
func NewWebhook(url, method string, success int, timeout time.Duration, log logintf) *Webhook {
|
||||||
return &Webhook{
|
return &Webhook{
|
||||||
url: url,
|
url: url,
|
||||||
|
|
@ -50,12 +50,12 @@ func NewWebhook(url, method string, success int, timeout time.Duration, log logi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name describes hook, implements Hook.Name
|
// Name describes hook, implements Hook.Name.
|
||||||
func (w *Webhook) Name() string {
|
func (w *Webhook) Name() string {
|
||||||
return "webhook"
|
return "webhook"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do calls webhook.url, implements Hook.Do
|
// Do calls webhook.url, implements Hook.Do.
|
||||||
func (w *Webhook) Do(ctx context.Context, hash string) error {
|
func (w *Webhook) Do(ctx context.Context, hash string) error {
|
||||||
req, err := http.NewRequest(w.method, w.url, nil)
|
req, err := http.NewRequest(w.method, w.url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package logging provides a logging interface.
|
||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package pid1 provides a simple way to convert the current process into an
|
||||||
|
// init-like process. This is useful for containerized applications that need
|
||||||
|
// to manage child processes.
|
||||||
package pid1
|
package pid1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -53,6 +56,7 @@ func runInit(firstborn int) (int, error) {
|
||||||
for sig := range sigs {
|
for sig := range sigs {
|
||||||
if sig != syscall.SIGCHLD {
|
if sig != syscall.SIGCHLD {
|
||||||
// Pass it on to the real process.
|
// Pass it on to the real process.
|
||||||
|
//nolint:forcetypeassert
|
||||||
if err := syscall.Kill(firstborn, sig.(syscall.Signal)); err != nil {
|
if err := syscall.Kill(firstborn, sig.(syscall.Signal)); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,14 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
// In case we come up as pid 1, act as init.
|
// In case we come up as pid 1, act as init.
|
||||||
if os.Getpid() == 1 {
|
if os.Getpid() == 1 {
|
||||||
fmt.Printf("detected pid 1, running as init\n")
|
fmt.Fprintf(os.Stdout, "detected pid 1, running as init\n")
|
||||||
code, err := pid1.ReRun()
|
code, err := pid1.ReRun()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
os.Exit(code)
|
os.Exit(code)
|
||||||
}
|
}
|
||||||
fmt.Printf("unhandled pid1 error: %v\n", err)
|
fmt.Fprintf(os.Stdout, "unhandled pid1 error: %v\n", err)
|
||||||
os.Exit(127)
|
os.Exit(127)
|
||||||
}
|
}
|
||||||
fmt.Printf("main app\n")
|
fmt.Fprintf(os.Stdout, "main app\n")
|
||||||
os.Exit(42)
|
os.Exit(42)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Package version contains version information for the current binary.
|
||||||
package version
|
package version
|
||||||
|
|
||||||
|
// VERSION is the version of the binary. This can be set by the linker at
|
||||||
|
// build time.
|
||||||
var VERSION = "UNKNOWN"
|
var VERSION = "UNKNOWN"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue