Skip to content

chore: run test-go-pg on macOS and Windows in regular CI #17853

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 22, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
enable go test cache in test-go-pg
  • Loading branch information
hugodutka committed May 22, 2025
commit 0edcb086b0b215af7c7411fe5401ae5e56872988
57 changes: 57 additions & 0 deletions .github/actions/setup-go-paths/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: "Setup Go Paths"
description: Overrides Go paths like GOCACHE and GOMODCACHE to use temporary directories.
outputs:
gocache:
description: "Value of GOCACHE"
value: ${{ steps.paths.outputs.gocache }}
gomodcache:
description: "Value of GOMODCACHE"
value: ${{ steps.paths.outputs.gomodcache }}
gopath:
description: "Value of GOPATH"
value: ${{ steps.paths.outputs.gopath }}
gotmp:
description: "Value of GOTMPDIR"
value: ${{ steps.paths.outputs.gotmp }}
cached-dirs:
description: "Go directories that should be cached between CI runs"
value: ${{ steps.paths.outputs.cached-dirs }}
runs:
using: "composite"
steps:
- name: Override Go paths
id: paths
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with:
script: |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind using the script here, but you can accomplish the same with bash by echoing to GITHUB_ENV and GITHUB_OUTPUT: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose to use the script to handle setting multi-line env variables. With bash, you have to be very careful with whitespace and indentation. It's error-prone.

const path = require('path');

// RUNNER_TEMP should be backed by a RAM disk on Windows if
// coder/setup-ramdisk-action was used
const runnerTemp = process.env.RUNNER_TEMP;
const gocacheDir = path.join(runnerTemp, 'go-cache');
const gomodcacheDir = path.join(runnerTemp, 'go-mod-cache');
const gopathDir = path.join(runnerTemp, 'go-path');
const gotmpDir = path.join(runnerTemp, 'go-tmp');

core.exportVariable('GOCACHE', gocacheDir);
core.exportVariable('GOMODCACHE', gomodcacheDir);
core.exportVariable('GOPATH', gopathDir);
core.exportVariable('GOTMPDIR', gotmpDir);

core.setOutput('gocache', gocacheDir);
core.setOutput('gomodcache', gomodcacheDir);
core.setOutput('gopath', gopathDir);
core.setOutput('gotmp', gotmpDir);

const cachedDirs = `${gocacheDir}\n${gomodcacheDir}`;
core.setOutput('cached-dirs', cachedDirs);

- name: Create directories
shell: bash
run: |
set -e
mkdir -p "$GOCACHE"
mkdir -p "$GOMODCACHE"
mkdir -p "$GOPATH"
mkdir -p "$GOTMPDIR"
32 changes: 8 additions & 24 deletions .github/actions/setup-go/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,26 @@ inputs:
use-preinstalled-go:
description: "Whether to use preinstalled Go."
default: "false"
use-temp-cache-dirs:
description: "Whether to use temporary GOCACHE and GOMODCACHE directories."
default: "false"
use-cache:
description: "Whether to use the cache."
default: "true"
runs:
using: "composite"
steps:
- name: Override GOCACHE and GOMODCACHE
shell: bash
if: inputs.use-temp-cache-dirs == 'true'
run: |
# cd to another directory to ensure we're not inside a Go project.
# That'd trigger Go to download the toolchain for that project.
cd "$RUNNER_TEMP"
# RUNNER_TEMP should be backed by a RAM disk on Windows if
# coder/setup-ramdisk-action was used
export GOCACHE_DIR="$RUNNER_TEMP""\go-cache"
export GOMODCACHE_DIR="$RUNNER_TEMP""\go-mod-cache"
export GOPATH_DIR="$RUNNER_TEMP""\go-path"
export GOTMP_DIR="$RUNNER_TEMP""\go-tmp"
mkdir -p "$GOCACHE_DIR"
mkdir -p "$GOMODCACHE_DIR"
mkdir -p "$GOPATH_DIR"
mkdir -p "$GOTMP_DIR"
go env -w GOCACHE="$GOCACHE_DIR"
go env -w GOMODCACHE="$GOMODCACHE_DIR"
go env -w GOPATH="$GOPATH_DIR"
go env -w GOTMPDIR="$GOTMP_DIR"
- name: Setup Go
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
with:
go-version: ${{ inputs.use-preinstalled-go == 'false' && inputs.version || '' }}
cache: ${{ inputs.use-cache }}

- name: Install gotestsum
shell: bash
run: go install gotest.tools/gotestsum@0d9599e513d70e5792bb9334869f82f6e8b53d4d # main as of 2025-05-15

