Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
300 changes: 298 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ permissions:
contents: read

jobs:
test-action:
name: GitHub Actions Test
test-java-action:
name: Java Smoke Test
runs-on: ubuntu-latest
container:
image: adoptopenjdk/openjdk11:latest
Expand All @@ -38,3 +38,299 @@ jobs:

java -version 2>&1 | tee $LOG_FILE
grep -q "$TRACER_INIT_LOG" $LOG_FILE || { echo "Error: Output does not contain tracer initialisation log: $TRACER_INIT_LOG"; exit 1; }

test-go-action-matrix:
name: Go Matrix (${{ matrix.name }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- case_id: root_go_124_success
name: root go1.24 success
runner_go: '1.26.1'
layout: root
project_go: '1.24.0'
go_module_dir: ''
expect_action_failure: false
run_go_tests: true
test_workdir: .
expected_dd_trace_go_version: v2.6.0
- case_id: root_go_125_success
name: root go1.25 success
runner_go: '1.26.1'
layout: root
project_go: '1.25.0'
go_module_dir: ''
expect_action_failure: false
run_go_tests: true
test_workdir: .
expected_dd_trace_go_version: v2.7.0
- case_id: root_go_122_skip
name: root go1.22 skip
runner_go: '1.26.1'
layout: root
project_go: '1.22.0'
go_module_dir: ''
expect_action_failure: false
run_go_tests: false
test_workdir: .
expected_dd_trace_go_version: ''
- case_id: runner_below_min_skip
name: runner below minimum partial failure
runner_go: '1.23.12'
layout: root
project_go: '1.24.0'
go_module_dir: ''
expect_action_failure: true
run_go_tests: false
test_workdir: .
expected_dd_trace_go_version: ''
- case_id: single_nested_go_124_auto
name: single nested go1.24 auto-detect
runner_go: '1.26.1'
layout: single_nested
project_go: '1.24.0'
go_module_dir: ''
expect_action_failure: false
run_go_tests: true
test_workdir: services/payments
expected_dd_trace_go_version: v2.6.0
- case_id: single_nested_go_125_auto
name: single nested go1.25 auto-detect
runner_go: '1.26.1'
layout: single_nested
project_go: '1.25.0'
go_module_dir: ''
expect_action_failure: false
run_go_tests: true
test_workdir: services/payments
expected_dd_trace_go_version: v2.7.0
- case_id: multiple_modules_without_override_skip
name: multiple modules without override skip
runner_go: '1.26.1'
layout: multiple_modules
project_go: '1.24.0'
second_project_go: '1.25.0'
go_module_dir: ''
expect_action_failure: false
run_go_tests: false
test_workdir: .
expected_dd_trace_go_version: ''
- case_id: multiple_modules_with_override_success
name: multiple modules with override success
runner_go: '1.26.1'
layout: multiple_modules
project_go: '1.25.0'
second_project_go: '1.24.0'
go_module_dir: ./services/payments
expect_action_failure: false
run_go_tests: true
test_workdir: services/payments
expected_dd_trace_go_version: v2.7.0
- case_id: missing_directory_fail
name: missing override directory failure
runner_go: '1.26.1'
layout: root
project_go: '1.24.0'
go_module_dir: ./services/does-not-exist
expect_action_failure: true
run_go_tests: false
test_workdir: .
expected_dd_trace_go_version: ''

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.runner_go }}
cache: false

- name: Create Go Scenario
shell: bash
run: |
set -euo pipefail

create_module() {
local module_dir="$1"
local module_name="$2"
local go_version="$3"
local package_name="$4"

mkdir -p "$module_dir"

cat > "$module_dir/go.mod" <<EOF
module $module_name

go $go_version
EOF

cat > "$module_dir/smoke_test.go" <<EOF
package $package_name

import "testing"

func TestSmoke(t *testing.T) {}
EOF
}

