From 597db75213d3ca1fa0705323eaa0d487f22f44c0 Mon Sep 17 00:00:00 2001 From: lpusok <7979773+lpusok@users.noreply.github.com> Date: Fri, 6 Oct 2023 17:20:58 +0200 Subject: [PATCH] Improve logs (#101) * Improve logs * dep update * Use v2 ruby environment * Updated sample app --- bitrise.yml | 8 +- config.go | 24 - dependencies.go | 35 + go.mod | 24 +- go.sum | 151 ++-- main.go | 35 +- vendor/github.com/beevik/etree/.travis.yml | 14 - vendor/github.com/beevik/etree/CONTRIBUTORS | 2 + vendor/github.com/beevik/etree/LICENSE | 2 +- vendor/github.com/beevik/etree/README.md | 1 - .../github.com/beevik/etree/RELEASE_NOTES.md | 44 + vendor/github.com/beevik/etree/etree.go | 777 +++++++++++------- vendor/github.com/beevik/etree/helpers.go | 154 +++- vendor/github.com/beevik/etree/path.go | 140 ++-- .../bitrise-init/models/configbuilder.go | 25 +- .../bitrise-io/bitrise-init/models/models.go | 16 +- .../bitrise-io/bitrise-init/models/option.go | 3 + .../bitrise-init/models/workflowbuilder.go | 2 + .../bitrise-init/scanners/android/android.go | 304 ++++--- .../bitrise-init/scanners/android/const.go | 16 - .../bitrise-init/scanners/android/utility.go | 228 ++--- .../bitrise-init/steps/cachesteps.go | 63 ++ .../bitrise-io/bitrise-init/steps/const.go | 190 ++--- .../bitrise-io/bitrise-init/steps/steps.go | 142 +--- .../bitrise-init/utility/utility.go | 10 + .../bitrise-io/bitrise/exitcode/exitcode.go | 8 + .../bitrise-io/bitrise/models/models.go | 140 +++- .../bitrise/models/models_methods.go | 76 +- .../bitrise/models/step_run_status.go | 79 ++ .../bitrise/models/workflow_run_plan.go | 37 + .../command/rubycommand/rubycommand.go | 9 +- .../go-steputils/v2/ruby/environment.go | 4 +- .../bitrise-io/stepman/models/models.go | 21 +- .../stepman/models/models_methods.go | 5 + .../stepman/models/version_constraint.go | 4 - vendor/github.com/gofrs/uuid/README.md | 4 +- vendor/github.com/gofrs/uuid/codec.go | 244 +++--- vendor/github.com/gofrs/uuid/fuzz.go | 11 +- vendor/github.com/gofrs/uuid/generator.go | 136 ++- vendor/github.com/gofrs/uuid/sql.go | 35 +- vendor/github.com/gofrs/uuid/uuid.go | 103 ++- .../hashicorp/go-retryablehttp/CHANGELOG.md | 9 + .../hashicorp/go-retryablehttp/CODEOWNERS | 1 + .../hashicorp/go-retryablehttp/LICENSE | 2 + .../hashicorp/go-retryablehttp/README.md | 19 - .../hashicorp/go-retryablehttp/client.go | 27 +- .../go-retryablehttp/roundtripper.go | 3 + vendor/github.com/stretchr/objx/README.md | 8 +- vendor/github.com/stretchr/objx/Taskfile.yml | 3 - vendor/github.com/stretchr/objx/accessors.go | 24 +- .../github.com/stretchr/objx/conversions.go | 4 +- vendor/github.com/stretchr/objx/doc.go | 44 +- vendor/github.com/stretchr/objx/map.go | 9 +- vendor/modules.txt | 37 +- 54 files changed, 2146 insertions(+), 1370 deletions(-) delete mode 100644 vendor/github.com/beevik/etree/.travis.yml delete mode 100644 vendor/github.com/bitrise-io/bitrise-init/scanners/android/const.go create mode 100644 vendor/github.com/bitrise-io/bitrise-init/steps/cachesteps.go create mode 100644 vendor/github.com/bitrise-io/bitrise/exitcode/exitcode.go create mode 100644 vendor/github.com/bitrise-io/bitrise/models/step_run_status.go create mode 100644 vendor/github.com/bitrise-io/bitrise/models/workflow_run_plan.go create mode 100644 vendor/github.com/hashicorp/go-retryablehttp/CHANGELOG.md create mode 100644 vendor/github.com/hashicorp/go-retryablehttp/CODEOWNERS diff --git a/bitrise.yml b/bitrise.yml index 25e9b2f..b0cf237 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -51,6 +51,9 @@ workflows: - work_dir: ./ - verbose_log: "yes" - connection: apple_id + - flutter-installer: + inputs: + - flutter_version: 3.13.6 - manage-ios-code-signing: run_if: "true" inputs: @@ -58,11 +61,6 @@ workflows: - scheme: $XCODE_SCHEME - configuration: Release - distribution_method: development - - flutter-installer: - run_if: "true" - title: Install Flutter - inputs: - - installation_bundle_url: https://storage.googleapis.com/flutter_infra_release/releases/stable/macos/flutter_macos_2.2.3-stable.zip - path::./: title: Test building a Flutter project inputs: diff --git a/config.go b/config.go index 20ea603..a51d837 100644 --- a/config.go +++ b/config.go @@ -3,11 +3,9 @@ package main import ( "fmt" "net/http" - "os" "strings" "github.com/bitrise-io/go-steputils/v2/stepconf" - "github.com/bitrise-io/go-utils/v2/command" "github.com/bitrise-io/go-utils/v2/retryhttp" "github.com/bitrise-io/go-xcode/appleauth" "github.com/bitrise-io/go-xcode/devportalservice" @@ -76,8 +74,6 @@ func (f FastlaneRunner) ProcessConfig() (Config, error) { } config.WorkDir = workDir - f.checkForRbenv(workDir) - // Select and fetch Apple authenication source authConfig, err := f.selectAppleAuthSource(config, authSources, authInputs) if err != nil { @@ -180,26 +176,6 @@ func (f FastlaneRunner) getWorkDir(config Config) (string, error) { return workDir, nil } -func (f FastlaneRunner) checkForRbenv(workDir string) { - f.logger.Println() - f.logger.Infof("Checking rbenv version") - if _, err := f.cmdLocator.LookPath("rbenv"); err == nil { - - cmd := f.rbyFactory.Create("rbenv", []string{"versions"}, &command.Opts{ - Stderr: os.Stderr, - Stdout: os.Stdout, - Dir: workDir, - }) - - f.logger.Donef("$ %s", cmd.PrintableCommandArgs()) - if err := cmd.Run(); err != nil { - f.logger.Warnf(err.Error()) - } - } else { - f.logger.Warnf("rbenv not found: %s", err) - } -} - func (f FastlaneRunner) selectAppleAuthSource(config Config, authSources []appleauth.Source, authInputs appleauth.Inputs) (appleauth.Credentials, error) { f.logger.Println() f.logger.Infof("Reading Apple Developer Portal authentication data") diff --git a/dependencies.go b/dependencies.go index 4b92a19..ea2a057 100644 --- a/dependencies.go +++ b/dependencies.go @@ -4,6 +4,7 @@ import ( "os" "strings" + "github.com/bitrise-io/go-steputils/v2/ruby" "github.com/bitrise-io/go-utils/v2/command" ) @@ -104,6 +105,40 @@ func (f FastlaneRunner) InstallDependencies(opts EnsureDependenciesOpts) error { } func (f FastlaneRunner) reportRubyVersion(useBundler bool, bundlerVersion string, workDir string) { + if f.rubyEnvironment.RubyInstallType() == ruby.ASDFRuby { + f.logger.Println() + f.logger.Infof("Checking selected Ruby version") + + cmd := f.rbyFactory.Create("asdf", []string{"current", "ruby"}, &command.Opts{ + Stderr: os.Stderr, + Stdout: os.Stdout, + Dir: workDir, + }) + + f.logger.Donef("$ %s", cmd.PrintableCommandArgs()) + if err := cmd.Run(); err != nil { + f.logger.Warnf("Failed to print selected Ruby version: %s", err) + } + } else if f.rubyEnvironment.RubyInstallType() == ruby.RbenvRuby { + f.logger.Println() + f.logger.Infof("Checking selected Ruby version") + if _, err := f.cmdLocator.LookPath("rbenv"); err == nil { + + cmd := f.rbyFactory.Create("rbenv", []string{"versions"}, &command.Opts{ + Stderr: os.Stderr, + Stdout: os.Stdout, + Dir: workDir, + }) + + f.logger.Donef("$ %s", cmd.PrintableCommandArgs()) + if err := cmd.Run(); err != nil { + f.logger.Warnf(err.Error()) + } + } else { + f.logger.Warnf("rbenv not found: %s", err) + } + } + var versionCmd command.Command options := &command.Opts{ Dir: workDir, diff --git a/go.mod b/go.mod index b016990..ae89091 100644 --- a/go.mod +++ b/go.mod @@ -3,31 +3,31 @@ module github.com/bitrise-io/steps-fastlane go 1.20 require ( - github.com/bitrise-io/bitrise-init v0.0.0-20220504131857-f00a24c7c8ba - github.com/bitrise-io/go-android/v2 v2.0.0-alpha.3 - github.com/bitrise-io/go-steputils v1.0.5 - github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.17 + github.com/bitrise-io/bitrise-init v0.0.0-20230901074816-efe492d99277 + github.com/bitrise-io/go-android/v2 v2.0.0-alpha.5 + github.com/bitrise-io/go-steputils v1.0.6 + github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.20 github.com/bitrise-io/go-utils v1.0.9 - github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.16 + github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.19 github.com/bitrise-io/go-xcode v1.0.16 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/stretchr/testify v1.8.4 ) require ( - github.com/beevik/etree v1.1.0 // indirect - github.com/bitrise-io/bitrise v0.0.0-20220719135434-7f794d69d858 // indirect - github.com/bitrise-io/envman v0.0.0-20220512153504-166d59151b78 // indirect - github.com/bitrise-io/stepman v0.0.0-20220718172049-e5ae0a09c2f2 // indirect + github.com/beevik/etree v1.2.0 // indirect + github.com/bitrise-io/bitrise v0.0.0-20230920132712-a20cb0493953 // indirect + github.com/bitrise-io/envman v0.0.0-20230802102824-1300c57d49c4 // indirect + github.com/bitrise-io/stepman v0.0.0-20230728094915-939f0fe5c19a // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/gofrs/uuid v4.3.1+incompatible // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/objx v0.5.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 7376b7c..a8d239c 100644 --- a/go.sum +++ b/go.sum @@ -1,62 +1,39 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= -github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= -github.com/bitrise-io/bitrise v0.0.0-20210519130014-380842fb41c1/go.mod h1:Jqf2PLwOKL1bYdbQIhVkNd55YyYKJBXyY0EtlRg5uw4= -github.com/bitrise-io/bitrise v0.0.0-20220719135434-7f794d69d858 h1:07+it7fY4jvBF7VW8Wxkfvba1KvYo7qhJPDtISz72To= -github.com/bitrise-io/bitrise v0.0.0-20220719135434-7f794d69d858/go.mod h1:tg665QKdaTciGYlv0TwVJW0GGqx4vS2/jAE8sahPRnY= -github.com/bitrise-io/bitrise-init v0.0.0-20220504131857-f00a24c7c8ba h1:uxnQ4A9MKeEAJFaHindNgHiMJTMgNN6MwzcfdU3+quU= -github.com/bitrise-io/bitrise-init v0.0.0-20220504131857-f00a24c7c8ba/go.mod h1:DN4SKPWki1kLKXtWWaKLqPOm8Yv9RQCoylkleqhApDc= -github.com/bitrise-io/colorstring v0.0.0-20180614154802-a8cd70115192/go.mod h1:CIHVcxZUvsG99XUJV6JlR7okNsMMGY81jMvPC20W+O0= -github.com/bitrise-io/envman v0.0.0-20200512105748-919e33f391ee/go.mod h1:m8pTp1o3Sw9uzDxb1WRm5IBRnMau2iOvPMSnRCAhQNI= -github.com/bitrise-io/envman v0.0.0-20210517135508-b2b4fe89eac5/go.mod h1:m8pTp1o3Sw9uzDxb1WRm5IBRnMau2iOvPMSnRCAhQNI= -github.com/bitrise-io/envman v0.0.0-20211026063720-03283f9c3f32/go.mod h1:L4WQyg88d87Z4dxNwrYEa0Cwd9/W0gSfXsibw30r8Vw= -github.com/bitrise-io/envman v0.0.0-20220401145857-d11e00a5dc55/go.mod h1:L4WQyg88d87Z4dxNwrYEa0Cwd9/W0gSfXsibw30r8Vw= -github.com/bitrise-io/envman v0.0.0-20220512153504-166d59151b78 h1:l+gCaGlS1yWYX9ualuzu0jlD3WZsJjqvMSE9KCynK5Q= -github.com/bitrise-io/envman v0.0.0-20220512153504-166d59151b78/go.mod h1:L4WQyg88d87Z4dxNwrYEa0Cwd9/W0gSfXsibw30r8Vw= -github.com/bitrise-io/go-android/v2 v2.0.0-alpha.3 h1:tCKogs4CmxEuiR2k330SFkiqQ9qX6Qz4viVGTMAGMPk= -github.com/bitrise-io/go-android/v2 v2.0.0-alpha.3/go.mod h1:pkrTuGB9KAgVTWsMJ8UjqKjSInaNcdp8En9Fxqg2krc= -github.com/bitrise-io/go-plist v0.0.0-20210301100253-4b1a112ccd10/go.mod h1:pARutiL3kEuRLV3JvswidvfCj+9Y3qMZtji2BDqLFsA= -github.com/bitrise-io/go-steputils v1.0.1/go.mod h1:YIUaQnIAyK4pCvQG0hYHVkSzKNT9uL2FWmkFNW4mfNI= +github.com/beevik/etree v1.2.0 h1:l7WETslUG/T+xOPs47dtd6jov2Ii/8/OjCldk5fYfQw= +github.com/beevik/etree v1.2.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc= +github.com/bitrise-io/bitrise v0.0.0-20230920132712-a20cb0493953 h1:rS8DshM/KP+n9wo//IZfy4pQHnLmpE3Z1rF1ajOo6eM= +github.com/bitrise-io/bitrise v0.0.0-20230920132712-a20cb0493953/go.mod h1:iFBfnKPLU0FAu4WRQacW46RCnmHxNw4pCCZ6br7DcIk= +github.com/bitrise-io/bitrise-init v0.0.0-20230901074816-efe492d99277 h1:9M6hXlQT3JlOhkX+voXPjh2v6XO0/RoxpUK47DWKmRI= +github.com/bitrise-io/bitrise-init v0.0.0-20230901074816-efe492d99277/go.mod h1:vNnQvJCk6BHH1AvaAqWTFdue9AiEeQ0uwODl8p1M/uE= +github.com/bitrise-io/envman v0.0.0-20230802102824-1300c57d49c4 h1:idT9p2ISMoW5SOz2ow3jWzxVNc4DkNreLeoTk8BGPHg= +github.com/bitrise-io/envman v0.0.0-20230802102824-1300c57d49c4/go.mod h1:eZDEXpkF4BguvTERmhij3Vwf7Y2qvnJBBW/61hQRip4= +github.com/bitrise-io/go-android/v2 v2.0.0-alpha.5 h1:iQ6ZEOzsetZXGyUeiYqdtZH7N5xWdzJCaIudsjgmyAQ= +github.com/bitrise-io/go-android/v2 v2.0.0-alpha.5/go.mod h1:Pln+erEcilflYfDmPloEKrziXD/Ba336xZZTe78ojCY= +github.com/bitrise-io/go-pkcs12 v0.0.0-20230913085202-b40653eb06c7/go.mod h1:fly5xmzjteedkhq4NJiEFbtC6KjvFdNeFxaTw2yF//k= github.com/bitrise-io/go-steputils v1.0.2/go.mod h1:YIUaQnIAyK4pCvQG0hYHVkSzKNT9uL2FWmkFNW4mfNI= -github.com/bitrise-io/go-steputils v1.0.5 h1:OBH7CPXeqIWFWJw6BOUMQnUb8guspwKr2RhYBhM9tfc= -github.com/bitrise-io/go-steputils v1.0.5/go.mod h1:YIUaQnIAyK4pCvQG0hYHVkSzKNT9uL2FWmkFNW4mfNI= -github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.17 h1:npcWC9jimYaJYlYBrPXxschwRAh6elJX01/1lEJ7mD8= -github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.17/go.mod h1:/ueNOKnsjcUrlt8Ck75WRNspL7E6nAAylvl9oGJtYio= -github.com/bitrise-io/go-utils v0.0.0-20200224122728-e212188d99b4/go.mod h1:tTEsKvbz1LbzuN/KpVFHXnLtcAPdEgIdM41s0lL407s= -github.com/bitrise-io/go-utils v0.0.0-20210505091801-98b7dc39ee61/go.mod h1:nhdaDQFvaMny1CugVV6KjK92/q97ENo0RuKSW5I4fbA= -github.com/bitrise-io/go-utils v0.0.0-20210505121718-07411d72e36e/go.mod h1:nhdaDQFvaMny1CugVV6KjK92/q97ENo0RuKSW5I4fbA= +github.com/bitrise-io/go-steputils v1.0.6 h1:eBRL70DWwEd7DWYGd5Ds7OSIY5HElzhoDOI6UuITKQg= +github.com/bitrise-io/go-steputils v1.0.6/go.mod h1:YIUaQnIAyK4pCvQG0hYHVkSzKNT9uL2FWmkFNW4mfNI= +github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.20 h1:ac+HUrl4H+2qM/0FmP6mOJQvoxSPpO68er3tKNJoM6E= +github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.20/go.mod h1:YeLAqkNuns7tiZNAlGJ8kOWvSEZy3SOKAQCv2CeWk5A= github.com/bitrise-io/go-utils v1.0.1/go.mod h1:ZY1DI+fEpZuFpO9szgDeICM4QbqoWVt0RSY3tRI1heY= github.com/bitrise-io/go-utils v1.0.2/go.mod h1:ZY1DI+fEpZuFpO9szgDeICM4QbqoWVt0RSY3tRI1heY= github.com/bitrise-io/go-utils v1.0.9 h1:wy7FewUpseNSTZr41BbGH0csfFqzptFt4zy2pOAEOg0= github.com/bitrise-io/go-utils v1.0.9/go.mod h1:ZY1DI+fEpZuFpO9szgDeICM4QbqoWVt0RSY3tRI1heY= -github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.6/go.mod h1:mysJdafur1ytXda0TeRsV+GxYCJFDU0QcCmYBgQf2Fc= github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.7/go.mod h1:6i0Gt0JRIbXpsrFDJT1YWghFfdN8qF26/fnpc/6d/88= -github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.16 h1:y+Yo0d8pYIjZiKhQuPM/Z5FY9/mu+wrWkyQlch8f9Po= -github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.16/go.mod h1:Laih4ji980SQkRgdnMCH0g4u2GZI/5nnbqmYT9UfKFQ= -github.com/bitrise-io/go-xcode v1.0.6/go.mod h1:Y0Wu2dXm0MilJ/4D3+gPHaNMlUcP+1DjIPoLPykq7wY= +github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.19 h1:55as5Iv0N4btuRP3YwRzN+BCMtKO210MnJ8mpxmeI7o= +github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.19/go.mod h1:Laih4ji980SQkRgdnMCH0g4u2GZI/5nnbqmYT9UfKFQ= github.com/bitrise-io/go-xcode v1.0.16 h1:G1IItfD2dvPNm7MLIWXFQHNPcafMVnw83M1lqCUH5L4= github.com/bitrise-io/go-xcode v1.0.16/go.mod h1:9OwsvrhZ4A2JxHVoEY7CPcABAKA+OE7FQqFfBfvbFuY= -github.com/bitrise-io/goinp v0.0.0-20210504152833-8559b0680ab1/go.mod h1:iRbd8zAXLeNy+0gic0eqNCxXvDGe8ZEY/uYX2CCeAoo= -github.com/bitrise-io/goinp v0.0.0-20211005113137-305e91b481f4/go.mod h1:iRbd8zAXLeNy+0gic0eqNCxXvDGe8ZEY/uYX2CCeAoo= -github.com/bitrise-io/gows v0.0.0-20210505125306-dd92ff463938/go.mod h1:3Cp9ceJ8wHl1Av6oEE2ff1iWaYLliQuD+oaNdyM0NWQ= -github.com/bitrise-io/gows v0.0.0-20211005113107-14f65e686b88/go.mod h1:3Cp9ceJ8wHl1Av6oEE2ff1iWaYLliQuD+oaNdyM0NWQ= -github.com/bitrise-io/pkcs12 v0.0.0-20211108084543-e52728e011c8/go.mod h1:UiXKNs0essbC14a2TvGlnUKo9isP9m4guPrp8KJHJpU= -github.com/bitrise-io/stepman v0.0.0-20210505110307-5c2296bcc558/go.mod h1:WLh58JYBgbD1Z/yyw1AkFz/90F6oBL0HS/luBpUW9dI= -github.com/bitrise-io/stepman v0.0.0-20210517135458-203f7a48d37a/go.mod h1:WLh58JYBgbD1Z/yyw1AkFz/90F6oBL0HS/luBpUW9dI= -github.com/bitrise-io/stepman v0.0.0-20220718172049-e5ae0a09c2f2 h1:JOiFJlKNYKoK6a7d7GaSqOklBvQAogUvqZF8xvmGw90= -github.com/bitrise-io/stepman v0.0.0-20220718172049-e5ae0a09c2f2/go.mod h1:25vk5IaQiOpXLMcjyJjY6RmZe6JEOqMe8TJoTvKgyuw= +github.com/bitrise-io/stepman v0.0.0-20230728094915-939f0fe5c19a h1:XM2PrNSUjpI4pIOZ1TcZdD4kh7KYN2D+yC6WYy22hoo= +github.com/bitrise-io/stepman v0.0.0-20230728094915-939f0fe5c19a/go.mod h1:Z46oQnRMHlbuiV0mCJBigT2bWO5j3TPQncKaL3jCwsk= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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= -github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= -github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= @@ -64,28 +41,17 @@ github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/S github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= -github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lwithers/minijks v1.1.0/go.mod h1:ypxkiQq/TirsT5/9wiF6lmNjYRabt2pm1XqKeaGnOj4= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -93,75 +59,74 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= +github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ= -github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgwk/qCfE= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200220224806-8a925fa4c0df/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/viktorbenei/cobra.v0 v0.0.0-20160704194906-5513220bc3d9/go.mod h1:ES58JZUprnB7l7btSIgwT2KtWLFz7nleq84TF6wsCjg= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 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.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= diff --git a/main.go b/main.go index 26fa1cd..8f764a8 100644 --- a/main.go +++ b/main.go @@ -65,21 +65,24 @@ func createStep(logger log.Logger) FastlaneRunner { logger.Warnf("%s", err) } + rubyEnv := ruby.NewEnvironment(rbyFactory, cmdLocator, logger) + pathModifier := pathutil.NewPathModifier() tracker := newStepTracker(envRepository, logger) - return NewFastlaneRunner(inputParser, logger, cmdLocator, cmdFactory, rbyFactory, pathModifier, tracker) + return NewFastlaneRunner(inputParser, logger, cmdLocator, cmdFactory, rbyFactory, rubyEnv, pathModifier, tracker) } // FastlaneRunner ... type FastlaneRunner struct { - inputParser stepconf.InputParser - logger log.Logger - cmdFactory command.Factory - cmdLocator env.CommandLocator - rbyFactory ruby.CommandFactory - pathModifier pathutil.PathModifier - tracker stepTracker + inputParser stepconf.InputParser + logger log.Logger + cmdFactory command.Factory + cmdLocator env.CommandLocator + rbyFactory ruby.CommandFactory + rubyEnvironment ruby.Environment + pathModifier pathutil.PathModifier + tracker stepTracker } // NewFastlaneRunner ... @@ -89,17 +92,19 @@ func NewFastlaneRunner( commandLocator env.CommandLocator, cmdFactory command.Factory, rbyFactory ruby.CommandFactory, + rubyEnvironment ruby.Environment, pathModifier pathutil.PathModifier, tracker stepTracker, ) FastlaneRunner { return FastlaneRunner{ - inputParser: stepInputParser, - logger: logger, - cmdLocator: commandLocator, - cmdFactory: cmdFactory, - rbyFactory: rbyFactory, - pathModifier: pathModifier, - tracker: tracker, + inputParser: stepInputParser, + logger: logger, + cmdLocator: commandLocator, + cmdFactory: cmdFactory, + rbyFactory: rbyFactory, + rubyEnvironment: rubyEnvironment, + pathModifier: pathModifier, + tracker: tracker, } } diff --git a/vendor/github.com/beevik/etree/.travis.yml b/vendor/github.com/beevik/etree/.travis.yml deleted file mode 100644 index f4cb25d..0000000 --- a/vendor/github.com/beevik/etree/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: go -sudo: false - -go: - - 1.11.x - - tip - -matrix: - allow_failures: - - go: tip - -script: - - go vet ./... - - go test -v ./... diff --git a/vendor/github.com/beevik/etree/CONTRIBUTORS b/vendor/github.com/beevik/etree/CONTRIBUTORS index 03211a8..da47407 100644 --- a/vendor/github.com/beevik/etree/CONTRIBUTORS +++ b/vendor/github.com/beevik/etree/CONTRIBUTORS @@ -8,3 +8,5 @@ Nicolas Piganeau (npiganeau) Chris Brown (ccbrown) Earncef Sequeira (earncef) Gabriel de Labachelerie (wuzuf) +Martin Dosch (mdosch) +Hugo Wetterberg (hugowetterberg) diff --git a/vendor/github.com/beevik/etree/LICENSE b/vendor/github.com/beevik/etree/LICENSE index 26f1f77..ef7b286 100644 --- a/vendor/github.com/beevik/etree/LICENSE +++ b/vendor/github.com/beevik/etree/LICENSE @@ -1,4 +1,4 @@ -Copyright 2015-2019 Brett Vickers. All rights reserved. +Copyright 2015-2023 Brett Vickers. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions diff --git a/vendor/github.com/beevik/etree/README.md b/vendor/github.com/beevik/etree/README.md index 08ec26b..62f0bab 100644 --- a/vendor/github.com/beevik/etree/README.md +++ b/vendor/github.com/beevik/etree/README.md @@ -1,4 +1,3 @@ -[![Build Status](https://travis-ci.org/beevik/etree.svg?branch=master)](https://travis-ci.org/beevik/etree) [![GoDoc](https://godoc.org/github.com/beevik/etree?status.svg)](https://godoc.org/github.com/beevik/etree) etree diff --git a/vendor/github.com/beevik/etree/RELEASE_NOTES.md b/vendor/github.com/beevik/etree/RELEASE_NOTES.md index ee59d7a..4a2ce2a 100644 --- a/vendor/github.com/beevik/etree/RELEASE_NOTES.md +++ b/vendor/github.com/beevik/etree/RELEASE_NOTES.md @@ -1,3 +1,47 @@ +Release v1.2.0 +============== + +**New Features** + +* Add the ability to write XML fragments using Token WriteTo functions. +* Add the ability to re-indent an XML element as though it were the root of + the document. +* Add a ReadSettings option to preserve CDATA blocks when reading and XML + document. + +Release v1.1.4 +============== + +**New Features** + +* Add the ability to preserve whitespace in leaf elements during indent. +* Add the ability to suppress a document-trailing newline during indent. +* Add choice of XML attribute quoting style (single-quote or double-quote). + +**Removed Features** + +* Removed the CDATA preservation change introduced in v1.1.3. It was + implemented in a way that broke the ability to process XML documents + encoded using non-UTF8 character sets. + +Release v1.1.3 +============== + +* XML reads now preserve CDATA sections instead of converting them to + standard character data. + +Release v1.1.2 +============== + +* Fixed a path parsing bug. +* The `Element.Text` function now handles comments embedded between + character data spans. + +Release v1.1.1 +============== + +* Updated go version in `go.mod` to 1.20 + Release v1.1.0 ============== diff --git a/vendor/github.com/beevik/etree/etree.go b/vendor/github.com/beevik/etree/etree.go index 9e24f90..83df8b2 100644 --- a/vendor/github.com/beevik/etree/etree.go +++ b/vendor/github.com/beevik/etree/etree.go @@ -18,14 +18,19 @@ import ( ) const ( - // NoIndent is used with Indent to disable all indenting. + // NoIndent is used with the IndentSettings record to remove all + // indenting. NoIndent = -1 ) // ErrXML is returned when XML parsing fails due to incorrect formatting. var ErrXML = errors.New("etree: invalid XML format") -// ReadSettings allow for changing the default behavior of the ReadFrom* +// cdataPrefix is used to detect CDATA text when ReadSettings.PreserveCData is +// true. +var cdataPrefix = []byte(" and '. Default: false. CanonicalAttrVal bool - // When outputting indented XML, use a carriage return and linefeed - // ("\r\n") as a new-line delimiter instead of just a linefeed ("\n"). - // This is useful on Windows-based systems. + // AttrSingleQuote causes attributes to use single quotes (attr='example') + // instead of double quotes (attr = "example") when set to true. Default: + // false. + AttrSingleQuote bool + + // UseCRLF causes the document's Indent* methods to use a carriage return + // followed by a linefeed ("\r\n") when outputting a newline. If false, + // only a linefeed is used ("\n"). Default: false. + // + // Deprecated: UseCRLF is deprecated. Use IndentSettings.UseCRLF instead. UseCRLF bool } @@ -78,25 +113,104 @@ func newWriteSettings() WriteSettings { CanonicalEndTags: false, CanonicalText: false, CanonicalAttrVal: false, + AttrSingleQuote: false, UseCRLF: false, } } -// A Token is an empty interface that represents an Element, CharData, -// Comment, Directive, or ProcInst. +// dup creates a duplicate of the WriteSettings object. +func (s *WriteSettings) dup() WriteSettings { + return *s +} + +// IndentSettings determine the behavior of the Document's Indent* methods. +type IndentSettings struct { + // Spaces indicates the number of spaces to insert for each level of + // indentation. Set to etree.NoIndent to remove all indentation. Ignored + // when UseTabs is true. Default: 4. + Spaces int + + // UseTabs causes tabs to be used instead of spaces when indenting. + // Default: false. + UseTabs bool + + // UseCRLF causes newlines to be written as a carriage return followed by + // a linefeed ("\r\n"). If false, only a linefeed character is output + // for a newline ("\n"). Default: false. + UseCRLF bool + + // PreserveLeafWhitespace causes indent methods to preserve whitespace + // within XML elements containing only non-CDATA character data. Default: + // false. + PreserveLeafWhitespace bool + + // SuppressTrailingWhitespace suppresses the generation of a trailing + // whitespace characters (such as newlines) at the end of the indented + // document. Default: false. + SuppressTrailingWhitespace bool +} + +// NewIndentSettings creates a default IndentSettings record. +func NewIndentSettings() *IndentSettings { + return &IndentSettings{ + Spaces: 4, + UseTabs: false, + UseCRLF: false, + PreserveLeafWhitespace: false, + SuppressTrailingWhitespace: false, + } +} + +type indentFunc func(depth int) string + +func getIndentFunc(s *IndentSettings) indentFunc { + if s.UseTabs { + if s.UseCRLF { + return func(depth int) string { return indentCRLF(depth, indentTabs) } + } else { + return func(depth int) string { return indentLF(depth, indentTabs) } + } + } else { + if s.Spaces < 0 { + return func(depth int) string { return "" } + } else if s.UseCRLF { + return func(depth int) string { return indentCRLF(depth*s.Spaces, indentSpaces) } + } else { + return func(depth int) string { return indentLF(depth*s.Spaces, indentSpaces) } + } + } +} + +// Writer is the interface that wraps the Write* methods called by each token +// type's WriteTo function. +type Writer interface { + io.StringWriter + io.ByteWriter + io.Writer +} + +// A Token is an interface type used to represent XML elements, character +// data, CDATA sections, XML comments, XML directives, and XML processing +// instructions. type Token interface { Parent() *Element Index() int + WriteTo(w Writer, s *WriteSettings) dup(parent *Element) Token setParent(parent *Element) setIndex(index int) - writeTo(w *bufio.Writer, s *WriteSettings) } -// A Document is a container holding a complete XML hierarchy. Its embedded -// element contains zero or more children, one of which is usually the root -// element. The embedded element may include other children such as -// processing instructions or BOM CharData tokens. +// A Document is a container holding a complete XML tree. +// +// A document has a single embedded element, which contains zero or more child +// tokens, one of which is usually the root element. The embedded element may +// include other children such as processing instruction tokens or character +// data tokens. The document's embedded element is never directly serialized; +// only its children are. +// +// A document also contains read and write settings, which influence the way +// the document is deserialized, serialized, and indented. type Document struct { Element ReadSettings ReadSettings @@ -112,7 +226,7 @@ type Element struct { index int // token index in parent's children } -// An Attr represents a key-value attribute of an XML element. +// An Attr represents a key-value attribute within an XML element. type Attr struct { Space, Key string // The attribute's namespace prefix and key Value string // The attribute value string @@ -123,17 +237,18 @@ type Attr struct { type charDataFlags uint8 const ( - // The CharData was created by an indent function as whitespace. + // The CharData contains only whitespace. whitespaceFlag charDataFlags = 1 << iota // The CharData contains a CDATA section. cdataFlag ) -// CharData can be used to represent character data or a CDATA section within -// an XML document. +// CharData may be used to represent simple text data or a CDATA section +// within an XML document. The Data property should never be modified +// directly; use the SetData method instead. type CharData struct { - Data string + Data string // the simple text or CDATA section content parent *Element index int flags charDataFlags @@ -141,22 +256,22 @@ type CharData struct { // A Comment represents an XML comment. type Comment struct { - Data string + Data string // the comment's text parent *Element index int } // A Directive represents an XML directive. type Directive struct { - Data string + Data string // the directive string parent *Element index int } // A ProcInst represents an XML processing instruction. type ProcInst struct { - Target string - Inst string + Target string // the processing instruction target + Inst string // the processing instruction value parent *Element index int } @@ -164,19 +279,32 @@ type ProcInst struct { // NewDocument creates an XML document without a root element. func NewDocument() *Document { return &Document{ - Element{Child: make([]Token, 0)}, - newReadSettings(), - newWriteSettings(), + Element: Element{Child: make([]Token, 0)}, + ReadSettings: newReadSettings(), + WriteSettings: newWriteSettings(), } } +// NewDocumentWithRoot creates an XML document and sets the element 'e' as its +// root element. If the element 'e' is already part of another document, it is +// first removed from its existing document. +func NewDocumentWithRoot(e *Element) *Document { + d := NewDocument() + d.SetRoot(e) + return d +} + // Copy returns a recursive, deep copy of the document. func (d *Document) Copy() *Document { - return &Document{*(d.dup(nil).(*Element)), d.ReadSettings, d.WriteSettings} + return &Document{ + Element: *(d.Element.dup(nil).(*Element)), + ReadSettings: d.ReadSettings.dup(), + WriteSettings: d.WriteSettings.dup(), + } } -// Root returns the root element of the document, or nil if there is no root -// element. +// Root returns the root element of the document. It returns nil if there is +// no root element. func (d *Document) Root() *Element { for _, t := range d.Child { if c, ok := t.(*Element); ok { @@ -186,25 +314,23 @@ func (d *Document) Root() *Element { return nil } -// SetRoot replaces the document's root element with e. If the document -// already has a root when this function is called, then the document's -// original root is unbound first. If the element e is bound to another -// document (or to another element within a document), then it is unbound -// first. +// SetRoot replaces the document's root element with the element 'e'. If the +// document already has a root element when this function is called, then the +// existing root element is unbound from the document. If the element 'e' is +// part of another document, then it is unbound from the other document. func (d *Document) SetRoot(e *Element) { if e.parent != nil { e.parent.RemoveChild(e) } - p := &d.Element - e.setParent(p) - // If there is already a root element, replace it. + p := &d.Element for i, t := range p.Child { if _, ok := t.(*Element); ok { t.setParent(nil) t.setIndex(-1) p.Child[i] = e + e.setParent(p) e.setIndex(i) return } @@ -214,15 +340,16 @@ func (d *Document) SetRoot(e *Element) { p.addChild(e) } -// ReadFrom reads XML from the reader r into the document d. It returns the -// number of bytes read and any error encountered. +// ReadFrom reads XML from the reader 'r' into this document. The function +// returns the number of bytes read and any error encountered. func (d *Document) ReadFrom(r io.Reader) (n int64, err error) { return d.Element.readFrom(r, d.ReadSettings) } -// ReadFromFile reads XML from the string s into the document d. -func (d *Document) ReadFromFile(filename string) error { - f, err := os.Open(filename) +// ReadFromFile reads XML from a local file at path 'filepath' into this +// document. +func (d *Document) ReadFromFile(filepath string) error { + f, err := os.Open(filepath) if err != nil { return err } @@ -231,34 +358,33 @@ func (d *Document) ReadFromFile(filename string) error { return err } -// ReadFromBytes reads XML from the byte slice b into the document d. +// ReadFromBytes reads XML from the byte slice 'b' into the this document. func (d *Document) ReadFromBytes(b []byte) error { _, err := d.ReadFrom(bytes.NewReader(b)) return err } -// ReadFromString reads XML from the string s into the document d. +// ReadFromString reads XML from the string 's' into this document. func (d *Document) ReadFromString(s string) error { _, err := d.ReadFrom(strings.NewReader(s)) return err } -// WriteTo serializes an XML document into the writer w. It -// returns the number of bytes written and any error encountered. +// WriteTo serializes the document out to the writer 'w'. The function returns +// the number of bytes written and any error encountered. func (d *Document) WriteTo(w io.Writer) (n int64, err error) { - cw := newCountWriter(w) - b := bufio.NewWriter(cw) + xw := newXmlWriter(w) + b := bufio.NewWriter(xw) for _, c := range d.Child { - c.writeTo(b, &d.WriteSettings) + c.WriteTo(b, &d.WriteSettings) } - err, n = b.Flush(), cw.bytes + err, n = b.Flush(), xw.bytes return } -// WriteToFile serializes an XML document into the file named -// filename. -func (d *Document) WriteToFile(filename string) error { - f, err := os.Create(filename) +// WriteToFile serializes the document out to the file at path 'filepath'. +func (d *Document) WriteToFile(filepath string) error { + f, err := os.Create(filepath) if err != nil { return err } @@ -267,8 +393,7 @@ func (d *Document) WriteToFile(filename string) error { return err } -// WriteToBytes serializes the XML document into a slice of -// bytes. +// WriteToBytes serializes this document into a slice of bytes. func (d *Document) WriteToBytes() (b []byte, err error) { var buf bytes.Buffer if _, err = d.WriteTo(&buf); err != nil { @@ -277,7 +402,7 @@ func (d *Document) WriteToBytes() (b []byte, err error) { return buf.Bytes(), nil } -// WriteToString serializes the XML document into a string. +// WriteToString serializes this document into a string. func (d *Document) WriteToString() (s string, err error) { var b []byte if b, err = d.WriteToBytes(); err != nil { @@ -286,41 +411,54 @@ func (d *Document) WriteToString() (s string, err error) { return string(b), nil } -type indentFunc func(depth int) string - // Indent modifies the document's element tree by inserting character data -// tokens containing newlines and indentation. The amount of indentation per -// depth level is given as spaces. Pass etree.NoIndent for spaces if you want -// no indentation at all. +// tokens containing newlines and spaces for indentation. The amount of +// indentation per depth level is given by the 'spaces' parameter. Other than +// the number of spaces, default IndentSettings are used. func (d *Document) Indent(spaces int) { - var indent indentFunc - switch { - case spaces < 0: - indent = func(depth int) string { return "" } - case d.WriteSettings.UseCRLF == true: - indent = func(depth int) string { return indentCRLF(depth*spaces, indentSpaces) } - default: - indent = func(depth int) string { return indentLF(depth*spaces, indentSpaces) } - } - d.Element.indent(0, indent) + s := NewIndentSettings() + s.Spaces = spaces + d.IndentWithSettings(s) } // IndentTabs modifies the document's element tree by inserting CharData -// tokens containing newlines and tabs for indentation. One tab is used per -// indentation level. +// tokens containing newlines and tabs for indentation. One tab is used per +// indentation level. Other than the use of tabs, default IndentSettings +// are used. func (d *Document) IndentTabs() { - var indent indentFunc - switch d.WriteSettings.UseCRLF { - case true: - indent = func(depth int) string { return indentCRLF(depth, indentTabs) } - default: - indent = func(depth int) string { return indentLF(depth, indentTabs) } + s := NewIndentSettings() + s.UseTabs = true + d.IndentWithSettings(s) +} + +// IndentWithSettings modifies the document's element tree by inserting +// character data tokens containing newlines and indentation. The behavior +// of the indentation algorithm is configured by the indent settings. +func (d *Document) IndentWithSettings(s *IndentSettings) { + // WriteSettings.UseCRLF is deprecated. Until removed from the package, it + // overrides IndentSettings.UseCRLF when true. + if d.WriteSettings.UseCRLF { + s.UseCRLF = true } - d.Element.indent(0, indent) + + d.Element.indent(0, getIndentFunc(s), s) + + if s.SuppressTrailingWhitespace { + d.Element.stripTrailingWhitespace() + } +} + +// Unindent modifies the document's element tree by removing character data +// tokens containing only whitespace. Other than the removal of indentation, +// default IndentSettings are used. +func (d *Document) Unindent() { + s := NewIndentSettings() + s.Spaces = NoIndent + d.IndentWithSettings(s) } -// NewElement creates an unparented element with the specified tag. The tag -// may be prefixed by a namespace prefix and a colon. +// NewElement creates an unparented element with the specified tag (i.e., +// name). The tag may include a namespace prefix followed by a colon. func NewElement(tag string) *Element { space, stag := spaceDecompose(tag) return newElement(space, stag, nil) @@ -345,7 +483,8 @@ func newElement(space, tag string, parent *Element) *Element { // Copy creates a recursive, deep copy of the element and all its attributes // and children. The returned element has no parent but can be parented to a -// another element using AddElement, or to a document using SetRoot. +// another element using AddChild, or added to a document with SetRoot or +// NewDocumentWithRoot. func (e *Element) Copy() *Element { return e.dup(nil).(*Element) } @@ -400,16 +539,6 @@ func (e *Element) findDefaultNamespaceURI() string { return e.parent.findDefaultNamespaceURI() } -// hasText returns true if the element has character data immediately -// folllowing the element's opening tag. -func (e *Element) hasText() bool { - if len(e.Child) == 0 { - return false - } - _, ok := e.Child[0].(*CharData) - return ok -} - // namespacePrefix returns the namespace prefix associated with the element. func (e *Element) namespacePrefix() string { return e.Space @@ -433,8 +562,10 @@ func (e *Element) Text() string { if text == "" { text = cd.Data } else { - text = text + cd.Data + text += cd.Data } + } else if _, ok := ch.(*Comment); ok { + // ignore } else { break } @@ -470,7 +601,7 @@ func (e *Element) Tail() string { if text == "" { text = cd.Data } else { - text = text + cd.Data + text += cd.Data } } else { break @@ -548,30 +679,30 @@ func (e *Element) findTermCharDataIndex(start int) int { return len(e.Child) } -// CreateElement creates an element with the specified tag and adds it as the -// last child element of the element e. The tag may be prefixed by a namespace -// prefix and a colon. +// CreateElement creates a new element with the specified tag (i.e., name) and +// adds it as the last child token of this element. The tag may include a +// prefix followed by a colon. func (e *Element) CreateElement(tag string) *Element { space, stag := spaceDecompose(tag) return newElement(space, stag, e) } -// AddChild adds the token t as the last child of element e. If token t was -// already the child of another element, it is first removed from its current +// AddChild adds the token 't' as the last child of the element. If token 't' +// was already the child of another element, it is first removed from its // parent element. func (e *Element) AddChild(t Token) { if t.Parent() != nil { t.Parent().RemoveChild(t) } - - t.setParent(e) e.addChild(t) } -// InsertChild inserts the token t before e's existing child token ex. If ex -// is nil or ex is not a child of e, then t is added to the end of e's child -// token list. If token t was already the child of another element, it is -// first removed from its current parent element. +// InsertChild inserts the token 't' into this element's list of children just +// before the element's existing child token 'ex'. If the existing element +// 'ex' does not appear in this element's list of child tokens, then 't' is +// added to the end of this element's list of child tokens. If token 't' is +// already the child of another element, it is first removed from the other +// element's list of child tokens. // // Deprecated: InsertChild is deprecated. Use InsertChildAt instead. func (e *Element) InsertChild(ex Token, t Token) { @@ -596,10 +727,10 @@ func (e *Element) InsertChild(ex Token, t Token) { } } -// InsertChildAt inserts the token t into the element e's list of child tokens -// just before the requested index. If the index is greater than or equal to -// the length of the list of child tokens, the token t is added to the end of -// the list. +// InsertChildAt inserts the token 't' into this element's list of child +// tokens just before the requested 'index'. If the index is greater than or +// equal to the length of the list of child tokens, then the token 't' is +// added to the end of the list of child tokens. func (e *Element) InsertChildAt(index int, t Token) { if index >= len(e.Child) { e.AddChild(t) @@ -624,9 +755,9 @@ func (e *Element) InsertChildAt(index int, t Token) { } } -// RemoveChild attempts to remove the token t from element e's list of -// children. If the token t is a child of e, then it is returned. Otherwise, -// nil is returned. +// RemoveChild attempts to remove the token 't' from this element's list of +// child tokens. If the token 't' was a child of this element, then it is +// removed and returned. Otherwise, nil is returned. func (e *Element) RemoveChild(t Token) Token { if t.Parent() != e { return nil @@ -634,9 +765,9 @@ func (e *Element) RemoveChild(t Token) Token { return e.RemoveChildAt(t.Index()) } -// RemoveChildAt removes the index-th child token from the element e. The -// removed child token is returned. If the index is out of bounds, no child is -// removed and nil is returned. +// RemoveChildAt removes the child token appearing in slot 'index' of this +// element's list of child tokens. The removed child token is then returned. +// If the index is out of bounds, no child is removed and nil is returned. func (e *Element) RemoveChildAt(index int) Token { if index >= len(e.Child) { return nil @@ -652,25 +783,42 @@ func (e *Element) RemoveChildAt(index int) Token { return t } -// ReadFrom reads XML from the reader r and stores the result as a new child -// of element e. +// ReadFrom reads XML from the reader 'ri' and stores the result as a new +// child of this element. func (e *Element) readFrom(ri io.Reader, settings ReadSettings) (n int64, err error) { - r := newCountReader(ri) + var r xmlReader + var pr *xmlPeekReader + if settings.PreserveCData { + pr = newXmlPeekReader(ri) + r = pr + } else { + r = newXmlSimpleReader(ri) + } + dec := xml.NewDecoder(r) dec.CharsetReader = settings.CharsetReader dec.Strict = !settings.Permissive dec.Entity = settings.Entity + var stack stack stack.push(e) for { + if pr != nil { + pr.PeekPrepare(dec.InputOffset(), len(cdataPrefix)) + } + t, err := dec.RawToken() + switch { case err == io.EOF: - return r.bytes, nil + if len(stack.data) != 1 { + return r.Bytes(), ErrXML + } + return r.Bytes(), nil case err != nil: - return r.bytes, err + return r.Bytes(), err case stack.empty(): - return r.bytes, ErrXML + return r.Bytes(), ErrXML } top := stack.peek().(*Element) @@ -683,12 +831,24 @@ func (e *Element) readFrom(ri io.Reader, settings ReadSettings) (n int64, err er } stack.push(e) case xml.EndElement: + if top.Tag != t.Name.Local || top.Space != t.Name.Space { + return r.Bytes(), ErrXML + } stack.pop() case xml.CharData: data := string(t) var flags charDataFlags - if isWhitespace(data) { - flags = whitespaceFlag + if pr != nil { + peekBuf := pr.PeekFinalize() + if bytes.Equal(peekBuf, cdataPrefix) { + flags = cdataFlag + } else if isWhitespace(data) { + flags = whitespaceFlag + } + } else { + if isWhitespace(data) { + flags = whitespaceFlag + } } newCharData(data, flags, top) case xml.Comment: @@ -701,9 +861,10 @@ func (e *Element) readFrom(ri io.Reader, settings ReadSettings) (n int64, err er } } -// SelectAttr finds an element attribute matching the requested key and -// returns it if found. Returns nil if no matching attribute is found. The key -// may be prefixed by a namespace prefix and a colon. +// SelectAttr finds an element attribute matching the requested 'key' and, if +// found, returns a pointer to the matching attribute. The function returns +// nil if no matching attribute is found. The key may include a namespace +// prefix followed by a colon. func (e *Element) SelectAttr(key string) *Attr { space, skey := spaceDecompose(key) for i, a := range e.Attr { @@ -714,9 +875,10 @@ func (e *Element) SelectAttr(key string) *Attr { return nil } -// SelectAttrValue finds an element attribute matching the requested key and -// returns its value if found. The key may be prefixed by a namespace prefix -// and a colon. If the key is not found, the dflt value is returned instead. +// SelectAttrValue finds an element attribute matching the requested 'key' and +// returns its value if found. If no matching attribute is found, the function +// returns the 'dflt' value instead. The key may include a namespace prefix +// followed by a colon. func (e *Element) SelectAttrValue(key, dflt string) string { space, skey := spaceDecompose(key) for _, a := range e.Attr { @@ -727,7 +889,7 @@ func (e *Element) SelectAttrValue(key, dflt string) string { return dflt } -// ChildElements returns all elements that are children of element e. +// ChildElements returns all elements that are children of this element. func (e *Element) ChildElements() []*Element { var elements []*Element for _, t := range e.Child { @@ -738,9 +900,9 @@ func (e *Element) ChildElements() []*Element { return elements } -// SelectElement returns the first child element with the given tag. The tag -// may be prefixed by a namespace prefix and a colon. Returns nil if no -// element with a matching tag was found. +// SelectElement returns the first child element with the given 'tag' (i.e., +// name). The function returns nil if no child element matching the tag is +// found. The tag may include a namespace prefix followed by a colon. func (e *Element) SelectElement(tag string) *Element { space, stag := spaceDecompose(tag) for _, t := range e.Child { @@ -751,8 +913,8 @@ func (e *Element) SelectElement(tag string) *Element { return nil } -// SelectElements returns a slice of all child elements with the given tag. -// The tag may be prefixed by a namespace prefix and a colon. +// SelectElements returns a slice of all child elements with the given 'tag' +// (i.e., name). The tag may include a namespace prefix followed by a colon. func (e *Element) SelectElements(tag string) []*Element { space, stag := spaceDecompose(tag) var elements []*Element @@ -764,39 +926,39 @@ func (e *Element) SelectElements(tag string) []*Element { return elements } -// FindElement returns the first element matched by the XPath-like path -// string. Returns nil if no element is found using the path. Panics if an -// invalid path string is supplied. +// FindElement returns the first element matched by the XPath-like 'path' +// string. The function returns nil if no child element is found using the +// path. It panics if an invalid path string is supplied. func (e *Element) FindElement(path string) *Element { return e.FindElementPath(MustCompilePath(path)) } -// FindElementPath returns the first element matched by the XPath-like path -// string. Returns nil if no element is found using the path. +// FindElementPath returns the first element matched by the 'path' object. The +// function returns nil if no element is found using the path. func (e *Element) FindElementPath(path Path) *Element { p := newPather() elements := p.traverse(e, path) - switch { - case len(elements) > 0: + if len(elements) > 0 { return elements[0] - default: - return nil } + return nil } -// FindElements returns a slice of elements matched by the XPath-like path -// string. Panics if an invalid path string is supplied. +// FindElements returns a slice of elements matched by the XPath-like 'path' +// string. The function returns nil if no child element is found using the +// path. It panics if an invalid path string is supplied. func (e *Element) FindElements(path string) []*Element { return e.FindElementsPath(MustCompilePath(path)) } -// FindElementsPath returns a slice of elements matched by the Path object. +// FindElementsPath returns a slice of elements matched by the 'path' object. func (e *Element) FindElementsPath(path Path) []*Element { p := newPather() return p.traverse(e, path) } -// GetPath returns the absolute path of the element. +// GetPath returns the absolute path of the element. The absolute path is the +// full path from the document's root. func (e *Element) GetPath() string { path := []string{} for seg := e; seg != nil; seg = seg.Parent() { @@ -813,9 +975,9 @@ func (e *Element) GetPath() string { return "/" + strings.Join(path, "/") } -// GetRelativePath returns the path of the element relative to the source +// GetRelativePath returns the path of this element relative to the 'source' // element. If the two elements are not part of the same element tree, then -// GetRelativePath returns the empty string. +// the function returns the empty string. func (e *Element) GetRelativePath(source *Element) string { var path []*Element @@ -884,10 +1046,20 @@ func (e *Element) GetRelativePath(source *Element) string { return strings.Join(parts, "/") } -// indent recursively inserts proper indentation between an -// XML element's child tokens. -func (e *Element) indent(depth int, indent indentFunc) { - e.stripIndent() +// IndentWithSettings modifies the element and its child tree by inserting +// character data tokens containing newlines and indentation. The behavior of +// the indentation algorithm is configured by the indent settings. Because +// this function indents the element as if it were at the root of a document, +// it is most useful when called just before writing the element as an XML +// fragment using WriteTo. +func (e *Element) IndentWithSettings(s *IndentSettings) { + e.indent(1, getIndentFunc(s), s) +} + +// indent recursively inserts proper indentation between an XML element's +// child tokens. +func (e *Element) indent(depth int, indent indentFunc, s *IndentSettings) { + e.stripIndent(s) n := len(e.Child) if n == 0 { return @@ -915,7 +1087,7 @@ func (e *Element) indent(depth int, indent indentFunc) { // Recursively process child elements. if ce, ok := c.(*Element); ok { - ce.indent(depth+1, indent) + ce.indent(depth+1, indent, s) } } @@ -931,7 +1103,7 @@ func (e *Element) indent(depth int, indent indentFunc) { } // stripIndent removes any previously inserted indentation. -func (e *Element) stripIndent() { +func (e *Element) stripIndent(s *IndentSettings) { // Count the number of non-indent child tokens n := len(e.Child) for _, c := range e.Child { @@ -942,6 +1114,9 @@ func (e *Element) stripIndent() { if n == len(e.Child) { return } + if n == 0 && len(e.Child) == 1 && s.PreserveLeafWhitespace { + return + } // Strip out indent CharData newChild := make([]Token, n) @@ -957,6 +1132,17 @@ func (e *Element) stripIndent() { e.Child = newChild } +// stripTrailingWhitespace removes any trailing whitespace CharData tokens +// from the element's children. +func (e *Element) stripTrailingWhitespace() { + for i := len(e.Child) - 1; i >= 0; i-- { + if cd, ok := e.Child[i].(*CharData); !ok || !cd.IsWhitespace() { + e.Child = e.Child[:i+1] + return + } + } +} + // dup duplicates the element. func (e *Element) dup(parent *Element) Token { ne := &Element{ @@ -970,47 +1156,35 @@ func (e *Element) dup(parent *Element) Token { for i, t := range e.Child { ne.Child[i] = t.dup(ne) } - for i, a := range e.Attr { - ne.Attr[i] = a - } + copy(ne.Attr, e.Attr) return ne } -// Parent returns the element token's parent element, or nil if it has no -// parent. +// Parent returns this element's parent element. It returns nil if this +// element has no parent. func (e *Element) Parent() *Element { return e.parent } // Index returns the index of this element within its parent element's -// list of child tokens. If this element has no parent element, the index -// is -1. +// list of child tokens. If this element has no parent, then the function +// returns -1. func (e *Element) Index() int { return e.index } -// setParent replaces the element token's parent. -func (e *Element) setParent(parent *Element) { - e.parent = parent -} - -// setIndex sets the element token's index within its parent's Child slice. -func (e *Element) setIndex(index int) { - e.index = index -} - -// writeTo serializes the element to the writer w. -func (e *Element) writeTo(w *bufio.Writer, s *WriteSettings) { +// WriteTo serializes the element to the writer w. +func (e *Element) WriteTo(w Writer, s *WriteSettings) { w.WriteByte('<') w.WriteString(e.FullTag()) for _, a := range e.Attr { w.WriteByte(' ') - a.writeTo(w, s) + a.WriteTo(w, s) } if len(e.Child) > 0 { - w.WriteString(">") + w.WriteByte('>') for _, c := range e.Child { - c.writeTo(w, s) + c.WriteTo(w, s) } w.Write([]byte{'<', '/'}) w.WriteString(e.FullTag()) @@ -1026,15 +1200,27 @@ func (e *Element) writeTo(w *bufio.Writer, s *WriteSettings) { } } +// setParent replaces this element token's parent. +func (e *Element) setParent(parent *Element) { + e.parent = parent +} + +// setIndex sets this element token's index within its parent's Child slice. +func (e *Element) setIndex(index int) { + e.index = index +} + // addChild adds a child token to the element e. func (e *Element) addChild(t Token) { + t.setParent(e) t.setIndex(len(e.Child)) e.Child = append(e.Child, t) } -// CreateAttr creates an attribute and adds it to element e. The key may be -// prefixed by a namespace prefix and a colon. If an attribute with the key -// already exists, its value is replaced. +// CreateAttr creates an attribute with the specified 'key' and 'value' and +// adds it to this element. If an attribute with same key already exists on +// this element, then its value is replaced. The key may include a namespace +// prefix followed by a colon. func (e *Element) CreateAttr(key, value string) *Attr { space, skey := spaceDecompose(key) return e.createAttr(space, skey, value, e) @@ -1058,10 +1244,10 @@ func (e *Element) createAttr(space, key, value string, parent *Element) *Attr { return &e.Attr[len(e.Attr)-1] } -// RemoveAttr removes and returns a copy of the first attribute of the element -// whose key matches the given key. The key may be prefixed by a namespace -// prefix and a colon. If a matching attribute does not exist, nil is -// returned. +// RemoveAttr removes the first attribute of this element whose key matches +// 'key'. It returns a copy of the removed attribute if a match is found. If +// no match is found, it returns nil. The key may include a namespace prefix +// followed by a colon. func (e *Element) RemoveAttr(key string) *Attr { space, skey := spaceDecompose(key) for i, a := range e.Attr { @@ -1078,7 +1264,7 @@ func (e *Element) RemoveAttr(key string) *Attr { return nil } -// SortAttrs sorts the element's attributes lexicographically by key. +// SortAttrs sorts this element's attributes lexicographically by key. func (e *Element) SortAttrs() { sort.Sort(byAttr(e.Attr)) } @@ -1101,7 +1287,7 @@ func (a byAttr) Less(i, j int) bool { return sp < 0 } -// FullKey returns the attribute a's complete key, including namespace prefix +// FullKey returns this attribute's complete key, including namespace prefix // if present. func (a *Attr) FullKey() string { if a.Space == "" { @@ -1110,22 +1296,29 @@ func (a *Attr) FullKey() string { return a.Space + ":" + a.Key } -// Element returns the element containing the attribute. +// Element returns a pointer to the element containing this attribute. func (a *Attr) Element() *Element { return a.element } -// NamespaceURI returns the XML namespace URI associated with the attribute. -// If the element is part of the XML default namespace, NamespaceURI returns -// the empty string. +// NamespaceURI returns the XML namespace URI associated with this attribute. +// The function returns the empty string if the attribute is unprefixed or +// if the attribute is part of the XML default namespace. func (a *Attr) NamespaceURI() string { - return a.element.NamespaceURI() + if a.Space == "" { + return "" + } + return a.element.findLocalNamespaceURI(a.Space) } -// writeTo serializes the attribute to the writer. -func (a *Attr) writeTo(w *bufio.Writer, s *WriteSettings) { +// WriteTo serializes the attribute to the writer. +func (a *Attr) WriteTo(w Writer, s *WriteSettings) { w.WriteString(a.FullKey()) - w.WriteString(`="`) + if s.AttrSingleQuote { + w.WriteString(`='`) + } else { + w.WriteString(`="`) + } var m escapeMode if s.CanonicalAttrVal { m = escapeCanonicalAttr @@ -1133,20 +1326,26 @@ func (a *Attr) writeTo(w *bufio.Writer, s *WriteSettings) { m = escapeNormal } escapeString(w, a.Value, m) - w.WriteByte('"') + if s.AttrSingleQuote { + w.WriteByte('\'') + } else { + w.WriteByte('"') + } } -// NewText creates a parentless CharData token containing character data. +// NewText creates an unparented CharData token containing simple text data. func NewText(text string) *CharData { return newCharData(text, 0, nil) } -// NewCData creates a parentless XML character CDATA section. +// NewCData creates an unparented XML character CDATA section with 'data' as +// its content. func NewCData(data string) *CharData { return newCharData(data, cdataFlag, nil) } -// NewCharData creates a parentless CharData token containing character data. +// NewCharData creates an unparented CharData token containing simple text +// data. // // Deprecated: NewCharData is deprecated. Instead, use NewText, which does the // same thing. @@ -1159,7 +1358,7 @@ func NewCharData(data string) *CharData { func newCharData(data string, flags charDataFlags, parent *Element) *CharData { c := &CharData{ Data: data, - parent: parent, + parent: nil, index: -1, flags: flags, } @@ -1169,75 +1368,67 @@ func newCharData(data string, flags charDataFlags, parent *Element) *CharData { return c } -// CreateText creates a CharData token containing character data and adds it -// as a child of element e. +// CreateText creates a CharData token containing simple text data and adds it +// to the end of this element's list of child tokens. func (e *Element) CreateText(text string) *CharData { return newCharData(text, 0, e) } -// CreateCData creates a CharData token containing a CDATA section and adds it -// as a child of element e. +// CreateCData creates a CharData token containing a CDATA section with 'data' +// as its content and adds it to the end of this element's list of child +// tokens. func (e *Element) CreateCData(data string) *CharData { return newCharData(data, cdataFlag, e) } -// CreateCharData creates a CharData token containing character data and adds -// it as a child of element e. +// CreateCharData creates a CharData token containing simple text data and +// adds it to the end of this element's list of child tokens. // // Deprecated: CreateCharData is deprecated. Instead, use CreateText, which // does the same thing. func (e *Element) CreateCharData(data string) *CharData { - return newCharData(data, 0, e) + return e.CreateText(data) } -// dup duplicates the character data. -func (c *CharData) dup(parent *Element) Token { - return &CharData{ - Data: c.Data, - flags: c.flags, - parent: parent, - index: c.index, +// SetData modifies the content of the CharData token. In the case of a +// CharData token containing simple text, the simple text is modified. In the +// case of a CharData token containing a CDATA section, the CDATA section's +// content is modified. +func (c *CharData) SetData(text string) { + c.Data = text + if isWhitespace(text) { + c.flags |= whitespaceFlag + } else { + c.flags &= ^whitespaceFlag } } -// IsCData returns true if the character data token is to be encoded as a -// CDATA section. +// IsCData returns true if this CharData token is contains a CDATA section. It +// returns false if the CharData token contains simple text. func (c *CharData) IsCData() bool { return (c.flags & cdataFlag) != 0 } -// IsWhitespace returns true if the character data token was created by one of -// the document Indent methods to contain only whitespace. +// IsWhitespace returns true if this CharData token contains only whitespace. func (c *CharData) IsWhitespace() bool { return (c.flags & whitespaceFlag) != 0 } -// Parent returns the character data token's parent element, or nil if it has -// no parent. +// Parent returns this CharData token's parent element, or nil if it has no +// parent. func (c *CharData) Parent() *Element { return c.parent } // Index returns the index of this CharData token within its parent element's -// list of child tokens. If this CharData token has no parent element, the -// index is -1. +// list of child tokens. If this CharData token has no parent, then the +// function returns -1. func (c *CharData) Index() int { return c.index } -// setParent replaces the character data token's parent. -func (c *CharData) setParent(parent *Element) { - c.parent = parent -} - -// setIndex sets the CharData token's index within its parent element's Child -// slice. -func (c *CharData) setIndex(index int) { - c.index = index -} - -// writeTo serializes character data to the writer. -func (c *CharData) writeTo(w *bufio.Writer, s *WriteSettings) { +// WriteTo serializes character data to the writer. +func (c *CharData) WriteTo(w Writer, s *WriteSettings) { if c.IsCData() { w.WriteString(`") +} + // setParent replaces the comment token's parent. func (c *Comment) setParent(parent *Element) { c.parent = parent @@ -1309,14 +1528,7 @@ func (c *Comment) setIndex(index int) { c.index = index } -// writeTo serialies the comment to the writer. -func (c *Comment) writeTo(w *bufio.Writer, s *WriteSettings) { - w.WriteString("") -} - -// NewDirective creates a parentless XML directive. +// NewDirective creates an unparented XML directive token. func NewDirective(data string) *Directive { return newDirective(data, nil) } @@ -1326,7 +1538,7 @@ func NewDirective(data string) *Directive { func newDirective(data string, parent *Element) *Directive { d := &Directive{ Data: data, - parent: parent, + parent: nil, index: -1, } if parent != nil { @@ -1335,8 +1547,8 @@ func newDirective(data string, parent *Element) *Directive { return d } -// CreateDirective creates an XML directive and adds it as the last child of -// element e. +// CreateDirective creates an XML directive token with the specified 'data' +// value and adds it as the last child token of this element. func (e *Element) CreateDirective(data string) *Directive { return newDirective(data, e) } @@ -1357,12 +1569,19 @@ func (d *Directive) Parent() *Element { } // Index returns the index of this Directive token within its parent element's -// list of child tokens. If this Directive token has no parent element, the -// index is -1. +// list of child tokens. If this Directive token has no parent, then the +// function returns -1. func (d *Directive) Index() int { return d.index } +// WriteTo serializes the XML directive to the writer. +func (d *Directive) WriteTo(w Writer, s *WriteSettings) { + w.WriteString("") +} + // setParent replaces the directive token's parent. func (d *Directive) setParent(parent *Element) { d.parent = parent @@ -1374,14 +1593,7 @@ func (d *Directive) setIndex(index int) { d.index = index } -// writeTo serializes the XML directive to the writer. -func (d *Directive) writeTo(w *bufio.Writer, s *WriteSettings) { - w.WriteString("") -} - -// NewProcInst creates a parentless XML processing instruction. +// NewProcInst creates an unparented XML processing instruction. func NewProcInst(target, inst string) *ProcInst { return newProcInst(target, inst, nil) } @@ -1392,7 +1604,7 @@ func newProcInst(target, inst string, parent *Element) *ProcInst { p := &ProcInst{ Target: target, Inst: inst, - parent: parent, + parent: nil, index: -1, } if parent != nil { @@ -1401,8 +1613,9 @@ func newProcInst(target, inst string, parent *Element) *ProcInst { return p } -// CreateProcInst creates a processing instruction and adds it as a child of -// element e. +// CreateProcInst creates an XML processing instruction token with the +// specified 'target' and instruction 'inst'. It is then added as the last +// child token of this element. func (e *Element) CreateProcInst(target, inst string) *ProcInst { return newProcInst(target, inst, e) } @@ -1424,12 +1637,23 @@ func (p *ProcInst) Parent() *Element { } // Index returns the index of this ProcInst token within its parent element's -// list of child tokens. If this ProcInst token has no parent element, the -// index is -1. +// list of child tokens. If this ProcInst token has no parent, then the +// function returns -1. func (p *ProcInst) Index() int { return p.index } +// WriteTo serializes the processing instruction to the writer. +func (p *ProcInst) WriteTo(w Writer, s *WriteSettings) { + w.WriteString("") +} + // setParent replaces the processing instruction token's parent. func (p *ProcInst) setParent(parent *Element) { p.parent = parent @@ -1440,14 +1664,3 @@ func (p *ProcInst) setParent(parent *Element) { func (p *ProcInst) setIndex(index int) { p.index = index } - -// writeTo serializes the processing instruction to the writer. -func (p *ProcInst) writeTo(w *bufio.Writer, s *WriteSettings) { - w.WriteString("") -} diff --git a/vendor/github.com/beevik/etree/helpers.go b/vendor/github.com/beevik/etree/helpers.go index 825e14e..b31fd75 100644 --- a/vendor/github.com/beevik/etree/helpers.go +++ b/vendor/github.com/beevik/etree/helpers.go @@ -5,7 +5,6 @@ package etree import ( - "bufio" "io" "strings" "unicode/utf8" @@ -83,38 +82,157 @@ func (f *fifo) grow() { f.data, f.head, f.tail = buf, 0, count } -// countReader implements a proxy reader that counts the number of +// xmlReader provides the interface by which an XML byte stream is +// processed and decoded. +type xmlReader interface { + Bytes() int64 + Read(p []byte) (n int, err error) +} + +// xmlSimpleReader implements a proxy reader that counts the number of // bytes read from its encapsulated reader. -type countReader struct { +type xmlSimpleReader struct { r io.Reader bytes int64 } -func newCountReader(r io.Reader) *countReader { - return &countReader{r: r} +func newXmlSimpleReader(r io.Reader) xmlReader { + return &xmlSimpleReader{r, 0} +} + +func (xr *xmlSimpleReader) Bytes() int64 { + return xr.bytes +} + +func (xr *xmlSimpleReader) Read(p []byte) (n int, err error) { + n, err = xr.r.Read(p) + xr.bytes += int64(n) + return n, err +} + +// xmlPeekReader implements a proxy reader that counts the number of +// bytes read from its encapsulated reader. It also allows the caller to +// "peek" at the previous portions of the buffer after they have been +// parsed. +type xmlPeekReader struct { + r io.Reader + bytes int64 // total bytes read by the Read function + buf []byte // internal read buffer + bufSize int // total bytes used in the read buffer + bufOffset int64 // total bytes read when buf was last filled + window []byte // current read buffer window + peekBuf []byte // buffer used to store data to be peeked at later + peekOffset int64 // total read offset of the start of the peek buffer +} + +func newXmlPeekReader(r io.Reader) *xmlPeekReader { + buf := make([]byte, 4096) + return &xmlPeekReader{ + r: r, + bytes: 0, + buf: buf, + bufSize: 0, + bufOffset: 0, + window: buf[0:0], + peekBuf: make([]byte, 0), + peekOffset: -1, + } +} + +func (xr *xmlPeekReader) Bytes() int64 { + return xr.bytes +} + +func (xr *xmlPeekReader) Read(p []byte) (n int, err error) { + if len(xr.window) == 0 { + err = xr.fill() + if err != nil { + return 0, err + } + if len(xr.window) == 0 { + return 0, nil + } + } + + if len(xr.window) < len(p) { + n = len(xr.window) + } else { + n = len(p) + } + + copy(p, xr.window) + xr.window = xr.window[n:] + xr.bytes += int64(n) + + return n, err +} + +func (xr *xmlPeekReader) PeekPrepare(offset int64, maxLen int) { + if maxLen > cap(xr.peekBuf) { + xr.peekBuf = make([]byte, 0, maxLen) + } + xr.peekBuf = xr.peekBuf[0:0] + xr.peekOffset = offset + xr.updatePeekBuf() +} + +func (xr *xmlPeekReader) PeekFinalize() []byte { + xr.updatePeekBuf() + return xr.peekBuf } -func (cr *countReader) Read(p []byte) (n int, err error) { - b, err := cr.r.Read(p) - cr.bytes += int64(b) - return b, err +func (xr *xmlPeekReader) fill() error { + xr.bufOffset = xr.bytes + xr.bufSize = 0 + n, err := xr.r.Read(xr.buf) + if err != nil { + xr.window, xr.bufSize = xr.buf[0:0], 0 + return err + } + xr.window, xr.bufSize = xr.buf[:n], n + xr.updatePeekBuf() + return nil +} + +func (xr *xmlPeekReader) updatePeekBuf() { + peekRemain := cap(xr.peekBuf) - len(xr.peekBuf) + if xr.peekOffset >= 0 && peekRemain > 0 { + rangeMin := xr.peekOffset + rangeMax := xr.peekOffset + int64(cap(xr.peekBuf)) + bufMin := xr.bufOffset + bufMax := xr.bufOffset + int64(xr.bufSize) + if rangeMin < bufMin { + rangeMin = bufMin + } + if rangeMax > bufMax { + rangeMax = bufMax + } + if rangeMax > rangeMin { + rangeMin -= xr.bufOffset + rangeMax -= xr.bufOffset + if int(rangeMax-rangeMin) > peekRemain { + rangeMax = rangeMin + int64(peekRemain) + } + xr.peekBuf = append(xr.peekBuf, xr.buf[rangeMin:rangeMax]...) + } + } } -// countWriter implements a proxy writer that counts the number of +// xmlWriter implements a proxy writer that counts the number of // bytes written by its encapsulated writer. -type countWriter struct { +type xmlWriter struct { w io.Writer bytes int64 } -func newCountWriter(w io.Writer) *countWriter { - return &countWriter{w: w} +func newXmlWriter(w io.Writer) *xmlWriter { + return &xmlWriter{w: w} } -func (cw *countWriter) Write(p []byte) (n int, err error) { - b, err := cw.w.Write(p) - cw.bytes += int64(b) - return b, err +func (xw *xmlWriter) Write(p []byte) (n int, err error) { + n, err = xw.w.Write(p) + xw.bytes += int64(n) + return n, err } // isWhitespace returns true if the byte slice contains only @@ -211,7 +329,7 @@ const ( ) // escapeString writes an escaped version of a string to the writer. -func escapeString(w *bufio.Writer, s string, m escapeMode) { +func escapeString(w Writer, s string, m escapeMode) { var esc []byte last := 0 for i := 0; i < len(s); { diff --git a/vendor/github.com/beevik/etree/path.go b/vendor/github.com/beevik/etree/path.go index 82db0ac..a6d67ac 100644 --- a/vendor/github.com/beevik/etree/path.go +++ b/vendor/github.com/beevik/etree/path.go @@ -19,66 +19,73 @@ be modified by one or more bracket-enclosed "filters". Selectors are used to traverse the etree from element to element, while filters are used to narrow the list of candidate elements at each node. -Although etree Path strings are similar to XPath strings -(https://www.w3.org/TR/1999/REC-xpath-19991116/), they have a more limited set -of selectors and filtering options. +Although etree Path strings are structurally and behaviorally similar to XPath +strings (https://www.w3.org/TR/1999/REC-xpath-19991116/), they have a more +limited set of selectors and filtering options. -The following selectors are supported by etree Path strings: +The following selectors are supported by etree paths: - . Select the current element. - .. Select the parent of the current element. - * Select all child elements of the current element. - / Select the root element when used at the start of a path. - // Select all descendants of the current element. - tag Select all child elements with a name matching the tag. + . Select the current element. + .. Select the parent of the current element. + * Select all child elements of the current element. + / Select the root element when used at the start of a path. + // Select all descendants of the current element. + tag Select all child elements with a name matching the tag. -The following basic filters are supported by etree Path strings: +The following basic filters are supported: - [@attrib] Keep elements with an attribute named attrib. - [@attrib='val'] Keep elements with an attribute named attrib and value matching val. - [tag] Keep elements with a child element named tag. - [tag='val'] Keep elements with a child element named tag and text matching val. - [n] Keep the n-th element, where n is a numeric index starting from 1. + [@attrib] Keep elements with an attribute named attrib. + [@attrib='val'] Keep elements with an attribute named attrib and value matching val. + [tag] Keep elements with a child element named tag. + [tag='val'] Keep elements with a child element named tag and text matching val. + [n] Keep the n-th element, where n is a numeric index starting from 1. -The following function filters are also supported: +The following function-based filters are supported: - [text()] Keep elements with non-empty text. - [text()='val'] Keep elements whose text matches val. - [local-name()='val'] Keep elements whose un-prefixed tag matches val. - [name()='val'] Keep elements whose full tag exactly matches val. - [namespace-prefix()='val'] Keep elements whose namespace prefix matches val. - [namespace-uri()='val'] Keep elements whose namespace URI matches val. + [text()] Keep elements with non-empty text. + [text()='val'] Keep elements whose text matches val. + [local-name()='val'] Keep elements whose un-prefixed tag matches val. + [name()='val'] Keep elements whose full tag exactly matches val. + [namespace-prefix()] Keep elements with non-empty namespace prefixes. + [namespace-prefix()='val'] Keep elements whose namespace prefix matches val. + [namespace-uri()] Keep elements with non-empty namespace URIs. + [namespace-uri()='val'] Keep elements whose namespace URI matches val. -Here are some examples of Path strings: +Below are some examples of etree path strings. -- Select the bookstore child element of the root element: - /bookstore +Select the bookstore child element of the root element: -- Beginning from the root element, select the title elements of all -descendant book elements having a 'category' attribute of 'WEB': - //book[@category='WEB']/title + /bookstore -- Beginning from the current element, select the first descendant -book element with a title child element containing the text 'Great -Expectations': - .//book[title='Great Expectations'][1] +Beginning from the root element, select the title elements of all descendant +book elements having a 'category' attribute of 'WEB': -- Beginning from the current element, select all child elements of -book elements with an attribute 'language' set to 'english': - ./book/*[@language='english'] + //book[@category='WEB']/title -- Beginning from the current element, select all child elements of -book elements containing the text 'special': - ./book/*[text()='special'] +Beginning from the current element, select the first descendant book element +with a title child element containing the text 'Great Expectations': -- Beginning from the current element, select all descendant book -elements whose title child element has a 'language' attribute of 'french': - .//book/title[@language='french']/.. + .//book[title='Great Expectations'][1] -- Beginning from the current element, select all book elements +Beginning from the current element, select all child elements of book elements +with an attribute 'language' set to 'english': + + ./book/*[@language='english'] + +Beginning from the current element, select all child elements of book elements +containing the text 'special': + + ./book/*[text()='special'] + +Beginning from the current element, select all descendant book elements whose +title child element has a 'language' attribute of 'french': + + .//book/title[@language='french']/.. + +Beginning from the current element, select all descendant book elements belonging to the http://www.w3.org/TR/html4/ namespace: - .//book[namespace-uri()='http://www.w3.org/TR/html4/'] + .//book[namespace-uri()='http://www.w3.org/TR/html4/'] */ type Path struct { segments []segment @@ -178,7 +185,7 @@ func (p *pather) traverse(e *Element, path Path) []*Element { return p.results } -// eval evalutes the current path node by applying the remaining +// eval evaluates the current path node by applying the remaining // path's selector rules against the node's element. func (p *pather) eval(n node) { p.candidates = p.candidates[0:0] @@ -210,7 +217,7 @@ type compiler struct { func (c *compiler) parsePath(path string) []segment { // If path ends with //, fix it if strings.HasSuffix(path, "//") { - path = path + "*" + path += "*" } var segments []segment @@ -232,7 +239,7 @@ func (c *compiler) parsePath(path string) []segment { } func splitPath(path string) []string { - pieces := make([]string, 0) + var pieces []string start := 0 inquote := false for i := 0; i+1 <= len(path); i++ { @@ -255,7 +262,7 @@ func (c *compiler) parseSegment(path string) segment { } for i := 1; i < len(pieces); i++ { fpath := pieces[i] - if fpath[len(fpath)-1] != ']' { + if len(fpath) == 0 || fpath[len(fpath)-1] != ']' { c.err = ErrPath("path has invalid filter [brackets].") break } @@ -280,15 +287,12 @@ func (c *compiler) parseSelector(path string) selector { } } -var fnTable = map[string]struct { - hasFn func(e *Element) bool - getValFn func(e *Element) string -}{ - "local-name": {nil, (*Element).name}, - "name": {nil, (*Element).FullTag}, - "namespace-prefix": {nil, (*Element).namespacePrefix}, - "namespace-uri": {nil, (*Element).NamespaceURI}, - "text": {(*Element).hasText, (*Element).Text}, +var fnTable = map[string]func(e *Element) string{ + "local-name": (*Element).name, + "name": (*Element).FullTag, + "namespace-prefix": (*Element).namespacePrefix, + "namespace-uri": (*Element).NamespaceURI, + "text": (*Element).Text, } // parseFilter parses a path filter contained within [brackets]. @@ -314,11 +318,11 @@ func (c *compiler) parseFilter(path string) filter { case key[0] == '@': return newFilterAttrVal(key[1:], value) case strings.HasSuffix(key, "()"): - fn := key[:len(key)-2] - if t, ok := fnTable[fn]; ok && t.getValFn != nil { - return newFilterFuncVal(t.getValFn, value) + name := key[:len(key)-2] + if fn, ok := fnTable[name]; ok { + return newFilterFuncVal(fn, value) } - c.err = ErrPath("path has unknown function " + fn) + c.err = ErrPath("path has unknown function " + name) return nil default: return newFilterChildText(key, value) @@ -330,11 +334,11 @@ func (c *compiler) parseFilter(path string) filter { case path[0] == '@': return newFilterAttr(path[1:]) case strings.HasSuffix(path, "()"): - fn := path[:len(path)-2] - if t, ok := fnTable[fn]; ok && t.hasFn != nil { - return newFilterFunc(t.hasFn) + name := path[:len(path)-2] + if fn, ok := fnTable[name]; ok { + return newFilterFunc(fn) } - c.err = ErrPath("path has unknown function " + fn) + c.err = ErrPath("path has unknown function " + name) return nil case isInteger(path): pos, _ := strconv.Atoi(path) @@ -496,16 +500,16 @@ func (f *filterAttrVal) apply(p *pather) { // filterFunc filters the candidate list for elements satisfying a custom // boolean function. type filterFunc struct { - fn func(e *Element) bool + fn func(e *Element) string } -func newFilterFunc(fn func(e *Element) bool) *filterFunc { +func newFilterFunc(fn func(e *Element) string) *filterFunc { return &filterFunc{fn} } func (f *filterFunc) apply(p *pather) { for _, c := range p.candidates { - if f.fn(c) { + if f.fn(c) != "" { p.scratch = append(p.scratch, c) } } diff --git a/vendor/github.com/bitrise-io/bitrise-init/models/configbuilder.go b/vendor/github.com/bitrise-io/bitrise-init/models/configbuilder.go index af85ee5..dac3058 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/models/configbuilder.go +++ b/vendor/github.com/bitrise-io/bitrise-init/models/configbuilder.go @@ -1,8 +1,6 @@ package models import ( - "errors" - bitriseModels "github.com/bitrise-io/bitrise/models" envmanModels "github.com/bitrise-io/envman/models" ) @@ -17,7 +15,7 @@ const ( DeployWorkflowID WorkflowID = "deploy" // FormatVersion ... - FormatVersion = bitriseModels.Version + FormatVersion = bitriseModels.FormatVersion defaultSteplibSource = "https://github.com/bitrise-io/bitrise-steplib.git" ) @@ -30,9 +28,7 @@ type ConfigBuilderModel struct { // NewDefaultConfigBuilder ... func NewDefaultConfigBuilder() *ConfigBuilderModel { return &ConfigBuilderModel{ - workflowBuilderMap: map[WorkflowID]*workflowBuilderModel{ - PrimaryWorkflowID: newDefaultWorkflowBuilder(), - }, + workflowBuilderMap: map[WorkflowID]*workflowBuilderModel{}, } } @@ -56,19 +52,23 @@ func (builder *ConfigBuilderModel) SetWorkflowDescriptionTo(workflow WorkflowID, workflowBuilder.Description = description } -// Generate ... -func (builder *ConfigBuilderModel) Generate(projectType string, appEnvs ...envmanModels.EnvironmentItemModel) (bitriseModels.BitriseDataModel, error) { - primaryWorkflowBuilder, ok := builder.workflowBuilderMap[PrimaryWorkflowID] - if !ok || primaryWorkflowBuilder == nil || len(primaryWorkflowBuilder.Steps) == 0 { - return bitriseModels.BitriseDataModel{}, errors.New("primary workflow not defined") +// SetWorkflowSummaryTo ... +func (builder *ConfigBuilderModel) SetWorkflowSummaryTo(workflow WorkflowID, summary string) { + workflowBuilder := builder.workflowBuilderMap[workflow] + if workflowBuilder == nil { + workflowBuilder = newDefaultWorkflowBuilder() + builder.workflowBuilderMap[workflow] = workflowBuilder } + workflowBuilder.Summary = summary +} +// Generate ... +func (builder *ConfigBuilderModel) Generate(projectType string, appEnvs ...envmanModels.EnvironmentItemModel) (bitriseModels.BitriseDataModel, error) { workflows := map[string]bitriseModels.WorkflowModel{} for workflowID, workflowBuilder := range builder.workflowBuilderMap { workflows[string(workflowID)] = workflowBuilder.generate() } - triggerMap := []bitriseModels.TriggerMapItemModel{} app := bitriseModels.AppModel{ Environments: appEnvs, } @@ -77,7 +77,6 @@ func (builder *ConfigBuilderModel) Generate(projectType string, appEnvs ...envma FormatVersion: FormatVersion, DefaultStepLibSource: defaultSteplibSource, ProjectType: projectType, - TriggerMap: triggerMap, Workflows: workflows, App: app, }, nil diff --git a/vendor/github.com/bitrise-io/bitrise-init/models/models.go b/vendor/github.com/bitrise-io/bitrise-init/models/models.go index f65f2e6..fd92931 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/models/models.go +++ b/vendor/github.com/bitrise-io/bitrise-init/models/models.go @@ -4,13 +4,10 @@ import ( "github.com/bitrise-io/go-steputils/step" ) -// BitriseConfigMap ... type BitriseConfigMap map[string]string -// Warnings ... type Warnings []string -// Errors ... type Errors []string // Icon is potential app icon. @@ -20,19 +17,15 @@ type Icon struct { Path string } -// Icons is an array of icons type Icons []Icon -// ErrorWithRecommendations ... type ErrorWithRecommendations struct { Error string Recommendations step.Recommendation } -// ErrorsWithRecommendations is an array with an Error and its Recommendations type ErrorsWithRecommendations []ErrorWithRecommendations -// ScanResultModel ... type ScanResultModel struct { ScannerToOptionRoot map[string]OptionNode `json:"options,omitempty" yaml:"options,omitempty"` ScannerToBitriseConfigMap map[string]BitriseConfigMap `json:"configs,omitempty" yaml:"configs,omitempty"` @@ -43,7 +36,14 @@ type ScanResultModel struct { Icons []Icon `json:"-" yaml:"-"` } -// AddErrorWithRecommendation ... +type SSHKeyActivation int + +const ( + SSHKeyActivationNone = iota + SSHKeyActivationMandatory + SSHKeyActivationConditional +) + func (result *ScanResultModel) AddErrorWithRecommendation(platform string, recommendation ErrorWithRecommendations) { if result.ScannerToErrorsWithRecommendations == nil { result.ScannerToErrorsWithRecommendations = map[string]ErrorsWithRecommendations{} diff --git a/vendor/github.com/bitrise-io/bitrise-init/models/option.go b/vendor/github.com/bitrise-io/bitrise-init/models/option.go index ea01a5f..ab8f65c 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/models/option.go +++ b/vendor/github.com/bitrise-io/bitrise-init/models/option.go @@ -34,6 +34,9 @@ const ( // Now, if this type is selected: // - we must show an input field to the user and it is NOT required to be filled, can be empty, and any name for the key will be the placeholder value for the input field TypeOptionalUserInput Type = "user_input_optional" + + // UserInputOptionDefaultValue can be used as a value (forValue) for adding a default new option to a TypeUserInput and TypeOptionalUserInput OptionNode via AddOption or AddConfig. + UserInputOptionDefaultValue = "" ) // OptionNode ... diff --git a/vendor/github.com/bitrise-io/bitrise-init/models/workflowbuilder.go b/vendor/github.com/bitrise-io/bitrise-init/models/workflowbuilder.go index 7b5288f..2a2470d 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/models/workflowbuilder.go +++ b/vendor/github.com/bitrise-io/bitrise-init/models/workflowbuilder.go @@ -5,6 +5,7 @@ import bitriseModels "github.com/bitrise-io/bitrise/models" type workflowBuilderModel struct { Steps []bitriseModels.StepListItemModel Description string + Summary string } func newDefaultWorkflowBuilder() *workflowBuilderModel { @@ -21,5 +22,6 @@ func (builder *workflowBuilderModel) generate() bitriseModels.WorkflowModel { return bitriseModels.WorkflowModel{ Steps: builder.Steps, Description: builder.Description, + Summary: builder.Summary, } } diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/android.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/android.go index 7f7d6ff..23b5cf7 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/android.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/android.go @@ -1,14 +1,57 @@ package android import ( - "fmt" "path/filepath" "gopkg.in/yaml.v2" - "github.com/bitrise-io/bitrise-init/analytics" "github.com/bitrise-io/bitrise-init/models" - "github.com/bitrise-io/go-utils/log" + "github.com/bitrise-io/bitrise-init/steps" + envmanModels "github.com/bitrise-io/envman/models" +) + +const ( + ScannerName = "android" + ConfigName = "android-config" + ConfigNameKotlinScript = "android-config-kts" + DefaultConfigName = "default-android-config" + DefaultConfigNameKotlinScript = "default-android-config-kts" + + testsWorkflowID = "run_tests" + testsWorkflowSummary = "Run your Android unit tests and get the test report." + testWorkflowDescription = "The workflow will first clone your Git repository, cache your Gradle dependencies, install Android tools, run your Android unit tests and save the test report." + + buildWorkflowID = "build_apk" + buildWorkflowSummary = "Run your Android unit tests and create an APK file to install your app on a device or share it with your team." + buildWorkflowDescription = "The workflow will first clone your Git repository, install Android tools, set the project's version code based on the build number, run Android lint and unit tests, build the project's APK file and save it." + + ProjectLocationInputKey = "project_location" + ProjectLocationInputEnvKey = "PROJECT_LOCATION" + ProjectLocationInputTitle = "The root directory of an Android project" + ProjectLocationInputSummary = "The root directory of your Android project, stored as an Environment Variable. In your Workflows, you can specify paths relative to this path. You can change this at any time." + + ModuleBuildGradlePathInputKey = "build_gradle_path" + + VariantInputKey = "variant" + VariantInputEnvKey = "VARIANT" + VariantInputTitle = "Variant" + VariantInputSummary = "Your Android build variant. You can add variants at any time, as well as further configure your existing variants later." + + ModuleInputKey = "module" + ModuleInputEnvKey = "MODULE" + ModuleInputTitle = "Module" + ModuleInputSummary = "Modules provide a container for your Android project's source code, resource files, and app level settings, such as the module-level build file and Android manifest file. Each module can be independently built, tested, and debugged. You can add new modules to your Bitrise builds at any time." + + BuildScriptInputTitle = "Does your app use Kotlin build scripts?" + BuildScriptInputSummary = "The workflow configuration slightly differs based on what language (Groovy or Kotlin) you used in your build scripts." + + GradlewPathInputKey = "gradlew_path" + + CacheLevelInputKey = "cache_level" + CacheLevelNone = "none" + + gradleKotlinBuildFile = "build.gradle.kts" + gradleKotlinSettingsFile = "settings.gradle.kts" ) // Scanner ... @@ -22,12 +65,12 @@ func NewScanner() *Scanner { } // Name ... -func (Scanner) Name() string { +func (scanner *Scanner) Name() string { return ScannerName } // ExcludedScannerNames ... -func (*Scanner) ExcludedScannerNames() []string { +func (scanner *Scanner) ExcludedScannerNames() []string { return nil } @@ -40,95 +83,6 @@ func (scanner *Scanner) DetectPlatform(searchDir string) (_ bool, err error) { return detected, err } -func detect(searchDir string) ([]Project, error) { - projectFiles := fileGroups{ - {"build.gradle", "build.gradle.kts"}, - {"settings.gradle", "settings.gradle.kts"}, - } - skipDirs := []string{".git", "CordovaLib", "node_modules"} - - log.TInfof("Searching for android files") - - projectRoots, err := walkMultipleFileGroups(searchDir, projectFiles, skipDirs) - if err != nil { - return nil, fmt.Errorf("failed to search for build.gradle files, error: %s", err) - } - - log.TPrintf("%d android files detected", len(projectRoots)) - for _, file := range projectRoots { - log.TPrintf("- %s", file) - } - - if len(projectRoots) == 0 { - return nil, nil - } - log.TSuccessf("Platform detected") - - projects, err := parseProjects(searchDir, projectRoots) - if err != nil { - return nil, err - } - - return projects, nil -} - -func parseProjects(searchDir string, projectRoots []string) ([]Project, error) { - var ( - lastErr error - projects []Project - ) - - for _, projectRoot := range projectRoots { - var warnings models.Warnings - - log.TInfof("Investigating Android project: %s", projectRoot) - - exists, err := containsLocalProperties(projectRoot) - if err != nil { - lastErr = err - log.TWarnf("%s", err) - - continue - } - if exists { - containsLocalPropertiesWarning := fmt.Sprintf("the local.properties file should NOT be checked into Version Control Systems, as it contains information specific to your local configuration, the location of the file is: %s", filepath.Join(projectRoot, "local.properties")) - warnings = []string{containsLocalPropertiesWarning} - } - - if err := checkGradlew(projectRoot); err != nil { - lastErr = err - log.TWarnf("%s", err) - - continue - } - - relProjectRoot, err := filepath.Rel(searchDir, projectRoot) - if err != nil { - lastErr = err - log.TWarnf("%s", err) - - continue - } - - icons, err := LookupIcons(projectRoot, searchDir) - if err != nil { - analytics.LogInfo("android-icon-lookup", analytics.DetectorErrorData("android", err), "Failed to lookup android icon") - } - - projects = append(projects, Project{ - RelPath: relProjectRoot, - Icons: icons, - Warnings: warnings, - }) - } - - if len(projects) == 0 { - return []Project{}, lastErr - } - - return projects, nil -} - // Options ... func (scanner *Scanner) Options() (models.OptionNode, models.Warnings, models.Icons, error) { projectLocationOption := models.NewOption(ProjectLocationInputTitle, ProjectLocationInputSummary, ProjectLocationInputEnvKey, models.TypeSelector) @@ -144,7 +98,11 @@ func (scanner *Scanner) Options() (models.OptionNode, models.Warnings, models.Ic iconIDs[i] = icon.Filename } - configOption := models.NewConfigOption(ConfigName, iconIDs) + name := ConfigName + if project.UsesKotlinBuildScript { + name = ConfigNameKotlinScript + } + configOption := models.NewConfigOption(name, iconIDs) moduleOption := models.NewOption(ModuleInputTitle, ModuleInputSummary, ModuleInputEnvKey, models.TypeUserInput) variantOption := models.NewOption(VariantInputTitle, VariantInputSummary, VariantInputEnvKey, models.TypeOptionalUserInput) @@ -161,49 +119,145 @@ func (scanner *Scanner) DefaultOptions() models.OptionNode { projectLocationOption := models.NewOption(ProjectLocationInputTitle, ProjectLocationInputSummary, ProjectLocationInputEnvKey, models.TypeUserInput) moduleOption := models.NewOption(ModuleInputTitle, ModuleInputSummary, ModuleInputEnvKey, models.TypeUserInput) variantOption := models.NewOption(VariantInputTitle, VariantInputSummary, VariantInputEnvKey, models.TypeOptionalUserInput) - configOption := models.NewConfigOption(DefaultConfigName, nil) - projectLocationOption.AddOption("", moduleOption) - moduleOption.AddOption("", variantOption) - variantOption.AddConfig("", configOption) + buildScriptOption := models.NewOption(BuildScriptInputTitle, BuildScriptInputSummary, "", models.TypeSelector) + regularConfigOption := models.NewConfigOption(DefaultConfigName, nil) + kotlinScriptConfigOption := models.NewConfigOption(DefaultConfigNameKotlinScript, nil) + + projectLocationOption.AddOption(models.UserInputOptionDefaultValue, moduleOption) + moduleOption.AddOption(models.UserInputOptionDefaultValue, variantOption) + variantOption.AddOption(models.UserInputOptionDefaultValue, buildScriptOption) + + buildScriptOption.AddConfig("yes", kotlinScriptConfigOption) + buildScriptOption.AddOption("no", regularConfigOption) return *projectLocationOption } // Configs ... -func (scanner *Scanner) Configs(isPrivateRepository bool) (models.BitriseConfigMap, error) { - configBuilder := scanner.generateConfigBuilder(isPrivateRepository) +func (scanner *Scanner) Configs(sshKeyActivation models.SSHKeyActivation) (models.BitriseConfigMap, error) { + params := configBuildingParameters(scanner.Projects) + return scanner.generateConfigs(sshKeyActivation, params) +} - config, err := configBuilder.Generate(ScannerName) - if err != nil { - return models.BitriseConfigMap{}, err +// DefaultConfigs ... +func (scanner *Scanner) DefaultConfigs() (models.BitriseConfigMap, error) { + params := []configBuildingParams{ + {name: DefaultConfigName, useKotlinScript: false}, + {name: DefaultConfigNameKotlinScript, useKotlinScript: true}, } + return scanner.generateConfigs(models.SSHKeyActivationConditional, params) +} - data, err := yaml.Marshal(config) - if err != nil { - return models.BitriseConfigMap{}, err - } +func (scanner *Scanner) generateConfigs(sshKeyActivation models.SSHKeyActivation, params []configBuildingParams) (models.BitriseConfigMap, error) { + bitriseDataMap := models.BitriseConfigMap{} - return models.BitriseConfigMap{ - ConfigName: string(data), - }, nil -} + for _, param := range params { + configBuilder := scanner.generateConfigBuilder(sshKeyActivation, param.useKotlinScript) -// DefaultConfigs ... -func (scanner *Scanner) DefaultConfigs() (models.BitriseConfigMap, error) { - configBuilder := scanner.generateConfigBuilder(true) + config, err := configBuilder.Generate(ScannerName) + if err != nil { + return models.BitriseConfigMap{}, err + } - config, err := configBuilder.Generate(ScannerName) - if err != nil { - return models.BitriseConfigMap{}, err - } + data, err := yaml.Marshal(config) + if err != nil { + return models.BitriseConfigMap{}, err + } - data, err := yaml.Marshal(config) - if err != nil { - return models.BitriseConfigMap{}, err + bitriseDataMap[param.name] = string(data) } - return models.BitriseConfigMap{ - DefaultConfigName: string(data), - }, nil + return bitriseDataMap, nil +} + +func (scanner *Scanner) generateConfigBuilder(sshKeyActivation models.SSHKeyActivation, useKotlinBuildScript bool) models.ConfigBuilderModel { + configBuilder := models.NewDefaultConfigBuilder() + + projectLocationEnv, gradlewPath, moduleEnv, variantEnv := "$"+ProjectLocationInputEnvKey, "$"+ProjectLocationInputEnvKey+"/gradlew", "$"+ModuleInputEnvKey, "$"+VariantInputEnvKey + + //-- test + configBuilder.AppendStepListItemsTo(testsWorkflowID, steps.DefaultPrepareStepList(steps.PrepareListParams{ + SSHKeyActivation: sshKeyActivation})...) + configBuilder.AppendStepListItemsTo(testsWorkflowID, steps.RestoreGradleCache()) + configBuilder.AppendStepListItemsTo(testsWorkflowID, steps.InstallMissingAndroidToolsStepListItem( + envmanModels.EnvironmentItemModel{GradlewPathInputKey: gradlewPath}, + )) + configBuilder.AppendStepListItemsTo(testsWorkflowID, steps.AndroidUnitTestStepListItem( + envmanModels.EnvironmentItemModel{ + ProjectLocationInputKey: projectLocationEnv, + }, + envmanModels.EnvironmentItemModel{ + VariantInputKey: variantEnv, + }, + envmanModels.EnvironmentItemModel{ + CacheLevelInputKey: CacheLevelNone, + }, + )) + configBuilder.AppendStepListItemsTo(testsWorkflowID, steps.SaveGradleCache()) + configBuilder.AppendStepListItemsTo(testsWorkflowID, steps.DefaultDeployStepList()...) + configBuilder.SetWorkflowSummaryTo(testsWorkflowID, testsWorkflowSummary) + configBuilder.SetWorkflowDescriptionTo(testsWorkflowID, testWorkflowDescription) + + //-- build + configBuilder.AppendStepListItemsTo(buildWorkflowID, steps.DefaultPrepareStepList(steps.PrepareListParams{ + SSHKeyActivation: sshKeyActivation, + })...) + configBuilder.AppendStepListItemsTo(buildWorkflowID, steps.InstallMissingAndroidToolsStepListItem( + envmanModels.EnvironmentItemModel{GradlewPathInputKey: gradlewPath}, + )) + + basePath := filepath.Join(projectLocationEnv, moduleEnv) + path := filepath.Join(basePath, "build.gradle") + if useKotlinBuildScript { + path = filepath.Join(basePath, gradleKotlinBuildFile) + } + configBuilder.AppendStepListItemsTo(buildWorkflowID, steps.ChangeAndroidVersionCodeAndVersionNameStepListItem( + envmanModels.EnvironmentItemModel{ModuleBuildGradlePathInputKey: path}, + )) + + configBuilder.AppendStepListItemsTo(buildWorkflowID, steps.AndroidLintStepListItem( + envmanModels.EnvironmentItemModel{ + ProjectLocationInputKey: projectLocationEnv, + }, + envmanModels.EnvironmentItemModel{ + VariantInputKey: variantEnv, + }, + envmanModels.EnvironmentItemModel{ + CacheLevelInputKey: CacheLevelNone, + }, + )) + configBuilder.AppendStepListItemsTo(buildWorkflowID, steps.AndroidUnitTestStepListItem( + envmanModels.EnvironmentItemModel{ + ProjectLocationInputKey: projectLocationEnv, + }, + envmanModels.EnvironmentItemModel{ + VariantInputKey: variantEnv, + }, + envmanModels.EnvironmentItemModel{ + CacheLevelInputKey: CacheLevelNone, + }, + )) + + configBuilder.AppendStepListItemsTo(buildWorkflowID, steps.AndroidBuildStepListItem( + envmanModels.EnvironmentItemModel{ + ProjectLocationInputKey: projectLocationEnv, + }, + envmanModels.EnvironmentItemModel{ + ModuleInputKey: moduleEnv, + }, + envmanModels.EnvironmentItemModel{ + VariantInputKey: variantEnv, + }, + envmanModels.EnvironmentItemModel{ + CacheLevelInputKey: CacheLevelNone, + }, + )) + configBuilder.AppendStepListItemsTo(buildWorkflowID, steps.SignAPKStepListItem()) + configBuilder.AppendStepListItemsTo(buildWorkflowID, steps.DefaultDeployStepList()...) + + configBuilder.SetWorkflowDescriptionTo(buildWorkflowID, buildWorkflowDescription) + configBuilder.SetWorkflowSummaryTo(buildWorkflowID, buildWorkflowSummary) + + return *configBuilder } diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/const.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/const.go deleted file mode 100644 index 0cc8df5..0000000 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/const.go +++ /dev/null @@ -1,16 +0,0 @@ -package android - -const ( - primaryWorkflowDescription = `Runs tests. - -Next steps: -- Check out [Getting started with Android apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-android-apps.html). -` - - deployWorkflowDescription = `Deploys app using [Deploy to bitrise.io Step](https://devcenter.bitrise.io/en/getting-started/getting-started-with-android-apps.html#deploying-an-android-app-to-bitrise-io-53056). - -Next steps: -- Check out [Getting started with Android apps](https://devcenter.bitrise.io/en/getting-started/getting-started-with-android-apps.html) for signing and deployment options. -- [Set up code signing with *Android Sign* Step](https://devcenter.bitrise.io/en/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step.html). -` -) diff --git a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/utility.go b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/utility.go index b53a5bf..9f8d8f6 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/scanners/android/utility.go +++ b/vendor/github.com/bitrise-io/bitrise-init/scanners/android/utility.go @@ -2,12 +2,14 @@ package android import ( "errors" + "fmt" "os" "path/filepath" + "github.com/bitrise-io/bitrise-init/analytics" "github.com/bitrise-io/bitrise-init/models" - "github.com/bitrise-io/bitrise-init/steps" - envmanModels "github.com/bitrise-io/envman/models" + "github.com/bitrise-io/bitrise-init/utility" + "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" ) @@ -16,37 +18,107 @@ type fileGroups [][]string var pathUtilIsPathExists = pathutil.IsPathExists var filePathWalk = filepath.Walk -// Constants ... -const ( - ScannerName = "android" - ConfigName = "android-config" - DefaultConfigName = "default-android-config" +// Project is an Android project on the filesystem +type Project struct { + RelPath string + UsesKotlinBuildScript bool + Icons models.Icons + Warnings models.Warnings +} - ProjectLocationInputKey = "project_location" - ProjectLocationInputEnvKey = "PROJECT_LOCATION" - ProjectLocationInputTitle = "The root directory of an Android project" - ProjectLocationInputSummary = "The root directory of your Android project, stored as an Environment Variable. In your Workflows, you can specify paths relative to this path. You can change this at any time." +func detect(searchDir string) ([]Project, error) { + projectFiles := fileGroups{ + {"build.gradle", gradleKotlinBuildFile}, + {"settings.gradle", gradleKotlinSettingsFile}, + } + skipDirs := []string{".git", "CordovaLib", "node_modules"} - ModuleBuildGradlePathInputKey = "build_gradle_path" + log.TInfof("Searching for android files") - VariantInputKey = "variant" - VariantInputEnvKey = "VARIANT" - VariantInputTitle = "Variant" - VariantInputSummary = "Your Android build variant. You can add variants at any time, as well as further configure your existing variants later." + projectRoots, err := walkMultipleFileGroups(searchDir, projectFiles, skipDirs) + if err != nil { + return nil, fmt.Errorf("failed to search for build.gradle files, error: %s", err) + } - ModuleInputKey = "module" - ModuleInputEnvKey = "MODULE" - ModuleInputTitle = "Module" - ModuleInputSummary = "Modules provide a container for your Android project's source code, resource files, and app level settings, such as the module-level build file and Android manifest file. Each module can be independently built, tested, and debugged. You can add new modules to your Bitrise builds at any time." + log.TPrintf("%d android files detected", len(projectRoots)) + for _, file := range projectRoots { + log.TPrintf("- %s", file) + } - GradlewPathInputKey = "gradlew_path" -) + if len(projectRoots) == 0 { + return nil, nil + } + log.TSuccessf("Platform detected") -// Project is an Android project on the filesystem -type Project struct { - RelPath string - Icons models.Icons - Warnings models.Warnings + projects, err := parseProjects(searchDir, projectRoots) + if err != nil { + return nil, err + } + + return projects, nil +} + +func parseProjects(searchDir string, projectRoots []string) ([]Project, error) { + var ( + lastErr error + projects []Project + ) + + for _, projectRoot := range projectRoots { + var warnings models.Warnings + + log.TInfof("Investigating Android project: %s", projectRoot) + + exists, err := containsLocalProperties(projectRoot) + if err != nil { + lastErr = err + log.TWarnf("%s", err) + + continue + } + if exists { + containsLocalPropertiesWarning := fmt.Sprintf("the local.properties file should NOT be checked into Version Control Systems, as it contains information specific to your local configuration, the location of the file is: %s", filepath.Join(projectRoot, "local.properties")) + warnings = []string{containsLocalPropertiesWarning} + } + + if err := checkGradlew(projectRoot); err != nil { + lastErr = err + log.TWarnf("%s", err) + + continue + } + + relProjectRoot, err := filepath.Rel(searchDir, projectRoot) + if err != nil { + lastErr = err + log.TWarnf("%s", err) + + continue + } + + icons, err := LookupIcons(projectRoot, searchDir) + if err != nil { + analytics.LogInfo("android-icon-lookup", analytics.DetectorErrorData("android", err), "Failed to lookup android icon") + } + + kotlinBuildScriptBased := usesKotlinBuildScripts(projectRoot) + projects = append(projects, Project{ + RelPath: relProjectRoot, + UsesKotlinBuildScript: kotlinBuildScriptBased, + Icons: icons, + Warnings: warnings, + }) + } + + if len(projects) == 0 { + return []Project{}, lastErr + } + + return projects, nil +} + +func usesKotlinBuildScripts(projectRoot string) bool { + return utility.FileExists(filepath.Join(projectRoot, gradleKotlinBuildFile)) && utility.FileExists(filepath.Join(projectRoot, gradleKotlinSettingsFile)) } func walk(src string, fn func(path string, info os.FileInfo) error) error { @@ -138,75 +210,35 @@ that the right Gradle version is installed and used for the build. More info/gui return nil } -func (scanner *Scanner) generateConfigBuilder(isPrivateRepository bool) models.ConfigBuilderModel { - configBuilder := models.NewDefaultConfigBuilder() - - projectLocationEnv, gradlewPath, moduleEnv, variantEnv := "$"+ProjectLocationInputEnvKey, "$"+ProjectLocationInputEnvKey+"/gradlew", "$"+ModuleInputEnvKey, "$"+VariantInputEnvKey - - //-- primary - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ - ShouldIncludeCache: true, - ShouldIncludeActivateSSH: isPrivateRepository, - })...) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.InstallMissingAndroidToolsStepListItem( - envmanModels.EnvironmentItemModel{GradlewPathInputKey: gradlewPath}, - )) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.AndroidUnitTestStepListItem( - envmanModels.EnvironmentItemModel{ - ProjectLocationInputKey: projectLocationEnv, - }, - envmanModels.EnvironmentItemModel{ - VariantInputKey: variantEnv, - }, - )) - configBuilder.AppendStepListItemsTo(models.PrimaryWorkflowID, steps.DefaultDeployStepListV2(true)...) - configBuilder.SetWorkflowDescriptionTo(models.PrimaryWorkflowID, primaryWorkflowDescription) - - //-- deploy - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultPrepareStepListV2(steps.PrepareListParams{ - ShouldIncludeCache: true, - ShouldIncludeActivateSSH: isPrivateRepository, - })...) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.InstallMissingAndroidToolsStepListItem( - envmanModels.EnvironmentItemModel{GradlewPathInputKey: gradlewPath}, - )) - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.ChangeAndroidVersionCodeAndVersionNameStepListItem( - envmanModels.EnvironmentItemModel{ModuleBuildGradlePathInputKey: filepath.Join(projectLocationEnv, moduleEnv, "build.gradle")}, - )) - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidLintStepListItem( - envmanModels.EnvironmentItemModel{ - ProjectLocationInputKey: projectLocationEnv, - }, - envmanModels.EnvironmentItemModel{ - VariantInputKey: variantEnv, - }, - )) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidUnitTestStepListItem( - envmanModels.EnvironmentItemModel{ - ProjectLocationInputKey: projectLocationEnv, - }, - envmanModels.EnvironmentItemModel{ - VariantInputKey: variantEnv, - }, - )) - - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.AndroidBuildStepListItem( - envmanModels.EnvironmentItemModel{ - ProjectLocationInputKey: projectLocationEnv, - }, - envmanModels.EnvironmentItemModel{ - ModuleInputKey: moduleEnv, - }, - envmanModels.EnvironmentItemModel{ - VariantInputKey: variantEnv, - }, - )) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.SignAPKStepListItem()) - configBuilder.AppendStepListItemsTo(models.DeployWorkflowID, steps.DefaultDeployStepListV2(true)...) - - configBuilder.SetWorkflowDescriptionTo(models.DeployWorkflowID, deployWorkflowDescription) - - return *configBuilder +type configBuildingParams struct { + name string + useKotlinScript bool +} + +func configBuildingParameters(projects []Project) []configBuildingParams { + regularProjectCount := 0 + kotlinBuildScriptProjectCount := 0 + + for _, project := range projects { + if project.UsesKotlinBuildScript { + kotlinBuildScriptProjectCount += 1 + } else { + regularProjectCount += 1 + } + } + + var params []configBuildingParams + if 0 < regularProjectCount { + params = append(params, configBuildingParams{ + name: ConfigName, + useKotlinScript: false, + }) + } + if 0 < kotlinBuildScriptProjectCount { + params = append(params, configBuildingParams{ + name: ConfigNameKotlinScript, + useKotlinScript: true, + }) + } + return params } diff --git a/vendor/github.com/bitrise-io/bitrise-init/steps/cachesteps.go b/vendor/github.com/bitrise-io/bitrise-init/steps/cachesteps.go new file mode 100644 index 0000000..da89625 --- /dev/null +++ b/vendor/github.com/bitrise-io/bitrise-init/steps/cachesteps.go @@ -0,0 +1,63 @@ +package steps + +import bitriseModels "github.com/bitrise-io/bitrise/models" + +func RestoreGradleCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheRestoreGradleID, CacheRestoreGradleVersion) + return stepListItem(stepIDComposite, "", "") +} + +func SaveGradleCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheSaveGradleID, CacheSaveGradleVersion) + return stepListItem(stepIDComposite, "", "") +} + +func RestoreCocoapodsCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheRestoreCocoapodsID, CacheRestoreCocoapodsVersion) + return stepListItem(stepIDComposite, "", "") +} + +func SaveCocoapodsCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheSaveCocoapodsID, CacheSaveCocoapodsVersion) + return stepListItem(stepIDComposite, "", "") +} + +func RestoreCarthageCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheRestoreCarthageID, CacheRestoreCarthageVersion) + return stepListItem(stepIDComposite, "", "") +} + +func SaveCarthageCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheSaveCarthageID, CacheSaveCarthageVersion) + return stepListItem(stepIDComposite, "", "") +} + +func RestoreNPMCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheRestoreNPMID, CacheRestoreNPMVersion) + return stepListItem(stepIDComposite, "", "") +} + +func SaveNPMCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheSaveNPMID, CacheSaveNPMVersion) + return stepListItem(stepIDComposite, "", "") +} + +func RestoreSPMCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheRestoreSPMID, CacheRestoreSPMVersion) + return stepListItem(stepIDComposite, "", "") +} + +func SaveSPMCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheSaveSPMID, CacheSaveSPMVersion) + return stepListItem(stepIDComposite, "", "") +} + +func RestoreDartCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheRestoreDartID, CacheRestoreDartVersion) + return stepListItem(stepIDComposite, "", "") +} + +func SaveDartCache() bitriseModels.StepListItemModel { + stepIDComposite := stepIDComposite(CacheSaveDartID, CacheSaveDartVersion) + return stepListItem(stepIDComposite, "", "") +} diff --git a/vendor/github.com/bitrise-io/bitrise-init/steps/const.go b/vendor/github.com/bitrise-io/bitrise-init/steps/const.go index dc806be..a2f768b 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/steps/const.go +++ b/vendor/github.com/bitrise-io/bitrise-init/steps/const.go @@ -1,258 +1,186 @@ package steps const ( - // ActivateSSHKeyID ... - ActivateSSHKeyID = "activate-ssh-key" - // ActivateSSHKeyVersion ... + ActivateSSHKeyID = "activate-ssh-key" ActivateSSHKeyVersion = "4" ) const ( - // AndroidLintID ... - AndroidLintID = "android-lint" - // AndroidLintVersion ... + AndroidLintID = "android-lint" AndroidLintVersion = "0" ) const ( - // AndroidUnitTestID ... - AndroidUnitTestID = "android-unit-test" - // AndroidUnitTestVersion ... + AndroidUnitTestID = "android-unit-test" AndroidUnitTestVersion = "1" ) const ( - // AndroidBuildID ... - AndroidBuildID = "android-build" - // AndroidBuildVersion ... + AndroidBuildID = "android-build" AndroidBuildVersion = "1" ) const ( - // GitCloneID ... - GitCloneID = "git-clone" - // GitCloneVersion ... - GitCloneVersion = "6" + GitCloneID = "git-clone" + GitCloneVersion = "8" ) const ( - // CachePullID ... - CachePullID = "cache-pull" - // CachePullVersion ... - CachePullVersion = "2" -) + CacheRestoreGradleID = "restore-gradle-cache" + CacheRestoreGradleVersion = "1" + CacheRestoreCocoapodsID = "restore-cocoapods-cache" + CacheRestoreCocoapodsVersion = "1" + CacheRestoreCarthageID = "restore-carthage-cache" + CacheRestoreCarthageVersion = "1" + CacheRestoreNPMID = "restore-npm-cache" + CacheRestoreNPMVersion = "1" + CacheRestoreSPMID = "restore-spm-cache" + CacheRestoreSPMVersion = "1" + CacheRestoreDartID = "restore-dart-cache" + CacheRestoreDartVersion = "1" -const ( - // CachePushID ... - CachePushID = "cache-push" - // CachePushVersion ... - CachePushVersion = "2" + CacheSaveGradleID = "save-gradle-cache" + CacheSaveGradleVersion = "1" + CacheSaveCocoapodsID = "save-cocoapods-cache" + CacheSaveCocoapodsVersion = "1" + CacheSaveCarthageID = "save-carthage-cache" + CacheSaveCarthageVersion = "1" + CacheSaveNPMID = "save-npm-cache" + CacheSaveNPMVersion = "1" + CacheSaveSPMID = "save-spm-cache" + CacheSaveSPMVersion = "1" + CacheSaveDartID = "save-dart-cache" + CacheSaveDartVersion = "1" ) const ( - // CertificateAndProfileInstallerID ... - CertificateAndProfileInstallerID = "certificate-and-profile-installer" - // CertificateAndProfileInstallerVersion ... + CertificateAndProfileInstallerID = "certificate-and-profile-installer" CertificateAndProfileInstallerVersion = "1" ) const ( - // ChangeAndroidVersionCodeAndVersionNameID ... - ChangeAndroidVersionCodeAndVersionNameID = "change-android-versioncode-and-versionname" - // ChangeAndroidVersionCodeAndVersionNameVersion ... + ChangeAndroidVersionCodeAndVersionNameID = "change-android-versioncode-and-versionname" ChangeAndroidVersionCodeAndVersionNameVersion = "1" ) const ( - // DeployToBitriseIoID ... - DeployToBitriseIoID = "deploy-to-bitrise-io" - // DeployToBitriseIoVersion ... + DeployToBitriseIoID = "deploy-to-bitrise-io" DeployToBitriseIoVersion = "2" ) const ( - // ScriptID ... - ScriptID = "script" - // ScriptVersion ... - ScriptVersion = "1" - // ScriptDefaultTitle ... - ScriptDefaultTitle = "Do anything with Script step" -) - -const ( - // SignAPKID ... - SignAPKID = "sign-apk" - // SignAPKVersion ... + SignAPKID = "sign-apk" SignAPKVersion = "1" ) const ( - // InstallMissingAndroidToolsID ... - InstallMissingAndroidToolsID = "install-missing-android-tools" - // InstallMissingAndroidToolsVersion ... + InstallMissingAndroidToolsID = "install-missing-android-tools" InstallMissingAndroidToolsVersion = "3" ) const ( - // FastlaneID ... - FastlaneID = "fastlane" - // FastlaneVersion ... + FastlaneID = "fastlane" FastlaneVersion = "3" ) const ( - // CocoapodsInstallID ... - CocoapodsInstallID = "cocoapods-install" - // CocoapodsInstallVersion ... + CocoapodsInstallID = "cocoapods-install" CocoapodsInstallVersion = "2" ) const ( - // CarthageID ... - CarthageID = "carthage" - // CarthageVersion ... + CarthageID = "carthage" CarthageVersion = "3" ) const ( - // RecreateUserSchemesID ... - RecreateUserSchemesID = "recreate-user-schemes" - // RecreateUserSchemesVersion ... - RecreateUserSchemesVersion = "1" + XcodeArchiveID = "xcode-archive" + XcodeArchiveVersion = "5" ) const ( - // XcodeArchiveID ... - XcodeArchiveID = "xcode-archive" - // XcodeArchiveVersion ... - XcodeArchiveVersion = "4" + XcodeTestID = "xcode-test" + XcodeTestVersion = "5" ) const ( - // XcodeTestID ... - XcodeTestID = "xcode-test" - // XcodeTestVersion ... - XcodeTestVersion = "4" + XcodeBuildForTestID = "xcode-build-for-test" + XcodeBuildForTestVersion = "3" ) const ( - // XcodeBuildForTestID ... - XcodeBuildForTestID = "xcode-build-for-test" - // XcodeBuildForTestVersion ... - XcodeBuildForTestVersion = "1" -) - -const ( - // XcodeArchiveMacID ... - XcodeArchiveMacID = "xcode-archive-mac" - // XcodeArchiveMacVersion ... + XcodeArchiveMacID = "xcode-archive-mac" XcodeArchiveMacVersion = "1" ) const ( - // ExportXCArchiveID ... - ExportXCArchiveID = "export-xcarchive" - // ExportXCArchiveVersion ... + ExportXCArchiveID = "export-xcarchive" ExportXCArchiveVersion = "4" ) const ( - // XcodeTestMacID ... - XcodeTestMacID = "xcode-test-mac" - // XcodeTestMacVersion ... + XcodeTestMacID = "xcode-test-mac" XcodeTestMacVersion = "1" ) const ( - // CordovaArchiveID ... - CordovaArchiveID = "cordova-archive" - // CordovaArchiveVersion ... + CordovaArchiveID = "cordova-archive" CordovaArchiveVersion = "3" ) const ( - // IonicArchiveID ... - IonicArchiveID = "ionic-archive" - // IonicArchiveVersion ... + IonicArchiveID = "ionic-archive" IonicArchiveVersion = "2" ) const ( - // GenerateCordovaBuildConfigID ... - GenerateCordovaBuildConfigID = "generate-cordova-build-configuration" - // GenerateCordovaBuildConfigVersion ... + GenerateCordovaBuildConfigID = "generate-cordova-build-configuration" GenerateCordovaBuildConfigVersion = "0" ) const ( - // JasmineTestRunnerID ... - JasmineTestRunnerID = "jasmine-runner" - // JasmineTestRunnerVersion ... + JasmineTestRunnerID = "jasmine-runner" JasmineTestRunnerVersion = "0" ) const ( - // KarmaJasmineTestRunnerID ... - KarmaJasmineTestRunnerID = "karma-jasmine-runner" - // KarmaJasmineTestRunnerVersion ... + KarmaJasmineTestRunnerID = "karma-jasmine-runner" KarmaJasmineTestRunnerVersion = "0" ) const ( - // NpmID ... - NpmID = "npm" - // NpmVersion ... + NpmID = "npm" NpmVersion = "1" ) const ( - // ExpoDetachID ... - ExpoDetachID = "expo-detach" - // ExpoDetachVersion ... - ExpoDetachVersion = "1" -) - -const ( - // RunEASBuildID ... - RunEASBuildID = "run-eas-build" - // RunEASBuildVersion ... + RunEASBuildID = "run-eas-build" RunEASBuildVersion = "0" ) -// RunEASBuildPlatforms ... var RunEASBuildPlatforms = []string{"all", "android", "ios"} const ( - // YarnID ... - YarnID = "yarn" - // YarnVersion ... + YarnID = "yarn" YarnVersion = "0" ) const ( - // FlutterInstallID ... - FlutterInstallID = "flutter-installer" - // FlutterInstallVersion ... + FlutterInstallID = "flutter-installer" FlutterInstallVersion = "0" ) const ( - // FlutterTestID ... - FlutterTestID = "flutter-test" - // FlutterTestVersion ... + FlutterTestID = "flutter-test" FlutterTestVersion = "1" ) const ( - // FlutterAnalyzeID ... - FlutterAnalyzeID = "flutter-analyze" - // FlutterAnalyzeVersion ... + FlutterAnalyzeID = "flutter-analyze" FlutterAnalyzeVersion = "0" ) const ( - // FlutterBuildID ... - FlutterBuildID = "flutter-build" - // FlutterBuildVersion ... + FlutterBuildID = "flutter-build" FlutterBuildVersion = "0" ) diff --git a/vendor/github.com/bitrise-io/bitrise-init/steps/steps.go b/vendor/github.com/bitrise-io/bitrise-init/steps/steps.go index 3ddb3cf..d9fa167 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/steps/steps.go +++ b/vendor/github.com/bitrise-io/bitrise-init/steps/steps.go @@ -1,6 +1,7 @@ package steps import ( + "github.com/bitrise-io/bitrise-init/models" bitriseModels "github.com/bitrise-io/bitrise/models" envmanModels "github.com/bitrise-io/envman/models" "github.com/bitrise-io/go-utils/pointers" @@ -9,8 +10,7 @@ import ( // PrepareListParams describes the default prepare Step options. type PrepareListParams struct { - ShouldIncludeCache bool - ShouldIncludeActivateSSH bool + SSHKeyActivation models.SSHKeyActivation } func stepIDComposite(ID, version string) string { @@ -37,233 +37,163 @@ func stepListItem(stepIDComposite, title, runIf string, inputs ...envmanModels.E } } -// DefaultPrepareStepList ... -func DefaultPrepareStepList(isIncludeCache bool) []bitriseModels.StepListItemModel { - runIfCondition := `{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}` - stepList := []bitriseModels.StepListItemModel{ - ActivateSSHKeyStepListItem(runIfCondition), - GitCloneStepListItem(), - } - - if isIncludeCache { - stepList = append(stepList, CachePullStepListItem()) - } - - return append(stepList, ScriptSteplistItem(ScriptDefaultTitle)) -} - -// DefaultPrepareStepListV2 ... -func DefaultPrepareStepListV2(params PrepareListParams) []bitriseModels.StepListItemModel { +func DefaultPrepareStepList(params PrepareListParams) []bitriseModels.StepListItemModel { stepList := []bitriseModels.StepListItemModel{} - if params.ShouldIncludeActivateSSH { - stepList = append(stepList, ActivateSSHKeyStepListItem("")) + switch params.SSHKeyActivation { + case models.SSHKeyActivationNone: + { + // No SSH key setup needed + } + case models.SSHKeyActivationMandatory: + { + // This needs the `SSH_RSA_PRIVATE_KEY` env to be defined, which depends on the selected path in the website + // add-new-app flow. + stepList = append(stepList, ActivateSSHKeyStepListItem("")) + } + case models.SSHKeyActivationConditional: + { + // Add the SSH key step just in case, but only run it if the required env var is available. + runCondition := `{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}` + stepList = append(stepList, ActivateSSHKeyStepListItem(runCondition)) + } } stepList = append(stepList, GitCloneStepListItem()) - if params.ShouldIncludeCache { - stepList = append(stepList, CachePullStepListItem()) - } - return stepList } -// DefaultDeployStepList ... -func DefaultDeployStepList(isIncludeCache bool) []bitriseModels.StepListItemModel { - stepList := []bitriseModels.StepListItemModel{ - DeployToBitriseIoStepListItem(), - } - - if isIncludeCache { - stepList = append(stepList, CachePushStepListItem()) - } - - return stepList -} - -// DefaultDeployStepListV2 ... -func DefaultDeployStepListV2(shouldIncludeCache bool) []bitriseModels.StepListItemModel { +func DefaultDeployStepList() []bitriseModels.StepListItemModel { stepList := []bitriseModels.StepListItemModel{} - if shouldIncludeCache { - stepList = append(stepList, CachePushStepListItem()) - } - stepList = append(stepList, DeployToBitriseIoStepListItem()) return stepList } -// ActivateSSHKeyStepListItem ... func ActivateSSHKeyStepListItem(runIfCondition string) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(ActivateSSHKeyID, ActivateSSHKeyVersion) return stepListItem(stepIDComposite, "", runIfCondition) } -// AndroidLintStepListItem ... func AndroidLintStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(AndroidLintID, AndroidLintVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// AndroidUnitTestStepListItem ... func AndroidUnitTestStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(AndroidUnitTestID, AndroidUnitTestVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// AndroidBuildStepListItem ... func AndroidBuildStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(AndroidBuildID, AndroidBuildVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// GitCloneStepListItem ... func GitCloneStepListItem() bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(GitCloneID, GitCloneVersion) return stepListItem(stepIDComposite, "", "") } -// CachePullStepListItem ... -func CachePullStepListItem() bitriseModels.StepListItemModel { - stepIDComposite := stepIDComposite(CachePullID, CachePullVersion) - return stepListItem(stepIDComposite, "", "") -} - -// CachePushStepListItem ... -func CachePushStepListItem() bitriseModels.StepListItemModel { - stepIDComposite := stepIDComposite(CachePushID, CachePushVersion) - return stepListItem(stepIDComposite, "", "") -} - -// CertificateAndProfileInstallerStepListItem ... func CertificateAndProfileInstallerStepListItem() bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(CertificateAndProfileInstallerID, CertificateAndProfileInstallerVersion) return stepListItem(stepIDComposite, "", "") } -// ChangeAndroidVersionCodeAndVersionNameStepListItem ... func ChangeAndroidVersionCodeAndVersionNameStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(ChangeAndroidVersionCodeAndVersionNameID, ChangeAndroidVersionCodeAndVersionNameVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// DeployToBitriseIoStepListItem ... func DeployToBitriseIoStepListItem() bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(DeployToBitriseIoID, DeployToBitriseIoVersion) return stepListItem(stepIDComposite, "", "") } -// ScriptSteplistItem ... -func ScriptSteplistItem(title string, inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { - stepIDComposite := stepIDComposite(ScriptID, ScriptVersion) - return stepListItem(stepIDComposite, title, "", inputs...) -} - -// SignAPKStepListItem ... func SignAPKStepListItem() bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(SignAPKID, SignAPKVersion) return stepListItem(stepIDComposite, "", `{{getenv "BITRISEIO_ANDROID_KEYSTORE_URL" | ne ""}}`) } -// InstallMissingAndroidToolsStepListItem .... func InstallMissingAndroidToolsStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(InstallMissingAndroidToolsID, InstallMissingAndroidToolsVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// FastlaneStepListItem ... func FastlaneStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(FastlaneID, FastlaneVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// CocoapodsInstallStepListItem ... func CocoapodsInstallStepListItem() bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(CocoapodsInstallID, CocoapodsInstallVersion) - return stepListItem(stepIDComposite, "", "") + return stepListItem(stepIDComposite, "", "", envmanModels.EnvironmentItemModel{ + "is_cache_disabled": "true", // Disable legacy caching when used in workflows with KV caching + }) } -// CarthageStepListItem ... func CarthageStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(CarthageID, CarthageVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// RecreateUserSchemesStepListItem ... -func RecreateUserSchemesStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { - stepIDComposite := stepIDComposite(RecreateUserSchemesID, RecreateUserSchemesVersion) - return stepListItem(stepIDComposite, "", "", inputs...) -} - -// XcodeArchiveStepListItem ... func XcodeArchiveStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(XcodeArchiveID, XcodeArchiveVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// XcodeBuildForTestStepListItem ... func XcodeBuildForTestStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(XcodeBuildForTestID, XcodeBuildForTestVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// XcodeTestStepListItem ... func XcodeTestStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(XcodeTestID, XcodeTestVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// XcodeArchiveMacStepListItem ... func XcodeArchiveMacStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(XcodeArchiveMacID, XcodeArchiveMacVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// ExportXCArchiveStepListItem ... func ExportXCArchiveStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(ExportXCArchiveID, ExportXCArchiveVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// XcodeTestMacStepListItem ... func XcodeTestMacStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(XcodeTestMacID, XcodeTestMacVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// CordovaArchiveStepListItem ... func CordovaArchiveStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(CordovaArchiveID, CordovaArchiveVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// IonicArchiveStepListItem ... func IonicArchiveStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(IonicArchiveID, IonicArchiveVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// GenerateCordovaBuildConfigStepListItem ... func GenerateCordovaBuildConfigStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(GenerateCordovaBuildConfigID, GenerateCordovaBuildConfigVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// JasmineTestRunnerStepListItem ... func JasmineTestRunnerStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(JasmineTestRunnerID, JasmineTestRunnerVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// KarmaJasmineTestRunnerStepListItem ... func KarmaJasmineTestRunnerStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(KarmaJasmineTestRunnerID, KarmaJasmineTestRunnerVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// NpmStepListItem ... func NpmStepListItem(command, workdir string) bitriseModels.StepListItemModel { var inputs []envmanModels.EnvironmentItemModel if workdir != "" { @@ -277,7 +207,6 @@ func NpmStepListItem(command, workdir string) bitriseModels.StepListItemModel { return stepListItem(stepIDComposite, "", "", inputs...) } -// RunEASBuildStepListItem ... func RunEASBuildStepListItem(workdir, platform string) bitriseModels.StepListItemModel { var inputs []envmanModels.EnvironmentItemModel if platform != "" { @@ -290,7 +219,6 @@ func RunEASBuildStepListItem(workdir, platform string) bitriseModels.StepListIte return stepListItem(stepIDComposite, "", "", inputs...) } -// YarnStepListItem ... func YarnStepListItem(command, workdir string) bitriseModels.StepListItemModel { var inputs []envmanModels.EnvironmentItemModel if workdir != "" { @@ -304,25 +232,37 @@ func YarnStepListItem(command, workdir string) bitriseModels.StepListItemModel { return stepListItem(stepIDComposite, "", "", inputs...) } -// FlutterInstallStepListItem ... -func FlutterInstallStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { +func FlutterInstallStepListItem(version string, isUpdate bool) bitriseModels.StepListItemModel { + const versionInputKey = "version" + const isUpdateInputKey = "is_update" + + var inputs []envmanModels.EnvironmentItemModel + + if version != "" { + inputs = append(inputs, envmanModels.EnvironmentItemModel{versionInputKey: version}) + } + + isUpdateStr := "false" + if isUpdate { + isUpdateStr = "true" + } + + inputs = append(inputs, envmanModels.EnvironmentItemModel{isUpdateInputKey: isUpdateStr}) + stepIDComposite := stepIDComposite(FlutterInstallID, FlutterInstallVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// FlutterTestStepListItem ... func FlutterTestStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(FlutterTestID, FlutterTestVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// FlutterAnalyzeStepListItem ... func FlutterAnalyzeStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(FlutterAnalyzeID, FlutterAnalyzeVersion) return stepListItem(stepIDComposite, "", "", inputs...) } -// FlutterBuildStepListItem ... func FlutterBuildStepListItem(inputs ...envmanModels.EnvironmentItemModel) bitriseModels.StepListItemModel { stepIDComposite := stepIDComposite(FlutterBuildID, FlutterBuildVersion) return stepListItem(stepIDComposite, "", "", inputs...) diff --git a/vendor/github.com/bitrise-io/bitrise-init/utility/utility.go b/vendor/github.com/bitrise-io/bitrise-init/utility/utility.go index cd0de28..338684b 100644 --- a/vendor/github.com/bitrise-io/bitrise-init/utility/utility.go +++ b/vendor/github.com/bitrise-io/bitrise-init/utility/utility.go @@ -2,6 +2,7 @@ package utility import ( "encoding/json" + "os" "path/filepath" "strings" @@ -55,3 +56,12 @@ func RelPath(basePth, pth string) (string, error) { return filepath.Rel(absBasePth, absPth) } + +// FileExists ... +func FileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} diff --git a/vendor/github.com/bitrise-io/bitrise/exitcode/exitcode.go b/vendor/github.com/bitrise-io/bitrise/exitcode/exitcode.go new file mode 100644 index 0000000..05a2906 --- /dev/null +++ b/vendor/github.com/bitrise-io/bitrise/exitcode/exitcode.go @@ -0,0 +1,8 @@ +package exitcode + +const ( + CLISuccess = 0 + CLIFailed = 1 + CLIAbortedWithCustomTimeout = 91 + CLIAbortedWithNoOutputTimeout = 92 +) diff --git a/vendor/github.com/bitrise-io/bitrise/models/models.go b/vendor/github.com/bitrise-io/bitrise/models/models.go index f4eb4fe..b5e5497 100644 --- a/vendor/github.com/bitrise-io/bitrise/models/models.go +++ b/vendor/github.com/bitrise-io/bitrise/models/models.go @@ -1,6 +1,8 @@ package models import ( + "fmt" + "strings" "time" envmanModels "github.com/bitrise-io/envman/models" @@ -8,21 +10,8 @@ import ( ) const ( - // StepRunStatusCodeSuccess ... - StepRunStatusCodeSuccess = 0 - // StepRunStatusCodeFailed ... - StepRunStatusCodeFailed = 1 - // StepRunStatusCodeFailedSkippable ... - StepRunStatusCodeFailedSkippable = 2 - // StepRunStatusCodeSkipped ... - StepRunStatusCodeSkipped = 3 - // StepRunStatusCodeSkippedWithRunIf ... - StepRunStatusCodeSkippedWithRunIf = 4 - // StepRunStatusCodePreparationFailed ... - StepRunStatusCodePreparationFailed = 5 - - // Version ... - Version = "11" + // FormatVersion ... + FormatVersion = "13" ) // StepListItemModel ... @@ -30,7 +19,10 @@ type StepListItemModel map[string]stepmanModels.StepModel // PipelineModel ... type PipelineModel struct { - Stages []StageListItemModel `json:"stages,omitempty" yaml:"stages,omitempty"` + Title string `json:"title,omitempty" yaml:"title,omitempty"` + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + Stages []StageListItemModel `json:"stages,omitempty" yaml:"stages,omitempty"` } // StageListItemModel ... @@ -38,7 +30,13 @@ type StageListItemModel map[string]StageModel // StageModel ... type StageModel struct { - Workflows []WorkflowListItemModel `json:"workflows,omitempty" yaml:"workflows,omitempty"` + Title string `json:"title,omitempty" yaml:"title,omitempty"` + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + ShouldAlwaysRun bool `json:"should_always_run,omitempty" yaml:"should_always_run,omitempty"` + AbortOnFail bool `json:"abort_on_fail,omitempty" yaml:"abort_on_fail,omitempty"` + RunIf string `json:"run_if,omitempty" yaml:"run_if,omitempty"` + Workflows []WorkflowListItemModel `json:"workflows,omitempty" yaml:"workflows,omitempty"` } // WorkflowListItemModel ... @@ -115,7 +113,8 @@ type BitriseDataModel struct { // StepIDData ... // structured representation of a composite-step-id -// a composite step id is: step-lib-source::step-id@1.0.0 +// +// a composite step id is: step-lib-source::step-id@1.0.0 type StepIDData struct { // SteplibSource : steplib source uri, or in case of local path just "path", and in case of direct git url just "git" SteplibSource string @@ -134,6 +133,7 @@ type BuildRunStartModel struct { // BuildRunResultsModel ... type BuildRunResultsModel struct { + WorkflowID string `json:"workflow_id" yaml:"workflow_id"` EventName string `json:"event_name" yaml:"event_name"` ProjectType string `json:"project_type" yaml:"project_type"` StartTime time.Time `json:"start_time" yaml:"start_time"` @@ -148,12 +148,114 @@ type BuildRunResultsModel struct { type StepRunResultsModel struct { StepInfo stepmanModels.StepInfoModel `json:"step_info" yaml:"step_info"` StepInputs map[string]string `json:"step_inputs" yaml:"step_inputs"` - Status int `json:"status" yaml:"status"` + Status StepRunStatus `json:"status" yaml:"status"` Idx int `json:"idx" yaml:"idx"` RunTime time.Duration `json:"run_time" yaml:"run_time"` StartTime time.Time `json:"start_time" yaml:"start_time"` ErrorStr string `json:"error_str" yaml:"error_str"` ExitCode int `json:"exit_code" yaml:"exit_code"` + + Timeout time.Duration `json:"-"` + NoOutputTimeout time.Duration `json:"-"` +} + +// StepError ... +type StepError struct { + Code int `json:"code"` + Message string `json:"message"` +} + +func (s StepRunResultsModel) StatusReasonAndErrors() (string, []StepError) { + switch s.Status { + case StepRunStatusCodeSuccess: + return "", nil + case StepRunStatusCodeSkipped: + return s.statusReason(), nil + case StepRunStatusCodeSkippedWithRunIf: + return s.statusReason(), nil + case StepRunStatusCodeFailedSkippable: + return s.statusReason(), s.error() + case StepRunStatusCodeFailed: + return "", s.error() + case StepRunStatusCodePreparationFailed: + return "", s.error() + case StepRunStatusAbortedWithCustomTimeout: + return "", s.error() + case StepRunStatusAbortedWithNoOutputTimeout: + return "", s.error() + default: + return "", nil + } +} + +func (s StepRunResultsModel) statusReason() string { + switch s.Status { + case StepRunStatusCodeSuccess, + StepRunStatusCodeFailed, + StepRunStatusCodePreparationFailed, + StepRunStatusAbortedWithCustomTimeout, + StepRunStatusAbortedWithNoOutputTimeout: + return "" + case StepRunStatusCodeFailedSkippable: + return `This Step failed, but it was marked as "is_skippable", so the build continued.` + case StepRunStatusCodeSkipped: + return `This Step was skipped, because a previous Step failed, and this Step was not marked "is_always_run".` + case StepRunStatusCodeSkippedWithRunIf: + return fmt.Sprintf(`This Step was skipped, because its "run_if" expression evaluated to false. +The "run_if" expression was: %s`, *s.StepInfo.Step.RunIf) + } + + return "" +} + +func (s StepRunResultsModel) error() []StepError { + message := "" + + switch s.Status { + case StepRunStatusCodeSuccess, + StepRunStatusCodeSkipped, + StepRunStatusCodeSkippedWithRunIf: + return nil + case StepRunStatusCodeFailedSkippable, + StepRunStatusCodeFailed, + StepRunStatusCodePreparationFailed: + message = s.ErrorStr + case StepRunStatusAbortedWithCustomTimeout: + message = fmt.Sprintf("This Step timed out after %s.", formatStatusReasonTimeInterval(s.Timeout)) + case StepRunStatusAbortedWithNoOutputTimeout: + message = fmt.Sprintf("This Step failed, because it has not sent any output for %s.", formatStatusReasonTimeInterval(s.NoOutputTimeout)) + } + + return []StepError{{ + Code: s.ExitCode, + Message: message, + }} +} + +func formatStatusReasonTimeInterval(timeInterval time.Duration) string { + var remaining int = int(timeInterval / time.Second) + h := int(remaining / 3600) + remaining = remaining - h*3600 + m := int(remaining / 60) + remaining = remaining - m*60 + s := remaining + + var formattedTimeInterval = "" + if h > 0 { + formattedTimeInterval += fmt.Sprintf("%dh ", h) + } + + if m > 0 { + formattedTimeInterval += fmt.Sprintf("%dm ", m) + } + + if s > 0 { + formattedTimeInterval += fmt.Sprintf("%ds", s) + } + + formattedTimeInterval = strings.TrimSpace(formattedTimeInterval) + + return formattedTimeInterval } // TestResultStepInfo ... diff --git a/vendor/github.com/bitrise-io/bitrise/models/models_methods.go b/vendor/github.com/bitrise-io/bitrise/models/models_methods.go index 389c313..65889cc 100644 --- a/vendor/github.com/bitrise-io/bitrise/models/models_methods.go +++ b/vendor/github.com/bitrise-io/bitrise/models/models_methods.go @@ -6,6 +6,7 @@ import ( "regexp" "strings" + "github.com/bitrise-io/bitrise/exitcode" envmanModels "github.com/bitrise-io/envman/models" "github.com/bitrise-io/go-utils/pointers" stepmanModels "github.com/bitrise-io/stepman/models" @@ -551,6 +552,11 @@ func validateStages(config *BitriseDataModel) ([]string, error) { for _, stageWorkflow := range stage.Workflows { found := false stageWorkflowID, err := GetWorkflowIDFromListItemModel(stageWorkflow) + + if isUtilityWorkflow(stageWorkflowID) { + return stageWarnings, fmt.Errorf("workflow (%s) defined in stage (%s), is a utility workflow", stageWorkflowID, ID) + } + if err != nil { return stageWarnings, err } @@ -569,6 +575,10 @@ func validateStages(config *BitriseDataModel) ([]string, error) { return stageWarnings, nil } +func isUtilityWorkflow(workflowID string) bool { + return strings.HasPrefix(workflowID, "_") +} + func validateWorkflows(config *BitriseDataModel) ([]string, error) { workflowWarnings := make([]string, 0) for ID, workflow := range config.Workflows { @@ -963,6 +973,9 @@ func MergeStepWith(step, otherStep stepmanModels.StepModel) (stepmanModels.StepM if otherStep.Timeout != nil { step.Timeout = pointers.NewIntPtr(*otherStep.Timeout) } + if otherStep.NoOutputTimeout != nil { + step.NoOutputTimeout = pointers.NewIntPtr(*otherStep.NoOutputTimeout) + } for _, input := range step.Inputs { key, _, err := input.GetKeyValuePair() @@ -1026,15 +1039,26 @@ func GetStageIDFromListItemModel(stageListItem StageListItemModel) (string, erro // ---------------------------- // --- StepIDData +// GetStepIDAndStep returns the Step ID and Step model described by the stepListItem. +// Use this on validated BitriseDataModels. +func (stepListItem StepListItemModel) GetStepIDAndStep() (string, stepmanModels.StepModel) { + for key, value := range stepListItem { + return key, value + } + return "", stepmanModels.StepModel{} +} + // GetStepIDStepDataPair ... func GetStepIDStepDataPair(stepListItem StepListItemModel) (string, stepmanModels.StepModel, error) { + if len(stepListItem) == 0 { + return "", stepmanModels.StepModel{}, errors.New("StepListItem does not contain a key-value pair") + } + if len(stepListItem) > 1 { return "", stepmanModels.StepModel{}, errors.New("StepListItem contains more than 1 key-value pair") } - for key, value := range stepListItem { - return key, value, nil - } - return "", stepmanModels.StepModel{}, errors.New("StepListItem does not contain a key-value pair") + stepID, step := stepListItem.GetStepIDAndStep() + return stepID, step, nil } // detaches source from the step node @@ -1126,9 +1150,6 @@ func CreateStepIDDataFromString(compositeVersionStr, defaultStepLibSource string } version := getStepVersion(compositeVersionStr) - if src == "git" && version == "" { - version = "master" - } return StepIDData{ IDorURI: id, @@ -1163,26 +1184,58 @@ func (sIDData StepIDData) IsUniqueResourceID() bool { // ---------------------------- // --- BuildRunResults -// IsStepLibUpdated ... func (buildRes BuildRunResultsModel) IsStepLibUpdated(stepLib string) bool { return (buildRes.StepmanUpdates[stepLib] > 0) } -// IsBuildFailed ... func (buildRes BuildRunResultsModel) IsBuildFailed() bool { return len(buildRes.FailedSteps) > 0 } -// HasFailedSkippableSteps ... +func (buildRes BuildRunResultsModel) ExitCode() int { + if !buildRes.IsBuildFailed() { + return 0 + } + + if buildRes.isBuildAbortedWithNoOutputTimeout() { + return exitcode.CLIAbortedWithNoOutputTimeout + } + + if buildRes.isBuildAbortedWithTimeout() { + return exitcode.CLIAbortedWithCustomTimeout + } + + return exitcode.CLIFailed +} + func (buildRes BuildRunResultsModel) HasFailedSkippableSteps() bool { return len(buildRes.FailedSkippableSteps) > 0 } -// ResultsCount ... func (buildRes BuildRunResultsModel) ResultsCount() int { return len(buildRes.SuccessSteps) + len(buildRes.FailedSteps) + len(buildRes.FailedSkippableSteps) + len(buildRes.SkippedSteps) } +func (buildRes BuildRunResultsModel) isBuildAbortedWithTimeout() bool { + for _, stepResult := range buildRes.FailedSteps { + if stepResult.Status == StepRunStatusAbortedWithCustomTimeout { + return true + } + } + + return false +} + +func (buildRes BuildRunResultsModel) isBuildAbortedWithNoOutputTimeout() bool { + for _, stepResult := range buildRes.FailedSteps { + if stepResult.Status == StepRunStatusAbortedWithNoOutputTimeout { + return true + } + } + + return false +} + func (buildRes BuildRunResultsModel) unorderedResults() []StepRunResultsModel { results := append([]StepRunResultsModel{}, buildRes.SuccessSteps...) results = append(results, buildRes.FailedSteps...) @@ -1190,7 +1243,6 @@ func (buildRes BuildRunResultsModel) unorderedResults() []StepRunResultsModel { return append(results, buildRes.SkippedSteps...) } -//OrderedResults ... func (buildRes BuildRunResultsModel) OrderedResults() []StepRunResultsModel { results := make([]StepRunResultsModel, buildRes.ResultsCount()) unorderedResults := buildRes.unorderedResults() diff --git a/vendor/github.com/bitrise-io/bitrise/models/step_run_status.go b/vendor/github.com/bitrise-io/bitrise/models/step_run_status.go new file mode 100644 index 0000000..008636e --- /dev/null +++ b/vendor/github.com/bitrise-io/bitrise/models/step_run_status.go @@ -0,0 +1,79 @@ +package models + +// StepRunStatus ... +type StepRunStatus int + +const ( + StepRunStatusCodeSuccess StepRunStatus = 0 + StepRunStatusCodeFailed StepRunStatus = 1 + StepRunStatusCodeFailedSkippable StepRunStatus = 2 + StepRunStatusCodeSkipped StepRunStatus = 3 + StepRunStatusCodeSkippedWithRunIf StepRunStatus = 4 + StepRunStatusCodePreparationFailed StepRunStatus = 5 + StepRunStatusAbortedWithCustomTimeout StepRunStatus = 7 // step times out due to a custom timeout + StepRunStatusAbortedWithNoOutputTimeout StepRunStatus = 8 // step times out due to no output received (hang) +) + +func NewStepRunStatus(status string) StepRunStatus { + switch status { + case "success": + return StepRunStatusCodeSuccess + case "failed": + return StepRunStatusCodeFailed + case "failed_skippable": + return StepRunStatusCodeFailedSkippable + case "skipped": + return StepRunStatusCodeSkipped + case "skipped_with_run_if": + return StepRunStatusCodeSkippedWithRunIf + case "preparation_failed": + return StepRunStatusCodePreparationFailed + case "aborted_with_custom_timeout": + return StepRunStatusAbortedWithCustomTimeout + case "aborted_with_no_output": + return StepRunStatusAbortedWithNoOutputTimeout + default: + return -1 + } +} + +func (s StepRunStatus) String() string { + switch s { + case StepRunStatusCodeSuccess: + return "success" + case StepRunStatusCodeFailed: + return "failed" + case StepRunStatusCodeFailedSkippable: + return "failed_skippable" + case StepRunStatusCodeSkipped: + return "skipped" + case StepRunStatusCodeSkippedWithRunIf: + return "skipped_with_run_if" + case StepRunStatusCodePreparationFailed: + return "preparation_failed" + case StepRunStatusAbortedWithCustomTimeout: + return "aborted_with_custom_timeout" + case StepRunStatusAbortedWithNoOutputTimeout: + return "aborted_with_no_output" + default: + return "unknown" + } +} + +func (s StepRunStatus) Name() string { + switch s { + case StepRunStatusCodeSuccess: + return "" + case StepRunStatusCodeFailed, + StepRunStatusCodePreparationFailed, + StepRunStatusCodeFailedSkippable, + StepRunStatusAbortedWithCustomTimeout, + StepRunStatusAbortedWithNoOutputTimeout: + return "Failed" + case StepRunStatusCodeSkipped, + StepRunStatusCodeSkippedWithRunIf: + return "Skipped" + default: + return "" + } +} diff --git a/vendor/github.com/bitrise-io/bitrise/models/workflow_run_plan.go b/vendor/github.com/bitrise-io/bitrise/models/workflow_run_plan.go new file mode 100644 index 0000000..f0de669 --- /dev/null +++ b/vendor/github.com/bitrise-io/bitrise/models/workflow_run_plan.go @@ -0,0 +1,37 @@ +package models + +import "time" + +type WorkflowRunModes struct { + CIMode bool + PRMode bool + DebugMode bool + SecretFilteringMode bool + SecretEnvsFilteringMode bool + NoOutputTimeout time.Duration +} + +type StepExecutionPlan struct { + UUID string `json:"uuid"` + StepID string `json:"step_id"` +} + +type WorkflowExecutionPlan struct { + UUID string `json:"uuid"` + WorkflowID string `json:"workflow_id"` + Steps []StepExecutionPlan `json:"steps"` +} + +type WorkflowRunPlan struct { + Version string `json:"version"` + LogFormatVersion string `json:"log_format_version"` + + CIMode bool `json:"ci_mode"` + PRMode bool `json:"pr_mode"` + DebugMode bool `json:"debug_mode"` + NoOutputTimeoutMode bool `json:"no_output_timeout_mode"` + SecretFilteringMode bool `json:"secret_filtering_mode"` + SecretEnvsFilteringMode bool `json:"secret_envs_filtering_mode"` + + ExecutionPlan []WorkflowExecutionPlan `json:"execution_plan"` +} diff --git a/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go b/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go index 32c6ba4..5ad75d6 100644 --- a/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go +++ b/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go @@ -66,15 +66,10 @@ func RubyInstallType() InstallType { installType = BrewRuby } else if cmdExist("rvm", "-v") { installType = RVMRuby + } else if cmdExist("asdf") && strings.Contains(whichRuby, ".asdf/shims/ruby") { + installType = ASDFRuby } else if cmdExist("rbenv", "-v") { installType = RbenvRuby - } else if cmdExist("asdf") { - // asdf doesn't store its installs in a definite location, - // but it does store its shims in a 'shims' directory, which - // is what we'll get from the `which ruby` call above. - if strings.Contains(whichRuby, "shims/ruby") { - installType = ASDFRuby - } } return installType diff --git a/vendor/github.com/bitrise-io/go-steputils/v2/ruby/environment.go b/vendor/github.com/bitrise-io/go-steputils/v2/ruby/environment.go index 63d32f2..3d8a021 100644 --- a/vendor/github.com/bitrise-io/go-steputils/v2/ruby/environment.go +++ b/vendor/github.com/bitrise-io/go-steputils/v2/ruby/environment.go @@ -80,8 +80,6 @@ func rubyInstallType(cmdLocator env.CommandLocator) InstallType { installType = BrewRuby } else if _, err := cmdLocator.LookPath("rvm"); err == nil { installType = RVMRuby - } else if _, err := cmdLocator.LookPath("rbenv"); err == nil { - installType = RbenvRuby } else if _, err := cmdLocator.LookPath("asdf"); err == nil { // asdf doesn't store its installs in a definite location, // but it does store its shims in a 'shims' directory, which @@ -89,6 +87,8 @@ func rubyInstallType(cmdLocator env.CommandLocator) InstallType { if strings.Contains(pth, "shims/ruby") { installType = ASDFRuby } + } else if _, err := cmdLocator.LookPath("rbenv"); err == nil { + installType = RbenvRuby } return installType diff --git a/vendor/github.com/bitrise-io/stepman/models/models.go b/vendor/github.com/bitrise-io/stepman/models/models.go index 7ab6ea6..2b502f1 100644 --- a/vendor/github.com/bitrise-io/stepman/models/models.go +++ b/vendor/github.com/bitrise-io/stepman/models/models.go @@ -63,11 +63,17 @@ type SwiftStepToolkitModel struct { ExecutableName string `json:"executable_name,omitempty" yaml:"executable_name,omitempty"` } +// KotlinStepToolkitModel ... +type KotlinStepToolkitModel struct { + ExecutableName string `json:"executable_name,omitempty" yaml:"executable_name,omitempty"` +} + // StepToolkitModel ... type StepToolkitModel struct { - Bash *BashStepToolkitModel `json:"bash,omitempty" yaml:"bash,omitempty"` - Go *GoStepToolkitModel `json:"go,omitempty" yaml:"go,omitempty"` - Swift *SwiftStepToolkitModel `json:"swift,omitempty" yaml:"swift,omitempty"` + Bash *BashStepToolkitModel `json:"bash,omitempty" yaml:"bash,omitempty"` + Go *GoStepToolkitModel `json:"go,omitempty" yaml:"go,omitempty"` + Swift *SwiftStepToolkitModel `json:"swift,omitempty" yaml:"swift,omitempty"` + Kotlin *KotlinStepToolkitModel `json:"kotlin,omitempty" yaml:"kotlin,omitempty"` } // StepModel ... @@ -99,9 +105,12 @@ type StepModel struct { // steps will run which are marked with IsAlwaysRun. IsSkippable *bool `json:"is_skippable,omitempty" yaml:"is_skippable,omitempty"` // RunIf : only run the step if the template example evaluates to true - RunIf *string `json:"run_if,omitempty" yaml:"run_if,omitempty"` - Timeout *int `json:"timeout,omitempty" yaml:"timeout,omitempty"` - Meta map[string]interface{} `json:"meta,omitempty" yaml:"meta,omitempty"` + RunIf *string `json:"run_if,omitempty" yaml:"run_if,omitempty"` + Timeout *int `json:"timeout,omitempty" yaml:"timeout,omitempty"` + // The timeout (in seconds) until a Step with no output (stdout/stderr) is aborted + // 0 means timeout is disabled. + NoOutputTimeout *int `json:"no_output_timeout,omitempty" yaml:"no_output_timeout,omitempty"` + Meta map[string]interface{} `json:"meta,omitempty" yaml:"meta,omitempty"` // Inputs []envmanModels.EnvironmentItemModel `json:"inputs,omitempty" yaml:"inputs,omitempty"` Outputs []envmanModels.EnvironmentItemModel `json:"outputs,omitempty" yaml:"outputs,omitempty"` diff --git a/vendor/github.com/bitrise-io/stepman/models/models_methods.go b/vendor/github.com/bitrise-io/stepman/models/models_methods.go index 87928d8..c7ef9c8 100644 --- a/vendor/github.com/bitrise-io/stepman/models/models_methods.go +++ b/vendor/github.com/bitrise-io/stepman/models/models_methods.go @@ -177,6 +177,10 @@ func (step *StepModel) AuditBeforeShare() error { return errors.New("Invalid step: timeout less then 0") } + if step.NoOutputTimeout != nil && *step.NoOutputTimeout < 0 { + return errors.New("Invalid step: 'no_output_timeout' is less then 0") + } + return step.ValidateInputAndOutputEnvs(true) } @@ -230,6 +234,7 @@ func (step *StepModel) FillMissingDefaults() error { if step.Timeout == nil { step.Timeout = pointers.NewIntPtr(DefaultTimeout) } + // NoOutputTimeout is left as is, so we can tell when it is nil (unset) vs set to 0 (disabled). for _, input := range step.Inputs { err := input.FillMissingDefaults() diff --git a/vendor/github.com/bitrise-io/stepman/models/version_constraint.go b/vendor/github.com/bitrise-io/stepman/models/version_constraint.go index e8cbcae..783ec88 100644 --- a/vendor/github.com/bitrise-io/stepman/models/version_constraint.go +++ b/vendor/github.com/bitrise-io/stepman/models/version_constraint.go @@ -4,8 +4,6 @@ import ( "fmt" "strconv" "strings" - - "github.com/bitrise-io/go-utils/log" ) // Semver represents a semantic version @@ -154,7 +152,6 @@ func latestMatchingStepVersion(constraint VersionConstraint, stepVersions StepGr for fullVersion, step := range stepVersions.Versions { stepVersion, err := parseSemver(fullVersion) if err != nil { - log.Warnf("Invalid step (%s) version: %s", step.Source, fullVersion) continue } if stepVersion.Major != constraint.Version.Major || @@ -184,7 +181,6 @@ func latestMatchingStepVersion(constraint VersionConstraint, stepVersions StepGr for fullVersion, step := range stepVersions.Versions { stepVersion, err := parseSemver(fullVersion) if err != nil { - log.Warnf("Invalid step (%s) version: %s", step.Source, fullVersion) continue } if stepVersion.Major != constraint.Version.Major { diff --git a/vendor/github.com/gofrs/uuid/README.md b/vendor/github.com/gofrs/uuid/README.md index f5db14f..4f73bec 100644 --- a/vendor/github.com/gofrs/uuid/README.md +++ b/vendor/github.com/gofrs/uuid/README.md @@ -17,7 +17,7 @@ This package supports the following UUID versions: * Version 5, based on SHA-1 hashing of a named value (RFC-4122) This package also supports experimental Universally Unique Identifier implementations based on a -[draft RFC](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03) that updates RFC-4122 +[draft RFC](https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html) that updates RFC-4122 * Version 6, a k-sortable id based on timestamp, and field-compatible with v1 (draft-peabody-dispatch-new-uuid-format, RFC-4122) * Version 7, a k-sortable id based on timestamp (draft-peabody-dispatch-new-uuid-format, RFC-4122) @@ -114,4 +114,4 @@ func main() { * [RFC-4122](https://tools.ietf.org/html/rfc4122) * [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01) -* [New UUID Formats RFC Draft (Peabody) Rev 03](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03) +* [New UUID Formats RFC Draft (Peabody) Rev 04](https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#) diff --git a/vendor/github.com/gofrs/uuid/codec.go b/vendor/github.com/gofrs/uuid/codec.go index e3014c6..6650264 100644 --- a/vendor/github.com/gofrs/uuid/codec.go +++ b/vendor/github.com/gofrs/uuid/codec.go @@ -22,8 +22,7 @@ package uuid import ( - "bytes" - "encoding/hex" + "errors" "fmt" ) @@ -45,11 +44,77 @@ func FromBytesOrNil(input []byte) UUID { return uuid } +var errInvalidFormat = errors.New("uuid: invalid UUID format") + +func fromHexChar(c byte) byte { + switch { + case '0' <= c && c <= '9': + return c - '0' + case 'a' <= c && c <= 'f': + return c - 'a' + 10 + case 'A' <= c && c <= 'F': + return c - 'A' + 10 + } + return 255 +} + +// Parse parses the UUID stored in the string text. Parsing and supported +// formats are the same as UnmarshalText. +func (u *UUID) Parse(s string) error { + switch len(s) { + case 32: // hash + case 36: // canonical + case 34, 38: + if s[0] != '{' || s[len(s)-1] != '}' { + return fmt.Errorf("uuid: incorrect UUID format in string %q", s) + } + s = s[1 : len(s)-1] + case 41, 45: + if s[:9] != "urn:uuid:" { + return fmt.Errorf("uuid: incorrect UUID format in string %q", s[:9]) + } + s = s[9:] + default: + return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(s), s) + } + // canonical + if len(s) == 36 { + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return fmt.Errorf("uuid: incorrect UUID format in string %q", s) + } + for i, x := range [16]byte{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34, + } { + v1 := fromHexChar(s[x]) + v2 := fromHexChar(s[x+1]) + if v1|v2 == 255 { + return errInvalidFormat + } + u[i] = (v1 << 4) | v2 + } + return nil + } + // hash like + for i := 0; i < 32; i += 2 { + v1 := fromHexChar(s[i]) + v2 := fromHexChar(s[i+1]) + if v1|v2 == 255 { + return errInvalidFormat + } + u[i/2] = (v1 << 4) | v2 + } + return nil +} + // FromString returns a UUID parsed from the input string. // Input is expected in a form accepted by UnmarshalText. -func FromString(input string) (UUID, error) { - u := UUID{} - err := u.UnmarshalText([]byte(input)) +func FromString(text string) (UUID, error) { + var u UUID + err := u.Parse(text) return u, err } @@ -66,133 +131,90 @@ func FromStringOrNil(input string) UUID { // MarshalText implements the encoding.TextMarshaler interface. // The encoding is the same as returned by the String() method. func (u UUID) MarshalText() ([]byte, error) { - return []byte(u.String()), nil + var buf [36]byte + encodeCanonical(buf[:], u) + return buf[:], nil } // UnmarshalText implements the encoding.TextUnmarshaler interface. // Following formats are supported: // -// "6ba7b810-9dad-11d1-80b4-00c04fd430c8", -// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", -// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" -// "6ba7b8109dad11d180b400c04fd430c8" -// "{6ba7b8109dad11d180b400c04fd430c8}", -// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8" +// "6ba7b810-9dad-11d1-80b4-00c04fd430c8", +// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", +// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" +// "6ba7b8109dad11d180b400c04fd430c8" +// "{6ba7b8109dad11d180b400c04fd430c8}", +// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8" // // ABNF for supported UUID text representation follows: // -// URN := 'urn' -// UUID-NID := 'uuid' -// -// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | -// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | -// 'A' | 'B' | 'C' | 'D' | 'E' | 'F' +// URN := 'urn' +// UUID-NID := 'uuid' // -// hexoct := hexdig hexdig -// 2hexoct := hexoct hexoct -// 4hexoct := 2hexoct 2hexoct -// 6hexoct := 4hexoct 2hexoct -// 12hexoct := 6hexoct 6hexoct +// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | +// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | +// 'A' | 'B' | 'C' | 'D' | 'E' | 'F' // -// hashlike := 12hexoct -// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct +// hexoct := hexdig hexdig +// 2hexoct := hexoct hexoct +// 4hexoct := 2hexoct 2hexoct +// 6hexoct := 4hexoct 2hexoct +// 12hexoct := 6hexoct 6hexoct // -// plain := canonical | hashlike -// uuid := canonical | hashlike | braced | urn +// hashlike := 12hexoct +// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct // -// braced := '{' plain '}' | '{' hashlike '}' -// urn := URN ':' UUID-NID ':' plain +// plain := canonical | hashlike +// uuid := canonical | hashlike | braced | urn // -func (u *UUID) UnmarshalText(text []byte) error { - switch len(text) { - case 32: - return u.decodeHashLike(text) +// braced := '{' plain '}' | '{' hashlike '}' +// urn := URN ':' UUID-NID ':' plain +func (u *UUID) UnmarshalText(b []byte) error { + switch len(b) { + case 32: // hash + case 36: // canonical case 34, 38: - return u.decodeBraced(text) - case 36: - return u.decodeCanonical(text) + if b[0] != '{' || b[len(b)-1] != '}' { + return fmt.Errorf("uuid: incorrect UUID format in string %q", b) + } + b = b[1 : len(b)-1] case 41, 45: - return u.decodeURN(text) + if string(b[:9]) != "urn:uuid:" { + return fmt.Errorf("uuid: incorrect UUID format in string %q", b[:9]) + } + b = b[9:] default: - return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(text), text) - } -} - -// decodeCanonical decodes UUID strings that are formatted as defined in RFC-4122 (section 3): -// "6ba7b810-9dad-11d1-80b4-00c04fd430c8". -func (u *UUID) decodeCanonical(t []byte) error { - if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' { - return fmt.Errorf("uuid: incorrect UUID format in string %q", t) + return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(b), b) } - - src := t - dst := u[:] - - for i, byteGroup := range byteGroups { - if i > 0 { - src = src[1:] // skip dash + if len(b) == 36 { + if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { + return fmt.Errorf("uuid: incorrect UUID format in string %q", b) } - _, err := hex.Decode(dst[:byteGroup/2], src[:byteGroup]) - if err != nil { - return err + for i, x := range [16]byte{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34, + } { + v1 := fromHexChar(b[x]) + v2 := fromHexChar(b[x+1]) + if v1|v2 == 255 { + return errInvalidFormat + } + u[i] = (v1 << 4) | v2 } - src = src[byteGroup:] - dst = dst[byteGroup/2:] - } - - return nil -} - -// decodeHashLike decodes UUID strings that are using the following format: -// "6ba7b8109dad11d180b400c04fd430c8". -func (u *UUID) decodeHashLike(t []byte) error { - src := t[:] - dst := u[:] - - _, err := hex.Decode(dst, src) - return err -} - -// decodeBraced decodes UUID strings that are using the following formats: -// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" -// "{6ba7b8109dad11d180b400c04fd430c8}". -func (u *UUID) decodeBraced(t []byte) error { - l := len(t) - - if t[0] != '{' || t[l-1] != '}' { - return fmt.Errorf("uuid: incorrect UUID format in string %q", t) + return nil } - - return u.decodePlain(t[1 : l-1]) -} - -// decodeURN decodes UUID strings that are using the following formats: -// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" -// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8". -func (u *UUID) decodeURN(t []byte) error { - total := len(t) - - urnUUIDPrefix := t[:9] - - if !bytes.Equal(urnUUIDPrefix, urnPrefix) { - return fmt.Errorf("uuid: incorrect UUID format in string %q", t) - } - - return u.decodePlain(t[9:total]) -} - -// decodePlain decodes UUID strings that are using the following formats: -// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format -// "6ba7b8109dad11d180b400c04fd430c8". -func (u *UUID) decodePlain(t []byte) error { - switch len(t) { - case 32: - return u.decodeHashLike(t) - case 36: - return u.decodeCanonical(t) - default: - return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(t), t) + for i := 0; i < 32; i += 2 { + v1 := fromHexChar(b[i]) + v2 := fromHexChar(b[i+1]) + if v1|v2 == 255 { + return errInvalidFormat + } + u[i/2] = (v1 << 4) | v2 } + return nil } // MarshalBinary implements the encoding.BinaryMarshaler interface. diff --git a/vendor/github.com/gofrs/uuid/fuzz.go b/vendor/github.com/gofrs/uuid/fuzz.go index afaefbc..ccf8d4c 100644 --- a/vendor/github.com/gofrs/uuid/fuzz.go +++ b/vendor/github.com/gofrs/uuid/fuzz.go @@ -19,6 +19,7 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +//go:build gofuzz // +build gofuzz package uuid @@ -27,15 +28,15 @@ package uuid // // To run: // -// $ go get github.com/dvyukov/go-fuzz/... -// $ cd $GOPATH/src/github.com/gofrs/uuid -// $ go-fuzz-build github.com/gofrs/uuid -// $ go-fuzz -bin=uuid-fuzz.zip -workdir=./testdata +// $ go get github.com/dvyukov/go-fuzz/... +// $ cd $GOPATH/src/github.com/gofrs/uuid +// $ go-fuzz-build github.com/gofrs/uuid +// $ go-fuzz -bin=uuid-fuzz.zip -workdir=./testdata // // If you make significant changes to FromString / UnmarshalText and add // new cases to fromStringTests (in codec_test.go), please run // -// $ go test -seed_fuzz_corpus +// $ go test -seed_fuzz_corpus // // to seed the corpus with the new interesting inputs, then run the fuzzer. func Fuzz(data []byte) int { diff --git a/vendor/github.com/gofrs/uuid/generator.go b/vendor/github.com/gofrs/uuid/generator.go index 4550bc6..44be9e1 100644 --- a/vendor/github.com/gofrs/uuid/generator.go +++ b/vendor/github.com/gofrs/uuid/generator.go @@ -38,7 +38,8 @@ import ( // UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970). const epochStart = 122192928000000000 -type epochFunc func() time.Time +// EpochFunc is the function type used to provide the current time. +type EpochFunc func() time.Time // HWAddrFunc is the function type used to provide hardware (MAC) addresses. type HWAddrFunc func() (net.HardwareAddr, error) @@ -80,9 +81,9 @@ func NewV6() (UUID, error) { } // NewV7 returns a k-sortable UUID based on the current millisecond precision -// UNIX epoch and 74 bits of pseudorandom data. +// UNIX epoch and 74 bits of pseudorandom data. It supports single-node batch generation (multiple UUIDs in the same timestamp) with a Monotonic Random counter. // -// This is implemented based on revision 03 of the Peabody UUID draft, and may +// This is implemented based on revision 04 of the Peabody UUID draft, and may // be subject to change pending further revisions. Until the final specification // revision is finished, changes required to implement updates to the spec will // not be considered a breaking change. They will happen as a minor version @@ -119,13 +120,16 @@ type Gen struct { rand io.Reader - epochFunc epochFunc + epochFunc EpochFunc hwAddrFunc HWAddrFunc lastTime uint64 clockSequence uint16 hardwareAddr [6]byte } +// GenOption is a function type that can be used to configure a Gen generator. +type GenOption func(*Gen) + // interface check -- build will fail if *Gen doesn't satisfy Generator var _ Generator = (*Gen)(nil) @@ -147,18 +151,82 @@ func NewGen() *Gen { // MAC address being used, you'll need to create a new generator using this // function. func NewGenWithHWAF(hwaf HWAddrFunc) *Gen { - return &Gen{ + return NewGenWithOptions(WithHWAddrFunc(hwaf)) +} + +// NewGenWithOptions returns a new instance of Gen with the options provided. +// Most people should use NewGen() or NewGenWithHWAF() instead. +// +// To customize the generator, you can pass in one or more GenOption functions. +// For example: +// +// gen := NewGenWithOptions( +// WithHWAddrFunc(myHWAddrFunc), +// WithEpochFunc(myEpochFunc), +// WithRandomReader(myRandomReader), +// ) +// +// NewGenWithOptions(WithHWAddrFunc(myHWAddrFunc)) is equivalent to calling +// NewGenWithHWAF(myHWAddrFunc) +// NewGenWithOptions() is equivalent to calling NewGen() +func NewGenWithOptions(opts ...GenOption) *Gen { + gen := &Gen{ epochFunc: time.Now, - hwAddrFunc: hwaf, + hwAddrFunc: defaultHWAddrFunc, rand: rand.Reader, } + + for _, opt := range opts { + opt(gen) + } + + return gen +} + +// WithHWAddrFunc is a GenOption that allows you to provide your own HWAddrFunc +// function. +// When this option is nil, the defaultHWAddrFunc is used. +func WithHWAddrFunc(hwaf HWAddrFunc) GenOption { + return func(gen *Gen) { + if hwaf == nil { + hwaf = defaultHWAddrFunc + } + + gen.hwAddrFunc = hwaf + } +} + +// WithEpochFunc is a GenOption that allows you to provide your own EpochFunc +// function. +// When this option is nil, time.Now is used. +func WithEpochFunc(epochf EpochFunc) GenOption { + return func(gen *Gen) { + if epochf == nil { + epochf = time.Now + } + + gen.epochFunc = epochf + } +} + +// WithRandomReader is a GenOption that allows you to provide your own random +// reader. +// When this option is nil, the default rand.Reader is used. +func WithRandomReader(reader io.Reader) GenOption { + return func(gen *Gen) { + if reader == nil { + reader = rand.Reader + } + + gen.rand = reader + } } // NewV1 returns a UUID based on the current timestamp and MAC address. func (g *Gen) NewV1() (UUID, error) { u := UUID{} - timeNow, clockSeq, err := g.getClockSequence() + timeNow, clockSeq, err := g.getClockSequence(false) if err != nil { return Nil, err } @@ -225,7 +293,7 @@ func (g *Gen) NewV6() (UUID, error) { return Nil, err } - timeNow, clockSeq, err := g.getClockSequence() + timeNow, clockSeq, err := g.getClockSequence(false) if err != nil { return Nil, err } @@ -241,8 +309,12 @@ func (g *Gen) NewV6() (UUID, error) { return u, nil } -// getClockSequence returns the epoch and clock sequence for V1 and V6 UUIDs. -func (g *Gen) getClockSequence() (uint64, uint16, error) { +// getClockSequence returns the epoch and clock sequence for V1,V6 and V7 UUIDs. +// +// When useUnixTSMs is false, it uses the Coordinated Universal Time (UTC) as a count of 100- +// +// nanosecond intervals since 00:00:00.00, 15 October 1582 (the date of Gregorian reform to the Christian calendar). +func (g *Gen) getClockSequence(useUnixTSMs bool) (uint64, uint16, error) { var err error g.clockSequenceOnce.Do(func() { buf := make([]byte, 2) @@ -258,7 +330,12 @@ func (g *Gen) getClockSequence() (uint64, uint16, error) { g.storageMutex.Lock() defer g.storageMutex.Unlock() - timeNow := g.getEpoch() + var timeNow uint64 + if useUnixTSMs { + timeNow = uint64(g.epochFunc().UnixMilli()) + } else { + timeNow = g.getEpoch() + } // Clock didn't change since last UUID generation. // Should increase clock sequence. if timeNow <= g.lastTime { @@ -272,28 +349,51 @@ func (g *Gen) getClockSequence() (uint64, uint16, error) { // NewV7 returns a k-sortable UUID based on the current millisecond precision // UNIX epoch and 74 bits of pseudorandom data. // -// This is implemented based on revision 03 of the Peabody UUID draft, and may +// This is implemented based on revision 04 of the Peabody UUID draft, and may // be subject to change pending further revisions. Until the final specification // revision is finished, changes required to implement updates to the spec will // not be considered a breaking change. They will happen as a minor version // releases until the spec is final. func (g *Gen) NewV7() (UUID, error) { var u UUID - - if _, err := io.ReadFull(g.rand, u[6:]); err != nil { + /* https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#name-uuid-version-7 + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unix_ts_ms | ver | rand_a | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |var| rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | rand_b | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ + + ms, clockSeq, err := g.getClockSequence(true) + if err != nil { return Nil, err } - - tn := g.epochFunc() - ms := uint64(tn.Unix())*1e3 + uint64(tn.Nanosecond())/1e6 - u[0] = byte(ms >> 40) + //UUIDv7 features a 48 bit timestamp. First 32bit (4bytes) represents seconds since 1970, followed by 2 bytes for the ms granularity. + u[0] = byte(ms >> 40) //1-6 bytes: big-endian unsigned number of Unix epoch timestamp u[1] = byte(ms >> 32) u[2] = byte(ms >> 24) u[3] = byte(ms >> 16) u[4] = byte(ms >> 8) u[5] = byte(ms) + //support batching by using a monotonic pseudo-random sequence + //The 6th byte contains the version and partially rand_a data. + //We will lose the most significant bites from the clockSeq (with SetVersion), but it is ok, we need the least significant that contains the counter to ensure the monotonic property + binary.BigEndian.PutUint16(u[6:8], clockSeq) // set rand_a with clock seq which is random and monotonic + + //override first 4bits of u[6]. u.SetVersion(V7) + + //set rand_b 64bits of pseudo-random bits (first 2 will be overridden) + if _, err = io.ReadFull(g.rand, u[8:16]); err != nil { + return Nil, err + } + //override first 2 bits of byte[8] for the variant u.SetVariant(VariantRFC4122) return u, nil diff --git a/vendor/github.com/gofrs/uuid/sql.go b/vendor/github.com/gofrs/uuid/sql.go index 6f254a4..01d5d88 100644 --- a/vendor/github.com/gofrs/uuid/sql.go +++ b/vendor/github.com/gofrs/uuid/sql.go @@ -22,12 +22,14 @@ package uuid import ( - "bytes" + "database/sql" "database/sql/driver" - "encoding/json" "fmt" ) +var _ driver.Valuer = UUID{} +var _ sql.Scanner = (*UUID)(nil) + // Value implements the driver.Valuer interface. func (u UUID) Value() (driver.Value, error) { return u.String(), nil @@ -49,7 +51,9 @@ func (u *UUID) Scan(src interface{}) error { return u.UnmarshalText(src) case string: - return u.UnmarshalText([]byte(src)) + uu, err := FromString(src) + *u = uu + return err } return fmt.Errorf("uuid: cannot convert %T to UUID", src) @@ -83,27 +87,30 @@ func (u *NullUUID) Scan(src interface{}) error { return u.UUID.Scan(src) } +var nullJSON = []byte("null") + // MarshalJSON marshals the NullUUID as null or the nested UUID func (u NullUUID) MarshalJSON() ([]byte, error) { if !u.Valid { - return json.Marshal(nil) + return nullJSON, nil } - - return json.Marshal(u.UUID) + var buf [38]byte + buf[0] = '"' + encodeCanonical(buf[1:37], u.UUID) + buf[37] = '"' + return buf[:], nil } // UnmarshalJSON unmarshals a NullUUID func (u *NullUUID) UnmarshalJSON(b []byte) error { - if bytes.Equal(b, []byte("null")) { + if string(b) == "null" { u.UUID, u.Valid = Nil, false return nil } - - if err := json.Unmarshal(b, &u.UUID); err != nil { - return err + if n := len(b); n >= 2 && b[0] == '"' { + b = b[1 : n-1] } - - u.Valid = true - - return nil + err := u.UUID.UnmarshalText(b) + u.Valid = (err == nil) + return err } diff --git a/vendor/github.com/gofrs/uuid/uuid.go b/vendor/github.com/gofrs/uuid/uuid.go index e747e54..5320fb5 100644 --- a/vendor/github.com/gofrs/uuid/uuid.go +++ b/vendor/github.com/gofrs/uuid/uuid.go @@ -44,8 +44,6 @@ import ( "encoding/binary" "encoding/hex" "fmt" - "io" - "strings" "time" ) @@ -133,12 +131,6 @@ func TimestampFromV6(u UUID) (Timestamp, error) { return Timestamp(uint64(low) + (uint64(mid) << 12) + (uint64(hi) << 28)), nil } -// String parse helpers. -var ( - urnPrefix = []byte("urn:uuid:") - byteGroups = []int{8, 4, 4, 4, 12} -) - // Nil is the nil UUID, as specified in RFC-4122, that has all 128 bits set to // zero. var Nil = UUID{} @@ -182,22 +174,33 @@ func (u UUID) Bytes() []byte { return u[:] } +// encodeCanonical encodes the canonical RFC-4122 form of UUID u into the +// first 36 bytes dst. +func encodeCanonical(dst []byte, u UUID) { + const hextable = "0123456789abcdef" + dst[8] = '-' + dst[13] = '-' + dst[18] = '-' + dst[23] = '-' + for i, x := range [16]byte{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34, + } { + c := u[i] + dst[x] = hextable[c>>4] + dst[x+1] = hextable[c&0x0f] + } +} + // String returns a canonical RFC-4122 string representation of the UUID: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. func (u UUID) String() string { - buf := make([]byte, 36) - - hex.Encode(buf[0:8], u[0:4]) - buf[8] = '-' - hex.Encode(buf[9:13], u[4:6]) - buf[13] = '-' - hex.Encode(buf[14:18], u[6:8]) - buf[18] = '-' - hex.Encode(buf[19:23], u[8:10]) - buf[23] = '-' - hex.Encode(buf[24:], u[10:]) - - return string(buf) + var buf [36]byte + encodeCanonical(buf[:], u) + return string(buf[:]) } // Format implements fmt.Formatter for UUID values. @@ -210,52 +213,41 @@ func (u UUID) String() string { // All other verbs not handled directly by the fmt package (like '%p') are unsupported and will return // "%!verb(uuid.UUID=value)" as recommended by the fmt package. func (u UUID) Format(f fmt.State, c rune) { + if c == 'v' && f.Flag('#') { + fmt.Fprintf(f, "%#v", [Size]byte(u)) + return + } switch c { case 'x', 'X': - s := hex.EncodeToString(u.Bytes()) + b := make([]byte, 32) + hex.Encode(b, u[:]) if c == 'X' { - s = strings.Map(toCapitalHexDigits, s) - } - _, _ = io.WriteString(f, s) - case 'v': - var s string - if f.Flag('#') { - s = fmt.Sprintf("%#v", [Size]byte(u)) - } else { - s = u.String() + toUpperHex(b) } - _, _ = io.WriteString(f, s) - case 's', 'S': - s := u.String() + _, _ = f.Write(b) + case 'v', 's', 'S': + b, _ := u.MarshalText() if c == 'S' { - s = strings.Map(toCapitalHexDigits, s) + toUpperHex(b) } - _, _ = io.WriteString(f, s) + _, _ = f.Write(b) case 'q': - _, _ = io.WriteString(f, `"`+u.String()+`"`) + b := make([]byte, 38) + b[0] = '"' + encodeCanonical(b[1:], u) + b[37] = '"' + _, _ = f.Write(b) default: // invalid/unsupported format verb fmt.Fprintf(f, "%%!%c(uuid.UUID=%s)", c, u.String()) } } -func toCapitalHexDigits(ch rune) rune { - // convert a-f hex digits to A-F - switch ch { - case 'a': - return 'A' - case 'b': - return 'B' - case 'c': - return 'C' - case 'd': - return 'D' - case 'e': - return 'E' - case 'f': - return 'F' - default: - return ch +func toUpperHex(b []byte) { + for i, c := range b { + if 'a' <= c && c <= 'f' { + b[i] = c - ('a' - 'A') + } } } @@ -283,7 +275,8 @@ func (u *UUID) SetVariant(v byte) { // Must is a helper that wraps a call to a function returning (UUID, error) // and panics if the error is non-nil. It is intended for use in variable // initializations such as -// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000")) +// +// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000")) func Must(u UUID, err error) UUID { if err != nil { panic(err) diff --git a/vendor/github.com/hashicorp/go-retryablehttp/CHANGELOG.md b/vendor/github.com/hashicorp/go-retryablehttp/CHANGELOG.md new file mode 100644 index 0000000..33686e4 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/CHANGELOG.md @@ -0,0 +1,9 @@ +## 0.7.4 (Jun 6, 2023) + +BUG FIXES + +- client: fixing an issue where the Content-Type header wouldn't be sent with an empty payload when using HTTP/2 [GH-194] + +## 0.7.3 (May 15, 2023) + +Initial release diff --git a/vendor/github.com/hashicorp/go-retryablehttp/CODEOWNERS b/vendor/github.com/hashicorp/go-retryablehttp/CODEOWNERS new file mode 100644 index 0000000..f8389c9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/CODEOWNERS @@ -0,0 +1 @@ +* @hashicorp/release-engineering \ No newline at end of file diff --git a/vendor/github.com/hashicorp/go-retryablehttp/LICENSE b/vendor/github.com/hashicorp/go-retryablehttp/LICENSE index e87a115..f4f97ee 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/LICENSE +++ b/vendor/github.com/hashicorp/go-retryablehttp/LICENSE @@ -1,3 +1,5 @@ +Copyright (c) 2015 HashiCorp, Inc. + Mozilla Public License, version 2.0 1. Definitions diff --git a/vendor/github.com/hashicorp/go-retryablehttp/README.md b/vendor/github.com/hashicorp/go-retryablehttp/README.md index 09f5eaf..8943bec 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/README.md +++ b/vendor/github.com/hashicorp/go-retryablehttp/README.md @@ -45,25 +45,6 @@ The returned response object is an `*http.Response`, the same thing you would usually get from `net/http`. Had the request failed one or more times, the above call would block and retry with exponential backoff. -## Retrying cases that fail after a seeming success - -It's possible for a request to succeed in the sense that the expected response headers are received, but then to encounter network-level errors while reading the response body. In go-retryablehttp's most basic usage, this error would not be retryable, due to the out-of-band handling of the response body. In some cases it may be desirable to handle the response body as part of the retryable operation. - -A toy example (which will retry the full request and succeed on the second attempt) is shown below: - -```go -c := retryablehttp.NewClient() -r := retryablehttp.NewRequest("GET", "://foo", nil) -handlerShouldRetry := true -r.SetResponseHandler(func(*http.Response) error { - if !handlerShouldRetry { - return nil - } - handlerShouldRetry = false - return errors.New("retryable error") -}) -``` - ## Getting a stdlib `*http.Client` with retries It's possible to convert a `*retryablehttp.Client` directly to a `*http.Client`. diff --git a/vendor/github.com/hashicorp/go-retryablehttp/client.go b/vendor/github.com/hashicorp/go-retryablehttp/client.go index 57116e9..cad96bd 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/client.go +++ b/vendor/github.com/hashicorp/go-retryablehttp/client.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Package retryablehttp provides a familiar HTTP client interface with // automatic retries and exponential backoff. It is a thin wrapper over the // standard net/http client library and exposes nearly the same public API. @@ -80,8 +83,15 @@ var ( type ReaderFunc func() (io.Reader, error) // ResponseHandlerFunc is a type of function that takes in a Response, and does something with it. -// It only runs if the initial part of the request was successful. -// If an error is returned, the client's retry policy will be used to determine whether to retry the whole request. +// The ResponseHandlerFunc is called when the HTTP client successfully receives a response and the +// CheckRetry function indicates that a retry of the base request is not necessary. +// If an error is returned from this function, the CheckRetry policy will be used to determine +// whether to retry the whole request (including this handler). +// +// Make sure to check status codes! Even if the request was completed it may have a non-2xx status code. +// +// The response body is not automatically closed. It must be closed either by the ResponseHandlerFunc or +// by the caller out-of-band. Failure to do so will result in a memory leak. type ResponseHandlerFunc func(*http.Response) error // LenReader is an interface implemented by many in-memory io.Reader's. Used @@ -250,10 +260,17 @@ func getBodyReaderAndContentLength(rawBody interface{}) (ReaderFunc, int64, erro if err != nil { return nil, 0, err } - bodyReader = func() (io.Reader, error) { - return bytes.NewReader(buf), nil + if len(buf) == 0 { + bodyReader = func() (io.Reader, error) { + return http.NoBody, nil + } + contentLength = 0 + } else { + bodyReader = func() (io.Reader, error) { + return bytes.NewReader(buf), nil + } + contentLength = int64(len(buf)) } - contentLength = int64(len(buf)) // No body provided, nothing to do case nil: diff --git a/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go b/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go index 8f3ee35..8c407ad 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go +++ b/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package retryablehttp import ( diff --git a/vendor/github.com/stretchr/objx/README.md b/vendor/github.com/stretchr/objx/README.md index 246660b..736e1eb 100644 --- a/vendor/github.com/stretchr/objx/README.md +++ b/vendor/github.com/stretchr/objx/README.md @@ -4,20 +4,20 @@ [![Maintainability](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/maintainability)](https://codeclimate.com/github/stretchr/objx/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/test_coverage)](https://codeclimate.com/github/stretchr/objx/test_coverage) [![Sourcegraph](https://sourcegraph.com/github.com/stretchr/objx/-/badge.svg)](https://sourcegraph.com/github.com/stretchr/objx) -[![GoDoc](https://godoc.org/github.com/stretchr/objx?status.svg)](https://godoc.org/github.com/stretchr/objx) +[![GoDoc](https://pkg.go.dev/badge/github.com/stretchr/objx?utm_source=godoc)](https://pkg.go.dev/github.com/stretchr/objx) Objx - Go package for dealing with maps, slices, JSON and other data. Get started: - Install Objx with [one line of code](#installation), or [update it with another](#staying-up-to-date) -- Check out the API Documentation http://godoc.org/github.com/stretchr/objx +- Check out the API Documentation http://pkg.go.dev/github.com/stretchr/objx ## Overview Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc. ### Pattern -Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going: +Objx uses a predictable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going: m, err := objx.FromJSON(json) @@ -74,7 +74,7 @@ To update Objx to the latest version, run: go get -u github.com/stretchr/objx ### Supported go versions -We support the lastest three major Go versions, which are 1.10, 1.11 and 1.12 at the moment. +We currently support the most recent major Go versions from 1.13 onward. ## Contributing Please feel free to submit issues, fork the repository and send pull requests! diff --git a/vendor/github.com/stretchr/objx/Taskfile.yml b/vendor/github.com/stretchr/objx/Taskfile.yml index 7746f51..39f49d5 100644 --- a/vendor/github.com/stretchr/objx/Taskfile.yml +++ b/vendor/github.com/stretchr/objx/Taskfile.yml @@ -1,8 +1,5 @@ version: '2' -env: - GOFLAGS: -mod=vendor - tasks: default: deps: [test] diff --git a/vendor/github.com/stretchr/objx/accessors.go b/vendor/github.com/stretchr/objx/accessors.go index 4c60455..72f1d1c 100644 --- a/vendor/github.com/stretchr/objx/accessors.go +++ b/vendor/github.com/stretchr/objx/accessors.go @@ -14,17 +14,17 @@ const ( // For example, `location.address.city` PathSeparator string = "." - // arrayAccesRegexString is the regex used to extract the array number + // arrayAccessRegexString is the regex used to extract the array number // from the access path - arrayAccesRegexString = `^(.+)\[([0-9]+)\]$` + arrayAccessRegexString = `^(.+)\[([0-9]+)\]$` // mapAccessRegexString is the regex used to extract the map key // from the access path mapAccessRegexString = `^([^\[]*)\[([^\]]+)\](.*)$` ) -// arrayAccesRegex is the compiled arrayAccesRegexString -var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString) +// arrayAccessRegex is the compiled arrayAccessRegexString +var arrayAccessRegex = regexp.MustCompile(arrayAccessRegexString) // mapAccessRegex is the compiled mapAccessRegexString var mapAccessRegex = regexp.MustCompile(mapAccessRegexString) @@ -37,11 +37,11 @@ var mapAccessRegex = regexp.MustCompile(mapAccessRegexString) // // Get can only operate directly on map[string]interface{} and []interface. // -// Example +// # Example // // To access the title of the third chapter of the second book, do: // -// o.Get("books[1].chapters[2].title") +// o.Get("books[1].chapters[2].title") func (m Map) Get(selector string) *Value { rawObj := access(m, selector, nil, false) return &Value{data: rawObj} @@ -52,26 +52,26 @@ func (m Map) Get(selector string) *Value { // // Set can only operate directly on map[string]interface{} and []interface // -// Example +// # Example // // To set the title of the third chapter of the second book, do: // -// o.Set("books[1].chapters[2].title","Time to Go") +// o.Set("books[1].chapters[2].title","Time to Go") func (m Map) Set(selector string, value interface{}) Map { access(m, selector, value, true) return m } -// getIndex returns the index, which is hold in s by two braches. -// It also returns s withour the index part, e.g. name[1] will return (1, name). +// getIndex returns the index, which is hold in s by two branches. +// It also returns s without the index part, e.g. name[1] will return (1, name). // If no index is found, -1 is returned func getIndex(s string) (int, string) { - arrayMatches := arrayAccesRegex.FindStringSubmatch(s) + arrayMatches := arrayAccessRegex.FindStringSubmatch(s) if len(arrayMatches) > 0 { // Get the key into the map selector := arrayMatches[1] // Get the index into the array at the key - // We know this cannt fail because arrayMatches[2] is an int for sure + // We know this can't fail because arrayMatches[2] is an int for sure index, _ := strconv.Atoi(arrayMatches[2]) return index, selector } diff --git a/vendor/github.com/stretchr/objx/conversions.go b/vendor/github.com/stretchr/objx/conversions.go index 080aa46..01c63d7 100644 --- a/vendor/github.com/stretchr/objx/conversions.go +++ b/vendor/github.com/stretchr/objx/conversions.go @@ -15,7 +15,7 @@ import ( const SignatureSeparator = "_" // URLValuesSliceKeySuffix is the character that is used to -// specify a suffic for slices parsed by URLValues. +// specify a suffix for slices parsed by URLValues. // If the suffix is set to "[i]", then the index of the slice // is used in place of i // Ex: Suffix "[]" would have the form a[]=b&a[]=c @@ -30,7 +30,7 @@ const ( ) // SetURLValuesSliceKeySuffix sets the character that is used to -// specify a suffic for slices parsed by URLValues. +// specify a suffix for slices parsed by URLValues. // If the suffix is set to "[i]", then the index of the slice // is used in place of i // Ex: Suffix "[]" would have the form a[]=b&a[]=c diff --git a/vendor/github.com/stretchr/objx/doc.go b/vendor/github.com/stretchr/objx/doc.go index 6d6af1a..b170af7 100644 --- a/vendor/github.com/stretchr/objx/doc.go +++ b/vendor/github.com/stretchr/objx/doc.go @@ -1,19 +1,19 @@ /* -Objx - Go package for dealing with maps, slices, JSON and other data. +Package objx provides utilities for dealing with maps, slices, JSON and other data. -Overview +# Overview Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc. -Pattern +# Pattern -Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. +Objx uses a predictable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going: - m, err := objx.FromJSON(json) + m, err := objx.FromJSON(json) NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, the rest will be optimistic and try to figure things out without panicking. @@ -21,46 +21,46 @@ the rest will be optimistic and try to figure things out without panicking. Use `Get` to access the value you're interested in. You can use dot and array notation too: - m.Get("places[0].latlng") + m.Get("places[0].latlng") Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type. - if m.Get("code").IsStr() { // Your code... } + if m.Get("code").IsStr() { // Your code... } Or you can just assume the type, and use one of the strong type methods to extract the real value: - m.Get("code").Int() + m.Get("code").Int() If there's no value there (or if it's the wrong type) then a default value will be returned, or you can be explicit about the default value. - Get("code").Int(-1) + Get("code").Int(-1) If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, manipulating and selecting that data. You can find out more by exploring the index below. -Reading data +# Reading data A simple example of how to use Objx: - // Use MustFromJSON to make an objx.Map from some JSON - m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`) + // Use MustFromJSON to make an objx.Map from some JSON + m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`) - // Get the details - name := m.Get("name").Str() - age := m.Get("age").Int() + // Get the details + name := m.Get("name").Str() + age := m.Get("age").Int() - // Get their nickname (or use their name if they don't have one) - nickname := m.Get("nickname").Str(name) + // Get their nickname (or use their name if they don't have one) + nickname := m.Get("nickname").Str(name) -Ranging +# Ranging Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For example, to `range` the data, do what you would expect: - m := objx.MustFromJSON(json) - for key, value := range m { - // Your code... - } + m := objx.MustFromJSON(json) + for key, value := range m { + // Your code... + } */ package objx diff --git a/vendor/github.com/stretchr/objx/map.go b/vendor/github.com/stretchr/objx/map.go index a64712a..ab9f9ae 100644 --- a/vendor/github.com/stretchr/objx/map.go +++ b/vendor/github.com/stretchr/objx/map.go @@ -47,17 +47,16 @@ func New(data interface{}) Map { // // The arguments follow a key, value pattern. // -// // Returns nil if any key argument is non-string or if there are an odd number of arguments. // -// Example +// # Example // // To easily create Maps: // -// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true)) +// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true)) // -// // creates an Map equivalent to -// m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}} +// // creates an Map equivalent to +// m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}} func MSI(keyAndValuePairs ...interface{}) Map { newMap := Map{} keyAndValuePairsLen := len(keyAndValuePairs) diff --git a/vendor/modules.txt b/vendor/modules.txt index 90418d7..36d3fb3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,23 +1,24 @@ -# github.com/beevik/etree v1.1.0 -## explicit +# github.com/beevik/etree v1.2.0 +## explicit; go 1.13 github.com/beevik/etree -# github.com/bitrise-io/bitrise v0.0.0-20220719135434-7f794d69d858 -## explicit; go 1.16 +# github.com/bitrise-io/bitrise v0.0.0-20230920132712-a20cb0493953 +## explicit; go 1.17 +github.com/bitrise-io/bitrise/exitcode github.com/bitrise-io/bitrise/models -# github.com/bitrise-io/bitrise-init v0.0.0-20220504131857-f00a24c7c8ba -## explicit; go 1.16 +# github.com/bitrise-io/bitrise-init v0.0.0-20230901074816-efe492d99277 +## explicit; go 1.18 github.com/bitrise-io/bitrise-init/analytics github.com/bitrise-io/bitrise-init/models github.com/bitrise-io/bitrise-init/scanners/android github.com/bitrise-io/bitrise-init/steps github.com/bitrise-io/bitrise-init/utility -# github.com/bitrise-io/envman v0.0.0-20220512153504-166d59151b78 -## explicit; go 1.16 +# github.com/bitrise-io/envman v0.0.0-20230802102824-1300c57d49c4 +## explicit; go 1.18 github.com/bitrise-io/envman/models -# github.com/bitrise-io/go-android/v2 v2.0.0-alpha.3 +# github.com/bitrise-io/go-android/v2 v2.0.0-alpha.5 ## explicit; go 1.16 github.com/bitrise-io/go-android/v2/cache -# github.com/bitrise-io/go-steputils v1.0.5 +# github.com/bitrise-io/go-steputils v1.0.6 ## explicit; go 1.15 github.com/bitrise-io/go-steputils/cache github.com/bitrise-io/go-steputils/command/gems @@ -25,7 +26,7 @@ github.com/bitrise-io/go-steputils/command/rubycommand github.com/bitrise-io/go-steputils/input github.com/bitrise-io/go-steputils/step github.com/bitrise-io/go-steputils/tools -# github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.17 +# github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.20 ## explicit; go 1.17 github.com/bitrise-io/go-steputils/v2/ruby github.com/bitrise-io/go-steputils/v2/stepconf @@ -41,7 +42,7 @@ github.com/bitrise-io/go-utils/parseutil github.com/bitrise-io/go-utils/pathutil github.com/bitrise-io/go-utils/pointers github.com/bitrise-io/go-utils/sliceutil -# github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.16 +# github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.19 ## explicit; go 1.17 github.com/bitrise-io/go-utils/v2/analytics github.com/bitrise-io/go-utils/v2/command @@ -56,19 +57,19 @@ github.com/bitrise-io/go-utils/v2/retryhttp ## explicit; go 1.20 github.com/bitrise-io/go-xcode/appleauth github.com/bitrise-io/go-xcode/devportalservice -# github.com/bitrise-io/stepman v0.0.0-20220718172049-e5ae0a09c2f2 -## explicit; go 1.16 +# github.com/bitrise-io/stepman v0.0.0-20230728094915-939f0fe5c19a +## explicit; go 1.18 github.com/bitrise-io/stepman/models # github.com/davecgh/go-spew v1.1.1 ## explicit github.com/davecgh/go-spew/spew -# github.com/gofrs/uuid v4.3.1+incompatible +# github.com/gofrs/uuid v4.4.0+incompatible ## explicit github.com/gofrs/uuid # github.com/hashicorp/go-cleanhttp v0.5.2 ## explicit; go 1.13 github.com/hashicorp/go-cleanhttp -# github.com/hashicorp/go-retryablehttp v0.7.1 +# github.com/hashicorp/go-retryablehttp v0.7.4 ## explicit; go 1.13 github.com/hashicorp/go-retryablehttp # github.com/hashicorp/go-version v1.6.0 @@ -86,8 +87,8 @@ github.com/pmezard/go-difflib/difflib # github.com/ryanuber/go-glob v1.0.0 ## explicit github.com/ryanuber/go-glob -# github.com/stretchr/objx v0.5.0 -## explicit; go 1.12 +# github.com/stretchr/objx v0.5.1 +## explicit; go 1.13 github.com/stretchr/objx # github.com/stretchr/testify v1.8.4 ## explicit; go 1.20