- name: Install mtimehash
shell: bash
run: go install github.com/slsyy/mtimehash/cmd/mtimehash@a6b5da4ed2c4a40e7b805534b004e9fde7b53ce0 # v1.0.0

# It isn't necessary that we ever do this, but it helps
# separate the "setup" from the "run" times.
- name: go mod download
Expand Down
72 changes: 56 additions & 16 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -336,21 +336,23 @@ jobs:
# a separate repository to allow its use before actions/checkout.
- name: Setup RAM Disks
if: runner.os == 'Windows'
uses: coder/setup-ramdisk-action@81c5c441bda00c6c3d6bcee2e5a33ed4aadbbcc1
uses: coder/setup-ramdisk-action@a4b59caa8be2e88c348abeef042d7c1a33d8743e

- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 1

- name: Setup Go Paths
uses: ./.github/actions/setup-go-paths
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously we were only doing this on Windows, should we do the same here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step is now used to standardize the Go cache location on disk so the "download cache step" knows where to put it. Without it, it's somewhat complicated to figure out the paths so it works cross-OS and if Go isn't installed.


- name: Setup Go
uses: ./.github/actions/setup-go
with:
# Runners have Go baked-in and Go will automatically
# download the toolchain configured in go.mod, so we don't
# need to reinstall it. It's faster on Windows runners.
use-preinstalled-go: ${{ runner.os == 'Windows' }}
use-temp-cache-dirs: ${{ runner.os == 'Windows' }}

- name: Setup Terraform
uses: ./.github/actions/setup-tf
Expand Down Expand Up @@ -490,21 +492,33 @@ jobs:
# a separate repository to allow its use before actions/checkout.
- name: Setup RAM Disks
if: runner.os == 'Windows'
uses: coder/setup-ramdisk-action@79dacfe70c47ad6d6c0dd7f45412368802641439
uses: coder/setup-ramdisk-action@a4b59caa8be2e88c348abeef042d7c1a33d8743e

- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 1

- name: Setup Go Paths
id: go-paths
uses: ./.github/actions/setup-go-paths

- name: Download Go Build Cache
id: download-go-build-cache
uses: ./.github/actions/test-cache/download
with:
key-prefix: test-go-build-${{ runner.os }}-${{ runner.arch }}
cache-path: ${{ steps.go-paths.outputs.cached-dirs }}

- name: Setup Go
uses: ./.github/actions/setup-go
with:
# Runners have Go baked-in and Go will automatically
# download the toolchain configured in go.mod, so we don't
# need to reinstall it. It's faster on Windows runners.
use-preinstalled-go: ${{ runner.os == 'Windows' }}
use-temp-cache-dirs: ${{ runner.os == 'Windows' }}
# Cache is already downloaded above
use-cache: false

- name: Setup Terraform
uses: ./.github/actions/setup-tf
Expand All @@ -515,6 +529,15 @@ jobs:
with:
key-prefix: test-go-pg-${{ runner.os }}-${{ runner.arch }}

- name: Normalize File and Directory Timestamps
shell: bash
# Normalize file modification timestamps so that go test can use the
# cache from the previous CI run. See https://github.com/golang/go/issues/58571
# for more details.
run: |
find . -type f ! -path ./.git/\*\* | mtimehash
find . -type d ! -path ./.git/\*\* -exec touch -t 200601010000 {} +

- name: Test with PostgreSQL Database
env:
POSTGRES_VERSION: "13"
Expand All @@ -523,6 +546,9 @@ jobs:
LC_ALL: "en_US.UTF-8"
shell: bash
run: |
set -o errexit
set -o pipefail

if [ "${{ runner.os }}" == "Windows" ]; then
# Create a temp dir on the R: ramdisk drive for Windows. The default
# C: drive is extremely slow: https://github.com/actions/runner-images/issues/8755
Expand All @@ -533,6 +559,8 @@ jobs:
mkdir -p /tmp/tmpfs
sudo mount_tmpfs -o noowners -s 8g /tmp/tmpfs
go run scripts/embedded-pg/main.go -path /tmp/tmpfs/embedded-pg
elif [ "${{ runner.os }}" == "Linux" ]; then
make test-postgres-docker
fi

# if macOS, install google-chrome for scaletests
Expand All @@ -542,10 +570,6 @@ jobs:
brew install google-chrome
fi

# By default Go will use the number of logical CPUs, which
# is a fine default.
PARALLEL_FLAG=""

