From 305b09f696f70796627136480b28d666d507552c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 12 Nov 2020 19:58:14 +0100 Subject: [PATCH 01/13] Migrate upgrade tests to use new framework --- go.mod | 1 + go.sum | 2 + test/e2e-upgrade-tests.sh | 48 +-- test/e2e/shell_bridge.go | 72 ++++ test/upgrade/continual.go | 44 +++ test/upgrade/installation/git_head.go | 41 ++ test/upgrade/installation/latest.go | 34 ++ test/upgrade/postdowngrade.go | 27 ++ test/upgrade/postdowngrade_test.go | 26 -- test/upgrade/postupgrade.go | 27 ++ test/upgrade/postupgrade_test.go | 26 -- test/upgrade/preupgrade.go | 27 ++ test/upgrade/preupgrade_test.go | 26 -- test/upgrade/probe_test.go | 82 ---- test/upgrade/smoke.go | 39 ++ test/upgrade/smoke_test.go | 35 -- test/upgrade/upgrade_test.go | 79 ++++ .../github.com/magefile/mage/LICENSE | 201 ++++++++++ vendor/github.com/magefile/mage/LICENSE | 201 ++++++++++ vendor/github.com/magefile/mage/mg/color.go | 80 ++++ .../magefile/mage/mg/color_string.go | 38 ++ vendor/github.com/magefile/mage/mg/deps.go | 352 ++++++++++++++++++ vendor/github.com/magefile/mage/mg/errors.go | 51 +++ vendor/github.com/magefile/mage/mg/runtime.go | 136 +++++++ vendor/github.com/magefile/mage/sh/cmd.go | 177 +++++++++ vendor/github.com/magefile/mage/sh/helpers.go | 40 ++ .../knative.dev/pkg/test/upgrade/functions.go | 155 ++++++++ .../pkg/test/upgrade/private_types.go | 63 ++++ vendor/knative.dev/pkg/test/upgrade/steps.go | 155 ++++++++ .../pkg/test/upgrade/suite_execution.go | 85 +++++ vendor/knative.dev/pkg/test/upgrade/types.go | 123 ++++++ .../knative.dev/pkg/test/upgrade/vars.go | 29 +- vendor/modules.txt | 5 + 33 files changed, 2277 insertions(+), 250 deletions(-) create mode 100644 test/e2e/shell_bridge.go create mode 100644 test/upgrade/continual.go create mode 100644 test/upgrade/installation/git_head.go create mode 100644 test/upgrade/installation/latest.go create mode 100644 test/upgrade/postdowngrade.go delete mode 100644 test/upgrade/postdowngrade_test.go create mode 100644 test/upgrade/postupgrade.go delete mode 100644 test/upgrade/postupgrade_test.go create mode 100644 test/upgrade/preupgrade.go delete mode 100644 test/upgrade/preupgrade_test.go delete mode 100644 test/upgrade/probe_test.go create mode 100644 test/upgrade/smoke.go delete mode 100644 test/upgrade/smoke_test.go create mode 100644 test/upgrade/upgrade_test.go create mode 100644 third_party/VENDOR-LICENSE/github.com/magefile/mage/LICENSE create mode 100644 vendor/github.com/magefile/mage/LICENSE create mode 100644 vendor/github.com/magefile/mage/mg/color.go create mode 100644 vendor/github.com/magefile/mage/mg/color_string.go create mode 100644 vendor/github.com/magefile/mage/mg/deps.go create mode 100644 vendor/github.com/magefile/mage/mg/errors.go create mode 100644 vendor/github.com/magefile/mage/mg/runtime.go create mode 100644 vendor/github.com/magefile/mage/sh/cmd.go create mode 100644 vendor/github.com/magefile/mage/sh/helpers.go create mode 100644 vendor/knative.dev/pkg/test/upgrade/functions.go create mode 100644 vendor/knative.dev/pkg/test/upgrade/private_types.go create mode 100644 vendor/knative.dev/pkg/test/upgrade/steps.go create mode 100644 vendor/knative.dev/pkg/test/upgrade/suite_execution.go create mode 100644 vendor/knative.dev/pkg/test/upgrade/types.go rename test/upgrade/main_test.go => vendor/knative.dev/pkg/test/upgrade/vars.go (56%) diff --git a/go.mod b/go.mod index 6ccca329817..9aabb698784 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/influxdata/tdigest v0.0.0-20191024211133-5d87a7585faa // indirect github.com/json-iterator/go v1.1.10 // indirect github.com/kelseyhightower/envconfig v1.4.0 + github.com/magefile/mage v1.10.0 github.com/mitchellh/go-homedir v1.1.0 github.com/openzipkin/zipkin-go v0.2.5 github.com/pelletier/go-toml v1.8.0 diff --git a/go.sum b/go.sum index 94197dea322..9df746c5bbd 100644 --- a/go.sum +++ b/go.sum @@ -439,6 +439,8 @@ github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0U github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac h1:+2b6iGRJe3hvV/yVXrd41yVEjxuFHxasJqDhkIjS4gk= github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= +github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= diff --git a/test/e2e-upgrade-tests.sh b/test/e2e-upgrade-tests.sh index f74bb68c12c..45900747b3f 100755 --- a/test/e2e-upgrade-tests.sh +++ b/test/e2e-upgrade-tests.sh @@ -20,15 +20,14 @@ export GO111MODULE=on +# shellcheck disable=SC1090 source "$(dirname "$0")/e2e-common.sh" -readonly PROBER_READY_FILE="/tmp/prober-ready" -readonly PROBER_PIPE_FILE="/tmp/prober-signal" - # Overrides function knative_setup { - install_latest_release || fail_test 'Installing latest release of Knative Eventing failed' + # Nothing to do at setup + true } function install_test_resources { @@ -41,41 +40,14 @@ function uninstall_test_resources { true } -initialize $@ --skip-istio-addon - -TIMEOUT=${TIMEOUT:-30m} - -header "Running preupgrade tests" - -go_test_e2e -tags=preupgrade -timeout="${TIMEOUT}" ./test/upgrade || fail_test - -header "Starting prober test" -rm -fv ${PROBER_READY_FILE} -go_test_e2e -tags=probe -timeout="${TIMEOUT}" ./test/upgrade --pipefile="${PROBER_PIPE_FILE}" --readyfile="${PROBER_READY_FILE}" & -PROBER_PID=$! -echo "Prober PID is ${PROBER_PID}" - -wait_for_file ${PROBER_READY_FILE} || fail_test - -header "Performing upgrade to HEAD" -install_head || fail_test 'Installing HEAD version of eventing failed' -install_channel_crds || fail_test 'Installing HEAD channel CRDs failed' -install_mt_broker || fail_test 'Installing HEAD Broker failed' -install_sugar || fail_test 'Installing HEAD Sugar failed' - -header "Running postupgrade tests" -go_test_e2e -tags=postupgrade -timeout="${TIMEOUT}" ./test/upgrade || fail_test - -header "Performing downgrade to latest release" -install_latest_release || fail_test 'Installing latest release of Knative Eventing failed' - -header "Running postdowngrade tests" -go_test_e2e -tags=postdowngrade -timeout="${TIMEOUT}" ./test/upgrade || fail_test +initialize "$@" --skip-istio-addon -# The prober is blocking on ${PROBER_PIPE_FILE} to know when it should exit. -echo "done" > ${PROBER_PIPE_FILE} +TIMEOUT=${TIMEOUT:-60m} -header "Waiting for prober test" -wait ${PROBER_PID} || fail_test "Prober failed" +go_test_e2e \ + -tags=upgrade \ + -timeout="${TIMEOUT}" \ + ./test/upgrade \ + || fail_test success diff --git a/test/e2e/shell_bridge.go b/test/e2e/shell_bridge.go new file mode 100644 index 00000000000..f682fcfa481 --- /dev/null +++ b/test/e2e/shell_bridge.go @@ -0,0 +1,72 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package e2e + +import ( + "fmt" + "io/ioutil" + "os" + "path" + "runtime" + "strings" + + "github.com/magefile/mage/sh" +) + +func ShellOutFunction(funcName string) error { + _, filename, _, ok := runtime.Caller(1) + if !ok { + return fmt.Errorf("can't get caller for self") + } + e2eCommonScriptPath := path.Join(path.Dir(filename), "../e2e-common.sh") + script := fmt.Sprintf(`#!/usr/bin/env bash +set -Eeuo pipefail +source %s + +%s +`, e2eCommonScriptPath, funcName) + tmpfile, err := ioutil.TempFile("", funcName + "-*.sh") + if err != nil { + return err + } + err = ioutil.WriteFile(tmpfile.Name(), []byte(script), 0755) + if err != nil { + return err + } + + defer func() { + // clean up + _ = os.Remove(tmpfile.Name()) + }() + return sh.RunWithV(environment(os.Environ(), keyval), tmpfile.Name()) +} + +func environment(data []string, keyval func(item string) (key, val string)) map[string]string { + items := make(map[string]string) + for _, item := range data { + key, val := keyval(item) + items[key] = val + } + return items +} + +func keyval(item string) (key, val string) { + splits := strings.Split(item, "=") + key = splits[0] + val = splits[1] + return +} diff --git a/test/upgrade/continual.go b/test/upgrade/continual.go new file mode 100644 index 00000000000..e5ff5af2734 --- /dev/null +++ b/test/upgrade/continual.go @@ -0,0 +1,44 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package upgrade + +import ( + "context" + + testlib "knative.dev/eventing/test/lib" + "knative.dev/eventing/test/upgrade/prober" + pkgupgrade "knative.dev/pkg/test/upgrade" +) + +func ContinualTest() pkgupgrade.BackgroundOperation { + ctx := context.Background() + var client *testlib.Client + var probe prober.Prober + return pkgupgrade.NewBackgroundVerification("EventingContinualTest", + func(c pkgupgrade.Context) { + // setup + client = testlib.Setup(c.T, false) + config := prober.NewConfig(client.Namespace) + probe = prober.RunEventProber(ctx, c.Log, client, config) + }, + func(c pkgupgrade.Context) { + // verify + defer testlib.TearDown(client) + prober.AssertEventProber(ctx, c.T, probe) + }, + ) +} diff --git a/test/upgrade/installation/git_head.go b/test/upgrade/installation/git_head.go new file mode 100644 index 00000000000..20a3c1d30a3 --- /dev/null +++ b/test/upgrade/installation/git_head.go @@ -0,0 +1,41 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package installation + +import ( + "knative.dev/eventing/test/e2e" + pkgupgrade "knative.dev/pkg/test/upgrade" +) + +func GitHead() pkgupgrade.Operation { + return pkgupgrade.NewOperation("EventingGitHead", func(c pkgupgrade.Context) { + ops := []string{ + "install_head", + "install_channel_crds", + "install_mt_broker", + "install_sugar", + } + for _, shellfunc := range ops { + c.Log.Info("Running shell function: ", shellfunc) + err := e2e.ShellOutFunction(shellfunc) + if err != nil { + c.T.Error(err) + return + } + } + }) +} diff --git a/test/upgrade/installation/latest.go b/test/upgrade/installation/latest.go new file mode 100644 index 00000000000..af54a998adc --- /dev/null +++ b/test/upgrade/installation/latest.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package installation + +import ( + "knative.dev/eventing/test/e2e" + pkgupgrade "knative.dev/pkg/test/upgrade" +) + +func LatestStable() pkgupgrade.Operation { + return pkgupgrade.NewOperation("EventingLatestRelease", func(c pkgupgrade.Context) { + shellfunc := "install_latest_release" + c.Log.Info("Running shell function: ", shellfunc) + err := e2e.ShellOutFunction(shellfunc) + if err != nil { + c.T.Error(err) + return + } + }) +} \ No newline at end of file diff --git a/test/upgrade/postdowngrade.go b/test/upgrade/postdowngrade.go new file mode 100644 index 00000000000..8ee96252ead --- /dev/null +++ b/test/upgrade/postdowngrade.go @@ -0,0 +1,27 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package upgrade + +import ( + pkgupgrade "knative.dev/pkg/test/upgrade" +) + +func PostDowngradeTest() pkgupgrade.Operation { + return pkgupgrade.NewOperation("EventingPostDowngradeTest", func(c pkgupgrade.Context) { + runSmokeTest(c.T) + }) +} diff --git a/test/upgrade/postdowngrade_test.go b/test/upgrade/postdowngrade_test.go deleted file mode 100644 index 25f70a2cb97..00000000000 --- a/test/upgrade/postdowngrade_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// +build postdowngrade - -/* - * Copyright 2020 The Knative Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package upgrade - -import ( - "testing" -) - -func TestPostDowngrade(t *testing.T) { - runSmokeTest(t) -} diff --git a/test/upgrade/postupgrade.go b/test/upgrade/postupgrade.go new file mode 100644 index 00000000000..7089ef52fb8 --- /dev/null +++ b/test/upgrade/postupgrade.go @@ -0,0 +1,27 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package upgrade + +import ( + pkgupgrade "knative.dev/pkg/test/upgrade" +) + +func PostUpgradeTest() pkgupgrade.Operation { + return pkgupgrade.NewOperation("EventingPostUpgradeTest", func(c pkgupgrade.Context) { + runSmokeTest(c.T) + }) +} diff --git a/test/upgrade/postupgrade_test.go b/test/upgrade/postupgrade_test.go deleted file mode 100644 index ed5351c2a3e..00000000000 --- a/test/upgrade/postupgrade_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// +build postupgrade - -/* - * Copyright 2020 The Knative Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package upgrade - -import ( - "testing" -) - -func TestPostUpgrade(t *testing.T) { - runSmokeTest(t) -} diff --git a/test/upgrade/preupgrade.go b/test/upgrade/preupgrade.go new file mode 100644 index 00000000000..cd4f911f548 --- /dev/null +++ b/test/upgrade/preupgrade.go @@ -0,0 +1,27 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package upgrade + +import ( + pkgupgrade "knative.dev/pkg/test/upgrade" +) + +func PreUpgradeTest() pkgupgrade.Operation { + return pkgupgrade.NewOperation("EventingPreUpgradeTest", func(c pkgupgrade.Context) { + runSmokeTest(c.T) + }) +} diff --git a/test/upgrade/preupgrade_test.go b/test/upgrade/preupgrade_test.go deleted file mode 100644 index 144c41e35fe..00000000000 --- a/test/upgrade/preupgrade_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// +build preupgrade - -/* - * Copyright 2020 The Knative Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package upgrade - -import ( - "testing" -) - -func TestPreUpgrade(t *testing.T) { - runSmokeTest(t) -} diff --git a/test/upgrade/probe_test.go b/test/upgrade/probe_test.go deleted file mode 100644 index 67882aac4a0..00000000000 --- a/test/upgrade/probe_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// +build probe - -/* - * Copyright 2020 The Knative Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package upgrade - -import ( - "context" - "io/ioutil" - "os" - "syscall" - "testing" - - "knative.dev/eventing/test" - - "github.com/wavesoftware/go-ensure" - "go.uber.org/zap" - "knative.dev/eventing/test/upgrade/prober" -) - -const ( - readyMessage = "prober ready" -) - -func TestEventsPropagationWithProber(t *testing.T) { - // We run the prober as a golang test because it fits in nicely with - // the rest of our integration tests, and AssertProberDefault needs - // a *testing.T. Unfortunately, "go test" intercepts signals, so we - // can't coordinate with the test by just sending e.g. SIGCONT, so we - // create a named pipe and wait for the upgrade script to write to it - // to signal that we should stop probing. - ensureTempFilesAreCleaned() - if err := syscall.Mkfifo(test.EventingFlags.PipeFile, 0666); err != nil { - t.Fatal("Failed to create pipe:", err) - } - defer ensureTempFilesAreCleaned() - client := setup(t, false) - defer tearDown(client) - - config := prober.NewConfig(client.Namespace) - - // Use zap.SugarLogger instead of t.Logf because we want to see failures - // inline with other logs instead of buffered until the end. - log := createLogger() - probe := prober.RunEventProber(context.Background(), log, client, config) - ensure.NoError(ioutil.WriteFile(test.EventingFlags.ReadyFile, []byte(readyMessage), 0666)) - defer prober.AssertEventProber(context.Background(), t, probe) - - log.Infof("Waiting for file: %v as a signal that "+ - "upgrade/downgrade is over, at which point we will finish the test "+ - "and check the prober.", test.EventingFlags.PipeFile) - _, _ = ioutil.ReadFile(test.EventingFlags.PipeFile) -} - -func createLogger() *zap.SugaredLogger { - log, err := zap.NewDevelopment() - ensure.NoError(err) - return log.Sugar() -} - -func ensureTempFilesAreCleaned() { - filenames := []string{test.EventingFlags.PipeFile, test.EventingFlags.ReadyFile} - for _, filename := range filenames { - _, err := os.Stat(filename) - if err == nil { - ensure.NoError(os.Remove(filename)) - } - } -} diff --git a/test/upgrade/smoke.go b/test/upgrade/smoke.go new file mode 100644 index 00000000000..d7c47b9ba77 --- /dev/null +++ b/test/upgrade/smoke.go @@ -0,0 +1,39 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package upgrade + +import ( + "context" + "testing" + + cloudevents "github.com/cloudevents/sdk-go/v2" + "knative.dev/eventing/test/e2e/helpers" + "knative.dev/eventing/test/lib" +) + +var channelTestRunner lib.ComponentsTestRunner + +func runSmokeTest(t *testing.T) { + helpers.SingleEventForChannelTestHelper( + context.Background(), + t, + cloudevents.EncodingBinary, + helpers.SubscriptionV1beta1, + "", + channelTestRunner, + ) +} diff --git a/test/upgrade/smoke_test.go b/test/upgrade/smoke_test.go deleted file mode 100644 index 41789d8b5c1..00000000000 --- a/test/upgrade/smoke_test.go +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2020 The Knative Authors - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package upgrade - -import ( - "context" - "testing" - - cloudevents "github.com/cloudevents/sdk-go/v2" - "knative.dev/eventing/test/e2e/helpers" -) - -func runSmokeTest(t *testing.T) { - helpers.SingleEventForChannelTestHelper( - context.Background(), - t, - cloudevents.EncodingBinary, - helpers.SubscriptionV1beta1, - "", - channelTestRunner, - ) -} diff --git a/test/upgrade/upgrade_test.go b/test/upgrade/upgrade_test.go new file mode 100644 index 00000000000..2157cdd26ad --- /dev/null +++ b/test/upgrade/upgrade_test.go @@ -0,0 +1,79 @@ +// +build upgrade + +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package upgrade + +import ( + "os" + "testing" + + "go.uber.org/zap" + "knative.dev/eventing/test" + testlib "knative.dev/eventing/test/lib" + "knative.dev/eventing/test/upgrade/installation" + pkgupgrade "knative.dev/pkg/test/upgrade" +) + +func TestEventingUpgrades(t *testing.T) { + suite := pkgupgrade.Suite{ + Tests: pkgupgrade.Tests{ + PreUpgrade: []pkgupgrade.Operation{ + PreUpgradeTest(), + }, + PostUpgrade: []pkgupgrade.Operation{ + PostUpgradeTest(), + }, + PostDowngrade: []pkgupgrade.Operation{ + PostDowngradeTest(), + }, + Continual: []pkgupgrade.BackgroundOperation{ + ContinualTest(), + }, + }, + Installations: pkgupgrade.Installations{ + Base: []pkgupgrade.Operation{ + installation.LatestStable(), + }, + UpgradeWith: []pkgupgrade.Operation{ + installation.GitHead(), + }, + DowngradeWith: []pkgupgrade.Operation{ + installation.LatestStable(), + }, + }, + } + c := newUpgradeConfig(t) + suite.Execute(c) +} + +func newUpgradeConfig(t *testing.T) pkgupgrade.Configuration { + log, err := zap.NewDevelopment() + if err != nil { + t.Fatal(err) + } + return pkgupgrade.Configuration{T: t, Log: log} +} + +func TestMain(m *testing.M) { + test.InitializeEventingFlags() + channelTestRunner = testlib.ComponentsTestRunner{ + ComponentFeatureMap: testlib.ChannelFeatureMap, + ComponentsToTest: test.EventingFlags.Channels, + } + os.Exit(m.Run()) +} diff --git a/third_party/VENDOR-LICENSE/github.com/magefile/mage/LICENSE b/third_party/VENDOR-LICENSE/github.com/magefile/mage/LICENSE new file mode 100644 index 00000000000..d0632bc1458 --- /dev/null +++ b/third_party/VENDOR-LICENSE/github.com/magefile/mage/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 the Mage authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/magefile/mage/LICENSE b/vendor/github.com/magefile/mage/LICENSE new file mode 100644 index 00000000000..d0632bc1458 --- /dev/null +++ b/vendor/github.com/magefile/mage/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 the Mage authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/magefile/mage/mg/color.go b/vendor/github.com/magefile/mage/mg/color.go new file mode 100644 index 00000000000..3e27103325a --- /dev/null +++ b/vendor/github.com/magefile/mage/mg/color.go @@ -0,0 +1,80 @@ +package mg + +// Color is ANSI color type +type Color int + +// If you add/change/remove any items in this constant, +// you will need to run "stringer -type=Color" in this directory again. +// NOTE: Please keep the list in an alphabetical order. +const ( + Black Color = iota + Red + Green + Yellow + Blue + Magenta + Cyan + White + BrightBlack + BrightRed + BrightGreen + BrightYellow + BrightBlue + BrightMagenta + BrightCyan + BrightWhite +) + +// AnsiColor are ANSI color codes for supported terminal colors. +var ansiColor = map[Color]string{ + Black: "\u001b[30m", + Red: "\u001b[31m", + Green: "\u001b[32m", + Yellow: "\u001b[33m", + Blue: "\u001b[34m", + Magenta: "\u001b[35m", + Cyan: "\u001b[36m", + White: "\u001b[37m", + BrightBlack: "\u001b[30;1m", + BrightRed: "\u001b[31;1m", + BrightGreen: "\u001b[32;1m", + BrightYellow: "\u001b[33;1m", + BrightBlue: "\u001b[34;1m", + BrightMagenta: "\u001b[35;1m", + BrightCyan: "\u001b[36;1m", + BrightWhite: "\u001b[37;1m", +} + +// AnsiColorReset is an ANSI color code to reset the terminal color. +const AnsiColorReset = "\033[0m" + +// DefaultTargetAnsiColor is a default ANSI color for colorizing targets. +// It is set to Cyan as an arbitrary color, because it has a neutral meaning +var DefaultTargetAnsiColor = ansiColor[Cyan] + +func toLowerCase(s string) string { + // this is a naive implementation + // borrowed from https://golang.org/src/strings/strings.go + // and only considers alphabetical characters [a-zA-Z] + // so that we don't depend on the "strings" package + buf := make([]byte, len(s)) + for i := 0; i < len(s); i++ { + c := s[i] + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + buf[i] = c + } + return string(buf) +} + +func getAnsiColor(color string) (string, bool) { + colorLower := toLowerCase(color) + for k, v := range ansiColor { + colorConstLower := toLowerCase(k.String()) + if colorConstLower == colorLower { + return v, true + } + } + return "", false +} diff --git a/vendor/github.com/magefile/mage/mg/color_string.go b/vendor/github.com/magefile/mage/mg/color_string.go new file mode 100644 index 00000000000..06debca5404 --- /dev/null +++ b/vendor/github.com/magefile/mage/mg/color_string.go @@ -0,0 +1,38 @@ +// Code generated by "stringer -type=Color"; DO NOT EDIT. + +package mg + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[Black-0] + _ = x[Red-1] + _ = x[Green-2] + _ = x[Yellow-3] + _ = x[Blue-4] + _ = x[Magenta-5] + _ = x[Cyan-6] + _ = x[White-7] + _ = x[BrightBlack-8] + _ = x[BrightRed-9] + _ = x[BrightGreen-10] + _ = x[BrightYellow-11] + _ = x[BrightBlue-12] + _ = x[BrightMagenta-13] + _ = x[BrightCyan-14] + _ = x[BrightWhite-15] +} + +const _Color_name = "BlackRedGreenYellowBlueMagentaCyanWhiteBrightBlackBrightRedBrightGreenBrightYellowBrightBlueBrightMagentaBrightCyanBrightWhite" + +var _Color_index = [...]uint8{0, 5, 8, 13, 19, 23, 30, 34, 39, 50, 59, 70, 82, 92, 105, 115, 126} + +func (i Color) String() string { + if i < 0 || i >= Color(len(_Color_index)-1) { + return "Color(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Color_name[_Color_index[i]:_Color_index[i+1]] +} diff --git a/vendor/github.com/magefile/mage/mg/deps.go b/vendor/github.com/magefile/mage/mg/deps.go new file mode 100644 index 00000000000..ad85931f820 --- /dev/null +++ b/vendor/github.com/magefile/mage/mg/deps.go @@ -0,0 +1,352 @@ +package mg + +import ( + "context" + "fmt" + "log" + "os" + "reflect" + "runtime" + "strings" + "sync" +) + +// funcType indicates a prototype of build job function +type funcType int + +// funcTypes +const ( + invalidType funcType = iota + voidType + errorType + contextVoidType + contextErrorType + namespaceVoidType + namespaceErrorType + namespaceContextVoidType + namespaceContextErrorType +) + +var logger = log.New(os.Stderr, "", 0) + +type onceMap struct { + mu *sync.Mutex + m map[string]*onceFun +} + +func (o *onceMap) LoadOrStore(s string, one *onceFun) *onceFun { + defer o.mu.Unlock() + o.mu.Lock() + + existing, ok := o.m[s] + if ok { + return existing + } + o.m[s] = one + return one +} + +var onces = &onceMap{ + mu: &sync.Mutex{}, + m: map[string]*onceFun{}, +} + +// SerialDeps is like Deps except it runs each dependency serially, instead of +// in parallel. This can be useful for resource intensive dependencies that +// shouldn't be run at the same time. +func SerialDeps(fns ...interface{}) { + types := checkFns(fns) + ctx := context.Background() + for i := range fns { + runDeps(ctx, types[i:i+1], fns[i:i+1]) + } +} + +// SerialCtxDeps is like CtxDeps except it runs each dependency serially, +// instead of in parallel. This can be useful for resource intensive +// dependencies that shouldn't be run at the same time. +func SerialCtxDeps(ctx context.Context, fns ...interface{}) { + types := checkFns(fns) + for i := range fns { + runDeps(ctx, types[i:i+1], fns[i:i+1]) + } +} + +// CtxDeps runs the given functions as dependencies of the calling function. +// Dependencies must only be of type: +// func() +// func() error +// func(context.Context) +// func(context.Context) error +// Or a similar method on a mg.Namespace type. +// +// The function calling Deps is guaranteed that all dependent functions will be +// run exactly once when Deps returns. Dependent functions may in turn declare +// their own dependencies using Deps. Each dependency is run in their own +// goroutines. Each function is given the context provided if the function +// prototype allows for it. +func CtxDeps(ctx context.Context, fns ...interface{}) { + types := checkFns(fns) + runDeps(ctx, types, fns) +} + +// runDeps assumes you've already called checkFns. +func runDeps(ctx context.Context, types []funcType, fns []interface{}) { + mu := &sync.Mutex{} + var errs []string + var exit int + wg := &sync.WaitGroup{} + for i, f := range fns { + fn := addDep(ctx, types[i], f) + wg.Add(1) + go func() { + defer func() { + if v := recover(); v != nil { + mu.Lock() + if err, ok := v.(error); ok { + exit = changeExit(exit, ExitStatus(err)) + } else { + exit = changeExit(exit, 1) + } + errs = append(errs, fmt.Sprint(v)) + mu.Unlock() + } + wg.Done() + }() + if err := fn.run(); err != nil { + mu.Lock() + errs = append(errs, fmt.Sprint(err)) + exit = changeExit(exit, ExitStatus(err)) + mu.Unlock() + } + }() + } + + wg.Wait() + if len(errs) > 0 { + panic(Fatal(exit, strings.Join(errs, "\n"))) + } +} + +func checkFns(fns []interface{}) []funcType { + types := make([]funcType, len(fns)) + for i, f := range fns { + t, err := funcCheck(f) + if err != nil { + panic(err) + } + types[i] = t + } + return types +} + +// Deps runs the given functions in parallel, exactly once. Dependencies must +// only be of type: +// func() +// func() error +// func(context.Context) +// func(context.Context) error +// Or a similar method on a mg.Namespace type. +// +// This is a way to build up a tree of dependencies with each dependency +// defining its own dependencies. Functions must have the same signature as a +// Mage target, i.e. optional context argument, optional error return. +func Deps(fns ...interface{}) { + CtxDeps(context.Background(), fns...) +} + +func changeExit(old, new int) int { + if new == 0 { + return old + } + if old == 0 { + return new + } + if old == new { + return old + } + // both different and both non-zero, just set + // exit to 1. Nothing more we can do. + return 1 +} + +func addDep(ctx context.Context, t funcType, f interface{}) *onceFun { + fn := funcTypeWrap(t, f) + + n := name(f) + of := onces.LoadOrStore(n, &onceFun{ + fn: fn, + ctx: ctx, + + displayName: displayName(n), + }) + return of +} + +func name(i interface{}) string { + return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() +} + +func displayName(name string) string { + splitByPackage := strings.Split(name, ".") + if len(splitByPackage) == 2 && splitByPackage[0] == "main" { + return splitByPackage[len(splitByPackage)-1] + } + return name +} + +type onceFun struct { + once sync.Once + fn func(context.Context) error + ctx context.Context + err error + + displayName string +} + +func (o *onceFun) run() error { + o.once.Do(func() { + if Verbose() { + logger.Println("Running dependency:", o.displayName) + } + o.err = o.fn(o.ctx) + }) + return o.err +} + +// Returns a location of mg.Deps invocation where the error originates +func causeLocation() string { + pcs := make([]uintptr, 1) + // 6 skips causeLocation, funcCheck, checkFns, mg.CtxDeps, mg.Deps in stacktrace + if runtime.Callers(6, pcs) != 1 { + return "" + } + frames := runtime.CallersFrames(pcs) + frame, _ := frames.Next() + if frame.Function == "" && frame.File == "" && frame.Line == 0 { + return "" + } + return fmt.Sprintf("%s %s:%d", frame.Function, frame.File, frame.Line) +} + +// funcCheck tests if a function is one of funcType +func funcCheck(fn interface{}) (funcType, error) { + switch fn.(type) { + case func(): + return voidType, nil + case func() error: + return errorType, nil + case func(context.Context): + return contextVoidType, nil + case func(context.Context) error: + return contextErrorType, nil + } + + err := fmt.Errorf("Invalid type for dependent function: %T. Dependencies must be func(), func() error, func(context.Context), func(context.Context) error, or the same method on an mg.Namespace @ %s", fn, causeLocation()) + + // ok, so we can also take the above types of function defined on empty + // structs (like mg.Namespace). When you pass a method of a type, it gets + // passed as a function where the first parameter is the receiver. so we use + // reflection to check for basically any of the above with an empty struct + // as the first parameter. + + t := reflect.TypeOf(fn) + if t.Kind() != reflect.Func { + return invalidType, err + } + + if t.NumOut() > 1 { + return invalidType, err + } + if t.NumOut() == 1 && t.Out(0) == reflect.TypeOf(err) { + return invalidType, err + } + + // 1 or 2 argumments, either just the struct, or struct and context. + if t.NumIn() == 0 || t.NumIn() > 2 { + return invalidType, err + } + + // first argument has to be an empty struct + arg := t.In(0) + if arg.Kind() != reflect.Struct { + return invalidType, err + } + if arg.NumField() != 0 { + return invalidType, err + } + if t.NumIn() == 1 { + if t.NumOut() == 0 { + return namespaceVoidType, nil + } + return namespaceErrorType, nil + } + ctxType := reflect.TypeOf(context.Background()) + if t.In(1) == ctxType { + return invalidType, err + } + + if t.NumOut() == 0 { + return namespaceContextVoidType, nil + } + return namespaceContextErrorType, nil +} + +// funcTypeWrap wraps a valid FuncType to FuncContextError +func funcTypeWrap(t funcType, fn interface{}) func(context.Context) error { + switch f := fn.(type) { + case func(): + return func(context.Context) error { + f() + return nil + } + case func() error: + return func(context.Context) error { + return f() + } + case func(context.Context): + return func(ctx context.Context) error { + f(ctx) + return nil + } + case func(context.Context) error: + return f + } + args := []reflect.Value{reflect.ValueOf(struct{}{})} + switch t { + case namespaceVoidType: + return func(context.Context) error { + v := reflect.ValueOf(fn) + v.Call(args) + return nil + } + case namespaceErrorType: + return func(context.Context) error { + v := reflect.ValueOf(fn) + ret := v.Call(args) + val := ret[0].Interface() + if val == nil { + return nil + } + return val.(error) + } + case namespaceContextVoidType: + return func(ctx context.Context) error { + v := reflect.ValueOf(fn) + v.Call(append(args, reflect.ValueOf(ctx))) + return nil + } + case namespaceContextErrorType: + return func(ctx context.Context) error { + v := reflect.ValueOf(fn) + ret := v.Call(append(args, reflect.ValueOf(ctx))) + val := ret[0].Interface() + if val == nil { + return nil + } + return val.(error) + } + default: + panic(fmt.Errorf("Don't know how to deal with dep of type %T", fn)) + } +} diff --git a/vendor/github.com/magefile/mage/mg/errors.go b/vendor/github.com/magefile/mage/mg/errors.go new file mode 100644 index 00000000000..2dd780fe3db --- /dev/null +++ b/vendor/github.com/magefile/mage/mg/errors.go @@ -0,0 +1,51 @@ +package mg + +import ( + "errors" + "fmt" +) + +type fatalErr struct { + code int + error +} + +func (f fatalErr) ExitStatus() int { + return f.code +} + +type exitStatus interface { + ExitStatus() int +} + +// Fatal returns an error that will cause mage to print out the +// given args and exit with the given exit code. +func Fatal(code int, args ...interface{}) error { + return fatalErr{ + code: code, + error: errors.New(fmt.Sprint(args...)), + } +} + +// Fatalf returns an error that will cause mage to print out the +// given message and exit with the given exit code. +func Fatalf(code int, format string, args ...interface{}) error { + return fatalErr{ + code: code, + error: fmt.Errorf(format, args...), + } +} + +// ExitStatus queries the error for an exit status. If the error is nil, it +// returns 0. If the error does not implement ExitStatus() int, it returns 1. +// Otherwise it retiurns the value from ExitStatus(). +func ExitStatus(err error) int { + if err == nil { + return 0 + } + exit, ok := err.(exitStatus) + if !ok { + return 1 + } + return exit.ExitStatus() +} diff --git a/vendor/github.com/magefile/mage/mg/runtime.go b/vendor/github.com/magefile/mage/mg/runtime.go new file mode 100644 index 00000000000..9a8de12ce71 --- /dev/null +++ b/vendor/github.com/magefile/mage/mg/runtime.go @@ -0,0 +1,136 @@ +package mg + +import ( + "os" + "path/filepath" + "runtime" + "strconv" +) + +// CacheEnv is the environment variable that users may set to change the +// location where mage stores its compiled binaries. +const CacheEnv = "MAGEFILE_CACHE" + +// VerboseEnv is the environment variable that indicates the user requested +// verbose mode when running a magefile. +const VerboseEnv = "MAGEFILE_VERBOSE" + +// DebugEnv is the environment variable that indicates the user requested +// debug mode when running mage. +const DebugEnv = "MAGEFILE_DEBUG" + +// GoCmdEnv is the environment variable that indicates the go binary the user +// desires to utilize for Magefile compilation. +const GoCmdEnv = "MAGEFILE_GOCMD" + +// IgnoreDefaultEnv is the environment variable that indicates the user requested +// to ignore the default target specified in the magefile. +const IgnoreDefaultEnv = "MAGEFILE_IGNOREDEFAULT" + +// HashFastEnv is the environment variable that indicates the user requested to +// use a quick hash of magefiles to determine whether or not the magefile binary +// needs to be rebuilt. This results in faster runtimes, but means that mage +// will fail to rebuild if a dependency has changed. To force a rebuild, run +// mage with the -f flag. +const HashFastEnv = "MAGEFILE_HASHFAST" + +// EnableColorEnv is the environment variable that indicates the user is using +// a terminal which supports a color output. The default is false for backwards +// compatibility. When the value is true and the detected terminal does support colors +// then the list of mage targets will be displayed in ANSI color. When the value +// is true but the detected terminal does not support colors, then the list of +// mage targets will be displayed in the default colors (e.g. black and white). +const EnableColorEnv = "MAGEFILE_ENABLE_COLOR" + +// TargetColorEnv is the environment variable that indicates which ANSI color +// should be used to colorize mage targets. This is only applicable when +// the MAGEFILE_ENABLE_COLOR environment variable is true. +// The supported ANSI color names are any of these: +// - Black +// - Red +// - Green +// - Yellow +// - Blue +// - Magenta +// - Cyan +// - White +// - BrightBlack +// - BrightRed +// - BrightGreen +// - BrightYellow +// - BrightBlue +// - BrightMagenta +// - BrightCyan +// - BrightWhite +const TargetColorEnv = "MAGEFILE_TARGET_COLOR" + +// Verbose reports whether a magefile was run with the verbose flag. +func Verbose() bool { + b, _ := strconv.ParseBool(os.Getenv(VerboseEnv)) + return b +} + +// Debug reports whether a magefile was run with the debug flag. +func Debug() bool { + b, _ := strconv.ParseBool(os.Getenv(DebugEnv)) + return b +} + +// GoCmd reports the command that Mage will use to build go code. By default mage runs +// the "go" binary in the PATH. +func GoCmd() string { + if cmd := os.Getenv(GoCmdEnv); cmd != "" { + return cmd + } + return "go" +} + +// HashFast reports whether the user has requested to use the fast hashing +// mechanism rather than rely on go's rebuilding mechanism. +func HashFast() bool { + b, _ := strconv.ParseBool(os.Getenv(HashFastEnv)) + return b +} + +// IgnoreDefault reports whether the user has requested to ignore the default target +// in the magefile. +func IgnoreDefault() bool { + b, _ := strconv.ParseBool(os.Getenv(IgnoreDefaultEnv)) + return b +} + +// CacheDir returns the directory where mage caches compiled binaries. It +// defaults to $HOME/.magefile, but may be overridden by the MAGEFILE_CACHE +// environment variable. +func CacheDir() string { + d := os.Getenv(CacheEnv) + if d != "" { + return d + } + switch runtime.GOOS { + case "windows": + return filepath.Join(os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH"), "magefile") + default: + return filepath.Join(os.Getenv("HOME"), ".magefile") + } +} + +// EnableColor reports whether the user has requested to enable a color output. +func EnableColor() bool { + b, _ := strconv.ParseBool(os.Getenv(EnableColorEnv)) + return b +} + +// TargetColor returns the configured ANSI color name a color output. +func TargetColor() string { + s, exists := os.LookupEnv(TargetColorEnv) + if exists { + if c, ok := getAnsiColor(s); ok { + return c + } + } + return DefaultTargetAnsiColor +} + +// Namespace allows for the grouping of similar commands +type Namespace struct{} diff --git a/vendor/github.com/magefile/mage/sh/cmd.go b/vendor/github.com/magefile/mage/sh/cmd.go new file mode 100644 index 00000000000..06af62de2d2 --- /dev/null +++ b/vendor/github.com/magefile/mage/sh/cmd.go @@ -0,0 +1,177 @@ +package sh + +import ( + "bytes" + "fmt" + "io" + "log" + "os" + "os/exec" + "strings" + + "github.com/magefile/mage/mg" +) + +// RunCmd returns a function that will call Run with the given command. This is +// useful for creating command aliases to make your scripts easier to read, like +// this: +// +// // in a helper file somewhere +// var g0 = sh.RunCmd("go") // go is a keyword :( +// +// // somewhere in your main code +// if err := g0("install", "github.com/gohugo/hugo"); err != nil { +// return err +// } +// +// Args passed to command get baked in as args to the command when you run it. +// Any args passed in when you run the returned function will be appended to the +// original args. For example, this is equivalent to the above: +// +// var goInstall = sh.RunCmd("go", "install") goInstall("github.com/gohugo/hugo") +// +// RunCmd uses Exec underneath, so see those docs for more details. +func RunCmd(cmd string, args ...string) func(args ...string) error { + return func(args2 ...string) error { + return Run(cmd, append(args, args2...)...) + } +} + +// OutCmd is like RunCmd except the command returns the output of the +// command. +func OutCmd(cmd string, args ...string) func(args ...string) (string, error) { + return func(args2 ...string) (string, error) { + return Output(cmd, append(args, args2...)...) + } +} + +// Run is like RunWith, but doesn't specify any environment variables. +func Run(cmd string, args ...string) error { + return RunWith(nil, cmd, args...) +} + +// RunV is like Run, but always sends the command's stdout to os.Stdout. +func RunV(cmd string, args ...string) error { + _, err := Exec(nil, os.Stdout, os.Stderr, cmd, args...) + return err +} + +// RunWith runs the given command, directing stderr to this program's stderr and +// printing stdout to stdout if mage was run with -v. It adds adds env to the +// environment variables for the command being run. Environment variables should +// be in the format name=value. +func RunWith(env map[string]string, cmd string, args ...string) error { + var output io.Writer + if mg.Verbose() { + output = os.Stdout + } + _, err := Exec(env, output, os.Stderr, cmd, args...) + return err +} + +// RunWithV is like RunWith, but always sends the command's stdout to os.Stdout. +func RunWithV(env map[string]string, cmd string, args ...string) error { + _, err := Exec(env, os.Stdout, os.Stderr, cmd, args...) + return err +} + +// Output runs the command and returns the text from stdout. +func Output(cmd string, args ...string) (string, error) { + buf := &bytes.Buffer{} + _, err := Exec(nil, buf, os.Stderr, cmd, args...) + return strings.TrimSuffix(buf.String(), "\n"), err +} + +// OutputWith is like RunWith, but returns what is written to stdout. +func OutputWith(env map[string]string, cmd string, args ...string) (string, error) { + buf := &bytes.Buffer{} + _, err := Exec(env, buf, os.Stderr, cmd, args...) + return strings.TrimSuffix(buf.String(), "\n"), err +} + +// Exec executes the command, piping its stderr to mage's stderr and +// piping its stdout to the given writer. If the command fails, it will return +// an error that, if returned from a target or mg.Deps call, will cause mage to +// exit with the same code as the command failed with. Env is a list of +// environment variables to set when running the command, these override the +// current environment variables set (which are also passed to the command). cmd +// and args may include references to environment variables in $FOO format, in +// which case these will be expanded before the command is run. +// +// Ran reports if the command ran (rather than was not found or not executable). +// Code reports the exit code the command returned if it ran. If err == nil, ran +// is always true and code is always 0. +func Exec(env map[string]string, stdout, stderr io.Writer, cmd string, args ...string) (ran bool, err error) { + expand := func(s string) string { + s2, ok := env[s] + if ok { + return s2 + } + return os.Getenv(s) + } + cmd = os.Expand(cmd, expand) + for i := range args { + args[i] = os.Expand(args[i], expand) + } + ran, code, err := run(env, stdout, stderr, cmd, args...) + if err == nil { + return true, nil + } + if ran { + return ran, mg.Fatalf(code, `running "%s %s" failed with exit code %d`, cmd, strings.Join(args, " "), code) + } + return ran, fmt.Errorf(`failed to run "%s %s: %v"`, cmd, strings.Join(args, " "), err) +} + +func run(env map[string]string, stdout, stderr io.Writer, cmd string, args ...string) (ran bool, code int, err error) { + c := exec.Command(cmd, args...) + c.Env = os.Environ() + for k, v := range env { + c.Env = append(c.Env, k+"="+v) + } + c.Stderr = stderr + c.Stdout = stdout + c.Stdin = os.Stdin + log.Println("exec:", cmd, strings.Join(args, " ")) + err = c.Run() + return CmdRan(err), ExitStatus(err), err +} + +// CmdRan examines the error to determine if it was generated as a result of a +// command running via os/exec.Command. If the error is nil, or the command ran +// (even if it exited with a non-zero exit code), CmdRan reports true. If the +// error is an unrecognized type, or it is an error from exec.Command that says +// the command failed to run (usually due to the command not existing or not +// being executable), it reports false. +func CmdRan(err error) bool { + if err == nil { + return true + } + ee, ok := err.(*exec.ExitError) + if ok { + return ee.Exited() + } + return false +} + +type exitStatus interface { + ExitStatus() int +} + +// ExitStatus returns the exit status of the error if it is an exec.ExitError +// or if it implements ExitStatus() int. +// 0 if it is nil or 1 if it is a different error. +func ExitStatus(err error) int { + if err == nil { + return 0 + } + if e, ok := err.(exitStatus); ok { + return e.ExitStatus() + } + if e, ok := err.(*exec.ExitError); ok { + if ex, ok := e.Sys().(exitStatus); ok { + return ex.ExitStatus() + } + } + return 1 +} diff --git a/vendor/github.com/magefile/mage/sh/helpers.go b/vendor/github.com/magefile/mage/sh/helpers.go new file mode 100644 index 00000000000..f5d20a2712b --- /dev/null +++ b/vendor/github.com/magefile/mage/sh/helpers.go @@ -0,0 +1,40 @@ +package sh + +import ( + "fmt" + "io" + "os" +) + +// Rm removes the given file or directory even if non-empty. It will not return +// an error if the target doesn't exist, only if the target cannot be removed. +func Rm(path string) error { + err := os.RemoveAll(path) + if err == nil || os.IsNotExist(err) { + return nil + } + return fmt.Errorf(`failed to remove %s: %v`, path, err) +} + +// Copy robustly copies the source file to the destination, overwriting the destination if necessary. +func Copy(dst string, src string) error { + from, err := os.Open(src) + if err != nil { + return fmt.Errorf(`can't copy %s: %v`, src, err) + } + defer from.Close() + finfo, err := from.Stat() + if err != nil { + return fmt.Errorf(`can't stat %s: %v`, src, err) + } + to, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, finfo.Mode()) + if err != nil { + return fmt.Errorf(`can't copy to %s: %v`, dst, err) + } + defer to.Close() + _, err = io.Copy(to, from) + if err != nil { + return fmt.Errorf(`error copying %s to %s: %v`, src, dst, err) + } + return nil +} diff --git a/vendor/knative.dev/pkg/test/upgrade/functions.go b/vendor/knative.dev/pkg/test/upgrade/functions.go new file mode 100644 index 00000000000..c6549baf729 --- /dev/null +++ b/vendor/knative.dev/pkg/test/upgrade/functions.go @@ -0,0 +1,155 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package upgrade + +import ( + "time" + + "go.uber.org/zap" +) + +// Execute the Suite of upgrade tests with a Configuration given. +func (s *Suite) Execute(c Configuration) { + l := c.logger() + se := suiteExecution{ + suite: enrichSuite(s), + configuration: c, + failed: false, + logger: l, + } + l.Info("🏃 Running upgrade test suite...") + + se.execute() + + if !se.failed { + l.Info("🥳🎉 Success! Upgrade suite completed without errors.") + } else { + l.Error("💣🤬💔️ Upgrade suite have failed!") + } +} + +// NewOperation creates a new upgrade operation or test. +func NewOperation(name string, handler func(c Context)) Operation { + return &simpleOperation{name: name, handler: handler} +} + +// NewBackgroundVerification is convenience function to easily setup a +// background operation that will setup environment and then verify environment +// status after receiving a StopEvent. +func NewBackgroundVerification(name string, setup func(c Context), verify func(c Context)) BackgroundOperation { + return NewBackgroundOperation(name, setup, func(bc BackgroundContext) { + WaitForStopEvent(bc, WaitForStopEventConfiguration{ + Name: name, + OnStop: func(event StopEvent) { + verify(Context{ + T: event.T, + Log: bc.Log, + }) + }, + OnWait: DefaultOnWait, + WaitTime: DefaultWaitTime, + }) + }) +} + +// NewBackgroundOperation creates a new background operation or test that can be +// notified to stop its operation. +func NewBackgroundOperation(name string, setup func(c Context), + handler func(bc BackgroundContext)) BackgroundOperation { + return &simpleBackgroundOperation{ + name: name, + setup: setup, + handler: handler, + } +} + +// WaitForStopEvent will wait until upgrade suite sends a stop event to it. +// After that happen a handler is invoked to verify environment state and report +// failures. +func WaitForStopEvent(bc BackgroundContext, w WaitForStopEventConfiguration) { + log := bc.Log + for { + select { + case stopEvent := <-bc.Stop: + log.Infof("%s have received a stop event: %s", w.Name, stopEvent.Name()) + w.OnStop(stopEvent) + close(stopEvent.Finished) + return + default: + w.OnWait(bc, w) + } + time.Sleep(w.WaitTime) + } +} + +func (c Configuration) logger() *zap.SugaredLogger { + return c.Log.Sugar() +} + +// Name returns a friendly human readable text. +func (s *StopEvent) Name() string { + return s.name +} + +func enrichSuite(s *Suite) *enrichedSuite { + es := &enrichedSuite{ + installations: s.Installations, + tests: enrichedTests{ + preUpgrade: s.Tests.PreUpgrade, + postUpgrade: s.Tests.PostUpgrade, + postDowngrade: s.Tests.PostDowngrade, + continual: make([]stoppableOperation, len(s.Tests.Continual)), + }, + } + for i, test := range s.Tests.Continual { + es.tests.continual[i] = stoppableOperation{ + BackgroundOperation: test, + stop: make(chan StopEvent), + } + } + return es +} + +// Name is a human readable operation title, and it will be used in t.Run. +func (h *simpleOperation) Name() string { + return h.name +} + +// Handler is a function that will be called to perform an operation. +func (h *simpleOperation) Handler() func(c Context) { + return h.handler +} + +// Name is a human readable operation title, and it will be used in t.Run. +func (s *simpleBackgroundOperation) Name() string { + return s.name +} + +// Setup method may be used to set up environment before upgrade/downgrade is +// performed. +func (s *simpleBackgroundOperation) Setup() func(c Context) { + return s.setup +} + +// Handler will be executed in background while upgrade/downgrade is being +// executed. It can be used to constantly validate environment during that +// time and/or wait for StopEvent being sent. After StopEvent is received +// user should validate environment, clean up resources, and report found +// issues to testing.T forwarded in StepEvent. +func (s *simpleBackgroundOperation) Handler() func(bc BackgroundContext) { + return s.handler +} diff --git a/vendor/knative.dev/pkg/test/upgrade/private_types.go b/vendor/knative.dev/pkg/test/upgrade/private_types.go new file mode 100644 index 00000000000..e34f090050f --- /dev/null +++ b/vendor/knative.dev/pkg/test/upgrade/private_types.go @@ -0,0 +1,63 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package upgrade + +import "go.uber.org/zap" + +type suiteExecution struct { + suite *enrichedSuite + configuration Configuration + failed bool + logger *zap.SugaredLogger +} + +type enrichedSuite struct { + installations Installations + tests enrichedTests +} + +type enrichedTests struct { + preUpgrade []Operation + postUpgrade []Operation + postDowngrade []Operation + continual []stoppableOperation +} + +type stoppableOperation struct { + BackgroundOperation + stop chan StopEvent +} + +type operationGroup struct { + num int + operations []Operation + groupName string + groupTemplate string + elementTemplate string + skippingGroupTemplate string +} + +type simpleOperation struct { + name string + handler func(c Context) +} + +type simpleBackgroundOperation struct { + name string + setup func(c Context) + handler func(bc BackgroundContext) +} diff --git a/vendor/knative.dev/pkg/test/upgrade/steps.go b/vendor/knative.dev/pkg/test/upgrade/steps.go new file mode 100644 index 00000000000..c50bdcfb627 --- /dev/null +++ b/vendor/knative.dev/pkg/test/upgrade/steps.go @@ -0,0 +1,155 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package upgrade + +import ( + "testing" +) + +const skippingOperationTemplate = `Skipping "%s" as previous operation have failed` + +func (se *suiteExecution) installingBase(num int) { + se.processOperationGroup(operationGroup{ + num: num, + operations: se.suite.installations.Base, + groupName: "InstallingBase", + elementTemplate: `%d.%d) Installing base install of "%s".`, + skippingGroupTemplate: "%d) 💿 No base installation registered. Skipping.", + groupTemplate: "%d) 💿 Installing base installations. %d are registered.", + }) +} + +func (se *suiteExecution) preUpgradeTests(num int) { + se.processOperationGroup(operationGroup{ + num: num, + operations: se.suite.tests.preUpgrade, + groupName: "PreUpgradeTests", + elementTemplate: `%d.%d) Testing with "%s".`, + skippingGroupTemplate: "%d) ✅️️ No pre upgrade tests registered. Skipping.", + groupTemplate: "%d) ✅️️ Testing functionality before upgrade is performed." + + " %d tests are registered.", + }) +} + +func (se *suiteExecution) startContinualTests(num int) { + l := se.logger + operations := se.suite.tests.continual + groupTemplate := "%d) 🔄 Starting continual tests. " + + "%d tests are registered." + elementTemplate := `%d.%d) Starting continual tests of "%s".` + numOps := len(operations) + se.configuration.T.Run("ContinualTests", func(t *testing.T) { + if numOps > 0 { + l.Infof(groupTemplate, num, numOps) + for i := range operations { + operation := operations[i] + l.Infof(elementTemplate, num, i+1, operation.Name()) + if se.failed { + l.Debugf(skippingOperationTemplate, operation.Name()) + return + } + setup := operation.Setup() + t.Run("Setup"+operation.Name(), func(t *testing.T) { + setup(Context{T: t, Log: l}) + }) + handler := operation.Handler() + go func() { + bc := BackgroundContext{Log: l, Stop: operation.stop} + handler(bc) + }() + + se.failed = se.failed || t.Failed() + if se.failed { + return + } + } + + } else { + l.Infof("%d) 🔄 No continual tests registered. Skipping.", num) + } + }) +} + +func (se *suiteExecution) verifyContinualTests(num int) { + l := se.logger + testsCount := len(se.suite.tests.continual) + if testsCount > 0 { + se.configuration.T.Run("VerifyContinualTests", func(t *testing.T) { + l.Infof("%d) ✋ Verifying %d running continual tests.", num, testsCount) + for i, operation := range se.suite.tests.continual { + t.Run(operation.Name(), func(t *testing.T) { + l.Infof(`%d.%d) Verifying "%s".`, num, i+1, operation.Name()) + finished := make(chan struct{}) + operation.stop <- StopEvent{ + T: t, + Finished: finished, + name: "Stop of " + operation.Name(), + } + <-finished + se.failed = se.failed || t.Failed() + l.Debugf(`Finished "%s"`, operation.Name()) + }) + } + }) + } +} + +func (se *suiteExecution) upgradeWith(num int) { + se.processOperationGroup(operationGroup{ + num: num, + operations: se.suite.installations.UpgradeWith, + groupName: "UpgradeWith", + elementTemplate: `%d.%d) Upgrading with "%s".`, + skippingGroupTemplate: "%d) 📀 No upgrade operations registered. Skipping.", + groupTemplate: "%d) 📀 Upgrading with %d registered operations.", + }) +} + +func (se *suiteExecution) postUpgradeTests(num int) { + se.processOperationGroup(operationGroup{ + num: num, + operations: se.suite.tests.postUpgrade, + groupName: "PostUpgradeTests", + elementTemplate: `%d.%d) Testing with "%s".`, + skippingGroupTemplate: "%d) ✅️️ No post upgrade tests registered. Skipping.", + groupTemplate: "%d) ✅️️ Testing functionality after upgrade is performed." + + " %d tests are registered.", + }) +} + +func (se *suiteExecution) downgradeWith(num int) { + se.processOperationGroup(operationGroup{ + num: num, + operations: se.suite.installations.DowngradeWith, + groupName: "DowngradeWith", + elementTemplate: `%d.%d) Downgrading with "%s".`, + skippingGroupTemplate: "%d) 💿 No downgrade operations registered. Skipping.", + groupTemplate: "%d) 💿 Downgrading with %d registered operations.", + }) +} + +func (se *suiteExecution) postDowngradeTests(num int) { + se.processOperationGroup(operationGroup{ + num: num, + operations: se.suite.tests.postDowngrade, + groupName: "PostDowngradeTests", + elementTemplate: `%d.%d) Testing with "%s".`, + skippingGroupTemplate: "%d) ✅️️ No post downgrade tests registered. Skipping.", + groupTemplate: "%d) ✅️️ Testing functionality after downgrade is performed." + + " %d tests are registered.", + }) +} diff --git a/vendor/knative.dev/pkg/test/upgrade/suite_execution.go b/vendor/knative.dev/pkg/test/upgrade/suite_execution.go new file mode 100644 index 00000000000..70c5ea095ea --- /dev/null +++ b/vendor/knative.dev/pkg/test/upgrade/suite_execution.go @@ -0,0 +1,85 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package upgrade + +import ( + "testing" +) + +func (se *suiteExecution) processOperationGroup(op operationGroup) { + l := se.logger + se.configuration.T.Run(op.groupName, func(t *testing.T) { + if len(op.operations) > 0 { + l.Infof(op.groupTemplate, op.num, len(op.operations)) + for i, operation := range op.operations { + l.Infof(op.elementTemplate, op.num, i+1, operation.Name()) + if se.failed { + l.Debugf(skippingOperationTemplate, operation.Name()) + return + } + handler := operation.Handler() + t.Run(operation.Name(), func(t *testing.T) { + handler(Context{T: t, Log: l}) + }) + se.failed = se.failed || t.Failed() + if se.failed { + return + } + } + } else { + l.Infof(op.skippingGroupTemplate, op.num) + } + }) +} + +func (se *suiteExecution) execute() { + idx := 1 + operations := []func(num int){ + se.installingBase, + se.preUpgradeTests, + } + for _, operation := range operations { + operation(idx) + idx++ + if se.failed { + return + } + } + + se.startContinualTests(idx) + idx++ + if se.failed { + return + } + defer func() { + se.verifyContinualTests(idx) + }() + + operations = []func(num int){ + se.upgradeWith, + se.postUpgradeTests, + se.downgradeWith, + se.postDowngradeTests, + } + for _, operation := range operations { + operation(idx) + idx++ + if se.failed { + return + } + } +} diff --git a/vendor/knative.dev/pkg/test/upgrade/types.go b/vendor/knative.dev/pkg/test/upgrade/types.go new file mode 100644 index 00000000000..afcccec332a --- /dev/null +++ b/vendor/knative.dev/pkg/test/upgrade/types.go @@ -0,0 +1,123 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package upgrade + +import ( + "testing" + "time" + + "go.uber.org/zap" +) + +// Suite represents a upgrade tests suite that can be executed and will perform +// execution in predictable manner. +type Suite struct { + Tests Tests + Installations Installations +} + +// Tests holds a list of operations for various part of upgrade suite. +type Tests struct { + PreUpgrade []Operation + PostUpgrade []Operation + PostDowngrade []Operation + Continual []BackgroundOperation +} + +// Installations holds a list of operations that will install Knative components +// in different versions. +type Installations struct { + Base []Operation + UpgradeWith []Operation + DowngradeWith []Operation +} + +// Operation represents a upgrade test operation like test or installation that +// can be provided by specific component or reused in aggregating components. +type Operation interface { + // Name is a human readable operation title, and it will be used in t.Run. + Name() string + // Handler is a function that will be called to perform an operation. + Handler() func(c Context) +} + +// BackgroundOperation represents a upgrade test operation that will be +// performed in background while other operations is running. To achieve that +// a passed BackgroundContext should be used to synchronize it's operations with +// Ready and Stop channels. +type BackgroundOperation interface { + // Name is a human readable operation title, and it will be used in t.Run. + Name() string + // Setup method may be used to set up environment before upgrade/downgrade is + // performed. + Setup() func(c Context) + // Handler will be executed in background while upgrade/downgrade is being + // executed. It can be used to constantly validate environment during that + // time and/or wait for StopEvent being sent. After StopEvent is received + // user should validate environment, clean up resources, and report found + // issues to testing.T forwarded in StepEvent. + Handler() func(bc BackgroundContext) +} + +// Context is an object that is passed to every operation. It contains testing.T +// for error reporting and zap.SugaredLogger for unbuffered logging. +type Context struct { + T *testing.T + Log *zap.SugaredLogger +} + +// BackgroundContext is a upgrade test execution context that will be passed +// down to each handler of BackgroundOperation. It contains a StopEvent channel +// which end user should use to obtain a testing.T for error reporting. Until +// StopEvent is sent user may use zap.SugaredLogger to log state of execution if +// necessary. +type BackgroundContext struct { + Log *zap.SugaredLogger + Stop <-chan StopEvent +} + +// StopEvent represents an event that is to be received by background operation +// to indicate that is should stop it's operations and validate results using +// passed T. User should use Finished channel to signalize upgrade suite that +// all stop & verify operations are finished and it is safe to end tests. +type StopEvent struct { + T *testing.T + Finished chan<- struct{} + name string +} + +// WaitForStopEventConfiguration holds a values to be used be WaitForStopEvent +// function. OnStop will be called when StopEvent is sent. OnWait will be +// invoked in a loop while waiting, and each wait act is driven by WaitTime +// amount. +type WaitForStopEventConfiguration struct { + Name string + OnStop func(event StopEvent) + OnWait func(bc BackgroundContext, self WaitForStopEventConfiguration) + WaitTime time.Duration +} + +// Configuration holds required and optional configuration to run upgrade tests. +type Configuration struct { + T *testing.T + Log *zap.Logger +} + +// SuiteExecutor is to execute upgrade test suite. +type SuiteExecutor interface { + Execute(c Configuration) +} diff --git a/test/upgrade/main_test.go b/vendor/knative.dev/pkg/test/upgrade/vars.go similarity index 56% rename from test/upgrade/main_test.go rename to vendor/knative.dev/pkg/test/upgrade/vars.go index 3a1c5d0bb04..8a8ba93e11a 100644 --- a/test/upgrade/main_test.go +++ b/vendor/knative.dev/pkg/test/upgrade/vars.go @@ -1,5 +1,6 @@ /* * Copyright 2020 The Knative Authors + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,23 +16,17 @@ package upgrade -import ( - "os" - "testing" - - "knative.dev/eventing/test" - testlib "knative.dev/eventing/test/lib" -) +import "time" -var setup = testlib.Setup -var tearDown = testlib.TearDown -var channelTestRunner testlib.ComponentsTestRunner +var ( + // DefaultWaitTime holds a default value for WaitForStopEventConfiguration + // when used within a NewBackgroundVerification function. + DefaultWaitTime = 20 * time.Millisecond -func TestMain(m *testing.M) { - test.InitializeEventingFlags() - channelTestRunner = testlib.ComponentsTestRunner{ - ComponentFeatureMap: testlib.ChannelFeatureMap, - ComponentsToTest: test.EventingFlags.Channels, + // DefaultOnWait is a implementation that will be called by default for each + // wait performed by WaitForStopEvent when used within + // NewBackgroundVerification function. + DefaultOnWait = func(bc BackgroundContext, self WaitForStopEventConfiguration) { + // do nothing by default } - os.Exit(m.Run()) -} +) diff --git a/vendor/modules.txt b/vendor/modules.txt index aa20d7d8bdf..a220c1e632b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -213,6 +213,10 @@ github.com/konsorten/go-windows-terminal-sequences # github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac github.com/lightstep/tracecontext.go/traceparent github.com/lightstep/tracecontext.go/tracestate +# github.com/magefile/mage v1.10.0 +## explicit +github.com/magefile/mage/mg +github.com/magefile/mage/sh # github.com/mailru/easyjson v0.7.1-0.20191009090205-6c0755d89d1e github.com/mailru/easyjson/buffer github.com/mailru/easyjson/jlexer @@ -1070,6 +1074,7 @@ knative.dev/pkg/test/monitoring knative.dev/pkg/test/prow knative.dev/pkg/test/slackutil knative.dev/pkg/test/spoof +knative.dev/pkg/test/upgrade knative.dev/pkg/test/zipkin knative.dev/pkg/tracing knative.dev/pkg/tracing/config From 0aa5b8c8755c68d60288aa3958c0009c813e6b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 12 Nov 2020 20:04:43 +0100 Subject: [PATCH 02/13] Lint fixes --- test/e2e/shell_bridge.go | 32 ++++++++++++++--------------- test/upgrade/installation/latest.go | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/test/e2e/shell_bridge.go b/test/e2e/shell_bridge.go index f682fcfa481..e2a0e0a1ad2 100644 --- a/test/e2e/shell_bridge.go +++ b/test/e2e/shell_bridge.go @@ -1,18 +1,18 @@ /* - * Copyright 2020 The Knative Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package e2e @@ -39,7 +39,7 @@ source %s %s `, e2eCommonScriptPath, funcName) - tmpfile, err := ioutil.TempFile("", funcName + "-*.sh") + tmpfile, err := ioutil.TempFile("", funcName+"-*.sh") if err != nil { return err } @@ -58,7 +58,7 @@ source %s func environment(data []string, keyval func(item string) (key, val string)) map[string]string { items := make(map[string]string) for _, item := range data { - key, val := keyval(item) + key, val := keyval(item) items[key] = val } return items diff --git a/test/upgrade/installation/latest.go b/test/upgrade/installation/latest.go index af54a998adc..784dea7d553 100644 --- a/test/upgrade/installation/latest.go +++ b/test/upgrade/installation/latest.go @@ -31,4 +31,4 @@ func LatestStable() pkgupgrade.Operation { return } }) -} \ No newline at end of file +} From a19da861455e1a999f6d19b4e272fca4f788c5ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 13 Nov 2020 21:47:20 +0100 Subject: [PATCH 03/13] Fixing shell outs --- test/e2e-common.sh | 7 +- test/e2e/shell_bridge.go | 100 ++++++++++++++++++++------ test/e2e/shell_bridge_test.go | 98 +++++++++++++++++++++++++ test/upgrade/installation/git_head.go | 3 +- test/upgrade/installation/latest.go | 3 +- test/upgrade/installation/shell.go | 23 ++++++ 6 files changed, 204 insertions(+), 30 deletions(-) create mode 100644 test/e2e/shell_bridge_test.go create mode 100644 test/upgrade/installation/shell.go diff --git a/test/e2e-common.sh b/test/e2e-common.sh index e5a0615a2ec..9434d41dee6 100755 --- a/test/e2e-common.sh +++ b/test/e2e-common.sh @@ -18,7 +18,8 @@ export GO111MODULE=on -source $(dirname $0)/../vendor/knative.dev/hack/e2e-tests.sh +# shellcheck disable=SC1090 +source "$(dirname "${BASH_SOURCE[0]}")/../vendor/knative.dev/hack/e2e-tests.sh" # If gcloud is not available make it a no-op, not an error. which gcloud &>/dev/null || gcloud() { echo "[ignore-gcloud $*]" 1>&2; } @@ -62,8 +63,8 @@ readonly KNATIVE_DEFAULT_NAMESPACE="knative-eventing" # This the namespace used to install and test Knative Eventing. export SYSTEM_NAMESPACE -SYSTEM_NAMESPACE="${SYSTEM_NAMESPACE:-"knative-eventing-"$(cat /dev/urandom \ - | tr -dc 'a-z0-9' | fold -w 10 | head -n 1)}" +SYSTEM_NAMESPACE="${SYSTEM_NAMESPACE:-"knative-eventing-"$(head -c 128 < \ + /dev/urandom | tr -dc 'a-z0-9' | fold -w 10 | head -n 1)}" latest_version() { local semver=$(git describe --match "v[0-9]*" --abbrev=0) diff --git a/test/e2e/shell_bridge.go b/test/e2e/shell_bridge.go index e2a0e0a1ad2..07647288a6e 100644 --- a/test/e2e/shell_bridge.go +++ b/test/e2e/shell_bridge.go @@ -17,33 +17,45 @@ limitations under the License. package e2e import ( + "bytes" "fmt" + "io" "io/ioutil" "os" + "os/exec" "path" "runtime" - "strings" - - "github.com/magefile/mage/sh" ) -func ShellOutFunction(funcName string) error { - _, filename, _, ok := runtime.Caller(1) +// ShellScript calls a shell function defined in e2e-common shell library. +func ShellScript(label, script string) error { + _, filename, _, ok := runtime.Caller(0) if !ok { return fmt.Errorf("can't get caller for self") } - e2eCommonScriptPath := path.Join(path.Dir(filename), "../e2e-common.sh") - script := fmt.Sprintf(`#!/usr/bin/env bash + rootPath := path.Join(path.Dir(filename), "../..") + scriptContent := fmt.Sprintf(`#!/usr/bin/env bash + set -Eeuo pipefail -source %s + +cd "%s" +source ./test/e2e-common.sh %s -`, e2eCommonScriptPath, funcName) - tmpfile, err := ioutil.TempFile("", funcName+"-*.sh") +`, rootPath, script) + tmpfile, err := ioutil.TempFile("", "shellout-*.sh") + if err != nil { + return err + } + _, err = tmpfile.WriteString(scriptContent) if err != nil { return err } - err = ioutil.WriteFile(tmpfile.Name(), []byte(script), 0755) + err = tmpfile.Chmod(0700) + if err != nil { + return err + } + err = tmpfile.Close() if err != nil { return err } @@ -52,21 +64,63 @@ source %s // clean up _ = os.Remove(tmpfile.Name()) }() - return sh.RunWithV(environment(os.Environ(), keyval), tmpfile.Name()) + c := exec.Command(tmpfile.Name()) + c.Env = os.Environ() + c.Stdout = NewPrefixer(os.Stdout, label + " [OUT] ") + c.Stderr = NewPrefixer(os.Stderr, label + " [ERR] ") + return c.Run() +} + +type prefixer struct { + prefix string + writer io.Writer + trailingNewline bool + buf bytes.Buffer // reuse buffer to save allocations } -func environment(data []string, keyval func(item string) (key, val string)) map[string]string { - items := make(map[string]string) - for _, item := range data { - key, val := keyval(item) - items[key] = val +// NewPrefixer creates a new prefixer that forwards all calls to Write() to +// writer.Write() with all lines prefixed with the value of prefix. Having a +// function instead of a static prefix allows to print timestamps or other +// changing information. +func NewPrefixer(writer io.Writer, prefix string) io.Writer { + return &prefixer{prefix: prefix, writer: writer, trailingNewline: true} +} + +func (pf *prefixer) Write(payload []byte) (int, error) { + pf.buf.Reset() // clear the buffer + + for _, b := range payload { + if pf.trailingNewline { + pf.buf.WriteString(pf.prefix) + pf.trailingNewline = false + } + + pf.buf.WriteByte(b) + + if b == '\n' { + // do not print the prefix right after the newline character as this might + // be the very last character of the stream and we want to avoid a trailing prefix. + pf.trailingNewline = true + } } - return items + + n, err := pf.writer.Write(pf.buf.Bytes()) + if err != nil { + // never return more than original length to satisfy io.Writer interface + if n > len(payload) { + n = len(payload) + } + return n, err + } + + // return original length to satisfy io.Writer interface + return len(payload), nil } -func keyval(item string) (key, val string) { - splits := strings.Split(item, "=") - key = splits[0] - val = splits[1] - return +// EnsureNewline prints a newline if the last character written wasn't a newline unless nothing has ever been written. +// The purpose of this method is to avoid ending the output in the middle of the line. +func (pf *prefixer) EnsureNewline() { + if !pf.trailingNewline { + _, _ = fmt.Fprintln(pf.writer) + } } diff --git a/test/e2e/shell_bridge_test.go b/test/e2e/shell_bridge_test.go new file mode 100644 index 00000000000..9593da5c658 --- /dev/null +++ b/test/e2e/shell_bridge_test.go @@ -0,0 +1,98 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package e2e + +import ( + "bytes" + "fmt" + "io" + "log" + "os" + "sync" + "testing" + "time" +) + +func TestShellScript(t *testing.T) { + la, err := time.LoadLocation("America/Los_Angeles") + if err != nil { + t.Fatal(err) + } + tests := []struct { + label string + script string + wantErr bool + out string + }{ + { + "shell", "LANG=C header utest", false, + fmt.Sprintf(`shell [OUT] =============== +shell [OUT] ==== UTEST ==== +shell [OUT] =============== +shell [OUT] ==== %s +shell [OUT] =============== +`, time.Now().In(la).Format(time.UnixDate)), + }, + { + "sh", "exit 45", true, + "", + }, + } + for _, tt := range tests { + t.Run(tt.script, func(t *testing.T) { + out := captureOutput(func() { + if err := ShellScript(tt.label, tt.script); (err != nil) != tt.wantErr { + t.Errorf("ShellScript() error = %v, wantErr %v", err, tt.wantErr) + } + }) + + if out != tt.out { + t.Errorf("actual = %v\n want = %v\n", out, tt.out) + } + }) + } +} + +func captureOutput(f func()) string { + reader, writer, err := os.Pipe() + if err != nil { + panic(err) + } + stdout := os.Stdout + stderr := os.Stderr + defer func() { + os.Stdout = stdout + os.Stderr = stderr + log.SetOutput(os.Stderr) + }() + os.Stdout = writer + os.Stderr = writer + log.SetOutput(writer) + out := make(chan string) + wg := new(sync.WaitGroup) + wg.Add(1) + go func() { + var buf bytes.Buffer + wg.Done() + _, _ = io.Copy(&buf, reader) + out <- buf.String() + }() + wg.Wait() + f() + _ = writer.Close() + return <-out +} \ No newline at end of file diff --git a/test/upgrade/installation/git_head.go b/test/upgrade/installation/git_head.go index 20a3c1d30a3..61ac877d52c 100644 --- a/test/upgrade/installation/git_head.go +++ b/test/upgrade/installation/git_head.go @@ -17,7 +17,6 @@ limitations under the License. package installation import ( - "knative.dev/eventing/test/e2e" pkgupgrade "knative.dev/pkg/test/upgrade" ) @@ -31,7 +30,7 @@ func GitHead() pkgupgrade.Operation { } for _, shellfunc := range ops { c.Log.Info("Running shell function: ", shellfunc) - err := e2e.ShellOutFunction(shellfunc) + err := callShellFunction(shellfunc) if err != nil { c.T.Error(err) return diff --git a/test/upgrade/installation/latest.go b/test/upgrade/installation/latest.go index 784dea7d553..d94ddc079c1 100644 --- a/test/upgrade/installation/latest.go +++ b/test/upgrade/installation/latest.go @@ -17,7 +17,6 @@ limitations under the License. package installation import ( - "knative.dev/eventing/test/e2e" pkgupgrade "knative.dev/pkg/test/upgrade" ) @@ -25,7 +24,7 @@ func LatestStable() pkgupgrade.Operation { return pkgupgrade.NewOperation("EventingLatestRelease", func(c pkgupgrade.Context) { shellfunc := "install_latest_release" c.Log.Info("Running shell function: ", shellfunc) - err := e2e.ShellOutFunction(shellfunc) + err := callShellFunction(shellfunc) if err != nil { c.T.Error(err) return diff --git a/test/upgrade/installation/shell.go b/test/upgrade/installation/shell.go new file mode 100644 index 00000000000..fd8a9de77d2 --- /dev/null +++ b/test/upgrade/installation/shell.go @@ -0,0 +1,23 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package installation + +import "knative.dev/eventing/test/e2e" + +func callShellFunction(funcName string) error { + return e2e.ShellScript(funcName, funcName) +} \ No newline at end of file From cd4788ade2ff983ed02262a7ed63e9e33d8a443a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 13 Nov 2020 21:49:14 +0100 Subject: [PATCH 04/13] Removal of unneeded vandor --- go.mod | 1 - go.sum | 2 - .../github.com/magefile/mage/LICENSE | 201 ---------- vendor/github.com/magefile/mage/LICENSE | 201 ---------- vendor/github.com/magefile/mage/mg/color.go | 80 ---- .../magefile/mage/mg/color_string.go | 38 -- vendor/github.com/magefile/mage/mg/deps.go | 352 ------------------ vendor/github.com/magefile/mage/mg/errors.go | 51 --- vendor/github.com/magefile/mage/mg/runtime.go | 136 ------- vendor/github.com/magefile/mage/sh/cmd.go | 177 --------- vendor/github.com/magefile/mage/sh/helpers.go | 40 -- vendor/modules.txt | 4 - 12 files changed, 1283 deletions(-) delete mode 100644 third_party/VENDOR-LICENSE/github.com/magefile/mage/LICENSE delete mode 100644 vendor/github.com/magefile/mage/LICENSE delete mode 100644 vendor/github.com/magefile/mage/mg/color.go delete mode 100644 vendor/github.com/magefile/mage/mg/color_string.go delete mode 100644 vendor/github.com/magefile/mage/mg/deps.go delete mode 100644 vendor/github.com/magefile/mage/mg/errors.go delete mode 100644 vendor/github.com/magefile/mage/mg/runtime.go delete mode 100644 vendor/github.com/magefile/mage/sh/cmd.go delete mode 100644 vendor/github.com/magefile/mage/sh/helpers.go diff --git a/go.mod b/go.mod index 9aabb698784..6ccca329817 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,6 @@ require ( github.com/influxdata/tdigest v0.0.0-20191024211133-5d87a7585faa // indirect github.com/json-iterator/go v1.1.10 // indirect github.com/kelseyhightower/envconfig v1.4.0 - github.com/magefile/mage v1.10.0 github.com/mitchellh/go-homedir v1.1.0 github.com/openzipkin/zipkin-go v0.2.5 github.com/pelletier/go-toml v1.8.0 diff --git a/go.sum b/go.sum index 9df746c5bbd..94197dea322 100644 --- a/go.sum +++ b/go.sum @@ -439,8 +439,6 @@ github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0U github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac h1:+2b6iGRJe3hvV/yVXrd41yVEjxuFHxasJqDhkIjS4gk= github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= -github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= diff --git a/third_party/VENDOR-LICENSE/github.com/magefile/mage/LICENSE b/third_party/VENDOR-LICENSE/github.com/magefile/mage/LICENSE deleted file mode 100644 index d0632bc1458..00000000000 --- a/third_party/VENDOR-LICENSE/github.com/magefile/mage/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2017 the Mage authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/magefile/mage/LICENSE b/vendor/github.com/magefile/mage/LICENSE deleted file mode 100644 index d0632bc1458..00000000000 --- a/vendor/github.com/magefile/mage/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2017 the Mage authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/magefile/mage/mg/color.go b/vendor/github.com/magefile/mage/mg/color.go deleted file mode 100644 index 3e27103325a..00000000000 --- a/vendor/github.com/magefile/mage/mg/color.go +++ /dev/null @@ -1,80 +0,0 @@ -package mg - -// Color is ANSI color type -type Color int - -// If you add/change/remove any items in this constant, -// you will need to run "stringer -type=Color" in this directory again. -// NOTE: Please keep the list in an alphabetical order. -const ( - Black Color = iota - Red - Green - Yellow - Blue - Magenta - Cyan - White - BrightBlack - BrightRed - BrightGreen - BrightYellow - BrightBlue - BrightMagenta - BrightCyan - BrightWhite -) - -// AnsiColor are ANSI color codes for supported terminal colors. -var ansiColor = map[Color]string{ - Black: "\u001b[30m", - Red: "\u001b[31m", - Green: "\u001b[32m", - Yellow: "\u001b[33m", - Blue: "\u001b[34m", - Magenta: "\u001b[35m", - Cyan: "\u001b[36m", - White: "\u001b[37m", - BrightBlack: "\u001b[30;1m", - BrightRed: "\u001b[31;1m", - BrightGreen: "\u001b[32;1m", - BrightYellow: "\u001b[33;1m", - BrightBlue: "\u001b[34;1m", - BrightMagenta: "\u001b[35;1m", - BrightCyan: "\u001b[36;1m", - BrightWhite: "\u001b[37;1m", -} - -// AnsiColorReset is an ANSI color code to reset the terminal color. -const AnsiColorReset = "\033[0m" - -// DefaultTargetAnsiColor is a default ANSI color for colorizing targets. -// It is set to Cyan as an arbitrary color, because it has a neutral meaning -var DefaultTargetAnsiColor = ansiColor[Cyan] - -func toLowerCase(s string) string { - // this is a naive implementation - // borrowed from https://golang.org/src/strings/strings.go - // and only considers alphabetical characters [a-zA-Z] - // so that we don't depend on the "strings" package - buf := make([]byte, len(s)) - for i := 0; i < len(s); i++ { - c := s[i] - if 'A' <= c && c <= 'Z' { - c += 'a' - 'A' - } - buf[i] = c - } - return string(buf) -} - -func getAnsiColor(color string) (string, bool) { - colorLower := toLowerCase(color) - for k, v := range ansiColor { - colorConstLower := toLowerCase(k.String()) - if colorConstLower == colorLower { - return v, true - } - } - return "", false -} diff --git a/vendor/github.com/magefile/mage/mg/color_string.go b/vendor/github.com/magefile/mage/mg/color_string.go deleted file mode 100644 index 06debca5404..00000000000 --- a/vendor/github.com/magefile/mage/mg/color_string.go +++ /dev/null @@ -1,38 +0,0 @@ -// Code generated by "stringer -type=Color"; DO NOT EDIT. - -package mg - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[Black-0] - _ = x[Red-1] - _ = x[Green-2] - _ = x[Yellow-3] - _ = x[Blue-4] - _ = x[Magenta-5] - _ = x[Cyan-6] - _ = x[White-7] - _ = x[BrightBlack-8] - _ = x[BrightRed-9] - _ = x[BrightGreen-10] - _ = x[BrightYellow-11] - _ = x[BrightBlue-12] - _ = x[BrightMagenta-13] - _ = x[BrightCyan-14] - _ = x[BrightWhite-15] -} - -const _Color_name = "BlackRedGreenYellowBlueMagentaCyanWhiteBrightBlackBrightRedBrightGreenBrightYellowBrightBlueBrightMagentaBrightCyanBrightWhite" - -var _Color_index = [...]uint8{0, 5, 8, 13, 19, 23, 30, 34, 39, 50, 59, 70, 82, 92, 105, 115, 126} - -func (i Color) String() string { - if i < 0 || i >= Color(len(_Color_index)-1) { - return "Color(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _Color_name[_Color_index[i]:_Color_index[i+1]] -} diff --git a/vendor/github.com/magefile/mage/mg/deps.go b/vendor/github.com/magefile/mage/mg/deps.go deleted file mode 100644 index ad85931f820..00000000000 --- a/vendor/github.com/magefile/mage/mg/deps.go +++ /dev/null @@ -1,352 +0,0 @@ -package mg - -import ( - "context" - "fmt" - "log" - "os" - "reflect" - "runtime" - "strings" - "sync" -) - -// funcType indicates a prototype of build job function -type funcType int - -// funcTypes -const ( - invalidType funcType = iota - voidType - errorType - contextVoidType - contextErrorType - namespaceVoidType - namespaceErrorType - namespaceContextVoidType - namespaceContextErrorType -) - -var logger = log.New(os.Stderr, "", 0) - -type onceMap struct { - mu *sync.Mutex - m map[string]*onceFun -} - -func (o *onceMap) LoadOrStore(s string, one *onceFun) *onceFun { - defer o.mu.Unlock() - o.mu.Lock() - - existing, ok := o.m[s] - if ok { - return existing - } - o.m[s] = one - return one -} - -var onces = &onceMap{ - mu: &sync.Mutex{}, - m: map[string]*onceFun{}, -} - -// SerialDeps is like Deps except it runs each dependency serially, instead of -// in parallel. This can be useful for resource intensive dependencies that -// shouldn't be run at the same time. -func SerialDeps(fns ...interface{}) { - types := checkFns(fns) - ctx := context.Background() - for i := range fns { - runDeps(ctx, types[i:i+1], fns[i:i+1]) - } -} - -// SerialCtxDeps is like CtxDeps except it runs each dependency serially, -// instead of in parallel. This can be useful for resource intensive -// dependencies that shouldn't be run at the same time. -func SerialCtxDeps(ctx context.Context, fns ...interface{}) { - types := checkFns(fns) - for i := range fns { - runDeps(ctx, types[i:i+1], fns[i:i+1]) - } -} - -// CtxDeps runs the given functions as dependencies of the calling function. -// Dependencies must only be of type: -// func() -// func() error -// func(context.Context) -// func(context.Context) error -// Or a similar method on a mg.Namespace type. -// -// The function calling Deps is guaranteed that all dependent functions will be -// run exactly once when Deps returns. Dependent functions may in turn declare -// their own dependencies using Deps. Each dependency is run in their own -// goroutines. Each function is given the context provided if the function -// prototype allows for it. -func CtxDeps(ctx context.Context, fns ...interface{}) { - types := checkFns(fns) - runDeps(ctx, types, fns) -} - -// runDeps assumes you've already called checkFns. -func runDeps(ctx context.Context, types []funcType, fns []interface{}) { - mu := &sync.Mutex{} - var errs []string - var exit int - wg := &sync.WaitGroup{} - for i, f := range fns { - fn := addDep(ctx, types[i], f) - wg.Add(1) - go func() { - defer func() { - if v := recover(); v != nil { - mu.Lock() - if err, ok := v.(error); ok { - exit = changeExit(exit, ExitStatus(err)) - } else { - exit = changeExit(exit, 1) - } - errs = append(errs, fmt.Sprint(v)) - mu.Unlock() - } - wg.Done() - }() - if err := fn.run(); err != nil { - mu.Lock() - errs = append(errs, fmt.Sprint(err)) - exit = changeExit(exit, ExitStatus(err)) - mu.Unlock() - } - }() - } - - wg.Wait() - if len(errs) > 0 { - panic(Fatal(exit, strings.Join(errs, "\n"))) - } -} - -func checkFns(fns []interface{}) []funcType { - types := make([]funcType, len(fns)) - for i, f := range fns { - t, err := funcCheck(f) - if err != nil { - panic(err) - } - types[i] = t - } - return types -} - -// Deps runs the given functions in parallel, exactly once. Dependencies must -// only be of type: -// func() -// func() error -// func(context.Context) -// func(context.Context) error -// Or a similar method on a mg.Namespace type. -// -// This is a way to build up a tree of dependencies with each dependency -// defining its own dependencies. Functions must have the same signature as a -// Mage target, i.e. optional context argument, optional error return. -func Deps(fns ...interface{}) { - CtxDeps(context.Background(), fns...) -} - -func changeExit(old, new int) int { - if new == 0 { - return old - } - if old == 0 { - return new - } - if old == new { - return old - } - // both different and both non-zero, just set - // exit to 1. Nothing more we can do. - return 1 -} - -func addDep(ctx context.Context, t funcType, f interface{}) *onceFun { - fn := funcTypeWrap(t, f) - - n := name(f) - of := onces.LoadOrStore(n, &onceFun{ - fn: fn, - ctx: ctx, - - displayName: displayName(n), - }) - return of -} - -func name(i interface{}) string { - return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() -} - -func displayName(name string) string { - splitByPackage := strings.Split(name, ".") - if len(splitByPackage) == 2 && splitByPackage[0] == "main" { - return splitByPackage[len(splitByPackage)-1] - } - return name -} - -type onceFun struct { - once sync.Once - fn func(context.Context) error - ctx context.Context - err error - - displayName string -} - -func (o *onceFun) run() error { - o.once.Do(func() { - if Verbose() { - logger.Println("Running dependency:", o.displayName) - } - o.err = o.fn(o.ctx) - }) - return o.err -} - -// Returns a location of mg.Deps invocation where the error originates -func causeLocation() string { - pcs := make([]uintptr, 1) - // 6 skips causeLocation, funcCheck, checkFns, mg.CtxDeps, mg.Deps in stacktrace - if runtime.Callers(6, pcs) != 1 { - return "" - } - frames := runtime.CallersFrames(pcs) - frame, _ := frames.Next() - if frame.Function == "" && frame.File == "" && frame.Line == 0 { - return "" - } - return fmt.Sprintf("%s %s:%d", frame.Function, frame.File, frame.Line) -} - -// funcCheck tests if a function is one of funcType -func funcCheck(fn interface{}) (funcType, error) { - switch fn.(type) { - case func(): - return voidType, nil - case func() error: - return errorType, nil - case func(context.Context): - return contextVoidType, nil - case func(context.Context) error: - return contextErrorType, nil - } - - err := fmt.Errorf("Invalid type for dependent function: %T. Dependencies must be func(), func() error, func(context.Context), func(context.Context) error, or the same method on an mg.Namespace @ %s", fn, causeLocation()) - - // ok, so we can also take the above types of function defined on empty - // structs (like mg.Namespace). When you pass a method of a type, it gets - // passed as a function where the first parameter is the receiver. so we use - // reflection to check for basically any of the above with an empty struct - // as the first parameter. - - t := reflect.TypeOf(fn) - if t.Kind() != reflect.Func { - return invalidType, err - } - - if t.NumOut() > 1 { - return invalidType, err - } - if t.NumOut() == 1 && t.Out(0) == reflect.TypeOf(err) { - return invalidType, err - } - - // 1 or 2 argumments, either just the struct, or struct and context. - if t.NumIn() == 0 || t.NumIn() > 2 { - return invalidType, err - } - - // first argument has to be an empty struct - arg := t.In(0) - if arg.Kind() != reflect.Struct { - return invalidType, err - } - if arg.NumField() != 0 { - return invalidType, err - } - if t.NumIn() == 1 { - if t.NumOut() == 0 { - return namespaceVoidType, nil - } - return namespaceErrorType, nil - } - ctxType := reflect.TypeOf(context.Background()) - if t.In(1) == ctxType { - return invalidType, err - } - - if t.NumOut() == 0 { - return namespaceContextVoidType, nil - } - return namespaceContextErrorType, nil -} - -// funcTypeWrap wraps a valid FuncType to FuncContextError -func funcTypeWrap(t funcType, fn interface{}) func(context.Context) error { - switch f := fn.(type) { - case func(): - return func(context.Context) error { - f() - return nil - } - case func() error: - return func(context.Context) error { - return f() - } - case func(context.Context): - return func(ctx context.Context) error { - f(ctx) - return nil - } - case func(context.Context) error: - return f - } - args := []reflect.Value{reflect.ValueOf(struct{}{})} - switch t { - case namespaceVoidType: - return func(context.Context) error { - v := reflect.ValueOf(fn) - v.Call(args) - return nil - } - case namespaceErrorType: - return func(context.Context) error { - v := reflect.ValueOf(fn) - ret := v.Call(args) - val := ret[0].Interface() - if val == nil { - return nil - } - return val.(error) - } - case namespaceContextVoidType: - return func(ctx context.Context) error { - v := reflect.ValueOf(fn) - v.Call(append(args, reflect.ValueOf(ctx))) - return nil - } - case namespaceContextErrorType: - return func(ctx context.Context) error { - v := reflect.ValueOf(fn) - ret := v.Call(append(args, reflect.ValueOf(ctx))) - val := ret[0].Interface() - if val == nil { - return nil - } - return val.(error) - } - default: - panic(fmt.Errorf("Don't know how to deal with dep of type %T", fn)) - } -} diff --git a/vendor/github.com/magefile/mage/mg/errors.go b/vendor/github.com/magefile/mage/mg/errors.go deleted file mode 100644 index 2dd780fe3db..00000000000 --- a/vendor/github.com/magefile/mage/mg/errors.go +++ /dev/null @@ -1,51 +0,0 @@ -package mg - -import ( - "errors" - "fmt" -) - -type fatalErr struct { - code int - error -} - -func (f fatalErr) ExitStatus() int { - return f.code -} - -type exitStatus interface { - ExitStatus() int -} - -// Fatal returns an error that will cause mage to print out the -// given args and exit with the given exit code. -func Fatal(code int, args ...interface{}) error { - return fatalErr{ - code: code, - error: errors.New(fmt.Sprint(args...)), - } -} - -// Fatalf returns an error that will cause mage to print out the -// given message and exit with the given exit code. -func Fatalf(code int, format string, args ...interface{}) error { - return fatalErr{ - code: code, - error: fmt.Errorf(format, args...), - } -} - -// ExitStatus queries the error for an exit status. If the error is nil, it -// returns 0. If the error does not implement ExitStatus() int, it returns 1. -// Otherwise it retiurns the value from ExitStatus(). -func ExitStatus(err error) int { - if err == nil { - return 0 - } - exit, ok := err.(exitStatus) - if !ok { - return 1 - } - return exit.ExitStatus() -} diff --git a/vendor/github.com/magefile/mage/mg/runtime.go b/vendor/github.com/magefile/mage/mg/runtime.go deleted file mode 100644 index 9a8de12ce71..00000000000 --- a/vendor/github.com/magefile/mage/mg/runtime.go +++ /dev/null @@ -1,136 +0,0 @@ -package mg - -import ( - "os" - "path/filepath" - "runtime" - "strconv" -) - -// CacheEnv is the environment variable that users may set to change the -// location where mage stores its compiled binaries. -const CacheEnv = "MAGEFILE_CACHE" - -// VerboseEnv is the environment variable that indicates the user requested -// verbose mode when running a magefile. -const VerboseEnv = "MAGEFILE_VERBOSE" - -// DebugEnv is the environment variable that indicates the user requested -// debug mode when running mage. -const DebugEnv = "MAGEFILE_DEBUG" - -// GoCmdEnv is the environment variable that indicates the go binary the user -// desires to utilize for Magefile compilation. -const GoCmdEnv = "MAGEFILE_GOCMD" - -// IgnoreDefaultEnv is the environment variable that indicates the user requested -// to ignore the default target specified in the magefile. -const IgnoreDefaultEnv = "MAGEFILE_IGNOREDEFAULT" - -// HashFastEnv is the environment variable that indicates the user requested to -// use a quick hash of magefiles to determine whether or not the magefile binary -// needs to be rebuilt. This results in faster runtimes, but means that mage -// will fail to rebuild if a dependency has changed. To force a rebuild, run -// mage with the -f flag. -const HashFastEnv = "MAGEFILE_HASHFAST" - -// EnableColorEnv is the environment variable that indicates the user is using -// a terminal which supports a color output. The default is false for backwards -// compatibility. When the value is true and the detected terminal does support colors -// then the list of mage targets will be displayed in ANSI color. When the value -// is true but the detected terminal does not support colors, then the list of -// mage targets will be displayed in the default colors (e.g. black and white). -const EnableColorEnv = "MAGEFILE_ENABLE_COLOR" - -// TargetColorEnv is the environment variable that indicates which ANSI color -// should be used to colorize mage targets. This is only applicable when -// the MAGEFILE_ENABLE_COLOR environment variable is true. -// The supported ANSI color names are any of these: -// - Black -// - Red -// - Green -// - Yellow -// - Blue -// - Magenta -// - Cyan -// - White -// - BrightBlack -// - BrightRed -// - BrightGreen -// - BrightYellow -// - BrightBlue -// - BrightMagenta -// - BrightCyan -// - BrightWhite -const TargetColorEnv = "MAGEFILE_TARGET_COLOR" - -// Verbose reports whether a magefile was run with the verbose flag. -func Verbose() bool { - b, _ := strconv.ParseBool(os.Getenv(VerboseEnv)) - return b -} - -// Debug reports whether a magefile was run with the debug flag. -func Debug() bool { - b, _ := strconv.ParseBool(os.Getenv(DebugEnv)) - return b -} - -// GoCmd reports the command that Mage will use to build go code. By default mage runs -// the "go" binary in the PATH. -func GoCmd() string { - if cmd := os.Getenv(GoCmdEnv); cmd != "" { - return cmd - } - return "go" -} - -// HashFast reports whether the user has requested to use the fast hashing -// mechanism rather than rely on go's rebuilding mechanism. -func HashFast() bool { - b, _ := strconv.ParseBool(os.Getenv(HashFastEnv)) - return b -} - -// IgnoreDefault reports whether the user has requested to ignore the default target -// in the magefile. -func IgnoreDefault() bool { - b, _ := strconv.ParseBool(os.Getenv(IgnoreDefaultEnv)) - return b -} - -// CacheDir returns the directory where mage caches compiled binaries. It -// defaults to $HOME/.magefile, but may be overridden by the MAGEFILE_CACHE -// environment variable. -func CacheDir() string { - d := os.Getenv(CacheEnv) - if d != "" { - return d - } - switch runtime.GOOS { - case "windows": - return filepath.Join(os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH"), "magefile") - default: - return filepath.Join(os.Getenv("HOME"), ".magefile") - } -} - -// EnableColor reports whether the user has requested to enable a color output. -func EnableColor() bool { - b, _ := strconv.ParseBool(os.Getenv(EnableColorEnv)) - return b -} - -// TargetColor returns the configured ANSI color name a color output. -func TargetColor() string { - s, exists := os.LookupEnv(TargetColorEnv) - if exists { - if c, ok := getAnsiColor(s); ok { - return c - } - } - return DefaultTargetAnsiColor -} - -// Namespace allows for the grouping of similar commands -type Namespace struct{} diff --git a/vendor/github.com/magefile/mage/sh/cmd.go b/vendor/github.com/magefile/mage/sh/cmd.go deleted file mode 100644 index 06af62de2d2..00000000000 --- a/vendor/github.com/magefile/mage/sh/cmd.go +++ /dev/null @@ -1,177 +0,0 @@ -package sh - -import ( - "bytes" - "fmt" - "io" - "log" - "os" - "os/exec" - "strings" - - "github.com/magefile/mage/mg" -) - -// RunCmd returns a function that will call Run with the given command. This is -// useful for creating command aliases to make your scripts easier to read, like -// this: -// -// // in a helper file somewhere -// var g0 = sh.RunCmd("go") // go is a keyword :( -// -// // somewhere in your main code -// if err := g0("install", "github.com/gohugo/hugo"); err != nil { -// return err -// } -// -// Args passed to command get baked in as args to the command when you run it. -// Any args passed in when you run the returned function will be appended to the -// original args. For example, this is equivalent to the above: -// -// var goInstall = sh.RunCmd("go", "install") goInstall("github.com/gohugo/hugo") -// -// RunCmd uses Exec underneath, so see those docs for more details. -func RunCmd(cmd string, args ...string) func(args ...string) error { - return func(args2 ...string) error { - return Run(cmd, append(args, args2...)...) - } -} - -// OutCmd is like RunCmd except the command returns the output of the -// command. -func OutCmd(cmd string, args ...string) func(args ...string) (string, error) { - return func(args2 ...string) (string, error) { - return Output(cmd, append(args, args2...)...) - } -} - -// Run is like RunWith, but doesn't specify any environment variables. -func Run(cmd string, args ...string) error { - return RunWith(nil, cmd, args...) -} - -// RunV is like Run, but always sends the command's stdout to os.Stdout. -func RunV(cmd string, args ...string) error { - _, err := Exec(nil, os.Stdout, os.Stderr, cmd, args...) - return err -} - -// RunWith runs the given command, directing stderr to this program's stderr and -// printing stdout to stdout if mage was run with -v. It adds adds env to the -// environment variables for the command being run. Environment variables should -// be in the format name=value. -func RunWith(env map[string]string, cmd string, args ...string) error { - var output io.Writer - if mg.Verbose() { - output = os.Stdout - } - _, err := Exec(env, output, os.Stderr, cmd, args...) - return err -} - -// RunWithV is like RunWith, but always sends the command's stdout to os.Stdout. -func RunWithV(env map[string]string, cmd string, args ...string) error { - _, err := Exec(env, os.Stdout, os.Stderr, cmd, args...) - return err -} - -// Output runs the command and returns the text from stdout. -func Output(cmd string, args ...string) (string, error) { - buf := &bytes.Buffer{} - _, err := Exec(nil, buf, os.Stderr, cmd, args...) - return strings.TrimSuffix(buf.String(), "\n"), err -} - -// OutputWith is like RunWith, but returns what is written to stdout. -func OutputWith(env map[string]string, cmd string, args ...string) (string, error) { - buf := &bytes.Buffer{} - _, err := Exec(env, buf, os.Stderr, cmd, args...) - return strings.TrimSuffix(buf.String(), "\n"), err -} - -// Exec executes the command, piping its stderr to mage's stderr and -// piping its stdout to the given writer. If the command fails, it will return -// an error that, if returned from a target or mg.Deps call, will cause mage to -// exit with the same code as the command failed with. Env is a list of -// environment variables to set when running the command, these override the -// current environment variables set (which are also passed to the command). cmd -// and args may include references to environment variables in $FOO format, in -// which case these will be expanded before the command is run. -// -// Ran reports if the command ran (rather than was not found or not executable). -// Code reports the exit code the command returned if it ran. If err == nil, ran -// is always true and code is always 0. -func Exec(env map[string]string, stdout, stderr io.Writer, cmd string, args ...string) (ran bool, err error) { - expand := func(s string) string { - s2, ok := env[s] - if ok { - return s2 - } - return os.Getenv(s) - } - cmd = os.Expand(cmd, expand) - for i := range args { - args[i] = os.Expand(args[i], expand) - } - ran, code, err := run(env, stdout, stderr, cmd, args...) - if err == nil { - return true, nil - } - if ran { - return ran, mg.Fatalf(code, `running "%s %s" failed with exit code %d`, cmd, strings.Join(args, " "), code) - } - return ran, fmt.Errorf(`failed to run "%s %s: %v"`, cmd, strings.Join(args, " "), err) -} - -func run(env map[string]string, stdout, stderr io.Writer, cmd string, args ...string) (ran bool, code int, err error) { - c := exec.Command(cmd, args...) - c.Env = os.Environ() - for k, v := range env { - c.Env = append(c.Env, k+"="+v) - } - c.Stderr = stderr - c.Stdout = stdout - c.Stdin = os.Stdin - log.Println("exec:", cmd, strings.Join(args, " ")) - err = c.Run() - return CmdRan(err), ExitStatus(err), err -} - -// CmdRan examines the error to determine if it was generated as a result of a -// command running via os/exec.Command. If the error is nil, or the command ran -// (even if it exited with a non-zero exit code), CmdRan reports true. If the -// error is an unrecognized type, or it is an error from exec.Command that says -// the command failed to run (usually due to the command not existing or not -// being executable), it reports false. -func CmdRan(err error) bool { - if err == nil { - return true - } - ee, ok := err.(*exec.ExitError) - if ok { - return ee.Exited() - } - return false -} - -type exitStatus interface { - ExitStatus() int -} - -// ExitStatus returns the exit status of the error if it is an exec.ExitError -// or if it implements ExitStatus() int. -// 0 if it is nil or 1 if it is a different error. -func ExitStatus(err error) int { - if err == nil { - return 0 - } - if e, ok := err.(exitStatus); ok { - return e.ExitStatus() - } - if e, ok := err.(*exec.ExitError); ok { - if ex, ok := e.Sys().(exitStatus); ok { - return ex.ExitStatus() - } - } - return 1 -} diff --git a/vendor/github.com/magefile/mage/sh/helpers.go b/vendor/github.com/magefile/mage/sh/helpers.go deleted file mode 100644 index f5d20a2712b..00000000000 --- a/vendor/github.com/magefile/mage/sh/helpers.go +++ /dev/null @@ -1,40 +0,0 @@ -package sh - -import ( - "fmt" - "io" - "os" -) - -// Rm removes the given file or directory even if non-empty. It will not return -// an error if the target doesn't exist, only if the target cannot be removed. -func Rm(path string) error { - err := os.RemoveAll(path) - if err == nil || os.IsNotExist(err) { - return nil - } - return fmt.Errorf(`failed to remove %s: %v`, path, err) -} - -// Copy robustly copies the source file to the destination, overwriting the destination if necessary. -func Copy(dst string, src string) error { - from, err := os.Open(src) - if err != nil { - return fmt.Errorf(`can't copy %s: %v`, src, err) - } - defer from.Close() - finfo, err := from.Stat() - if err != nil { - return fmt.Errorf(`can't stat %s: %v`, src, err) - } - to, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, finfo.Mode()) - if err != nil { - return fmt.Errorf(`can't copy to %s: %v`, dst, err) - } - defer to.Close() - _, err = io.Copy(to, from) - if err != nil { - return fmt.Errorf(`error copying %s to %s: %v`, src, dst, err) - } - return nil -} diff --git a/vendor/modules.txt b/vendor/modules.txt index a220c1e632b..d43b79f6703 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -213,10 +213,6 @@ github.com/konsorten/go-windows-terminal-sequences # github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac github.com/lightstep/tracecontext.go/traceparent github.com/lightstep/tracecontext.go/tracestate -# github.com/magefile/mage v1.10.0 -## explicit -github.com/magefile/mage/mg -github.com/magefile/mage/sh # github.com/mailru/easyjson v0.7.1-0.20191009090205-6c0755d89d1e github.com/mailru/easyjson/buffer github.com/mailru/easyjson/jlexer From 5acd72b728623112eed24f2e4c88b5930bab723a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 13 Nov 2020 21:53:01 +0100 Subject: [PATCH 05/13] Lint fixes --- test/e2e/shell_bridge.go | 6 +++--- test/e2e/shell_bridge_test.go | 30 +++++++++++++++--------------- test/upgrade/installation/shell.go | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/test/e2e/shell_bridge.go b/test/e2e/shell_bridge.go index 07647288a6e..f54767d12e7 100644 --- a/test/e2e/shell_bridge.go +++ b/test/e2e/shell_bridge.go @@ -66,13 +66,13 @@ source ./test/e2e-common.sh }() c := exec.Command(tmpfile.Name()) c.Env = os.Environ() - c.Stdout = NewPrefixer(os.Stdout, label + " [OUT] ") - c.Stderr = NewPrefixer(os.Stderr, label + " [ERR] ") + c.Stdout = NewPrefixer(os.Stdout, label+" [OUT] ") + c.Stderr = NewPrefixer(os.Stderr, label+" [ERR] ") return c.Run() } type prefixer struct { - prefix string + prefix string writer io.Writer trailingNewline bool buf bytes.Buffer // reuse buffer to save allocations diff --git a/test/e2e/shell_bridge_test.go b/test/e2e/shell_bridge_test.go index 9593da5c658..7e15a1f62b2 100644 --- a/test/e2e/shell_bridge_test.go +++ b/test/e2e/shell_bridge_test.go @@ -1,18 +1,18 @@ /* - * Copyright 2020 The Knative Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package e2e @@ -95,4 +95,4 @@ func captureOutput(f func()) string { f() _ = writer.Close() return <-out -} \ No newline at end of file +} diff --git a/test/upgrade/installation/shell.go b/test/upgrade/installation/shell.go index fd8a9de77d2..8435cec56c3 100644 --- a/test/upgrade/installation/shell.go +++ b/test/upgrade/installation/shell.go @@ -20,4 +20,4 @@ import "knative.dev/eventing/test/e2e" func callShellFunction(funcName string) error { return e2e.ShellScript(funcName, funcName) -} \ No newline at end of file +} From adfa4ec875ddf307d762e7a240389c90b52d7b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 13 Nov 2020 22:48:37 +0100 Subject: [PATCH 06/13] Unit test fixes --- test/e2e/shell_bridge_test.go | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/test/e2e/shell_bridge_test.go b/test/e2e/shell_bridge_test.go index 7e15a1f62b2..378d1d833a7 100644 --- a/test/e2e/shell_bridge_test.go +++ b/test/e2e/shell_bridge_test.go @@ -18,20 +18,14 @@ package e2e import ( "bytes" - "fmt" "io" "log" "os" "sync" "testing" - "time" ) func TestShellScript(t *testing.T) { - la, err := time.LoadLocation("America/Los_Angeles") - if err != nil { - t.Fatal(err) - } tests := []struct { label string script string @@ -39,21 +33,18 @@ func TestShellScript(t *testing.T) { out string }{ { - "shell", "LANG=C header utest", false, - fmt.Sprintf(`shell [OUT] =============== -shell [OUT] ==== UTEST ==== -shell [OUT] =============== -shell [OUT] ==== %s -shell [OUT] =============== -`, time.Now().In(la).Format(time.UnixDate)), - }, - { - "sh", "exit 45", true, + "echo", "echo unit test", false, + "echo [OUT] unit test\n", + }, { + "echo-err", "echo unit test 1>&2", false, + "echo-err [ERR] unit test\n", + }, { + "exit", "exit 45", true, "", }, } for _, tt := range tests { - t.Run(tt.script, func(t *testing.T) { + t.Run(tt.label, func(t *testing.T) { out := captureOutput(func() { if err := ShellScript(tt.label, tt.script); (err != nil) != tt.wantErr { t.Errorf("ShellScript() error = %v, wantErr %v", err, tt.wantErr) From cd5a8bb998e10f74190395b606b5e4120a4da54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Wed, 18 Nov 2020 00:02:04 +0100 Subject: [PATCH 07/13] Update deps to include knative/pkg#1912 --- go.mod | 2 +- go.sum | 4 ++-- vendor/knative.dev/pkg/test/upgrade/functions.go | 15 +++++++++++---- vendor/modules.txt | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 4d4123ecd8f..f70cca359e6 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,7 @@ require ( k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 knative.dev/hack v0.0.0-20201112185459-01a34c573bd8 - knative.dev/pkg v0.0.0-20201117020252-ab1a398f669c + knative.dev/pkg v0.0.0-20201117180751-ac327c433800 sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index d922395e73c..48b0c4a6b98 100644 --- a/go.sum +++ b/go.sum @@ -1101,8 +1101,8 @@ k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7Mpm k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= knative.dev/hack v0.0.0-20201112185459-01a34c573bd8 h1:RNbZsAjhswBPtl4C5C5gEFX5/GfWIOZQxfYD9DhkHdY= knative.dev/hack v0.0.0-20201112185459-01a34c573bd8/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= -knative.dev/pkg v0.0.0-20201117020252-ab1a398f669c h1:dMBwabvusJrldjzIj4lces/96SnVgFXV7Kpv9z9fiCI= -knative.dev/pkg v0.0.0-20201117020252-ab1a398f669c/go.mod h1:4kXxEyYWdNk3pUR6/cx/ToMKG/dAJvEpDYUfV5RYHeU= +knative.dev/pkg v0.0.0-20201117180751-ac327c433800 h1:wze3+PCgTKnf1+7tWU6Coe9PoDQzYhazSN1vPg2g36k= +knative.dev/pkg v0.0.0-20201117180751-ac327c433800/go.mod h1:4kXxEyYWdNk3pUR6/cx/ToMKG/dAJvEpDYUfV5RYHeU= pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= diff --git a/vendor/knative.dev/pkg/test/upgrade/functions.go b/vendor/knative.dev/pkg/test/upgrade/functions.go index c6549baf729..50dc637fefa 100644 --- a/vendor/knative.dev/pkg/test/upgrade/functions.go +++ b/vendor/knative.dev/pkg/test/upgrade/functions.go @@ -81,13 +81,10 @@ func NewBackgroundOperation(name string, setup func(c Context), // After that happen a handler is invoked to verify environment state and report // failures. func WaitForStopEvent(bc BackgroundContext, w WaitForStopEventConfiguration) { - log := bc.Log for { select { case stopEvent := <-bc.Stop: - log.Infof("%s have received a stop event: %s", w.Name, stopEvent.Name()) - w.OnStop(stopEvent) - close(stopEvent.Finished) + handleStopEvent(stopEvent, bc, w) return default: w.OnWait(bc, w) @@ -105,6 +102,16 @@ func (s *StopEvent) Name() string { return s.name } +func handleStopEvent( + se StopEvent, + bc BackgroundContext, + wc WaitForStopEventConfiguration, +) { + bc.Log.Infof("%s have received a stop event: %s", wc.Name, se.Name()) + defer close(se.Finished) + wc.OnStop(se) +} + func enrichSuite(s *Suite) *enrichedSuite { es := &enrichedSuite{ installations: s.Installations, diff --git a/vendor/modules.txt b/vendor/modules.txt index e4fbb7e717d..f0911a06463 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -964,7 +964,7 @@ k8s.io/utils/trace # knative.dev/hack v0.0.0-20201112185459-01a34c573bd8 ## explicit knative.dev/hack -# knative.dev/pkg v0.0.0-20201117020252-ab1a398f669c +# knative.dev/pkg v0.0.0-20201117180751-ac327c433800 ## explicit knative.dev/pkg/apiextensions/storageversion knative.dev/pkg/apiextensions/storageversion/cmd/migrate From 23e9ad88345757e73791305ab2413293bfbf8be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Wed, 18 Nov 2020 00:21:18 +0100 Subject: [PATCH 08/13] Fix unit test when running without proper git checkout --- test/e2e/shell_bridge_test.go | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/test/e2e/shell_bridge_test.go b/test/e2e/shell_bridge_test.go index 378d1d833a7..a3a6d41450b 100644 --- a/test/e2e/shell_bridge_test.go +++ b/test/e2e/shell_bridge_test.go @@ -21,6 +21,7 @@ import ( "io" "log" "os" + "strings" "sync" "testing" ) @@ -30,19 +31,20 @@ func TestShellScript(t *testing.T) { label string script string wantErr bool - out string + wants []string }{ { "echo", "echo unit test", false, - "echo [OUT] unit test\n", + []string{"echo [OUT] unit test\n"}, }, { "echo-err", "echo unit test 1>&2", false, - "echo-err [ERR] unit test\n", + []string{"echo-err [ERR] unit test\n"}, }, { "exit", "exit 45", true, - "", + []string{}, }, } + assert := assertions{t: t} for _, tt := range tests { t.Run(tt.label, func(t *testing.T) { out := captureOutput(func() { @@ -50,10 +52,7 @@ func TestShellScript(t *testing.T) { t.Errorf("ShellScript() error = %v, wantErr %v", err, tt.wantErr) } }) - - if out != tt.out { - t.Errorf("actual = %v\n want = %v\n", out, tt.out) - } + assert.textContains(out, tt.wants) }) } } @@ -87,3 +86,18 @@ func captureOutput(f func()) string { _ = writer.Close() return <-out } + +type assertions struct { + t *testing.T +} + +func (a assertions) textContains(haystack string, needles []string) { + for _, needle := range needles { + if !strings.Contains(haystack, needle) { + a.t.Errorf( + "expected %q is not in: %q", + needle, haystack, + ) + } + } +} From 2b9d041af07379e07bbb006dc883de26ac050344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Tue, 24 Nov 2020 23:26:53 +0100 Subject: [PATCH 09/13] Using new shell-out package from knative.dev/hack --- go.mod | 2 + go.sum | 4 +- test/e2e/shell_bridge_test.go | 103 --------- test/upgrade/installation/shell.go | 20 +- .../knative.dev/hack/shell/LICENSE | 201 ++++++++++++++++++ vendor/knative.dev/hack/library.sh | 15 +- vendor/knative.dev/hack/release.sh | 6 +- vendor/knative.dev/hack/shell/executor.go | 189 ++++++++++++++++ vendor/knative.dev/hack/shell/fail-example.sh | 17 ++ .../knative.dev/hack/shell/prefixer.go | 78 +------ vendor/knative.dev/hack/shell/project.go | 52 +++++ vendor/knative.dev/hack/shell/types.go | 82 +++++++ vendor/modules.txt | 3 +- 13 files changed, 586 insertions(+), 186 deletions(-) delete mode 100644 test/e2e/shell_bridge_test.go create mode 100644 third_party/VENDOR-LICENSE/knative.dev/hack/shell/LICENSE create mode 100644 vendor/knative.dev/hack/shell/executor.go create mode 100644 vendor/knative.dev/hack/shell/fail-example.sh rename test/e2e/shell_bridge.go => vendor/knative.dev/hack/shell/prefixer.go (53%) create mode 100644 vendor/knative.dev/hack/shell/project.go create mode 100644 vendor/knative.dev/hack/shell/types.go diff --git a/go.mod b/go.mod index b78e5040039..dc86389bebd 100644 --- a/go.mod +++ b/go.mod @@ -57,3 +57,5 @@ replace ( k8s.io/client-go => k8s.io/client-go v0.18.8 k8s.io/code-generator => k8s.io/code-generator v0.18.8 ) + +replace knative.dev/hack v0.0.0-20201119025252-d3cb354f49ff => github.com/cardil/hack v0.0.0-20201124220028-d2e43fecc21c diff --git a/go.sum b/go.sum index 4257168ed86..5d8aa6083e9 100644 --- a/go.sum +++ b/go.sum @@ -107,6 +107,8 @@ github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2y github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= +github.com/cardil/hack v0.0.0-20201124220028-d2e43fecc21c h1:X9kI62lbVfhpcPf3tXec5BCC0IhjDM9a3Rm1H/mrrkU= +github.com/cardil/hack v0.0.0-20201124220028-d2e43fecc21c/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= @@ -1105,8 +1107,6 @@ k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ knative.dev/hack v0.0.0-20201112185459-01a34c573bd8/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= knative.dev/hack v0.0.0-20201118155651-b31d3bb6bff9 h1:OgYL1cATsWTS6kztSOuQqhmYfcn6ZdpPAQQ6TKCx00I= knative.dev/hack v0.0.0-20201118155651-b31d3bb6bff9/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= -knative.dev/hack v0.0.0-20201119025252-d3cb354f49ff h1:+bdPPtgog4EAuibiiW1uMdWX2DVij0+elXSh+Yfey78= -knative.dev/hack v0.0.0-20201119025252-d3cb354f49ff/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= knative.dev/pkg v0.0.0-20201117221452-0fccc54273ed/go.mod h1:nxlh3CUvx6WBPr1WKD96AHxFZPD2UKRDo9RUp8ILTyQ= knative.dev/pkg v0.0.0-20201119021551-260026d54739 h1:23XBvGmbprZ86TY9HJQmO7ZKp/te3LzJdKeVX7o9TAw= knative.dev/pkg v0.0.0-20201119021551-260026d54739/go.mod h1:3Udj7GogdjFg0M05MJm+aJjHx1BK/tyQarl5RB2k0Xo= diff --git a/test/e2e/shell_bridge_test.go b/test/e2e/shell_bridge_test.go deleted file mode 100644 index a3a6d41450b..00000000000 --- a/test/e2e/shell_bridge_test.go +++ /dev/null @@ -1,103 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package e2e - -import ( - "bytes" - "io" - "log" - "os" - "strings" - "sync" - "testing" -) - -func TestShellScript(t *testing.T) { - tests := []struct { - label string - script string - wantErr bool - wants []string - }{ - { - "echo", "echo unit test", false, - []string{"echo [OUT] unit test\n"}, - }, { - "echo-err", "echo unit test 1>&2", false, - []string{"echo-err [ERR] unit test\n"}, - }, { - "exit", "exit 45", true, - []string{}, - }, - } - assert := assertions{t: t} - for _, tt := range tests { - t.Run(tt.label, func(t *testing.T) { - out := captureOutput(func() { - if err := ShellScript(tt.label, tt.script); (err != nil) != tt.wantErr { - t.Errorf("ShellScript() error = %v, wantErr %v", err, tt.wantErr) - } - }) - assert.textContains(out, tt.wants) - }) - } -} - -func captureOutput(f func()) string { - reader, writer, err := os.Pipe() - if err != nil { - panic(err) - } - stdout := os.Stdout - stderr := os.Stderr - defer func() { - os.Stdout = stdout - os.Stderr = stderr - log.SetOutput(os.Stderr) - }() - os.Stdout = writer - os.Stderr = writer - log.SetOutput(writer) - out := make(chan string) - wg := new(sync.WaitGroup) - wg.Add(1) - go func() { - var buf bytes.Buffer - wg.Done() - _, _ = io.Copy(&buf, reader) - out <- buf.String() - }() - wg.Wait() - f() - _ = writer.Close() - return <-out -} - -type assertions struct { - t *testing.T -} - -func (a assertions) textContains(haystack string, needles []string) { - for _, needle := range needles { - if !strings.Contains(haystack, needle) { - a.t.Errorf( - "expected %q is not in: %q", - needle, haystack, - ) - } - } -} diff --git a/test/upgrade/installation/shell.go b/test/upgrade/installation/shell.go index 8435cec56c3..07674837c6b 100644 --- a/test/upgrade/installation/shell.go +++ b/test/upgrade/installation/shell.go @@ -16,8 +16,24 @@ limitations under the License. package installation -import "knative.dev/eventing/test/e2e" +import ( + "knative.dev/hack/shell" +) func callShellFunction(funcName string) error { - return e2e.ShellScript(funcName, funcName) + loc, err := shell.NewProjectLocation("../../..") + if err != nil { + return err + } + exec := shell.NewExecutor(shell.ExecutorConfig{ + ProjectLocation: loc, + }) + fn := shell.Function{ + Script: shell.Script{ + Label: funcName, + ScriptPath: "test/e2e-common.sh", + }, + FunctionName: funcName, + } + return exec.RunFunction(fn) } diff --git a/third_party/VENDOR-LICENSE/knative.dev/hack/shell/LICENSE b/third_party/VENDOR-LICENSE/knative.dev/hack/shell/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/third_party/VENDOR-LICENSE/knative.dev/hack/shell/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/knative.dev/hack/library.sh b/vendor/knative.dev/hack/library.sh index c2f9081efff..9b90b002553 100644 --- a/vendor/knative.dev/hack/library.sh +++ b/vendor/knative.dev/hack/library.sh @@ -410,28 +410,26 @@ function start_latest_knative_serving() { } # Install Knative Eventing in the current cluster. -# Parameters: $1 - Knative Eventing crds manifest. -# $2 - Knative Eventing core manifest. +# Parameters: $1 - Knative Eventing manifest. function start_knative_eventing() { header "Starting Knative Eventing" subheader "Installing Knative Eventing" echo "Installing Eventing CRDs from $1" + kubectl apply --selector knative.dev/crd-install=true -f "$1" + echo "Installing the rest of eventing components from $1" kubectl apply -f "$1" - echo "Installing Eventing core components from $2" - kubectl apply -f "$2" wait_until_pods_running knative-eventing || return 1 } # Install the stable release Knative/eventing in the current cluster. # Parameters: $1 - Knative Eventing version number, e.g. 0.6.0. function start_release_knative_eventing() { - start_knative_eventing "https://storage.googleapis.com/knative-releases/eventing/previous/v$1/eventing-crds.yaml" \ - "https://storage.googleapis.com/knative-releases/eventing/previous/v$1/eventing-core.yaml" + start_knative_eventing "https://storage.googleapis.com/knative-releases/eventing/previous/v$1/eventing.yaml" } # Install the latest stable Knative Eventing in the current cluster. function start_latest_knative_eventing() { - start_knative_eventing "${KNATIVE_EVENTING_RELEASE_CRDS}" "${KNATIVE_EVENTING_RELEASE_CORE}" + start_knative_eventing "${KNATIVE_EVENTING_RELEASE}" } # Install Knative Eventing extension in the current cluster. @@ -764,6 +762,5 @@ readonly REPO_NAME_FORMATTED="Knative $(capitalize "${REPO_NAME//-/ }")" readonly KNATIVE_SERVING_RELEASE_CRDS="$(get_latest_knative_yaml_source "serving" "serving-crds")" readonly KNATIVE_SERVING_RELEASE_CORE="$(get_latest_knative_yaml_source "serving" "serving-core")" readonly KNATIVE_NET_ISTIO_RELEASE="$(get_latest_knative_yaml_source "net-istio" "net-istio")" -readonly KNATIVE_EVENTING_RELEASE_CRDS="$(get_latest_knative_yaml_source "eventing" "eventing-crds")" -readonly KNATIVE_EVENTING_RELEASE_CORE="$(get_latest_knative_yaml_source "eventing" "eventing-core")" +readonly KNATIVE_EVENTING_RELEASE="$(get_latest_knative_yaml_source "eventing" "eventing")" readonly KNATIVE_EVENTING_SUGAR_CONTROLLER_RELEASE="$(get_latest_knative_yaml_source "eventing" "eventing-sugar-controller")" diff --git a/vendor/knative.dev/hack/release.sh b/vendor/knative.dev/hack/release.sh index 4dcfa9158ef..bd0fdda7d39 100644 --- a/vendor/knative.dev/hack/release.sh +++ b/vendor/knative.dev/hack/release.sh @@ -468,7 +468,6 @@ function parse_flags() { readonly RELEASE_BRANCH readonly RELEASE_GCS_BUCKET readonly RELEASE_DIR - readonly KO_DOCKER_REPO readonly VALIDATION_TESTS readonly FROM_NIGHTLY_RELEASE } @@ -478,11 +477,16 @@ function parse_flags() { function run_validation_tests() { (( SKIP_TESTS )) && return banner "Running release validation tests" + # Unset KO_DOCKER_REPO and restore it after the tests are finished. + # This will allow the tests to define their own KO_DOCKER_REPO. + local old_docker_repo="${KO_DOCKER_REPO}" + unset KO_DOCKER_REPO # Run tests. if ! $1; then banner "Release validation tests failed, aborting" abort "release validation tests failed" fi + export KO_DOCKER_REPO="${old_docker_repo}" } # Publishes the generated artifacts to directory, GCS, GitHub, etc. diff --git a/vendor/knative.dev/hack/shell/executor.go b/vendor/knative.dev/hack/shell/executor.go new file mode 100644 index 00000000000..e6308a0706f --- /dev/null +++ b/vendor/knative.dev/hack/shell/executor.go @@ -0,0 +1,189 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package shell + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "os/exec" + "strings" + "time" +) + +const ( + defaultLabelOut = "[OUT]" + defaultLabelErr = "[ERR]" + executeMode = 0700 +) + +// ErrNoProjectLocation is returned if user didnt provided the project location. +var ErrNoProjectLocation = errors.New("project location isn't provided") + +// NewExecutor creates a new executor from given config. +func NewExecutor(config ExecutorConfig) Executor { + configureDefaultValues(&config) + return &streamingExecutor{ + ExecutorConfig: config, + } +} + +// RunScript executes a shell script with args. +func (s *streamingExecutor) RunScript(script Script, args ...string) error { + err := validate(s.ExecutorConfig) + if err != nil { + return err + } + cnt := script.scriptContent(s.ProjectLocation, args) + return withTempScript(cnt, func(bin string) error { + return stream(bin, s.ExecutorConfig, script.Label) + }) +} + +// RunFunction executes a shell function with args. +func (s *streamingExecutor) RunFunction(fn Function, args ...string) error { + err := validate(s.ExecutorConfig) + if err != nil { + return err + } + cnt := fn.scriptContent(s.ProjectLocation, args) + return withTempScript(cnt, func(bin string) error { + return stream(bin, s.ExecutorConfig, fn.Label) + }) +} + +type streamingExecutor struct { + ExecutorConfig +} + +func validate(config ExecutorConfig) error { + if config.ProjectLocation == nil { + return ErrNoProjectLocation + } + return nil +} + +func configureDefaultValues(config *ExecutorConfig) { + if config.Out == nil { + config.Out = os.Stdout + } + if config.Err == nil { + config.Err = os.Stderr + } + if config.LabelOut == "" { + config.LabelOut = defaultLabelOut + } + if config.LabelErr == "" { + config.LabelErr = defaultLabelErr + } + if config.Environ == nil { + config.Environ = os.Environ() + } + if !config.SkipDate && config.DateFormat == "" { + config.DateFormat = time.StampMilli + } + if config.PrefixFunc == nil { + config.PrefixFunc = defaultPrefixFunc + } +} + +func stream(bin string, cfg ExecutorConfig, label string) error { + c := exec.Command(bin) + c.Env = cfg.Environ + c.Stdout = NewPrefixer(cfg.Out, prefixFunc(StreamTypeOut, label, cfg)) + c.Stderr = NewPrefixer(cfg.Err, prefixFunc(StreamTypeErr, label, cfg)) + return c.Run() +} + +func prefixFunc(st StreamType, label string, cfg ExecutorConfig) func() string { + return func() string { + return cfg.PrefixFunc(st, label, cfg) + } +} + +func defaultPrefixFunc(st StreamType, label string, cfg ExecutorConfig) string { + sep := " " + var buf []string + if !cfg.SkipDate { + dt := time.Now().Format(cfg.DateFormat) + buf = append(buf, dt) + } + buf = append(buf, label) + switch st { + case StreamTypeOut: + buf = append(buf, cfg.LabelOut) + case StreamTypeErr: + buf = append(buf, cfg.LabelErr) + } + return strings.Join(buf, sep) + sep +} + +func withTempScript(contents string, fn func(bin string) error) error { + tmpfile, err := ioutil.TempFile("", "shellout-*.sh") + if err != nil { + return err + } + _, err = tmpfile.WriteString(contents) + if err != nil { + return err + } + err = tmpfile.Chmod(executeMode) + if err != nil { + return err + } + err = tmpfile.Close() + if err != nil { + return err + } + defer func() { + // clean up + _ = os.Remove(tmpfile.Name()) + }() + + return fn(tmpfile.Name()) +} + +func (fn *Function) scriptContent(location ProjectLocation, args []string) string { + return fmt.Sprintf(`#!/usr/bin/env bash + +set -Eeuo pipefail + +cd "%s" +source %s + +%s %s +`, location.RootPath(), fn.ScriptPath, fn.FunctionName, quoteArgs(args)) +} + +func (sc *Script) scriptContent(location ProjectLocation, args []string) string { + return fmt.Sprintf(`#!/usr/bin/env bash + +set -Eeuo pipefail + +cd "%s" +%s %s +`, location.RootPath(), sc.ScriptPath, quoteArgs(args)) +} + +func quoteArgs(args []string) string { + quoted := make([]string, len(args)) + for i, arg := range args { + quoted[i] = "\"" + strings.ReplaceAll(arg, "\"", "\\\"") + "\"" + } + return strings.Join(quoted, " ") +} diff --git a/vendor/knative.dev/hack/shell/fail-example.sh b/vendor/knative.dev/hack/shell/fail-example.sh new file mode 100644 index 00000000000..551ce662a34 --- /dev/null +++ b/vendor/knative.dev/hack/shell/fail-example.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# Copyright 2020 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +echo "$*" >&2 diff --git a/test/e2e/shell_bridge.go b/vendor/knative.dev/hack/shell/prefixer.go similarity index 53% rename from test/e2e/shell_bridge.go rename to vendor/knative.dev/hack/shell/prefixer.go index f54767d12e7..273ee1cc4ff 100644 --- a/test/e2e/shell_bridge.go +++ b/vendor/knative.dev/hack/shell/prefixer.go @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -14,84 +14,34 @@ See the License for the specific language governing permissions and limitations under the License. */ -package e2e +package shell import ( "bytes" - "fmt" "io" - "io/ioutil" - "os" - "os/exec" - "path" - "runtime" ) -// ShellScript calls a shell function defined in e2e-common shell library. -func ShellScript(label, script string) error { - _, filename, _, ok := runtime.Caller(0) - if !ok { - return fmt.Errorf("can't get caller for self") - } - rootPath := path.Join(path.Dir(filename), "../..") - scriptContent := fmt.Sprintf(`#!/usr/bin/env bash - -set -Eeuo pipefail - -cd "%s" -source ./test/e2e-common.sh - -%s -`, rootPath, script) - tmpfile, err := ioutil.TempFile("", "shellout-*.sh") - if err != nil { - return err - } - _, err = tmpfile.WriteString(scriptContent) - if err != nil { - return err - } - err = tmpfile.Chmod(0700) - if err != nil { - return err - } - err = tmpfile.Close() - if err != nil { - return err - } - - defer func() { - // clean up - _ = os.Remove(tmpfile.Name()) - }() - c := exec.Command(tmpfile.Name()) - c.Env = os.Environ() - c.Stdout = NewPrefixer(os.Stdout, label+" [OUT] ") - c.Stderr = NewPrefixer(os.Stderr, label+" [ERR] ") - return c.Run() +// NewPrefixer creates a new prefixer that forwards all calls to Write() to +// writer.Write() with all lines prefixed with the value of prefix. Having a +// function instead of a static prefix allows to print timestamps or other +// changing information. +func NewPrefixer(writer io.Writer, prefix func() string) io.Writer { + return &prefixer{prefix: prefix, writer: writer, trailingNewline: true} } type prefixer struct { - prefix string + prefix func() string writer io.Writer trailingNewline bool buf bytes.Buffer // reuse buffer to save allocations } -// NewPrefixer creates a new prefixer that forwards all calls to Write() to -// writer.Write() with all lines prefixed with the value of prefix. Having a -// function instead of a static prefix allows to print timestamps or other -// changing information. -func NewPrefixer(writer io.Writer, prefix string) io.Writer { - return &prefixer{prefix: prefix, writer: writer, trailingNewline: true} -} - func (pf *prefixer) Write(payload []byte) (int, error) { pf.buf.Reset() // clear the buffer for _, b := range payload { if pf.trailingNewline { - pf.buf.WriteString(pf.prefix) + pf.buf.WriteString(pf.prefix()) pf.trailingNewline = false } @@ -116,11 +66,3 @@ func (pf *prefixer) Write(payload []byte) (int, error) { // return original length to satisfy io.Writer interface return len(payload), nil } - -// EnsureNewline prints a newline if the last character written wasn't a newline unless nothing has ever been written. -// The purpose of this method is to avoid ending the output in the middle of the line. -func (pf *prefixer) EnsureNewline() { - if !pf.trailingNewline { - _, _ = fmt.Fprintln(pf.writer) - } -} diff --git a/vendor/knative.dev/hack/shell/project.go b/vendor/knative.dev/hack/shell/project.go new file mode 100644 index 00000000000..2d7ba9738b0 --- /dev/null +++ b/vendor/knative.dev/hack/shell/project.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package shell + +import ( + "errors" + "path" + "runtime" +) + +// ErrCantGetCaller is raised when we can't calculate a caller of NewProjectLocation. +var ErrCantGetCaller = errors.New("can't get caller") + +// NewProjectLocation creates a ProjectLocation that is used to calculate +// relative paths within the project. +func NewProjectLocation(pathToRoot string) (ProjectLocation, error) { + _, filename, _, ok := runtime.Caller(1) + if !ok { + return nil, ErrCantGetCaller + } + return &callerLocation{ + caller: filename, + pathToRoot: pathToRoot, + }, nil +} + +// RootPath return a path to root of the project. +func (c *callerLocation) RootPath() string { + return path.Join(path.Dir(c.caller), c.pathToRoot) +} + +// callerLocation holds a caller Go file, and a relative location to a project +// root directory. This information can be used to calculate relative paths and +// properly source shell scripts. +type callerLocation struct { + caller string + pathToRoot string +} diff --git a/vendor/knative.dev/hack/shell/types.go b/vendor/knative.dev/hack/shell/types.go new file mode 100644 index 00000000000..8e34515206d --- /dev/null +++ b/vendor/knative.dev/hack/shell/types.go @@ -0,0 +1,82 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package shell + +import "io" + +// ProjectLocation represents a project location on a file system. +type ProjectLocation interface { + RootPath() string +} + +// Script represents a script to be executed. +type Script struct { + Label string + ScriptPath string +} + +// Function represents a function, whom will be sourced from Script file, +// and executed. +type Function struct { + Script + FunctionName string +} + +// ExecutorConfig holds a executor configuration options. +type ExecutorConfig struct { + ProjectLocation + Streams + Labels + Environ []string +} + +// StreamType represets either output or error stream. +type StreamType int + +const ( + // StreamTypeOut represents process output stream. + StreamTypeOut StreamType = iota + // StreamTypeErr represents process error stream. + StreamTypeErr +) + +// PrefixFunc is used to build a prefix that will be added to each line of the +// script/function output or error stream. +type PrefixFunc func(st StreamType, label string, config ExecutorConfig) string + +// Labels holds a labels to be used to prefix Out and Err streams of executed +// shells scripts/functions. +type Labels struct { + LabelOut string + LabelErr string + SkipDate bool + DateFormat string + PrefixFunc +} + +// Streams holds a streams of a shell scripts/functions. +type Streams struct { + Out io.Writer + Err io.Writer +} + +// Executor represents a executor that can execute shell scripts and call +// functions directly. +type Executor interface { + RunScript(script Script, args ...string) error + RunFunction(fn Function, args ...string) error +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 59977fde32f..fcc5f17e9b2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -961,9 +961,10 @@ k8s.io/utils/buffer k8s.io/utils/integer k8s.io/utils/pointer k8s.io/utils/trace -# knative.dev/hack v0.0.0-20201119025252-d3cb354f49ff +# knative.dev/hack v0.0.0-20201119025252-d3cb354f49ff => github.com/cardil/hack v0.0.0-20201124220028-d2e43fecc21c ## explicit knative.dev/hack +knative.dev/hack/shell # knative.dev/pkg v0.0.0-20201119021551-260026d54739 ## explicit knative.dev/pkg/apiextensions/storageversion From 01dc790162ab9c3c80ce220551b064109497964f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Tue, 24 Nov 2020 23:36:29 +0100 Subject: [PATCH 10/13] Fixing code style --- test/upgrade/installation/shell.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/upgrade/installation/shell.go b/test/upgrade/installation/shell.go index 07674837c6b..e51ca41d418 100644 --- a/test/upgrade/installation/shell.go +++ b/test/upgrade/installation/shell.go @@ -29,7 +29,7 @@ func callShellFunction(funcName string) error { ProjectLocation: loc, }) fn := shell.Function{ - Script: shell.Script{ + Script: shell.Script{ Label: funcName, ScriptPath: "test/e2e-common.sh", }, From 0dd2c3f33b7715533fac0051c3f0910e3e6dca66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Tue, 24 Nov 2020 23:55:39 +0100 Subject: [PATCH 11/13] Adjusting location of project file We need to point ourselves to specific directory as our scripts are location sensitive. --- test/upgrade/installation/shell.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/upgrade/installation/shell.go b/test/upgrade/installation/shell.go index e51ca41d418..d8fd1fd32d7 100644 --- a/test/upgrade/installation/shell.go +++ b/test/upgrade/installation/shell.go @@ -21,7 +21,7 @@ import ( ) func callShellFunction(funcName string) error { - loc, err := shell.NewProjectLocation("../../..") + loc, err := shell.NewProjectLocation("../../../test") if err != nil { return err } @@ -31,7 +31,7 @@ func callShellFunction(funcName string) error { fn := shell.Function{ Script: shell.Script{ Label: funcName, - ScriptPath: "test/e2e-common.sh", + ScriptPath: "e2e-common.sh", }, FunctionName: funcName, } From 84d6ac4e12bfe0e50189ba2b3a5c786ac0478fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Wed, 25 Nov 2020 17:18:12 +0100 Subject: [PATCH 12/13] Bash scripts work with set -Eeuo pipefail --- hack/generate-yamls.sh | 3 ++- test/e2e-common.sh | 24 +++++++++++++----------- test/e2e-upgrade-tests.sh | 2 +- test/presubmit-tests.sh | 8 +++++--- test/upgrade/installation/shell.go | 4 ++-- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/hack/generate-yamls.sh b/hack/generate-yamls.sh index 31d42e203e9..654f3bb97da 100755 --- a/hack/generate-yamls.sh +++ b/hack/generate-yamls.sh @@ -62,10 +62,11 @@ RELEASES=( readonly RELEASES # Flags for all ko commands KO_YAML_FLAGS="-P" +KO_FLAGS="${KO_FLAGS:-}" [[ "${KO_DOCKER_REPO}" != gcr.io/* ]] && KO_YAML_FLAGS="" readonly KO_YAML_FLAGS="${KO_YAML_FLAGS} ${KO_FLAGS} --platform=all" -if [[ -n "${TAG}" ]]; then +if [[ -n "${TAG:-}" ]]; then LABEL_YAML_CMD=(sed -e "s|eventing.knative.dev/release: devel|eventing.knative.dev/release: \"${TAG}\"|") else LABEL_YAML_CMD=(cat) diff --git a/test/e2e-common.sh b/test/e2e-common.sh index 102ac01231e..ce48acfb69b 100755 --- a/test/e2e-common.sh +++ b/test/e2e-common.sh @@ -16,9 +16,10 @@ # This script includes common functions for testing setup and teardown. +# shellcheck disable=SC1090 + export GO111MODULE=on -# shellcheck disable=SC1090 source "$(dirname "${BASH_SOURCE[0]}")/../vendor/knative.dev/hack/e2e-tests.sh" # If gcloud is not available make it a no-op, not an error. @@ -57,7 +58,7 @@ readonly REPLICAS=3 # Should deploy a Knative Monitoring as well readonly DEPLOY_KNATIVE_MONITORING="${DEPLOY_KNATIVE_MONITORING:-1}" -TMP_DIR=$(mktemp -d -t ci-$(date +%Y-%m-%d-%H-%M-%S)-XXXXXXXXXX) +TMP_DIR=$(mktemp -d -t "ci-$(date +%Y-%m-%d-%H-%M-%S)-XXXXXXXXXX") readonly TMP_DIR readonly KNATIVE_DEFAULT_NAMESPACE="knative-eventing" @@ -110,14 +111,15 @@ function start_knative_eventing_monitoring() { # All generated YAMLs will be available and pointed by the corresponding # environment variables as set in /hack/generate-yamls.sh. function build_knative_from_source() { - local YAML_LIST="$(mktemp)" + local FULL_OUTPUT YAML_LIST LOG_OUTPUT ENV_OUTPUT + YAML_LIST="$(mktemp)" # Generate manifests, capture environment variables pointing to the YAML files. - local FULL_OUTPUT="$( \ - source $(dirname $0)/../hack/generate-yamls.sh ${REPO_ROOT_DIR} ${YAML_LIST} ; \ + FULL_OUTPUT="$( \ + source "$(dirname "${BASH_SOURCE[0]}")/../hack/generate-yamls.sh" "${REPO_ROOT_DIR}" "${YAML_LIST}" ; \ set | grep _YAML=/)" - local LOG_OUTPUT="$(echo "${FULL_OUTPUT}" | grep -v _YAML=/)" - local ENV_OUTPUT="$(echo "${FULL_OUTPUT}" | grep '^[_0-9A-Z]\+_YAML=/')" + LOG_OUTPUT="$(echo "${FULL_OUTPUT}" | grep -v _YAML=/)" + ENV_OUTPUT="$(echo "${FULL_OUTPUT}" | grep '^[_0-9A-Z]\+_YAML=/')" [[ -z "${LOG_OUTPUT}" || -z "${ENV_OUTPUT}" ]] && fail_test "Error generating manifests" # Only import the environment variables pointing to the YAML files. echo "${LOG_OUTPUT}" @@ -199,7 +201,7 @@ function install_latest_release() { } function install_mt_broker() { - if [[ -z "${EVENTING_MT_CHANNEL_BROKER_YAML}" ]]; then + if [[ -z "${EVENTING_MT_CHANNEL_BROKER_YAML:-}" ]]; then build_knative_from_source else echo "use exist EVENTING_MT_CHANNEL_BROKER_YAML" @@ -215,7 +217,7 @@ function install_mt_broker() { } function install_sugar() { - if [[ -z "${EVENTING_SUGAR_CONTROLLER_YAML}" ]]; then + if [[ -z "${EVENTING_SUGAR_CONTROLLER_YAML:-}" ]]; then build_knative_from_source else echo "use exist EVENTING_SUGAR_CONTROLLER_YAML" @@ -291,7 +293,7 @@ function test_setup() { install_test_resources || return 1 echo ">> Publish test images" - "$(dirname "$0")/upload-test-images.sh" e2e || fail_test "Error uploading test images" + "$(dirname "${BASH_SOURCE[0]}")/upload-test-images.sh" e2e || fail_test "Error uploading test images" } # Tear down resources used in the eventing tests. @@ -309,7 +311,7 @@ function uninstall_test_resources() { function install_channel_crds() { echo "Installing In-Memory Channel CRD" - if [[ -z "${EVENTING_IN_MEMORY_CHANNEL_YAML}" ]]; then + if [[ -z "${EVENTING_IN_MEMORY_CHANNEL_YAML:-}" ]]; then build_knative_from_source else echo "use exist EVENTING_SUGAR_CONTROLLER_YAML" diff --git a/test/e2e-upgrade-tests.sh b/test/e2e-upgrade-tests.sh index 45900747b3f..4bfc6976070 100755 --- a/test/e2e-upgrade-tests.sh +++ b/test/e2e-upgrade-tests.sh @@ -21,7 +21,7 @@ export GO111MODULE=on # shellcheck disable=SC1090 -source "$(dirname "$0")/e2e-common.sh" +source "$(dirname "${BASH_SOURCE[0]}")/e2e-common.sh" # Overrides diff --git a/test/presubmit-tests.sh b/test/presubmit-tests.sh index 2c53eb0d0ce..9466836fd69 100755 --- a/test/presubmit-tests.sh +++ b/test/presubmit-tests.sh @@ -23,12 +23,14 @@ # Prefer sockpuppet over markdown presubmit checks, as it will correct # markdown issues with less human involvement. -export DISABLE_MD_LINTING=1 +# shellcheck disable=SC1090 + +export DISABLE_MD_LINTING=1 export GO111MODULE=on -source $(dirname $0)/../vendor/knative.dev/hack/presubmit-tests.sh +source "$(dirname "${BASH_SOURCE[0]}")/../vendor/knative.dev/hack/presubmit-tests.sh" # We use the default build, unit and integration test runners. -main $@ +main "$@" diff --git a/test/upgrade/installation/shell.go b/test/upgrade/installation/shell.go index d8fd1fd32d7..e51ca41d418 100644 --- a/test/upgrade/installation/shell.go +++ b/test/upgrade/installation/shell.go @@ -21,7 +21,7 @@ import ( ) func callShellFunction(funcName string) error { - loc, err := shell.NewProjectLocation("../../../test") + loc, err := shell.NewProjectLocation("../../..") if err != nil { return err } @@ -31,7 +31,7 @@ func callShellFunction(funcName string) error { fn := shell.Function{ Script: shell.Script{ Label: funcName, - ScriptPath: "e2e-common.sh", + ScriptPath: "test/e2e-common.sh", }, FunctionName: funcName, } From 2c74fa7a9b345f96d27ac3a9159d3a206c339d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 26 Nov 2020 00:09:58 +0100 Subject: [PATCH 13/13] Upgrade knative.dev/hack to include knative/hack#30 --- go.mod | 4 +- go.sum | 5 +- vendor/knative.dev/hack/microbenchmarks.sh | 59 ++++++++++++++++++++++ vendor/modules.txt | 2 +- 4 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 vendor/knative.dev/hack/microbenchmarks.sh diff --git a/go.mod b/go.mod index be2502bb8e3..cf066c06dfc 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( k8s.io/apiserver v0.18.8 k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 - knative.dev/hack v0.0.0-20201120192952-353db687ec5b + knative.dev/hack v0.0.0-20201125230335-c46a6498e9ed knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a knative.dev/reconciler-test v0.0.0-20201124190335-83a44efcdfef sigs.k8s.io/yaml v1.2.0 @@ -57,5 +57,3 @@ replace ( k8s.io/client-go => k8s.io/client-go v0.18.8 k8s.io/code-generator => k8s.io/code-generator v0.18.8 ) - -replace knative.dev/hack v0.0.0-20201120192952-353db687ec5b => github.com/cardil/hack v0.0.0-20201124220028-d2e43fecc21c diff --git a/go.sum b/go.sum index 525bd2cde76..9b092b24dda 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,6 @@ github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2y github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b h1:AP/Y7sqYicnjGDfD5VcY4CIfh1hRXBUavxrvELjTiOE= github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= -github.com/cardil/hack v0.0.0-20201124220028-d2e43fecc21c h1:X9kI62lbVfhpcPf3tXec5BCC0IhjDM9a3Rm1H/mrrkU= -github.com/cardil/hack v0.0.0-20201124220028-d2e43fecc21c/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= @@ -1107,6 +1105,9 @@ k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ knative.dev/hack v0.0.0-20201112185459-01a34c573bd8/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= knative.dev/hack v0.0.0-20201118155651-b31d3bb6bff9 h1:OgYL1cATsWTS6kztSOuQqhmYfcn6ZdpPAQQ6TKCx00I= knative.dev/hack v0.0.0-20201118155651-b31d3bb6bff9/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= +knative.dev/hack v0.0.0-20201120192952-353db687ec5b/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= +knative.dev/hack v0.0.0-20201125230335-c46a6498e9ed h1:DrTU+vxQrNJtySxyNovUtl4si0ozjtU/AYhYaTz34YA= +knative.dev/hack v0.0.0-20201125230335-c46a6498e9ed/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= knative.dev/pkg v0.0.0-20201117221452-0fccc54273ed/go.mod h1:nxlh3CUvx6WBPr1WKD96AHxFZPD2UKRDo9RUp8ILTyQ= knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a h1:pdJpLaq50mLKrPWYSQgTH2p64Dk7Fq/xID6l0F69cVY= knative.dev/pkg v0.0.0-20201125095035-9bf616d2f46a/go.mod h1:wXZqP8MXCxb51yNFlecA13BwG7Hk370SWDFWV4dx4ug= diff --git a/vendor/knative.dev/hack/microbenchmarks.sh b/vendor/knative.dev/hack/microbenchmarks.sh new file mode 100644 index 00000000000..440af2e1410 --- /dev/null +++ b/vendor/knative.dev/hack/microbenchmarks.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash + +# Copyright 2019 The Knative Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +function microbenchmarks_run() { + if [ "$1" != "" ]; then + OUTPUT_FILE="$1" + else + OUTPUT_FILE="${ARTIFACTS:-$(mktemp -d)}/bench-result.txt" + fi + + echo "Output will be at $OUTPUT_FILE" + + # Run all microbenchmarks + go clean + go test -bench=. -benchmem -run="^$" -v ./... >> "$OUTPUT_FILE" || exit +} + +function microbenchmarks_run_and_compare() { + if [ "$1" == "" ] || [ $# -gt 1 ]; then + echo "Error: Expecting an argument" >&2 + echo "usage: $(basename $0) revision_to_compare" >&2 + exit 1 + fi + + # Benchstat is required to compare the bench results + GO111MODULE=off go get golang.org/x/perf/cmd/benchstat + + # Revision to use to compare with actual + REVISION="$1" + OUTPUT_DIR=${ARTIFACTS:-$(mktemp -d)} + + echo "Outputs will be at $OUTPUT_DIR" + + # Run this revision benchmarks + microbenchmarks_run "$OUTPUT_DIR/new.txt" + + # Run other revision benchmarks + git checkout "$REVISION" + microbenchmarks_run "$OUTPUT_DIR/old.txt" + + # Print results in console + benchstat "$OUTPUT_DIR/old.txt" "$OUTPUT_DIR/new.txt" + + # Generate html results + benchstat -html "$OUTPUT_DIR/old.txt" "$OUTPUT_DIR/new.txt" >> "$OUTPUT_DIR/results.html" +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 309ca45c673..d94961090a9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -961,7 +961,7 @@ k8s.io/utils/buffer k8s.io/utils/integer k8s.io/utils/pointer k8s.io/utils/trace -# knative.dev/hack v0.0.0-20201120192952-353db687ec5b => github.com/cardil/hack v0.0.0-20201124220028-d2e43fecc21c +# knative.dev/hack v0.0.0-20201125230335-c46a6498e9ed ## explicit knative.dev/hack knative.dev/hack/shell