From f8ca4f42ddf05da2271427a52e6fea79e68eac1c Mon Sep 17 00:00:00 2001 From: Grant Nelson Date: Thu, 20 Jun 2024 10:09:31 -0600 Subject: [PATCH] Moving from CircleCI to GHA --- .github/actions/setup-gopherjs/action.yml | 74 ++++++ .github/workflows/ci.yaml | 221 +++++++++++++++++ .github/workflows/lint.yaml | 25 -- .github/workflows/measure-size.yml | 12 +- README.md | 2 +- circle.yml | 290 ---------------------- doc/packages.md | 4 +- tests/gorepo/gorepo_test.go | 9 - 8 files changed, 305 insertions(+), 332 deletions(-) create mode 100644 .github/actions/setup-gopherjs/action.yml create mode 100644 .github/workflows/ci.yaml delete mode 100644 .github/workflows/lint.yaml delete mode 100644 circle.yml diff --git a/.github/actions/setup-gopherjs/action.yml b/.github/actions/setup-gopherjs/action.yml new file mode 100644 index 000000000..7bd1b7ab8 --- /dev/null +++ b/.github/actions/setup-gopherjs/action.yml @@ -0,0 +1,74 @@ +name: Setup GopherJS +description: Sets up Go, Node.js, and GopherJS + +inputs: + includeSyscall: + description: Indicates that the node-syscall package should be installed. + required: true + default: 'false' + + fixTemps: + description: Indicates that the Windows Temp variables should be fixed. + required: true + default: 'false' + +runs: + using: composite + steps: + - name: Fix Windows Temp Variables + if: inputs.fixTemps == 'true' + shell: pwsh + run: | + # see https://github.com/actions/runner-images/issues/712#issuecomment-613004302 + echo "TEMP=$env:USERPROFILE\AppData\Local\Temp" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 + echo "TMP=$env:USERPROFILE\AppData\Local\Temp" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 + echo "TMPDIR=$env:USERPROFILE\AppData\Local\Temp" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Setup Go Environment + working-directory: ${{ env.GOPHERJS_PATH }} + shell: bash + run: echo "GOROOT=$(go env GOROOT)" >> $GITHUB_ENV + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Install Node.js for non-Linux + if: inputs.includeSyscall != 'true' + working-directory: ${{ env.GOPHERJS_PATH }} + shell: bash + # Install required Node.js packages without optional (node-syscall). + run: npm install --omit=optional --no-package-lock + + - name: Install Node.js for Linux + if: inputs.includeSyscall == 'true' + working-directory: ${{ env.GOPHERJS_PATH }} + shell: bash + # Install required Node.js packages including optional (node-syscall). + run: | + npm install --include=optional --no-package-lock + + - name: Setup Node.js Environment + working-directory: ${{ env.GOPHERJS_PATH }} + shell: bash + # Make nodejs able to require installed modules from any working path. + run: echo "NODE_PATH=$(npm root)" >> $GITHUB_ENV + + - name: Install GopherJS + working-directory: ${{ env.GOPHERJS_PATH }} + shell: bash + run: go install -v + + - name: Setup information + shell: bash + run: | + echo ::notice::go version: $(go version) + echo ::notice::node version: $(node -v) + echo ::notice::npm version: $(npm -v) + echo ::notice::gopherjs version: $(gopherjs version) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 000000000..98ef4c45f --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,221 @@ +name: CI + +on: + push: + branches: [ "*" ] + pull_request: + branches: [ "*" ] + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +env: + GO_VERSION: 1.19.13 + NODE_VERSION: 12 + GOLANGCI_VERSION: v1.53.3 + GOPHERJS_EXPERIMENT: generics + SOURCE_MAP_SUPPORT: true + GOPATH: ${{ github.workspace }}/go + GOPHERJS_PATH: ${{ github.workspace }}/go/src/github.com/${{ github.repository }} + +jobs: + ubuntu_smoke: + name: Ubuntu Smoke + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: ${{ env.GOPHERJS_PATH }} + - name: Copy Actions + run: cp -r ${{ env.GOPHERJS_PATH }}/.github . + - name: Setup GopherJS + uses: ./.github/actions/setup-gopherjs/ + with: + includeSyscall: 'true' + - name: Test GopherJS + working-directory: ${{ env.GOPHERJS_PATH }} + run: go test -v -short ./... + - name: Run Tests + working-directory: ${{ env.GOPHERJS_PATH }} + run: | + gopherjs build -v net/http + gopherjs test -v --short fmt log ./tests + + windows_smoke: + name: Window Smoke + runs-on: windows-latest + env: + # Windows does not support source maps. + SOURCE_MAP_SUPPORT: false + steps: + - uses: actions/checkout@v4 + with: + path: ${{ env.GOPHERJS_PATH }} + - name: Copy Actions + run: cp -r ${{ env.GOPHERJS_PATH }}/.github . + - name: Setup GopherJS + uses: ./.github/actions/setup-gopherjs/ + with: + fixTemps: 'true' + - name: Test GopherJS + working-directory: ${{ env.GOPHERJS_PATH }} + run: go test -v -short ./... + - name: Run Tests + working-directory: ${{ env.GOPHERJS_PATH }} + run: | + gopherjs build -v net/http + gopherjs test -v --short fmt sort ./tests + + darwin_smoke: + name: Darwin Smoke + runs-on: macos-latest + env: + # Node version '12' is not found for darwin. + NODE_VERSION: 20 + steps: + - uses: actions/checkout@v4 + with: + path: ${{ env.GOPHERJS_PATH }} + - name: Copy Actions + run: cp -r ${{ env.GOPHERJS_PATH }}/.github . + - name: Setup GopherJS + uses: ./.github/actions/setup-gopherjs/ + - name: Test GopherJS + working-directory: ${{ env.GOPHERJS_PATH }} + run: go test -v -short ./... + - name: Run Tests + working-directory: ${{ env.GOPHERJS_PATH }} + run: | + gopherjs build -v net/http + gopherjs test -v --short fmt log os ./tests + + lint: + name: Lint Checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: ${{ env.GOPHERJS_PATH }} + - uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + - name: Install golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + working-directory: ${{ env.GOPHERJS_PATH }} + version: ${{ env.GOLANGCI_VERSION }} + only-new-issues: true + - name: Check go.mod + working-directory: ${{ env.GOPHERJS_PATH }} + run: go mod tidy && git diff --exit-code + - name: Check natives build tags + working-directory: ${{ env.GOPHERJS_PATH }} + # All those packages should have // +build js. + run: diff -u <(echo -n) <(go list ./compiler/natives/src/...) + + go_tests: + name: Go Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: ${{ env.GOPHERJS_PATH }} + - name: Copy Actions + run: cp -r ${{ env.GOPHERJS_PATH }}/.github . + - name: Setup GopherJS + uses: ./.github/actions/setup-gopherjs/ + - name: Run Tests + working-directory: ${{ env.GOPHERJS_PATH }} + # Run all tests except gorepo tests. + run: go test -v -race $(go list ./... | grep -v github.com/gopherjs/gopherjs/tests/gorepo) + + todomvc_check: + name: TodoMVC GO111MODULE Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: ${{ env.GOPHERJS_PATH }} + - name: Copy Actions + run: cp -r ${{ env.GOPHERJS_PATH }}/.github . + - name: Setup GopherJS + uses: ./.github/actions/setup-gopherjs/ + - name: TodoMVC in GOPATH mode + working-directory: ${{ env.GOPHERJS_PATH }} + env: + GO111MODULE: off + GOPATH: /tmp/gopath + run: | + mkdir -p $GOPATH/src/github.com/gopherjs/gopherjs + cp -r -p ${{ env.GOPHERJS_PATH }}/. $GOPATH/src/github.com/gopherjs/gopherjs/ + go get -v github.com/gopherjs/todomvc + gopherjs build -v -o /tmp/todomvc_gopath.js github.com/gopherjs/todomvc + gopherjs test -v github.com/gopherjs/todomvc/... + find $GOPATH + - name: TodoMVC in Go Modules mode + env: + GO111MODULE: on + GOPATH: /tmp/gmod + run: | + mkdir -p $GOPATH/src + cd /tmp + git clone --depth=1 https://github.com/gopherjs/todomvc.git + cd /tmp/todomvc + gopherjs build -v -o /tmp/todomvc_gomod.js github.com/gopherjs/todomvc + gopherjs test -v github.com/gopherjs/todomvc/... + find $GOPATH + - name: Compare GOPATH and Go Modules output + run: | + diff -u \ + <(sed 's/todomvc_gomod.js.map/todomvc_ignored.js.map/' /tmp/todomvc_gomod.js) \ + <(sed 's/todomvc_gopath.js.map/todomvc_ignored.js.map/' /tmp/todomvc_gopath.js) + + gopherjs_tests: + name: GopherJS Tests (${{ matrix.filter.name }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + filter: + - name: non-crypto + pattern: '-Pve "^crypto"' + - name: cypto + pattern: '-Pe "^crypto"' + steps: + - uses: actions/checkout@v4 + with: + path: ${{ env.GOPHERJS_PATH }} + - name: Copy Actions + run: cp -r ${{ env.GOPHERJS_PATH }}/.github . + - name: Setup GopherJS + uses: ./.github/actions/setup-gopherjs/ + - name: Run GopherJS tests + working-directory: ${{ env.GOPHERJS_PATH }} + run: | + PACKAGE_NAMES=$( \ + GOOS=js GOARCH=wasm go list std github.com/gopherjs/gopherjs/js/... github.com/gopherjs/gopherjs/tests/... \ + | grep -v -x -f .std_test_pkg_exclusions \ + | grep ${{ matrix.filter.pattern }} \ + ) + echo "Running tests for packages:" + echo "$PACKAGE_NAMES" + gopherjs test -p 4 --minify -v --short $PACKAGE_NAMES + + gorepo_tests: + name: Gorepo Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: ${{ env.GOPHERJS_PATH }} + - name: Copy Actions + run: cp -r ${{ env.GOPHERJS_PATH }}/.github . + - name: Setup GopherJS + uses: ./.github/actions/setup-gopherjs/ + - name: Run GopherJS tests + working-directory: ${{ env.GOPHERJS_PATH }} + run: go test -v github.com/gopherjs/gopherjs/tests/gorepo diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml deleted file mode 100644 index 03fa75d9c..000000000 --- a/.github/workflows/lint.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: golangci-lint -on: - pull_request: -permissions: - contents: read -jobs: - golangci: - name: lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-go@v3 - with: - go-version: "1.19.13" - - - name: golangci-lint - uses: golangci/golangci-lint-action@v3 - with: - version: v1.53.3 - only-new-issues: true - - - name: Check go.mod - run: | - go mod tidy && git diff --exit-code diff --git a/.github/workflows/measure-size.yml b/.github/workflows/measure-size.yml index ee4024e6a..1697b1127 100644 --- a/.github/workflows/measure-size.yml +++ b/.github/workflows/measure-size.yml @@ -2,16 +2,19 @@ name: Measure canonical app size on: ['pull_request'] +env: + GO_VERSION: '~1.19.13' + jobs: measure: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v5 with: - go-version: '~1.19.13' + go-version: ${{ env.GO_VERSION }} - uses: gopherjs/output-size-action/measure@main with: name: jQuery TodoMVC @@ -19,10 +22,9 @@ jobs: go-package: github.com/gopherjs/todomvc report_json: /tmp/report.json report_md: /tmp/report.md - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: size_report path: | /tmp/report.json /tmp/report.md - diff --git a/README.md b/README.md index 6966d9874..b653bb177 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![GoDoc](https://godoc.org/github.com/gopherjs/gopherjs/js?status.svg)](https://godoc.org/github.com/gopherjs/gopherjs/js) [![Sourcegraph](https://sourcegraph.com/github.com/gopherjs/gopherjs/-/badge.svg)](https://sourcegraph.com/github.com/gopherjs/gopherjs?badge) -[![Circle CI](https://circleci.com/gh/gopherjs/gopherjs.svg?style=svg)](https://circleci.com/gh/gopherjs/gopherjs) +[![Github Actions CI](https://github.com/gopherjs/gopherjs/actions/workflows/ci.yaml/badge.svg)](https://github.com/gopherjs/gopherjs/actions/workflows/ci.yaml) GopherJS compiles Go code ([go.dev](https://go.dev/)) to pure JavaScript code. Its main purpose is to give you the opportunity to write front-end code in Go which will still run in all browsers. diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 8d7a57e6f..000000000 --- a/circle.yml +++ /dev/null @@ -1,290 +0,0 @@ -# CircleCI configuration for GopherJS. -# -# This configuration has one build_and_test workflow designed to run on all commits -# and pull requests. It consists of three jobs: -# -# - build: Builds and runs GopherJS unit tests, as well as lints, smoke tests, etc. -# This job is designed to provide quickest feedback on the most important -# functionality. It should not include anything heavyweight and should be kept -# under 2-3 minutes of runtime. -# -# - gopherjs_tests: Runs standard library and GopherJS package tests using GopherJS -# *itself*. This is the most comprehensive test suite we have, and it is sharded -# into 4 parallel instances for faster execution. -# -# - gorepo_tests: Runs language tests from the Go compiler test suite. The objective -# of these tests is to ensure conformance of GopherJS to the upstream Go to the -# highest degree possible, considering differences in the runtime. -# -# If all tests passed, it is reasonably to assume that the version is more or less -# bug-free (although as of summer 2021 our test coverage is not ideal). -# -# For convenience of upgrades, NVM, Node.js and Go versions are specified as -# parameters at the top of the config. Increasing the version and ensuring that the -# workflow passes is sufficient to verify GopherJS compatibility with that version. -# -# Versions of Node modules GopherJS depends on are specified in package.json and can -# be changed there (remember to run `npm install` to update the lock file). - -version: 2.1 -executors: - gopherjs: - docker: - - image: cimg/base:stable - working_directory: ~/gopherjs - -workflows: - version: 2 - build_and_test: - jobs: - - build - - gopherjs_tests: - requires: - - build - - gorepo_tests: - requires: - - build - - darwin_smoke: - requires: - - build - - windows_smoke: - requires: - - build - -parameters: - go_version: - type: string - default: "1.19.13" - chocolatey_go_version: - type: string - # Chocolatey doesn't have 1.19.13, closest is 1.19.9 - default: "1.19.9" - nvm_version: - type: string - default: "0.38.0" - node_version: - type: string - default: "12" - -orbs: - win: circleci/windows@4.0.0 - go: circleci/go@1.7.1 - node: circleci/node@5.0.1 - -jobs: - build: - executor: gopherjs - environment: - GOPHERJS_EXPERIMENT: generics - steps: - - setup_and_install_gopherjs - - run: - name: Check natives build tags - command: diff -u <(echo -n) <(go list ./compiler/natives/src/...) # All those packages should have // +build js. - - run: - name: Smoke tests - command: | - gopherjs build -v net/http # Should build successfully. - gopherjs test -v fmt log # Should catch problems with test execution and source maps. - - run: - name: go test ... - command: | - set +e - # Run all tests except gorepo, which will be run separately in parallel. - go test -v -race $(go list ./... | grep -v github.com/gopherjs/gopherjs/tests/gorepo) | tee /tmp/test-go.txt - status="$?" - # Convert test output into junit format for CircleCI. - mkdir -p ~/test-reports/ - go-junit-report --full-class-name < /tmp/test-go.txt > ~/test-reports/go.xml - exit "$status" - - store_test_results: - path: ~/test-reports/ - - run: - name: TodoMVC in GOPATH mode - command: | - set -e - export GO111MODULE=off - export GOPATH=/tmp/gopath - mkdir -p $GOPATH/src/github.com/gopherjs/gopherjs - cp -r -p . $GOPATH/src/github.com/gopherjs/gopherjs/ - go get -v github.com/gopherjs/todomvc - gopherjs build -v -o /tmp/todomvc_gopath.js github.com/gopherjs/todomvc - gopherjs test -v github.com/gopherjs/todomvc/... - find $GOPATH - - run: - name: TodoMVC in Go Modules mode - command: | - set -e - export GO111MODULE=on - export GOPATH=/tmp/gomod - mkdir -p $GOPATH/src - cd /tmp - git clone --depth=1 https://github.com/gopherjs/todomvc.git - cd /tmp/todomvc - gopherjs build -v -o /tmp/todomvc_gomod.js github.com/gopherjs/todomvc - gopherjs test -v github.com/gopherjs/todomvc/... - find $GOPATH - - run: - name: Compare GOPATH and Go Modules output - command: diff -u <(sed 's/todomvc_gomod.js.map/todomvc_ignored.js.map/' /tmp/todomvc_gomod.js) <(sed 's/todomvc_gopath.js.map/todomvc_ignored.js.map/' /tmp/todomvc_gopath.js) - - gopherjs_tests: - executor: gopherjs - parallelism: 4 - environment: - GOPHERJS_EXPERIMENT: generics - steps: - - setup_and_install_gopherjs - - run: - name: gopherjs test ... - command: | - set +e - ulimit -s 10000 - PACKAGE_NAMES=$( \ - GOOS=js GOARCH=wasm go list std github.com/gopherjs/gopherjs/js/... github.com/gopherjs/gopherjs/tests/... \ - | grep -v -x -f .std_test_pkg_exclusions \ - | circleci tests split --split-by=timings --timings-type=classname \ - ) - gopherjs test -p 2 --minify -v --short $PACKAGE_NAMES \ - | tee /tmp/test-gopherjs.txt - status="$?" - set -e - # Convert test output into junit format for CircleCI. - mkdir -p ~/test-reports/ - go-junit-report --full-class-name < /tmp/test-gopherjs.txt > ~/test-reports/gopherjs-${CIRCLE_NODE_INDEX}.xml - exit "$status" - no_output_timeout: "1h" # Packages like math/big take a while to run all tests. - - store_test_results: - path: ~/test-reports/ - - gorepo_tests: - executor: gopherjs - environment: - GOPHERJS_EXPERIMENT: generics - parallelism: 4 - steps: - - setup_environment - - checkout - - install_deps - - install_gopherjs - - run: - name: Go Repository tests - command: | - go test -v github.com/gopherjs/gopherjs/tests/gorepo - - windows_smoke: - executor: - name: win/default - shell: powershell.exe - environment: - GOPHERJS_EXPERIMENT: generics - steps: - - checkout - - run: - name: Install Go - command: | - choco install golang --version="<< pipeline.parameters.chocolatey_go_version >>" -my --force -y - go version - (Get-Command go).Path - [Environment]::SetEnvironmentVariable( - "Path", - [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::Machine) + ";C:\Users\circleci\go\bin", - [EnvironmentVariableTarget]::Machine) - - - install_deps: - optional: false - - run: - name: Install GopherJS - command: - go install -v . - (Get-Command gopherjs).Path - - run: - name: Test GopherJS - command: go test -v -short ./... - - run: - name: Smoke tests - command: | - $env:NODE_PATH=$(npm root) - $env:SOURCE_MAP_SUPPORT=false - gopherjs build -v net/http - gopherjs test -v --short fmt sort ./tests - - darwin_smoke: - macos: - xcode: 13.4.1 # Mac OS 12.6.1, see https://circleci.com/docs/using-macos/ - environment: - GOPHERJS_EXPERIMENT: generics - steps: - - checkout - - setup_environment - - install_deps: - optional: false - - run: - name: Install GopherJS - command: go install -v . - - run: - name: Test GopherJS - command: go test -v -short ./... - - run: - name: Smoke tests - command: | - gopherjs build -v net/http - gopherjs test -v --short fmt log os ./tests - -commands: - setup_environment: - description: Set up Go, NVM and Node.js - steps: - - go/install: - version: << pipeline.parameters.go_version >> - - node/install: - node-version: << pipeline.parameters.node_version >> - - run: - name: Set up environment - command: | - echo 'export PATH="$PATH:$HOME/go/bin"' >> $BASH_ENV - echo 'export GO111MODULE=on' >> $BASH_ENV - echo 'export SOURCE_MAP_SUPPORT=true' >> $BASH_ENV - # Make nodejs able to require installed modules from any working path. - echo "export NODE_PATH=$(npm root)" >> $BASH_ENV - go version - node -v - go install -v github.com/nevkontakte/go-junit-report@forked # For CircleCI test reports. - install_deps: - description: Install Go and Node dependency packages - parameters: - optional: - default: true - type: boolean - description: Install node-syscall module and its dependencies. - steps: - - when: - condition: - not: << parameters.optional >> - steps: - - run: - name: Install required Node.js packages - command: | - # Extra flags to avoid installing node-syscall. - npm install --no-optional --no-package-lock - - when: - condition: << parameters.optional >> - steps: - - run: - name: Install required Node.js packages (including optional) - command: | - npm ci # Install our dependencies from package.json. - - go/mod-download - install_gopherjs: - description: Install GopherJS - steps: - - run: - name: Install GopherJS - command: go install -v && gopherjs version - setup_and_install_gopherjs: - description: A shorthand for setting up GopherJS environment and building the binary. - steps: - - setup_environment - - checkout - - install_deps - - install_gopherjs diff --git a/doc/packages.md b/doc/packages.md index b49db7319..ca1ff80e5 100644 --- a/doc/packages.md +++ b/doc/packages.md @@ -1,8 +1,8 @@ # Supported Packages -On each commit, Circle CI automatically compiles all supported packages with GopherJS and runs their tests: +On each commit, Github Actions CI automatically compiles all supported packages with GopherJS and runs their tests: -[![Circle CI](https://circleci.com/gh/gopherjs/gopherjs.svg?style=svg)](https://circleci.com/gh/gopherjs/gopherjs) +[![Github Actions CI](https://github.com/gopherjs/gopherjs/actions/workflows/ci.yaml/badge.svg)](https://github.com/gopherjs/gopherjs/actions/workflows/ci.yaml) | Name | Supported | Comment | | ------------------- | ------------ | --------------------------------------------------------------------------------- | diff --git a/tests/gorepo/gorepo_test.go b/tests/gorepo/gorepo_test.go index d80715948..5ab93e9af 100644 --- a/tests/gorepo/gorepo_test.go +++ b/tests/gorepo/gorepo_test.go @@ -21,15 +21,6 @@ func TestGoRepositoryCompilerTests(t *testing.T) { args = append(args, "-v") } - shards := os.Getenv("CIRCLE_NODE_TOTAL") - shard := os.Getenv("CIRCLE_NODE_INDEX") - if shards != "" && shard != "" { - // We are running under CircleCI parallel test job, so we need to shard execution. - args = append(args, "-shard="+shard, "-shards="+shards) - // CircleCI reports a lot more cores than we can actually use, so we have to limit concurrency. - args = append(args, "-n=2", "-l=2") - } - cmd := exec.Command(args[0], args[1:]...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stdout