# macOS will output "The default interactive shell is now zsh"
# intermittently in CI...
if [ "${{ matrix.os }}" == "macos-latest" ]; then
Expand All @@ -572,16 +596,32 @@ jobs:
NUM_PARALLEL_TESTS=8
fi

if [ "${{ runner.os }}" == "Linux" ]; then
make test-postgres
else
# We rerun failing tests to counteract flakiness coming from Postgres
# choking on macOS and Windows sometimes.
DB=ci gotestsum --rerun-fails=2 --rerun-fails-max-failures=50 \
--format standard-quiet --packages "./..." \
-- -v -p $NUM_PARALLEL_PACKAGES -parallel=$NUM_PARALLEL_TESTS -count=1
# by default, run tests with cache
TESTCOUNT=""
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
# on main, run tests without cache
TESTCOUNT="-count=1"
fi

mkdir -p "$RUNNER_TEMP/sym"
source scripts/normalize_path.sh
# terraform gets installed in a random directory, so we need to normalize
# the path to the terraform binary or a bunch of cached tests will be
# invalidated. See scripts/normalize_path.sh for more details.
normalize_path_with_symlinks "$RUNNER_TEMP/sym" "$(dirname $(which terraform))"
Comment on lines +553 to +556
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like it would be better if we changed the test to use system terraform if it's a suitable version, then we can just install it before starting the test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean we should use the terraform download function that's built into Coder?


# We rerun failing tests to counteract flakiness coming from Postgres
# choking on macOS and Windows sometimes.
DB=ci gotestsum --rerun-fails=2 --rerun-fails-max-failures=50 \
--format standard-quiet --packages "./..." \
-- -timeout=20m -v -p $NUM_PARALLEL_PACKAGES -parallel=$NUM_PARALLEL_TESTS $TESTCOUNT

- name: Upload Go Build Cache
uses: ./.github/actions/test-cache/upload
with:
cache-key: ${{ steps.download-go-build-cache.outputs.cache-key }}
cache-path: ${{ steps.go-paths.outputs.cached-dirs }}

- name: Upload Test Cache
uses: ./.github/actions/test-cache/upload
with:
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/nightly-gauntlet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,16 @@ jobs:
with:
fetch-depth: 1

- name: Setup Go Paths
uses: ./.github/actions/setup-go-paths

- name: Setup Go
uses: ./.github/actions/setup-go
with:
# Runners have Go baked-in and Go will automatically
# download the toolchain configured in go.mod, so we don't
# need to reinstall it. It's faster on Windows runners.
use-preinstalled-go: ${{ runner.os == 'Windows' }}
use-temp-cache-dirs: ${{ runner.os == 'Windows' }}

- name: Setup Terraform
uses: ./.github/actions/setup-tf
Expand Down
55 changes: 55 additions & 0 deletions scripts/normalize_path.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/bin/bash

# Call: normalize_path_with_symlinks [target_dir] [dir_prefix]
#
# Normalizes the PATH environment variable by replacing each directory that
# begins with dir_prefix with a symbolic link in target_dir. For example, if
# PATH is "/usr/bin:/bin", target_dir is /tmp, and dir_prefix is /usr, then
# PATH will become "/tmp/0:/bin", where /tmp/0 links to /usr/bin.
#
# This is useful for ensuring that PATH is consistent across CI runs and helps
# with reusing the same cache across them. Many of our go tests read the PATH
# variable, and if it changes between runs, the cache gets invalidated.
normalize_path_with_symlinks() {
local target_dir="${1:-}"
local dir_prefix="${2:-}"

if [[ -z "$target_dir" || -z "$dir_prefix" ]]; then
echo "Usage: normalize_path_with_symlinks <target_dir> <dir_prefix>"
return 1
fi

local old_path="$PATH"
local -a new_parts=()
local i=0

IFS=':' read -ra _parts <<<"$old_path"
for dir in "${_parts[@]}"; do
# Skip empty components that can arise from "::"
[[ -z $dir ]] && continue

# Skip directories that don't start with $dir_prefix
if [[ "$dir" != "$dir_prefix"* ]]; then
new_parts+=("$dir")
continue
fi

local link="$target_dir/$i"

# Replace any pre-existing file or link at $target_dir/$i
if [[ -e $link || -L $link ]]; then
rm -rf -- "$link"
fi

# without MSYS ln will deepcopy the directory on Windows
MSYS=winsymlinks:nativestrict ln -s -- "$dir" "$link"
new_parts+=("$link")
i=$((i + 1))
done

export PATH
PATH="$(
IFS=':'
echo "${new_parts[*]}"
)"
}