case "${{ matrix.layout }}" in
root)
create_module "." "example.com/test-visibility-action-smoke" "${{ matrix.project_go }}" "smoke"
;;
single_nested)
create_module "services/payments" "example.com/test-visibility-action-smoke/payments" "${{ matrix.project_go }}" "payments"
;;
multiple_modules)
create_module "services/payments" "example.com/test-visibility-action-smoke/payments" "${{ matrix.project_go }}" "payments"
create_module "services/orders" "example.com/test-visibility-action-smoke/orders" "${{ matrix.second_project_go }}" "orders"
;;
*)
echo "Error: Unknown layout '${{ matrix.layout }}'."
exit 1
;;
esac

mkdir -p .before
while IFS= read -r go_mod_path; do
snapshot_path=".before/${go_mod_path#./}.snapshot"
mkdir -p "$(dirname "$snapshot_path")"
cp "$go_mod_path" "$snapshot_path"
done < <(find . -path './.git' -prune -o -name go.mod -print | sort)

- name: Run Instrumentation Action
id: run-action
continue-on-error: ${{ matrix.expect_action_failure }}
uses: ./
with:
languages: go
api_key: "dummy"
go-tracer-version: v1.8.0
go-module-dir: ${{ matrix.go_module_dir }}
cache: false

- name: Assert Go Scenario
shell: bash
run: |
set -euo pipefail

action_outcome="${{ steps.run-action.outcome }}"

assert_file_unchanged() {
local path="$1"
local snapshot_path=".before/${path#./}.snapshot"

if ! cmp -s "$snapshot_path" "$path"; then
echo "Error: Expected $path to remain unchanged."
diff -u "$snapshot_path" "$path" || true
exit 1
fi
}

assert_file_absent() {
local path="$1"

if [ -e "$path" ]; then
echo "Error: Expected $path to be absent."
exit 1
fi
}

assert_instrumented_module() {
local module_dir="$1"
local go_ceiling="$2"
local selected_trace_version
local selected_trace_go_version

[ -n "${GOFLAGS:-}" ] || { echo "Error: GOFLAGS was not set."; exit 1; }
[ -n "${DD_TRACER_VERSION_GO:-}" ] || { echo "Error: DD_TRACER_VERSION_GO was not set."; exit 1; }
[ "$DD_TRACER_VERSION_GO" = "v1.8.0" ] || { echo "Error: Expected DD_TRACER_VERSION_GO to be v1.8.0, got '$DD_TRACER_VERSION_GO'."; exit 1; }
echo "$GOFLAGS" | grep -q "orchestrion toolexec" || { echo "Error: GOFLAGS does not include orchestrion."; exit 1; }
grep -Fq "github.com/DataDog/orchestrion v1.8.0" "$module_dir/go.mod" || { echo "Error: $module_dir/go.mod does not pin orchestrion to v1.8.0."; exit 1; }
grep -Fq "github.com/DataDog/dd-trace-go/orchestrion/all/v2 " "$module_dir/go.mod" || { echo "Error: $module_dir/go.mod does not pin orchestrion/all/v2."; exit 1; }
grep -Fq "github.com/DataDog/dd-trace-go/v2 " "$module_dir/go.mod" || { echo "Error: $module_dir/go.mod does not reference dd-trace-go/v2."; exit 1; }
[ -f "$module_dir/orchestrion.tool.go" ] || { echo "Error: Expected $module_dir/orchestrion.tool.go to exist."; exit 1; }

read -r selected_trace_version selected_trace_go_version < <(
env -u GOFLAGS bash -lc "cd \"$module_dir\" && go list -m -f '{{.Version}} {{.GoVersion}}' github.com/DataDog/dd-trace-go/orchestrion/all/v2"
)

[ -n "$selected_trace_version" ] || { echo "Error: Could not read the selected dd-trace-go version."; exit 1; }
[ -n "$selected_trace_go_version" ] || { echo "Error: Could not read the selected dd-trace-go Go version."; exit 1; }

if [ "$(printf '%s\n%s\n' "$selected_trace_go_version" "$go_ceiling" | sort -V | head -n 1)" != "$selected_trace_go_version" ]; then
echo "Error: Selected dd-trace-go Go version $selected_trace_go_version exceeds the project ceiling $go_ceiling."
exit 1
fi
}

assert_skipped_module() {
local module_dir="$1"

[ -z "${GOFLAGS:-}" ] || { echo "Error: Expected GOFLAGS to be unset."; exit 1; }
[ -z "${DD_TRACER_VERSION_GO:-}" ] || { echo "Error: Expected DD_TRACER_VERSION_GO to be unset."; exit 1; }
assert_file_unchanged "$module_dir/go.mod"
assert_file_absent "$module_dir/orchestrion.tool.go"
}

case "${{ matrix.case_id }}" in
root_go_124_success)
[ "$action_outcome" = "success" ] || { echo "Error: Expected the action to succeed."; exit 1; }
assert_instrumented_module "." "1.24.0"
;;
root_go_125_success)
[ "$action_outcome" = "success" ] || { echo "Error: Expected the action to succeed."; exit 1; }
assert_instrumented_module "." "1.25.0"
;;
root_go_122_skip)
[ "$action_outcome" = "success" ] || { echo "Error: Expected the action to skip cleanly."; exit 1; }
assert_skipped_module "."
;;
runner_below_min_skip)
[ "$action_outcome" = "failure" ] || { echo "Error: Expected the action to fail."; exit 1; }
[ -z "${GOFLAGS:-}" ] || { echo "Error: Expected GOFLAGS to be unset after the failure."; exit 1; }
[ -z "${DD_TRACER_VERSION_GO:-}" ] || { echo "Error: Expected DD_TRACER_VERSION_GO to be unset after the failure."; exit 1; }
grep -Fq "github.com/DataDog/dd-trace-go/v2 " "./go.mod" || { echo "Error: Expected the failed run to leave a dd-trace-go/v2 dependency behind."; exit 1; }
[ -f "./orchestrion.tool.go" ] || { echo "Error: Expected the failed run to leave orchestrion.tool.go behind."; exit 1; }
;;
single_nested_go_124_auto)
[ "$action_outcome" = "success" ] || { echo "Error: Expected the action to succeed."; exit 1; }
assert_instrumented_module "services/payments" "1.24.0"
;;
single_nested_go_125_auto)
[ "$action_outcome" = "success" ] || { echo "Error: Expected the action to succeed."; exit 1; }
assert_instrumented_module "services/payments" "1.25.0"
;;
multiple_modules_without_override_skip)
[ "$action_outcome" = "success" ] || { echo "Error: Expected the action to skip cleanly."; exit 1; }
assert_skipped_module "services/payments"
assert_skipped_module "services/orders"
;;
multiple_modules_with_override_success)
[ "$action_outcome" = "success" ] || { echo "Error: Expected the action to succeed."; exit 1; }
assert_instrumented_module "services/payments" "1.25.0"
assert_file_unchanged "services/orders/go.mod"
assert_file_absent "services/orders/orchestrion.tool.go"
;;
missing_directory_fail)
[ "$action_outcome" = "failure" ] || { echo "Error: Expected the action to fail."; exit 1; }
[ -z "${GOFLAGS:-}" ] || { echo "Error: Expected GOFLAGS to be unset after the failure."; exit 1; }
[ -z "${DD_TRACER_VERSION_GO:-}" ] || { echo "Error: Expected DD_TRACER_VERSION_GO to be unset after the failure."; exit 1; }
assert_file_unchanged "./go.mod"
assert_file_absent "./orchestrion.tool.go"
;;
*)
echo "Error: Unknown case '${{ matrix.case_id }}'."
exit 1
;;
esac

- name: Run Go Tests
if: ${{ matrix.run_go_tests }}
working-directory: ${{ matrix.test_workdir }}
run: go test -v ./...
env:
DD_TRACE_DEBUG: "true"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ replay_pid*

# Intellij
.idea

# macOS Finder metadata
.DS_Store
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ The action has the following parameters:
| python-tracer-version | The version of Datadog Python tracer to use. Defaults to the latest release. | false | |
| ruby-tracer-version | The version of datadog-ci Ruby gem to use. Defaults to the latest release. | false | |
| go-tracer-version | The version of Orchestrion to use. Defaults to the latest release. | false | |
| go-module-dir | Path to the Go module root directory to instrument. Use this when the repository contains multiple Go modules or the Go module is not in the workspace root. | false | |
| java-instrumented-build-system | If provided, only the specified build systems will be instrumented (allowed values are `gradle`,`maven`,`sbt`,`ant`,`all`). `all` is a special value that instruments every Java process. If this property is not provided, all known build systems will be instrumented (Gradle, Maven, SBT, Ant). | false | |
| cache | Enable caching of downloaded tracers. | false | true |
| print-github-step-summary | Print a summary of the installed tracers to the GitHub step summary. If set to false, the summary is printed to console instead. | false | true |
Expand All @@ -64,6 +65,19 @@ Any [additional configuration values](https://docs.datadoghq.com/tracing/trace_c
DD_TAGS: layer:api,team:intake,key:value
```

### Go multi-module repositories

If your repository contains multiple Go modules, or the Go module you want to instrument is not at the workspace root, set `go-module-dir` to the module root directory that contains the target `go.mod` file:

```yaml
- name: Configure Datadog Test Optimization
uses: datadog/test-visibility-github-action@v2
with:
languages: go
api_key: ${{ secrets.DD_API_KEY }}
go-module-dir: ./services/payments
```

## Limitations

For security reasons Github [does not allow](https://github.blog/changelog/2023-10-05-github-actions-node_options-is-now-restricted-from-github_env/) actions to alter the `NODE_OPTIONS` environment variable, so you'll have to pass it manually.
Expand Down
9 changes: 6 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ inputs:
go-tracer-version:
description: 'The version of Orchestrion automatic compile-time instrumentation of Go code (https://github.com/datadog/orchestrion) to use (optional). Defaults to the latest release.'
required: false
go-module-dir:
description: 'Path to the Go module root directory to instrument (optional). Use this when the repository contains multiple Go modules or the Go module is not in the workspace root.'
required: false
java-instrumented-build-system:
description: 'If provided, only the specified build systems will be instrumented (allowed values are `gradle` and `maven`). Otherwise every Java process will be instrumented.'
required: false
Expand Down Expand Up @@ -69,8 +72,8 @@ runs:
echo "$GITHUB_ACTION_PATH" >> $GITHUB_PATH
shell: bash
env:
INSTALLATION_SCRIPT_URL: https://install.datadoghq.com/scripts/install_test_visibility_v11.sh
INSTALLATION_SCRIPT_CHECKSUM: fc64c45fd4b45b4b01773c58a3a116bef212dc4095508a6e27e19e50e901bd55
INSTALLATION_SCRIPT_URL: https://install.datadoghq.com/scripts/install_test_visibility_v12.sh
INSTALLATION_SCRIPT_CHECKSUM: 91b6c7bb2c28ef5604c2a2b233da7d931a9b3b5d20b7872254ebb0e689e62f4a
GITHUB_ACTION_PATH: ${{ github.action_path }}

- name: Get Go cache directories
Expand Down Expand Up @@ -151,6 +154,7 @@ runs:
DD_SET_TRACER_VERSION_PYTHON: ${{ inputs.python-tracer-version }}
DD_SET_TRACER_VERSION_RUBY: ${{ inputs.ruby-tracer-version }}
DD_SET_TRACER_VERSION_GO: ${{ inputs.go-tracer-version }}
DD_CIVISIBILITY_GO_MODULE_DIR: ${{ inputs.go-module-dir }}
DD_INSTRUMENTATION_BUILD_SYSTEM_JAVA: ${{ inputs.java-instrumented-build-system }}

- name: Propagate optional site input to environment variable
Expand Down Expand Up @@ -203,4 +207,3 @@ runs:
rm -f $GITHUB_STEP_SUMMARY
fi
shell: bash

Loading