Commit faeef5c4 authored by Tim Hockin's avatar Tim Hockin

Use make as the main build tool

This allows us to start building real dependencies into Makefile. Leave old hack/* scripts in place but advise to use 'make'. There are a few rules that call things like 'go run' or 'build/*' that I left as-is for now.
parent 708e753c
...@@ -42,7 +42,7 @@ export KUBE_GOLDFLAGS ...@@ -42,7 +42,7 @@ export KUBE_GOLDFLAGS
# make all # make all
# make all WHAT=cmd/kubelet GOFLAGS=-v # make all WHAT=cmd/kubelet GOFLAGS=-v
all: all:
hack/build-go.sh $(WHAT) @hack/make-rules/build.sh $(WHAT)
.PHONY: all .PHONY: all
# Build ginkgo # Build ginkgo
...@@ -50,7 +50,7 @@ all: ...@@ -50,7 +50,7 @@ all:
# Example: # Example:
# make ginkgo # make ginkgo
ginkgo: ginkgo:
hack/build-go.sh vendor/github.com/onsi/ginkgo/ginkgo hack/make-rules/build.sh vendor/github.com/onsi/ginkgo/ginkgo
.PHONY: ginkgo .PHONY: ginkgo
# Runs all the presubmission verifications. # Runs all the presubmission verifications.
...@@ -62,7 +62,7 @@ ginkgo: ...@@ -62,7 +62,7 @@ ginkgo:
# make verify # make verify
# make verify BRANCH=branch_x # make verify BRANCH=branch_x
verify: verify:
KUBE_VERIFY_GIT_BRANCH=$(BRANCH) hack/verify-all.sh -v @KUBE_VERIFY_GIT_BRANCH=$(BRANCH) hack/make-rules/verify.sh -v
.PHONY: verify .PHONY: verify
# Build and run tests. # Build and run tests.
...@@ -79,24 +79,24 @@ verify: ...@@ -79,24 +79,24 @@ verify:
# make test # make test
# make check WHAT=pkg/kubelet GOFLAGS=-v # make check WHAT=pkg/kubelet GOFLAGS=-v
check test: check test:
hack/test-go.sh $(WHAT) $(TESTS) @hack/make-rules/test.sh $(WHAT) $(TESTS)
.PHONY: check test .PHONY: check test
# Build and run integration tests. # Build and run integration tests.
# #
# Example: # Example:
# make test_integration # make test-integration
test_integration: test-integration:
hack/test-integration.sh @hack/make-rules/test-integration.sh
.PHONY: test_integration test_integ .PHONY: test-integration
# Build and run end-to-end tests. # Build and run end-to-end tests.
# #
# Example: # Example:
# make test_e2e # make test-e2e
test_e2e: test-e2e: ginkgo
go run hack/e2e.go -v --build --up --test --down @go run hack/e2e.go -v --build --up --test --down
.PHONY: test_e2e .PHONY: test-e2e
# Build and run node end-to-end tests. # Build and run node end-to-end tests.
# #
...@@ -116,12 +116,20 @@ test_e2e: ...@@ -116,12 +116,20 @@ test_e2e:
# INSTANCE_PREFIX: for REMOTE=true only. Instances created from images will have the name "${INSTANCE_PREFIX}-${IMAGE_NAME}". Defaults to "test"/ # INSTANCE_PREFIX: for REMOTE=true only. Instances created from images will have the name "${INSTANCE_PREFIX}-${IMAGE_NAME}". Defaults to "test"/
# #
# Example: # Example:
# make test_e2e_node FOCUS=kubelet SKIP=container # make test-e2e-node FOCUS=kubelet SKIP=container
# make test_e2e_node REMOTE=true DELETE_INSTANCES=true # make test-e2e-node REMOTE=true DELETE_INSTANCES=true
# Build and run tests. # Build and run tests.
test_e2e_node: ginkgo test-e2e-node: ginkgo
hack/e2e-node-test.sh @hack/make-rules/test-e2e-node.sh
.PHONY: test_e2e_node .PHONY: test-e2e-node
# Build and run cmdline tests.
#
# Example:
# make test-cmd
test-cmd:
@hack/make-rules/test-cmd.sh
.PHONY: test-cmd
# Remove all build artifacts. # Remove all build artifacts.
# #
...@@ -139,15 +147,12 @@ clean: ...@@ -139,15 +147,12 @@ clean:
# WHAT: Directory names to vet. All *.go files under these # WHAT: Directory names to vet. All *.go files under these
# directories will be vetted. If not specified, "everything" will be # directories will be vetted. If not specified, "everything" will be
# vetted. # vetted.
# TESTS: Same as WHAT.
# GOFLAGS: Extra flags to pass to 'go' when building.
# GOLDFLAGS: Extra linking flags to pass to 'go' when building.
# #
# Example: # Example:
# make vet # make vet
# make vet WHAT=pkg/kubelet # make vet WHAT=pkg/kubelet
vet: vet:
hack/verify-govet.sh $(WHAT) $(TESTS) @hack/make-rules/vet.sh $(WHAT)
.PHONY: vet .PHONY: vet
# Build a release # Build a release
...@@ -155,7 +160,7 @@ vet: ...@@ -155,7 +160,7 @@ vet:
# Example: # Example:
# make release # make release
release: release:
build/release.sh @build/release.sh
.PHONY: release .PHONY: release
# Build a release, but skip tests # Build a release, but skip tests
...@@ -163,6 +168,5 @@ release: ...@@ -163,6 +168,5 @@ release:
# Example: # Example:
# make release-skip-tests # make release-skip-tests
release-skip-tests quick-release: release-skip-tests quick-release:
KUBE_RELEASE_RUN_TESTS=n KUBE_FASTBUILD=true build/release.sh @KUBE_RELEASE_RUN_TESTS=n KUBE_FASTBUILD=true build/release.sh
.PHONY: release-skip-tests quick-release .PHONY: release-skip-tests quick-release
...@@ -24,10 +24,11 @@ There is also early support for building Docker "run" containers ...@@ -24,10 +24,11 @@ There is also early support for building Docker "run" containers
The following scripts are found in the `build/` directory: The following scripts are found in the `build/` directory:
* `run.sh`: Run a command in a build docker container. Common invocations: * `run.sh`: Run a command in a build docker container. Common invocations:
* `run.sh hack/build-go.sh`: Build just linux binaries in the container. Pass options and packages as necessary. * `run.sh make`: Build just linux binaries in the container. Pass options and packages as necessary.
* `run.sh hack/build-cross.sh`: Build all binaries for all platforms * `run.sh hack/build-cross.sh`: Build all binaries for all platforms
* `run.sh hack/test-go.sh`: Run all unit tests * `run.sh make test`: Run all unit tests
* `run.sh hack/test-integration.sh`: Run integration test * `run.sh make test-integration`: Run integration test
* `run.sh make test-cmd`: Run CLI tests
* `copy-output.sh`: This will copy the contents of `_output/dockerized/bin` from any remote Docker container to the local `_output/dockerized/bin`. Right now this is only necessary on Mac OS X with `boot2docker` when your git repo isn't under `/Users`. * `copy-output.sh`: This will copy the contents of `_output/dockerized/bin` from any remote Docker container to the local `_output/dockerized/bin`. Right now this is only necessary on Mac OS X with `boot2docker` when your git repo isn't under `/Users`.
* `make-clean.sh`: Clean out the contents of `_output/dockerized` and remove any local built container images. * `make-clean.sh`: Clean out the contents of `_output/dockerized` and remove any local built container images.
* `shell.sh`: Drop into a `bash` shell in a build container with a snapshot of the current repo code. * `shell.sh`: Drop into a `bash` shell in a build container with a snapshot of the current repo code.
......
...@@ -33,8 +33,8 @@ kube::build::build_image ...@@ -33,8 +33,8 @@ kube::build::build_image
kube::build::run_build_command hack/build-cross.sh kube::build::run_build_command hack/build-cross.sh
if [[ $KUBE_RELEASE_RUN_TESTS =~ ^[yY]$ ]]; then if [[ $KUBE_RELEASE_RUN_TESTS =~ ^[yY]$ ]]; then
kube::build::run_build_command hack/test-go.sh kube::build::run_build_command make test
kube::build::run_build_command hack/test-integration.sh kube::build::run_build_command make test-integration
fi fi
if [[ "${FEDERATION:-}" == "true" ]];then if [[ "${FEDERATION:-}" == "true" ]];then
......
...@@ -514,7 +514,7 @@ function kube-down { ...@@ -514,7 +514,7 @@ function kube-down {
#} #}
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Cluster specific test helpers used from hack/e2e-test.sh # Cluster specific test helpers
# Execute prior to running tests to build a release if required for env. # Execute prior to running tests to build a release if required for env.
# #
......
...@@ -31,4 +31,4 @@ TEST_ARGS="$@" ...@@ -31,4 +31,4 @@ TEST_ARGS="$@"
KUBE_ROOT=$(cd "$(dirname "${BASH_SOURCE}")/../../.." && pwd) KUBE_ROOT=$(cd "$(dirname "${BASH_SOURCE}")/../../.." && pwd)
"${KUBE_ROOT}/contrib/mesos/ci/run.sh" make clean test_integration ${TEST_ARGS} "${KUBE_ROOT}/contrib/mesos/ci/run.sh" make clean test-integration ${TEST_ARGS}
...@@ -155,7 +155,7 @@ K8SM_IMAGE_NAME=haih/k8sm ...@@ -155,7 +155,7 @@ K8SM_IMAGE_NAME=haih/k8sm
git clone https://github.com/mesosphere/kubernetes git clone https://github.com/mesosphere/kubernetes
cd kubernetes cd kubernetes
git checkout release-v0.7-v1.1 git checkout release-v0.7-v1.1
KUBERNETES_CONTRIB=mesos build/run.sh hack/build-go.sh KUBERNETES_CONTRIB=mesos build/run.sh make
cd .. cd ..
sudo docker build -t $K8SM_IMAGE_NAME --no-cache . sudo docker build -t $K8SM_IMAGE_NAME --no-cache .
EOF EOF
......
...@@ -119,8 +119,8 @@ pkg/kubectl/cmd/util/factory.go. ...@@ -119,8 +119,8 @@ pkg/kubectl/cmd/util/factory.go.
1. Add your group in pkg/api/testapi/testapi.go, then you can access the group 1. Add your group in pkg/api/testapi/testapi.go, then you can access the group
in tests through testapi.`<group>`; in tests through testapi.`<group>`;
2. Add your "group/version" to `KUBE_API_VERSIONS` and `KUBE_TEST_API_VERSIONS` 2. Add your "group/version" to `KUBE_TEST_API_VERSIONS` in
in hack/test-go.sh. hack/make-rules/test.sh and hack/make-rules/test-integration.sh
TODO: Add a troubleshooting section. TODO: Add a troubleshooting section.
......
...@@ -71,11 +71,16 @@ up a GOPATH. ...@@ -71,11 +71,16 @@ up a GOPATH.
To build Kubernetes using your local Go development environment (generate linux To build Kubernetes using your local Go development environment (generate linux
binaries): binaries):
hack/build-go.sh ```sh
make
```
You may pass build options and packages to the script as necessary. To build You may pass build options and packages to the script as necessary. To build
binaries for all platforms: binaries for all platforms:
```sh
hack/build-cross.sh hack/build-cross.sh
```
## Workflow ## Workflow
...@@ -314,8 +319,8 @@ Three basic commands let you run unit, integration and/or e2e tests: ...@@ -314,8 +319,8 @@ Three basic commands let you run unit, integration and/or e2e tests:
```sh ```sh
cd kubernetes cd kubernetes
hack/test-go.sh # Run unit tests make test # Run unit tests
hack/test-integration.sh # Run integration tests, requires etcd make test-integration # Run integration tests, requires etcd
go run hack/e2e.go -v --build --up --test --down # Run e2e tests go run hack/e2e.go -v --build --up --test --down # Run e2e tests
``` ```
......
...@@ -57,7 +57,7 @@ Prerequisites: ...@@ -57,7 +57,7 @@ Prerequisites:
From the Kubernetes base directory, run: From the Kubernetes base directory, run:
```sh ```sh
make test_e2e_node make test-e2e-node
``` ```
This will: run the *ginkgo* binary against the subdirectory *test/e2e_node*, which will in turn: This will: run the *ginkgo* binary against the subdirectory *test/e2e_node*, which will in turn:
...@@ -87,7 +87,7 @@ Prerequisites: ...@@ -87,7 +87,7 @@ Prerequisites:
Run: Run:
```sh ```sh
make test_e2e_node REMOTE=true make test-e2e-node REMOTE=true
``` ```
This will: This will:
...@@ -124,7 +124,7 @@ provided by the default image. ...@@ -124,7 +124,7 @@ provided by the default image.
List the available test images using gcloud. List the available test images using gcloud.
```sh ```sh
make test_e2e_node LIST_IMAGES=true make test-e2e-node LIST_IMAGES=true
``` ```
This will output a list of the available images for the default image project. This will output a list of the available images for the default image project.
...@@ -132,7 +132,7 @@ This will output a list of the available images for the default image project. ...@@ -132,7 +132,7 @@ This will output a list of the available images for the default image project.
Then run: Then run:
```sh ```sh
make test_e2e_node REMOTE=true IMAGES="<comma-separated-list-images>" make test-e2e-node REMOTE=true IMAGES="<comma-separated-list-images>"
``` ```
## Run tests against a running GCE instance (not an image) ## Run tests against a running GCE instance (not an image)
...@@ -140,7 +140,7 @@ make test_e2e_node REMOTE=true IMAGES="<comma-separated-list-images>" ...@@ -140,7 +140,7 @@ make test_e2e_node REMOTE=true IMAGES="<comma-separated-list-images>"
This is useful if you have an host instance running already and want to run the tests there instead of on a new instance. This is useful if you have an host instance running already and want to run the tests there instead of on a new instance.
```sh ```sh
make test_e2e_node REMOTE=true HOSTS="<comma-separated-list-of-hostnames>" make test-e2e-node REMOTE=true HOSTS="<comma-separated-list-of-hostnames>"
``` ```
## Delete instance after tests run ## Delete instance after tests run
...@@ -148,7 +148,7 @@ make test_e2e_node REMOTE=true HOSTS="<comma-separated-list-of-hostnames>" ...@@ -148,7 +148,7 @@ make test_e2e_node REMOTE=true HOSTS="<comma-separated-list-of-hostnames>"
This is useful if you want recreate the instance for each test run to trigger flakes related to starting the instance. This is useful if you want recreate the instance for each test run to trigger flakes related to starting the instance.
```sh ```sh
make test_e2e_node REMOTE=true DELETE_INSTANCES=true make test-e2e-node REMOTE=true DELETE_INSTANCES=true
``` ```
## Keep instance, test binaries, and *processes* around after tests run ## Keep instance, test binaries, and *processes* around after tests run
...@@ -156,7 +156,7 @@ make test_e2e_node REMOTE=true DELETE_INSTANCES=true ...@@ -156,7 +156,7 @@ make test_e2e_node REMOTE=true DELETE_INSTANCES=true
This is useful if you want to manually inspect or debug the kubelet process run as part of the tests. This is useful if you want to manually inspect or debug the kubelet process run as part of the tests.
```sh ```sh
make test_e2e_node REMOTE=true CLEANUP=false make test-e2e-node REMOTE=true CLEANUP=false
``` ```
## Run tests using an image in another project ## Run tests using an image in another project
...@@ -164,7 +164,7 @@ make test_e2e_node REMOTE=true CLEANUP=false ...@@ -164,7 +164,7 @@ make test_e2e_node REMOTE=true CLEANUP=false
This is useful if you want to create your own host image in another project and use it for testing. This is useful if you want to create your own host image in another project and use it for testing.
```sh ```sh
make test_e2e_node REMOTE=true IMAGE_PROJECT="<name-of-project-with-images>" IMAGES="<image-name>" make test-e2e-node REMOTE=true IMAGE_PROJECT="<name-of-project-with-images>" IMAGES="<image-name>"
``` ```
Setting up your own host image may require additional steps such as installing etcd or docker. See Setting up your own host image may require additional steps such as installing etcd or docker. See
...@@ -176,7 +176,7 @@ This is useful if you want to create instances using a different name so that yo ...@@ -176,7 +176,7 @@ This is useful if you want to create instances using a different name so that yo
test in parallel against different instances of the same image. test in parallel against different instances of the same image.
```sh ```sh
make test_e2e_node REMOTE=true INSTANCE_PREFIX="my-prefix" make test-e2e-node REMOTE=true INSTANCE_PREFIX="my-prefix"
``` ```
# Additional Test Options for both Remote and Local execution # Additional Test Options for both Remote and Local execution
...@@ -186,13 +186,13 @@ make test_e2e_node REMOTE=true INSTANCE_PREFIX="my-prefix" ...@@ -186,13 +186,13 @@ make test_e2e_node REMOTE=true INSTANCE_PREFIX="my-prefix"
To run tests matching a regex: To run tests matching a regex:
```sh ```sh
make test_e2e_node REMOTE=true FOCUS="<regex-to-match>" make test-e2e-node REMOTE=true FOCUS="<regex-to-match>"
``` ```
To run tests NOT matching a regex: To run tests NOT matching a regex:
```sh ```sh
make test_e2e_node REMOTE=true SKIP="<regex-to-match>" make test-e2e-node REMOTE=true SKIP="<regex-to-match>"
``` ```
## Run tests continually until they fail ## Run tests continually until they fail
...@@ -202,7 +202,7 @@ run the tests until they fail. **Note: this will only perform test setup once ( ...@@ -202,7 +202,7 @@ run the tests until they fail. **Note: this will only perform test setup once (
less useful for catching flakes related creating the instance from an image.** less useful for catching flakes related creating the instance from an image.**
```sh ```sh
make test_e2e_node REMOTE=true RUN_UNTIL_FAILURE=true make test-e2e-node REMOTE=true RUN_UNTIL_FAILURE=true
``` ```
# Notes on tests run by the Kubernetes project during pre-, post- submit. # Notes on tests run by the Kubernetes project during pre-, post- submit.
......
...@@ -69,9 +69,9 @@ Additionally, for infrequent or new contributors, we require the on call to appl ...@@ -69,9 +69,9 @@ Additionally, for infrequent or new contributors, we require the on call to appl
The following will save time for both you and your reviewer: The following will save time for both you and your reviewer:
* Enable [pre-commit hooks](development.md#committing-changes-to-your-fork) and verify they pass. * Enable [pre-commit hooks](development.md#committing-changes-to-your-fork) and verify they pass.
* Verify `hack/verify-all.sh` passes. * Verify `make verify` passes.
* Verify `hack/test-go.sh` passes. * Verify `make test` passes.
* Verify `hack/test-integration.sh` passes. * Verify `make test-integration.sh` passes.
## Release Notes ## Release Notes
......
...@@ -257,9 +257,11 @@ been automated that need to happen after the branch has been cut: ...@@ -257,9 +257,11 @@ been automated that need to happen after the branch has been cut:
*Please note that this information may be out of date. The scripts are the *Please note that this information may be out of date. The scripts are the
authoritative source on how version injection works.* authoritative source on how version injection works.*
Kubernetes may be built from either a git tree (using `hack/build-go.sh`) or Kubernetes may be built from either a git tree or from a tarball. We use
from a tarball (using either `hack/build-go.sh` or `go install`) or directly by `make` to encapsulate a number of build steps into a single command. This
the Go native build system (using `go get`). includes generating code, which means that tools like `go build` might work
(once files are generated) but might be using stale generated code. `make` is
the supported way to build.
When building from git, we want to be able to insert specific information about When building from git, we want to be able to insert specific information about
the build tree at build time. In particular, we want to use the output of `git the build tree at build time. In particular, we want to use the output of `git
...@@ -294,7 +296,7 @@ yield binaries that will identify themselves as `v0.4-dev` and will not be able ...@@ -294,7 +296,7 @@ yield binaries that will identify themselves as `v0.4-dev` and will not be able
to provide you with a SHA1. to provide you with a SHA1.
To add the extra versioning information when building from git, the To add the extra versioning information when building from git, the
`hack/build-go.sh` script will gather that information (using `git describe` and `make` build will gather that information (using `git describe` and
`git rev-parse`) and then create a `-ldflags` string to pass to `go install` and `git rev-parse`) and then create a `-ldflags` string to pass to `go install` and
tell the Go linker to override the contents of those variables at build time. It tell the Go linker to override the contents of those variables at build time. It
can, for instance, tell it to override `gitVersion` and set it to can, for instance, tell it to override `gitVersion` and set it to
......
...@@ -170,7 +170,7 @@ You are running a single node setup. This has the limitation of only supporting ...@@ -170,7 +170,7 @@ You are running a single node setup. This has the limitation of only supporting
```sh ```sh
cd kubernetes cd kubernetes
hack/build-go.sh make
hack/local-up-cluster.sh hack/local-up-cluster.sh
``` ```
......
...@@ -83,13 +83,13 @@ passing, so it is often a good idea to make sure the e2e tests work as well. ...@@ -83,13 +83,13 @@ passing, so it is often a good idea to make sure the e2e tests work as well.
### Run all unit tests ### Run all unit tests
The `hack/test-go.sh` script is the entrypoint for running the unit tests that `make test` is the entrypoint for running the unit tests that ensures that
ensures that `GOPATH` is set up correctly. If you have `GOPATH` set up `GOPATH` is set up correctly. If you have `GOPATH` set up correctly, you can
correctly, you can also just use `go test` directly. also just use `go test` directly.
```sh ```sh
cd kubernetes cd kubernetes
hack/test-go.sh # Run all unit tests. make test # Run all unit tests.
``` ```
### Set go flags during unit tests ### Set go flags during unit tests
...@@ -99,18 +99,23 @@ You can set [go flags](https://golang.org/cmd/go/) by setting the ...@@ -99,18 +99,23 @@ You can set [go flags](https://golang.org/cmd/go/) by setting the
### Run unit tests from certain packages ### Run unit tests from certain packages
The `hack/test-go.sh` script accepts packages as arguments; the `make test` accepts packages as arguments; the `k8s.io/kubernetes` prefix is
`k8s.io/kubernetes` prefix is added automatically to these: added automatically to these:
```sh ```sh
hack/test-go.sh pkg/api # run tests for pkg/api make test WHAT=pkg/api # run tests for pkg/api
hack/test-go.sh pkg/api pkg/kubelet # run tests for pkg/api and pkg/kubelet ```
To run multiple targets you need quotes:
```sh
make test WHAT="pkg/api pkg/kubelet" # run tests for pkg/api and pkg/kubelet
``` ```
In a shell, it's often handy to use brace expansion: In a shell, it's often handy to use brace expansion:
```sh ```sh
hack/test-go.sh pkg/{api,kubelet} # run tests for pkg/api and pkg/kubelet make test WHAT=pkg/{api,kubelet} # run tests for pkg/api and pkg/kubelet
``` ```
### Run specific unit test cases in a package ### Run specific unit test cases in a package
...@@ -121,10 +126,10 @@ regular expression for the name of the test that should be run. ...@@ -121,10 +126,10 @@ regular expression for the name of the test that should be run.
```sh ```sh
# Runs TestValidatePod in pkg/api/validation with the verbose flag set # Runs TestValidatePod in pkg/api/validation with the verbose flag set
KUBE_GOFLAGS="-v" KUBE_TEST_ARGS='-run ^TestValidatePod$' hack/test-go.sh pkg/api/validation make test WHAT=pkg/api/validation KUBE_GOFLAGS="-v" KUBE_TEST_ARGS='-run ^TestValidatePod$'
# Runs tests that match the regex ValidatePod|ValidateConfigMap in pkg/api/validation # Runs tests that match the regex ValidatePod|ValidateConfigMap in pkg/api/validation
KUBE_GOFLAGS="-v" KUBE_TEST_ARGS="-run ValidatePod\|ValidateConfigMap$" hack/test-go.sh pkg/api/validation make test WHAT=pkg/api/validation KUBE_GOFLAGS="-v" KUBE_TEST_ARGS="-run ValidatePod\|ValidateConfigMap$"
``` ```
For other supported test flags, see the [golang For other supported test flags, see the [golang
...@@ -137,7 +142,7 @@ You can do this efficiently. ...@@ -137,7 +142,7 @@ You can do this efficiently.
```sh ```sh
# Have 2 workers run all tests 5 times each (10 total iterations). # Have 2 workers run all tests 5 times each (10 total iterations).
hack/test-go.sh -p 2 -i 5 make test PARALLEL=2 ITERATION=5
``` ```
For more advanced ideas please see [flaky-tests.md](flaky-tests.md). For more advanced ideas please see [flaky-tests.md](flaky-tests.md).
...@@ -149,7 +154,7 @@ Currently, collecting coverage is only supported for the Go unit tests. ...@@ -149,7 +154,7 @@ Currently, collecting coverage is only supported for the Go unit tests.
To run all unit tests and generate an HTML coverage report, run the following: To run all unit tests and generate an HTML coverage report, run the following:
```sh ```sh
KUBE_COVER=y hack/test-go.sh make test KUBE_COVER=y
``` ```
At the end of the run, an HTML report will be generated with the path At the end of the run, an HTML report will be generated with the path
...@@ -159,7 +164,7 @@ To run tests and collect coverage in only one package, pass its relative path ...@@ -159,7 +164,7 @@ To run tests and collect coverage in only one package, pass its relative path
under the `kubernetes` directory as an argument, for example: under the `kubernetes` directory as an argument, for example:
```sh ```sh
KUBE_COVER=y hack/test-go.sh pkg/kubectl make test WHAT=pkg/kubectl KUBE_COVER=y
``` ```
Multiple arguments can be passed, in which case the coverage results will be Multiple arguments can be passed, in which case the coverage results will be
...@@ -224,14 +229,14 @@ for those internal etcd instances with the `TEST_ETCD_DIR` environment variable. ...@@ -224,14 +229,14 @@ for those internal etcd instances with the `TEST_ETCD_DIR` environment variable.
### Run integration tests ### Run integration tests
The integration tests are run using the `hack/test-integration.sh` script. The integration tests are run using `make test-integration`.
The Kubernetes integration tests are writting using the normal golang testing The Kubernetes integration tests are writting using the normal golang testing
package but expect to have a running etcd instance to connect to. The `test- package but expect to have a running etcd instance to connect to. The `test-
integration.sh` script wraps `hack/test-go.sh` and sets up an etcd instance integration.sh` script wraps `make test` and sets up an etcd instance
for the integration tests to use. for the integration tests to use.
```sh ```sh
hack/test-integration.sh # Run all integration tests. make test-integration # Run all integration tests.
``` ```
This script runs the golang tests in package This script runs the golang tests in package
...@@ -244,7 +249,7 @@ You can use also use the `KUBE_TEST_ARGS` environment variable with the `hack ...@@ -244,7 +249,7 @@ You can use also use the `KUBE_TEST_ARGS` environment variable with the `hack
```sh ```sh
# Run integration test TestPodUpdateActiveDeadlineSeconds with the verbose flag set. # Run integration test TestPodUpdateActiveDeadlineSeconds with the verbose flag set.
KUBE_GOFLAGS="-v" KUBE_TEST_ARGS="-run ^TestPodUpdateActiveDeadlineSeconds$" hack/test-integration.sh make test-integration KUBE_GOFLAGS="-v" KUBE_TEST_ARGS="-run ^TestPodUpdateActiveDeadlineSeconds$"
``` ```
If you set `KUBE_TEST_ARGS`, the test case will be run with only the `v1` API If you set `KUBE_TEST_ARGS`, the test case will be run with only the `v1` API
......
...@@ -23,7 +23,8 @@ GOARCH?=$(shell go env GOARCH) ...@@ -23,7 +23,8 @@ GOARCH?=$(shell go env GOARCH)
GOOS?=$(shell go env GOOS) GOOS?=$(shell go env GOOS)
kubectl: kubectl:
KUBE_STATIC_OVERRIDES="kubectl" ../../hack/build-go.sh cmd/kubectl; cp ../../_output/local/bin/$(GOOS)/$(GOARCH)/kubectl . make -C ../../ WHAT=cmd/kubectl KUBE_STATIC_OVERRIDES="kubectl"; \
cp ../../_output/local/bin/$(GOOS)/$(GOARCH)/kubectl .
.tag: kubectl .tag: kubectl
./kubectl version -c | grep -o 'GitVersion:"[^"]*"' | cut -f 2 -d '"' > .tag ./kubectl version -c | grep -o 'GitVersion:"[^"]*"' | cut -f 2 -d '"' > .tag
......
...@@ -20,4 +20,8 @@ set -o pipefail ...@@ -20,4 +20,8 @@ set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
KUBE_COVER="" KUBE_RACE=" " "${KUBE_ROOT}/hack/test-go.sh" -- -test.run="^X" -benchtime=1s -bench=. -benchmem $@ make test \
WHAT="$*"
KUBE_COVER="" \
KUBE_RACE=" " \
KUBE_TEST_ARGS="-- -test.run='^X' -benchtime=1s -bench=. -benchmem" \
...@@ -40,7 +40,7 @@ runTests() { ...@@ -40,7 +40,7 @@ runTests() {
KUBE_TEST_ETCD_PREFIXES="registry" \ KUBE_TEST_ETCD_PREFIXES="registry" \
ETCD_CUSTOM_PREFIX="None" \ ETCD_CUSTOM_PREFIX="None" \
KUBE_TEST_ARGS="${ARGS}" \ KUBE_TEST_ARGS="${ARGS}" \
"${KUBE_ROOT}/hack/test-go.sh" test/integration make test WHAT=test/integration
cleanup cleanup
} }
......
#!/bin/bash #!/bin/bash
# Copyright 2014 The Kubernetes Authors. # Copyright 2016 The Kubernetes Authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
...@@ -14,14 +14,24 @@ ...@@ -14,14 +14,24 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# This script sets up a go workspace locally and builds all go components. # This script is a vestigial redirection. Please do not add "real" logic.
set -o errexit set -o errexit
set -o nounset set -o nounset
set -o pipefail set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::build_binaries "$@" # For help output
kube::golang::place_bins ARGHELP=""
if [[ "$#" -gt 0 ]]; then
ARGHELP="WHAT='$@'"
fi
echo "NOTE: $0 has been replaced by 'make' or 'make all'"
echo
echo "The equivalent of this invocation is: "
echo " make ${ARGHELP}"
echo
echo
make --no-print-directory -C "${KUBE_ROOT}" all WHAT="$*"
...@@ -45,7 +45,7 @@ fi ...@@ -45,7 +45,7 @@ fi
kube::build::verify_prereqs kube::build::verify_prereqs
kube::build::build_image kube::build::build_image
kube::build::run_build_command hack/build-go.sh cmd/hyperkube kube::build::run_build_command make WHAT=cmd/hyperkube
REGISTRY="${KUBE_DOCKER_REGISTRY}/${KUBE_DOCKER_OWNER}" \ REGISTRY="${KUBE_DOCKER_REGISTRY}/${KUBE_DOCKER_OWNER}" \
VERSION="${KUBE_DOCKER_VERSION}" \ VERSION="${KUBE_DOCKER_VERSION}" \
......
...@@ -14,121 +14,30 @@ ...@@ -14,121 +14,30 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. # This script is a vestigial redirection. Please do not add "real" logic.
source "${KUBE_ROOT}/hack/lib/init.sh"
focus=${FOCUS:-""} set -o errexit
skip=${SKIP:-""} set -o nounset
report=${REPORT:-"/tmp/"} set -o pipefail
artifacts=${ARTIFACTS:-"/tmp/_artifacts"}
remote=${REMOTE:-"false"}
images=${IMAGES:-""}
hosts=${HOSTS:-""}
if [[ $hosts == "" && $images == "" ]]; then
images="e2e-node-containervm-v20160321-image"
fi
image_project=${IMAGE_PROJECT:-"kubernetes-node-e2e-images"}
instance_prefix=${INSTANCE_PREFIX:-"test"}
cleanup=${CLEANUP:-"true"}
delete_instances=${DELETE_INSTANCES:-"false"}
run_until_failure=${RUN_UNTIL_FAILURE:-"false"}
list_images=${LIST_IMAGES:-"false"}
if [[ $list_images == "true" ]]; then KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
gcloud compute images list --project="${image_project}" | grep "e2e-node"
exit 0
fi
ginkgo=$(kube::util::find-binary "ginkgo") # For help output
if [[ -z "${ginkgo}" ]]; then ARGHELP=""
echo "You do not appear to have ginkgo built. Try 'make WHAT=vendor/github.com/onsi/ginkgo/ginkgo'" if [[ -n "${FOCUS:-}" ]]; then
exit 1 ARGHELP="FOCUS='${FOCUS}' "
fi fi
if [[ -n "${SKIP:-}" ]]; then
if [ $remote = true ] ; then ARGHELP="${ARGHELP}SKIP='${SKIP}'"
# Setup the directory to copy test artifacts (logs, junit.xml, etc) from remote host to local host
if [ ! -d "${artifacts}" ]; then
echo "Creating artifacts directory at ${artifacts}"
mkdir -p ${artifacts}
fi
echo "Test artifacts will be written to ${artifacts}"
# Get the compute zone
zone=$(gcloud info --format='value(config.properties.compute.zone)')
if [[ $zone == "" ]]; then
echo "Could not find gcloud compute/zone when running:\ngcloud info --format='value(config.properties.compute.zone)'"
exit 1
fi
# Get the compute project
project=$(gcloud info --format='value(config.project)')
if [[ $project == "" ]]; then
echo "Could not find gcloud project when running:\ngcloud info --format='value(config.project)'"
exit 1
fi
# Check if any of the images specified already have running instances. If so reuse those instances
# by moving the IMAGE to a HOST
if [[ $images != "" ]]; then
IFS=',' read -ra IM <<< "$images"
images=""
for i in "${IM[@]}"; do
if [[ $(gcloud compute instances list "${instance_prefix}-$i" | grep $i) ]]; then
if [[ $hosts != "" ]]; then
hosts="$hosts,"
fi
echo "Reusing host ${instance_prefix}-$i"
hosts="${hosts}${instance_prefix}-${i}"
else
if [[ $images != "" ]]; then
images="$images,"
fi
images="$images$i"
fi
done
fi
# Parse the flags to pass to ginkgo
ginkgoflags=""
if [[ $focus != "" ]]; then
ginkgoflags="$ginkgoflags -focus=$focus "
fi
if [[ $skip != "" ]]; then
ginkgoflags="$ginkgoflags -skip=$skip "
fi
if [[ $run_until_failure != "" ]]; then
ginkgoflags="$ginkgoflags -untilItFails=$run_until_failure "
fi
# Output the configuration we will try to run
echo "Running tests remotely using"
echo "Project: $project"
echo "Image Project: $image_project"
echo "Compute/Zone: $zone"
echo "Images: $images"
echo "Hosts: $hosts"
echo "Ginkgo Flags: $ginkgoflags"
# Invoke the runner
go run test/e2e_node/runner/run_e2e.go --logtostderr --vmodule=*=2 --ssh-env="gce" \
--zone="$zone" --project="$project" \
--hosts="$hosts" --images="$images" --cleanup="$cleanup" \
--results-dir="$artifacts" --ginkgo-flags="$ginkgoflags" \
--image-project="$image_project" --instance-name-prefix="$instance_prefix" --setup-node="true" \
--delete-instances="$delete_instances"
exit $?
else
# Refresh sudo credentials if not running on GCE.
if ! ping -c 1 -q metadata.google.internal &> /dev/null; then
sudo -v || exit 1
fi
# Test using the host the script was run on
# Provided for backwards compatibility
"${ginkgo}" --focus=$focus --skip=$skip "${KUBE_ROOT}/test/e2e_node/" --report-dir=${report} \
-- --alsologtostderr --v 2 --node-name $(hostname) --disable-kubenet=true --build-services=true --start-services=true --stop-services=true
exit $?
fi fi
echo "NOTE: $0 has been replaced by 'make test-e2e-node'"
echo
echo "This script supports a number of parameters passed as environment variables."
echo "Please see the Makfile for more details."
echo
echo "The equivalent of this invocation is: "
echo " make test-e2e-node ${ARGHELP}"
echo
echo
make --no-print-directory -C "${KUBE_ROOT}" test-e2e-node FOCUS=${FOCUS:-} SKIP=${SKIP:-}
...@@ -27,12 +27,14 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -27,12 +27,14 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" \ BINS=(
cmd/gendocs \ cmd/gendocs
cmd/genkubedocs \ cmd/genkubedocs
cmd/genman \ cmd/genman
cmd/genyaml \ cmd/genyaml
federation/cmd/genfeddocs federation/cmd/genfeddocs
)
make -C "${KUBE_ROOT}" WHAT="${BINS[*]}"
kube::util::ensure-temp-dir kube::util::ensure-temp-dir
......
...@@ -41,5 +41,5 @@ export KUBE_JUNIT_REPORT_DIR=${WORKSPACE}/_artifacts ...@@ -41,5 +41,5 @@ export KUBE_JUNIT_REPORT_DIR=${WORKSPACE}/_artifacts
# Save the verbose stdout as well. # Save the verbose stdout as well.
export KUBE_KEEP_VERBOSE_TEST_OUTPUT=y export KUBE_KEEP_VERBOSE_TEST_OUTPUT=y
./hack/test-go.sh make test
./hack/test-integration.sh make test-integration
...@@ -55,7 +55,7 @@ rm -rf Godeps/_workspace # Temporary until _workspace is fully obliterated ...@@ -55,7 +55,7 @@ rm -rf Godeps/_workspace # Temporary until _workspace is fully obliterated
go install ./cmd/... go install ./cmd/...
./hack/install-etcd.sh ./hack/install-etcd.sh
./hack/test-go.sh make test
./hack/test-cmd.sh make test-cmd
./hack/test-integration.sh make test-integration
./hack/test-update-storage-objects.sh ./hack/test-update-storage-objects.sh
...@@ -38,4 +38,4 @@ export LOG_LEVEL=4 ...@@ -38,4 +38,4 @@ export LOG_LEVEL=4
cd /go/src/k8s.io/kubernetes cd /go/src/k8s.io/kubernetes
./hack/install-etcd.sh ./hack/install-etcd.sh
./hack/verify-all.sh -v make verify VERBOSE=1
...@@ -34,4 +34,4 @@ export PATH=${GOPATH}/bin:${HOME}/third_party/etcd:/usr/local/go/bin:$PATH ...@@ -34,4 +34,4 @@ export PATH=${GOPATH}/bin:${HOME}/third_party/etcd:/usr/local/go/bin:$PATH
command -v etcd &>/dev/null || ./hack/install-etcd.sh command -v etcd &>/dev/null || ./hack/install-etcd.sh
go get -u github.com/tools/godep go get -u github.com/tools/godep
./hack/verify-all.sh -v make verify VERBOSE=1
...@@ -78,9 +78,7 @@ do ...@@ -78,9 +78,7 @@ do
done done
if [ "x$GO_OUT" == "x" ]; then if [ "x$GO_OUT" == "x" ]; then
"${KUBE_ROOT}/hack/build-go.sh" \ make -C "${KUBE_ROOT}" WHAT="cmd/kubectl cmd/hyperkube"
cmd/kubectl \
cmd/hyperkube
else else
echo "skipped the build." echo "skipped the build."
fi fi
......
#!/bin/bash
# Copyright 2014 The Kubernetes 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.
# This script sets up a go workspace locally and builds all go components.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::build_binaries "$@"
kube::golang::place_bins
This source diff could not be displayed because it is too large. You can view the blob instead.
#!/bin/bash
# Copyright 2016 The Kubernetes 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.
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
source "${KUBE_ROOT}/hack/lib/init.sh"
focus=${FOCUS:-""}
skip=${SKIP:-""}
report=${REPORT:-"/tmp/"}
artifacts=${ARTIFACTS:-"/tmp/_artifacts"}
remote=${REMOTE:-"false"}
images=${IMAGES:-""}
hosts=${HOSTS:-""}
if [[ $hosts == "" && $images == "" ]]; then
images="e2e-node-containervm-v20160321-image"
fi
image_project=${IMAGE_PROJECT:-"kubernetes-node-e2e-images"}
instance_prefix=${INSTANCE_PREFIX:-"test"}
cleanup=${CLEANUP:-"true"}
delete_instances=${DELETE_INSTANCES:-"false"}
run_until_failure=${RUN_UNTIL_FAILURE:-"false"}
list_images=${LIST_IMAGES:-"false"}
if [[ $list_images == "true" ]]; then
gcloud compute images list --project="${image_project}" | grep "e2e-node"
exit 0
fi
ginkgo=$(kube::util::find-binary "ginkgo")
if [[ -z "${ginkgo}" ]]; then
echo "You do not appear to have ginkgo built. Try 'make WHAT=vendor/github.com/onsi/ginkgo/ginkgo'"
exit 1
fi
if [ $remote = true ] ; then
# Setup the directory to copy test artifacts (logs, junit.xml, etc) from remote host to local host
if [ ! -d "${artifacts}" ]; then
echo "Creating artifacts directory at ${artifacts}"
mkdir -p ${artifacts}
fi
echo "Test artifacts will be written to ${artifacts}"
# Get the compute zone
zone=$(gcloud info --format='value(config.properties.compute.zone)')
if [[ $zone == "" ]]; then
echo "Could not find gcloud compute/zone when running:\ngcloud info --format='value(config.properties.compute.zone)'"
exit 1
fi
# Get the compute project
project=$(gcloud info --format='value(config.project)')
if [[ $project == "" ]]; then
echo "Could not find gcloud project when running:\ngcloud info --format='value(config.project)'"
exit 1
fi
# Check if any of the images specified already have running instances. If so reuse those instances
# by moving the IMAGE to a HOST
if [[ $images != "" ]]; then
IFS=',' read -ra IM <<< "$images"
images=""
for i in "${IM[@]}"; do
if [[ $(gcloud compute instances list "${instance_prefix}-$i" | grep $i) ]]; then
if [[ $hosts != "" ]]; then
hosts="$hosts,"
fi
echo "Reusing host ${instance_prefix}-$i"
hosts="${hosts}${instance_prefix}-${i}"
else
if [[ $images != "" ]]; then
images="$images,"
fi
images="$images$i"
fi
done
fi
# Parse the flags to pass to ginkgo
ginkgoflags=""
if [[ $focus != "" ]]; then
ginkgoflags="$ginkgoflags -focus=$focus "
fi
if [[ $skip != "" ]]; then
ginkgoflags="$ginkgoflags -skip=$skip "
fi
if [[ $run_until_failure != "" ]]; then
ginkgoflags="$ginkgoflags -untilItFails=$run_until_failure "
fi
# Output the configuration we will try to run
echo "Running tests remotely using"
echo "Project: $project"
echo "Image Project: $image_project"
echo "Compute/Zone: $zone"
echo "Images: $images"
echo "Hosts: $hosts"
echo "Ginkgo Flags: $ginkgoflags"
# Invoke the runner
go run test/e2e_node/runner/run_e2e.go --logtostderr --vmodule=*=2 --ssh-env="gce" \
--zone="$zone" --project="$project" \
--hosts="$hosts" --images="$images" --cleanup="$cleanup" \
--results-dir="$artifacts" --ginkgo-flags="$ginkgoflags" \
--image-project="$image_project" --instance-name-prefix="$instance_prefix" --setup-node="true" \
--delete-instances="$delete_instances"
exit $?
else
# Refresh sudo credentials if not running on GCE.
if ! ping -c 1 -q metadata.google.internal &> /dev/null; then
sudo -v || exit 1
fi
# Test using the host the script was run on
# Provided for backwards compatibility
"${ginkgo}" --focus=$focus --skip=$skip "${KUBE_ROOT}/test/e2e_node/" --report-dir=${report} \
-- --alsologtostderr --v 2 --node-name $(hostname) --disable-kubenet=true --build-services=true --start-services=true --stop-services=true
exit $?
fi
#!/bin/bash
# Copyright 2014 The Kubernetes 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.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
source "${KUBE_ROOT}/hack/lib/init.sh"
# Lists of API Versions of each groups that should be tested, groups are
# separated by comma, lists are separated by semicolon. e.g.,
# "v1,compute/v1alpha1,experimental/v1alpha2;v1,compute/v2,experimental/v1alpha3"
# TODO: It's going to be:
# KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1"}
# FIXME: due to current implementation of a test client (see: pkg/api/testapi/testapi.go)
# ONLY the last version is tested in each group.
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,autoscaling/v1,batch/v1,apps/v1alpha1,policy/v1alpha1,extensions/v1beta1,rbac.authorization.k8s.io/v1alpha1,certificates/v1alpha1"}
# Give integration tests longer to run
# TODO: allow a larger value to be passed in
#KUBE_TIMEOUT=${KUBE_TIMEOUT:--timeout 240s}
KUBE_TIMEOUT="-timeout 600s"
KUBE_INTEGRATION_TEST_MAX_CONCURRENCY=${KUBE_INTEGRATION_TEST_MAX_CONCURRENCY:-"-1"}
LOG_LEVEL=${LOG_LEVEL:-2}
KUBE_TEST_ARGS=${KUBE_TEST_ARGS:-}
kube::test::find_integration_test_dirs() {
(
cd ${KUBE_ROOT}
find test/integration -name '*_test.go' -print0 \
| xargs -0n1 dirname \
| sort -u
)
}
cleanup() {
kube::log::status "Cleaning up etcd"
kube::etcd::cleanup
kube::log::status "Integration test cleanup complete"
}
runTests() {
kube::log::status "Starting etcd instance"
kube::etcd::start
kube::log::status "Running integration test cases"
# TODO: Re-enable race detection when we switch to a thread-safe etcd client
# KUBE_RACE="-race"
make -C "${KUBE_ROOT}" test \
WHAT="$(kube::test::find_integration_test_dirs | paste -sd' ')" \
KUBE_GOFLAGS="${KUBE_GOFLAGS:-} -tags 'integration no-docker'" \
KUBE_RACE="" \
KUBE_TIMEOUT="${KUBE_TIMEOUT}" \
KUBE_TEST_API_VERSIONS="$1"
cleanup
}
checkEtcdOnPath() {
kube::log::status "Checking etcd is on PATH"
which etcd && return
kube::log::status "Cannot find etcd, cannot run integration tests."
kube::log::status "Please see docs/devel/testing.md for instructions."
return 1
}
checkEtcdOnPath
# Run cleanup to stop etcd on interrupt or other kill signal.
trap cleanup EXIT
# If a test case is specified, just run once with v1 API version and exit
if [[ -n "${KUBE_TEST_ARGS}" ]]; then
runTests v1
fi
# Convert the CSV to an array of API versions to test
IFS=';' read -a apiVersions <<< "${KUBE_TEST_API_VERSIONS}"
for apiVersion in "${apiVersions[@]}"; do
runTests "${apiVersion}"
done
#!/bin/bash
# Copyright 2014 The Kubernetes 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.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
source "${KUBE_ROOT}/cluster/lib/util.sh"
if [ -n "${VERBOSE}" ]; then
SILENT=false
else
SILENT=true
fi
# Excluded checks are always skipped.
EXCLUDED_CHECKS=(
"verify-linkcheck.sh" # runs in separate Jenkins job once per day due to high network usage
)
function is-excluded {
if [[ $1 -ef "$KUBE_ROOT/hack/verify-all.sh" ]]; then
return
fi
for e in ${EXCLUDED_CHECKS[@]}; do
if [[ $1 -ef "$KUBE_ROOT/hack/$e" ]]; then
return
fi
done
return 1
}
function run-cmd {
if ${SILENT}; then
"$@" &> /dev/null
else
"$@"
fi
}
function run-checks {
local -r pattern=$1
local -r runner=$2
for t in $(ls ${pattern})
do
if is-excluded "${t}" ; then
echo "Skipping ${t}"
continue
fi
echo -e "Verifying ${t}"
local start=$(date +%s)
run-cmd "${runner}" "${t}" && tr=$? || tr=$?
local elapsed=$(($(date +%s) - ${start}))
if [[ ${tr} -eq 0 ]]; then
echo -e "${color_green}SUCCESS${color_norm} ${t}\t${elapsed}s"
else
echo -e "${color_red}FAILED${color_norm} ${t}\t${elapsed}s"
ret=1
fi
done
}
while getopts ":v" opt; do
case ${opt} in
v)
SILENT=false
;;
\?)
echo "Invalid flag: -${OPTARG}" >&2
exit 1
;;
esac
done
if ${SILENT} ; then
echo "Running in silent mode, run with -v if you want to see script logs."
fi
ret=0
run-checks "${KUBE_ROOT}/hack/verify-*.sh" bash
run-checks "${KUBE_ROOT}/hack/verify-*.py" python
exit ${ret}
# ex: ts=2 sw=2 et filetype=sh
#!/bin/bash
# Copyright 2016 The Kubernetes 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.
set -o errexit
set -o nounset
set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
source "${KUBE_ROOT}/hack/lib/init.sh"
cd "${KUBE_ROOT}"
# This is required before we run govet for the results to be correct.
# See https://github.com/golang/go/issues/16086 for details.
go install ./cmd/...
# Use eval to preserve embedded quoted strings.
eval "goflags=(${KUBE_GOFLAGS:-})"
# Filter out arguments that start with "-" and move them to goflags.
targets=()
for arg; do
if [[ "${arg}" == -* ]]; then
goflags+=("${arg}")
else
targets+=("${arg}")
fi
done
if [[ ${#targets[@]} -eq 0 ]]; then
# Do not run on third_party directories.
targets=$(go list ./... | egrep -v "/(third_party|vendor)/")
fi
go vet "${goflags[@]:+${goflags[@]}}" ${targets[@]}
This source diff could not be displayed because it is too large. You can view the blob instead.
#!/bin/bash #!/bin/bash
# Copyright 2014 The Kubernetes Authors. # Copyright 2016 The Kubernetes Authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
...@@ -14,80 +14,22 @@ ...@@ -14,80 +14,22 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# This script is a vestigial redirection. Please do not add "real" logic.
set -o errexit set -o errexit
set -o nounset set -o nounset
set -o pipefail set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
# Lists of API Versions of each groups that should be tested, groups are
# separated by comma, lists are separated by semicolon. e.g.,
# "v1,compute/v1alpha1,experimental/v1alpha2;v1,compute/v2,experimental/v1alpha3"
# TODO: It's going to be:
# KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1"}
# FIXME: due to current implementation of a test client (see: pkg/api/testapi/testapi.go)
# ONLY the last version is tested in each group.
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,autoscaling/v1,batch/v1,apps/v1alpha1,policy/v1alpha1,extensions/v1beta1,rbac.authorization.k8s.io/v1alpha1,certificates/v1alpha1"}
# Give integration tests longer to run
# TODO: allow a larger value to be passed in
#KUBE_TIMEOUT=${KUBE_TIMEOUT:--timeout 240s}
KUBE_TIMEOUT="-timeout 600s"
KUBE_INTEGRATION_TEST_MAX_CONCURRENCY=${KUBE_INTEGRATION_TEST_MAX_CONCURRENCY:-"-1"}
LOG_LEVEL=${LOG_LEVEL:-2}
KUBE_TEST_ARGS=${KUBE_TEST_ARGS:-}
kube::test::find_integration_test_dirs() {
(
cd ${KUBE_ROOT}
find test/integration -name '*_test.go' -print0 \
| xargs -0n1 dirname \
| sort -u
)
}
cleanup() {
kube::log::status "Cleaning up etcd"
kube::etcd::cleanup
kube::log::status "Integration test cleanup complete"
}
runTests() {
kube::log::status "Starting etcd instance"
kube::etcd::start
kube::log::status "Running integration test cases"
# TODO: Re-enable race detection when we switch to a thread-safe etcd client
# KUBE_RACE="-race"
KUBE_GOFLAGS="${KUBE_GOFLAGS:-} -tags 'integration no-docker'" \
KUBE_RACE="" \
KUBE_TIMEOUT="${KUBE_TIMEOUT}" \
KUBE_TEST_API_VERSIONS="$1" \
"${KUBE_ROOT}/hack/test-go.sh" $(kube::test::find_integration_test_dirs)
cleanup
}
checkEtcdOnPath() {
kube::log::status "Checking etcd is on PATH"
which etcd && return
kube::log::status "Cannot find etcd, cannot run integration tests."
kube::log::status "Please see docs/devel/testing.md for instructions."
return 1
}
checkEtcdOnPath
# Run cleanup to stop etcd on interrupt or other kill signal.
trap cleanup EXIT
# If a test case is specified, just run once with v1 API version and exit echo "NOTE: $0 has been replaced by 'make test-integration'"
if [[ -n "${KUBE_TEST_ARGS}" ]]; then echo
runTests v1 echo "The equivalent of this invocation is: "
fi echo " make test-integration"
echo
echo
echo make --no-print-directory -C "${KUBE_ROOT}" test-integration
echo
echo
make --no-print-directory -C "${KUBE_ROOT}" test-integration
# Convert the CSV to an array of API versions to test
IFS=';' read -a apiVersions <<< "${KUBE_TEST_API_VERSIONS}"
for apiVersion in "${apiVersions[@]}"; do
runTests "${apiVersion}"
done
...@@ -92,7 +92,7 @@ function cleanup() { ...@@ -92,7 +92,7 @@ function cleanup() {
trap cleanup EXIT SIGINT trap cleanup EXIT SIGINT
"${KUBE_ROOT}/hack/build-go.sh" cmd/kube-apiserver make -C "${KUBE_ROOT}" WHAT=cmd/kube-apiserver
kube::etcd::start kube::etcd::start
......
...@@ -29,7 +29,7 @@ BUILD_TARGETS=( ...@@ -29,7 +29,7 @@ BUILD_TARGETS=(
cmd/libs/go2idl/deepcopy-gen cmd/libs/go2idl/deepcopy-gen
cmd/libs/go2idl/set-gen cmd/libs/go2idl/set-gen
) )
"${KUBE_ROOT}/hack/build-go.sh" ${BUILD_TARGETS[*]} make -C "${KUBE_ROOT}" WHAT="${BUILD_TARGETS[*]}"
clientgen=$(kube::util::find-binary "client-gen") clientgen=$(kube::util::find-binary "client-gen")
conversiongen=$(kube::util::find-binary "conversion-gen") conversiongen=$(kube::util::find-binary "conversion-gen")
......
...@@ -27,12 +27,14 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -27,12 +27,14 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" \ BINS=(
cmd/gendocs \ cmd/gendocs
cmd/genkubedocs \ cmd/genkubedocs
cmd/genman \ cmd/genman
cmd/genyaml \ cmd/genyaml
federation/cmd/genfeddocs federation/cmd/genfeddocs
)
make -C "${KUBE_ROOT}" WHAT="${BINS[*]}"
kube::util::ensure-temp-dir kube::util::ensure-temp-dir
......
...@@ -23,9 +23,11 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -23,9 +23,11 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
hack/build-go.sh \ BINS=(
cmd/libs/go2idl/go-to-protobuf \ cmd/libs/go2idl/go-to-protobuf
cmd/libs/go2idl/go-to-protobuf/protoc-gen-gogo cmd/libs/go2idl/go-to-protobuf/protoc-gen-gogo
)
make -C "${KUBE_ROOT}" WHAT="${BINS[*]}"
if [[ -z "$(which protoc)" || "$(protoc --version)" != "libprotoc 3.0."* ]]; then if [[ -z "$(which protoc)" || "$(protoc --version)" != "libprotoc 3.0."* ]]; then
echo "Generating protobuf requires protoc 3.0.0-beta1 or newer. Please download and" echo "Generating protobuf requires protoc 3.0.0-beta1 or newer. Please download and"
......
...@@ -26,8 +26,7 @@ git_upstream=$(kube::util::git_upstream_remote_name) ...@@ -26,8 +26,7 @@ git_upstream=$(kube::util::git_upstream_remote_name)
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" \ make -C "${KUBE_ROOT}" WHAT=cmd/mungedocs
cmd/mungedocs
kube::util::ensure-temp-dir kube::util::ensure-temp-dir
......
...@@ -33,7 +33,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -33,7 +33,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" cmd/kube-apiserver make -C "${KUBE_ROOT}" WHAT=cmd/kube-apiserver
function cleanup() function cleanup()
{ {
......
#!/bin/bash #!/bin/bash
# Copyright 2014 The Kubernetes Authors. # Copyright 2016 The Kubernetes Authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
...@@ -14,82 +14,24 @@ ...@@ -14,82 +14,24 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# This script is a vestigial redirection. Please do not add "real" logic.
set -o errexit set -o errexit
set -o nounset set -o nounset
set -o pipefail set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/cluster/lib/util.sh"
SILENT=true
# Excluded checks are always skipped.
EXCLUDED_CHECKS=(
"verify-linkcheck.sh" # runs in separate Jenkins job once per day due to high network usage
)
function is-excluded {
if [[ $1 -ef ${BASH_SOURCE} ]]; then
return
fi
for e in ${EXCLUDED_CHECKS[@]}; do
if [[ $1 -ef "$KUBE_ROOT/hack/$e" ]]; then
return
fi
done
return 1
}
function run-cmd {
if ${SILENT}; then
"$@" &> /dev/null
else
"$@"
fi
}
function run-checks { # For help output
local -r pattern=$1 ARGHELP=""
local -r runner=$2 if [[ -n "${KUBE_VERIFY_GIT_BRANCH:-}" ]]; then
ARGHELP="BRANCH=${KUBE_VERIFY_GIT_BRANCH}"
for t in $(ls ${pattern})
do
if is-excluded "${t}" ; then
echo "Skipping ${t}"
continue
fi
echo -e "Verifying ${t}"
local start=$(date +%s)
run-cmd "${runner}" "${t}" && tr=$? || tr=$?
local elapsed=$(($(date +%s) - ${start}))
if [[ ${tr} -eq 0 ]]; then
echo -e "${color_green}SUCCESS${color_norm} ${t}\t${elapsed}s"
else
echo -e "${color_red}FAILED${color_norm} ${t}\t${elapsed}s"
ret=1
fi
done
}
while getopts ":v" opt; do
case ${opt} in
v)
SILENT=false
;;
\?)
echo "Invalid flag: -${OPTARG}" >&2
exit 1
;;
esac
done
if ${SILENT} ; then
echo "Running in the silent mode, run with -v if you want to see script logs."
fi fi
ret=0 echo "NOTE: $0 has been replaced by 'make verify'"
run-checks "${KUBE_ROOT}/hack/verify-*.sh" bash echo
run-checks "${KUBE_ROOT}/hack/verify-*.py" python echo "The equivalent of this invocation is: "
exit ${ret} echo " make verify ${ARGHELP}"
echo
# ex: ts=2 sw=2 et filetype=sh echo
make --no-print-directory -C "${KUBE_ROOT}" verify BRANCH="${KUBE_VERIFY_GIT_BRANCH:-}"
...@@ -23,7 +23,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -23,7 +23,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" cmd/genswaggertypedocs make -C "${KUBE_ROOT}" WHAT=cmd/genswaggertypedocs
# Find binary # Find binary
genswaggertypedocs=$(kube::util::find-binary "genswaggertypedocs") genswaggertypedocs=$(kube::util::find-binary "genswaggertypedocs")
......
...@@ -23,12 +23,14 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -23,12 +23,14 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" \ BINS=(
cmd/gendocs \ cmd/gendocs
cmd/genkubedocs \ cmd/genkubedocs
cmd/genman \ cmd/genman
cmd/genyaml \ cmd/genyaml
federation/cmd/genfeddocs federation/cmd/genfeddocs
)
make -C "${KUBE_ROOT}" WHAT="${BINS[*]}"
kube::util::ensure-temp-dir kube::util::ensure-temp-dir
......
...@@ -23,7 +23,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -23,7 +23,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" cmd/genswaggertypedocs make -C "${KUBE_ROOT}" WHAT=cmd/genswaggertypedocs
# Find binary # Find binary
genswaggertypedocs=$(kube::util::find-binary "genswaggertypedocs") genswaggertypedocs=$(kube::util::find-binary "genswaggertypedocs")
...@@ -33,7 +33,7 @@ if [[ ! -x "$genswaggertypedocs" ]]; then ...@@ -33,7 +33,7 @@ if [[ ! -x "$genswaggertypedocs" ]]; then
echo "It looks as if you don't have a compiled genswaggertypedocs binary" echo "It looks as if you don't have a compiled genswaggertypedocs binary"
echo echo
echo "If you are running from a clone of the git repo, please run" echo "If you are running from a clone of the git repo, please run"
echo "'./hack/build-go.sh cmd/genswaggertypedocs'." echo "'make WHAT=cmd/genswaggertypedocs'."
} >&2 } >&2
exit 1 exit 1
fi fi
......
...@@ -14,36 +14,24 @@ ...@@ -14,36 +14,24 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# This script is a vestigial redirection. Please do not add "real" logic.
set -o errexit set -o errexit
set -o nounset set -o nounset
set -o pipefail set -o pipefail
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
source "${KUBE_ROOT}/hack/lib/init.sh"
cd "${KUBE_ROOT}" # For help output
ARGHELP=""
# This is required before we run govet for the results to be correct. if [[ "$#" -gt 0 ]]; then
# See https://github.com/golang/go/issues/16086 for details. ARGHELP="WHAT='$@'"
go install ./cmd/...
# Use eval to preserve embedded quoted strings.
eval "goflags=(${KUBE_GOFLAGS:-})"
# Filter out arguments that start with "-" and move them to goflags.
targets=()
for arg; do
if [[ "${arg}" == -* ]]; then
goflags+=("${arg}")
else
targets+=("${arg}")
fi
done
if [[ ${#targets[@]} -eq 0 ]]; then
# Do not run on third_party directories.
targets=$(go list ./... | egrep -v "/(third_party|vendor)/")
fi fi
go vet "${goflags[@]:+${goflags[@]}}" ${targets[@]} echo "NOTE: $0 has been replaced by 'make vet'"
echo
echo "The equivalent of this invocation is: "
echo " make vet ${ARGHELP}"
echo
echo
make --no-print-directory -C "${KUBE_ROOT}" vet WHAT="$@"
...@@ -23,6 +23,6 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -23,6 +23,6 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" cmd/libs/go2idl/import-boss make -C "${KUBE_ROOT}" WHAT=cmd/libs/go2idl/import-boss
$(kube::util::find-binary "import-boss") --verify-only $(kube::util::find-binary "import-boss") --verify-only
...@@ -23,7 +23,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -23,7 +23,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" cmd/linkcheck make -C "${KUBE_ROOT}" WHAT=cmd/linkcheck
linkcheck=$(kube::util::find-binary "linkcheck") linkcheck=$(kube::util::find-binary "linkcheck")
......
...@@ -26,8 +26,7 @@ git_upstream=$(kube::util::git_upstream_remote_name) ...@@ -26,8 +26,7 @@ git_upstream=$(kube::util::git_upstream_remote_name)
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" \ make -C "${KUBE_ROOT}/" WHAT=cmd/mungedocs
cmd/mungedocs
# Find binary # Find binary
mungedocs=$(kube::util::find-binary "mungedocs") mungedocs=$(kube::util::find-binary "mungedocs")
......
...@@ -23,7 +23,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -23,7 +23,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" cmd/kube-apiserver make -C "${KUBE_ROOT}" WHAT=cmd/kube-apiserver
apiserver=$(kube::util::find-binary "kube-apiserver") apiserver=$(kube::util::find-binary "kube-apiserver")
......
...@@ -23,7 +23,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh" ...@@ -23,7 +23,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
kube::golang::setup_env kube::golang::setup_env
"${KUBE_ROOT}/hack/build-go.sh" cmd/hyperkube make -C "${KUBE_ROOT}" WHAT=cmd/hyperkube
# add other BADSYMBOLS here. # add other BADSYMBOLS here.
BADSYMBOLS=( BADSYMBOLS=(
......
...@@ -7,7 +7,7 @@ readonly green=$(tput bold; tput setaf 2) ...@@ -7,7 +7,7 @@ readonly green=$(tput bold; tput setaf 2)
exit_code=0 exit_code=0
echo -ne "Checking that it builds... " echo -ne "Checking that it builds... "
if ! OUT=$("hack/build-go.sh" 2>&1); then if ! OUT=$(make 2>&1); then
echo echo
echo "${red}${OUT}" echo "${red}${OUT}"
exit_code=1 exit_code=1
......
...@@ -37,7 +37,7 @@ func (obj *ExtensionAPIObject) GetObjectKind() unversioned.ObjectKind { return & ...@@ -37,7 +37,7 @@ func (obj *ExtensionAPIObject) GetObjectKind() unversioned.ObjectKind { return &
func TestGetReference(t *testing.T) { func TestGetReference(t *testing.T) {
// when vendoring kube, if you don't force the set of registered versions (like this hack/test-go.sh does) // when vendoring kube, if you don't force the set of registered versions (like make test does)
// then you run into trouble because the types aren't registered in the scheme by anything. This does the // then you run into trouble because the types aren't registered in the scheme by anything. This does the
// register manually to allow unit test execution // register manually to allow unit test execution
if _, _, err := Scheme.ObjectKinds(&Pod{}); err != nil { if _, _, err := Scheme.ObjectKinds(&Pod{}); err != nil {
......
...@@ -43,7 +43,8 @@ func buildGo() { ...@@ -43,7 +43,8 @@ func buildGo() {
if err != nil { if err != nil {
glog.Fatalf("Failed to locate kubernetes root directory %v.", err) glog.Fatalf("Failed to locate kubernetes root directory %v.", err)
} }
cmd := exec.Command(filepath.Join(k8sRoot, "hack/build-go.sh"), buildTargets...) targets := strings.Join(buildTargets, " ")
cmd := exec.Command("make", "-C", k8sRoot, fmt.Sprintf("WHAT=%s", targets))
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
err = cmd.Run() err = cmd.Run()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment