-
Notifications
You must be signed in to change notification settings - Fork 699
chore: [CLI-1758] trigger Endpoint Explorer refresh after releases #7140
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -170,6 +170,44 @@ trigger_repository_event() { | |
| fi | ||
| } | ||
|
|
||
| # Request a channel-specific Endpoint Explorer refresh without making the CLI | ||
| # release depend on the dispatch or the resulting workflow. | ||
| trigger_endpoint_explorer_refresh() { | ||
| channel=$1 | ||
|
|
||
| if [ -z "${HAMMERHEAD_GITHUB_PAT:-}" ]; then | ||
| echo "WARNING: HAMMERHEAD_GITHUB_PAT is unavailable; Endpoint Explorer $channel refresh was not requested." | ||
| return 0 | ||
| fi | ||
|
|
||
| echo "Triggering Endpoint Explorer $channel refresh..." | ||
| curl_status=0 | ||
| response=$(curl \ | ||
| --location \ | ||
| --request POST \ | ||
| --connect-timeout 2 \ | ||
| --max-time 5 \ | ||
| --header "Accept: application/vnd.github+json" \ | ||
| --header "Authorization: Bearer $HAMMERHEAD_GITHUB_PAT" \ | ||
| --header "X-GitHub-Api-Version: 2022-11-28" \ | ||
| --data "{\"ref\":\"main\",\"inputs\":{\"channel\":\"$channel\"}}" \ | ||
| --write-out "%{http_code}" \ | ||
| --silent \ | ||
| --show-error \ | ||
| --output /dev/null \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't we follow same pattern of trigger_repository_event and output to a file? Then we could have more information about a failure? |
||
| "https://api.github.com/repos/snyk/endpoint-binary-explorer/actions/workflows/refresh-cli-data.yml/dispatches") || curl_status=$? | ||
|
|
||
| if [ "$curl_status" -ne 0 ]; then | ||
| echo "WARNING: Endpoint Explorer $channel refresh dispatch failed (curl exit $curl_status); continuing the CLI release." | ||
| elif [ "$response" != "204" ]; then | ||
| echo "WARNING: Endpoint Explorer $channel refresh was not requested (HTTP $response); continuing the CLI release." | ||
| else | ||
| echo "Endpoint Explorer $channel refresh requested." | ||
| fi | ||
|
|
||
| return 0 | ||
|
Comment on lines
+200
to
+208
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we have a different return value for the "WARNING" logs? Because right now it just logs (and might get lost / nobody sees it), but continues the flow normally in all cases. |
||
| } | ||
|
|
||
| trigger_build_agentic_integration() { | ||
| echo "Triggering build-and-release workflow at agentic-integration-wrappers..." | ||
| echo "Version: $VERSION_TAG" | ||
|
|
@@ -289,6 +327,12 @@ for arg in "${@}"; do | |
| # Trigger builds across distribution channel repositories | ||
| elif [ "${arg}" == "trigger-distribution-channels" ]; then | ||
| DISTRIBUTION_FAILURE=0 | ||
|
|
||
| # Refresh the Endpoint Explorer independently of the required distribution | ||
| # triggers. Release candidates are not represented by an Explorer channel. | ||
| if [ "$RELEASE_CHANNEL" == "stable" ] || [ "$RELEASE_CHANNEL" == "preview" ]; then | ||
| trigger_endpoint_explorer_refresh "$RELEASE_CHANNEL" | ||
| fi | ||
|
|
||
| # 1. Trigger snyk-images | ||
| trigger_repository_event "snyk-images" "build_and_push_images" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os" | ||
| "os/exec" | ||
| "path/filepath" | ||
| "strings" | ||
| "testing" | ||
| ) | ||
|
|
||
| func TestDistributionTriggersRequestEndpointExplorerRefresh(t *testing.T) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe you have to plug these tests to run in the CI, e.g. in config.yml, under - run:
name: Running release script tests
command: make test-release-scripts |
||
| for _, channel := range []string{"stable", "preview"} { | ||
| t.Run(channel, func(t *testing.T) { | ||
| result := runDistributionTriggers(t, channel, "204", "0") | ||
|
|
||
| if result.err != nil { | ||
| t.Fatalf("expected successful distribution triggers, got %v\n%s", result.err, result.output) | ||
| } | ||
| if !strings.Contains(result.output, "Endpoint Explorer "+channel+" refresh requested") { | ||
| t.Fatalf("expected accepted Explorer dispatch message, got:\n%s", result.output) | ||
| } | ||
| if !strings.Contains(result.curlArguments, "endpoint-binary-explorer/actions/workflows/refresh-cli-data.yml/dispatches") { | ||
| t.Fatalf("expected the Explorer workflow dispatch endpoint, got:\n%s", result.curlArguments) | ||
| } | ||
| if !strings.Contains(result.curlArguments, `"channel":"`+channel+`"`) { | ||
| t.Fatalf("expected %s workflow input, got:\n%s", channel, result.curlArguments) | ||
| } | ||
| if !strings.Contains(result.curlArguments, "--connect-timeout\n2") || !strings.Contains(result.curlArguments, "--max-time\n5") { | ||
| t.Fatalf("expected bounded Explorer dispatch timeouts, got:\n%s", result.curlArguments) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestDistributionTriggersIgnoreEndpointExplorerHTTPFailure(t *testing.T) { | ||
| result := runDistributionTriggers(t, "preview", "503", "0") | ||
|
|
||
| if result.err != nil { | ||
| t.Fatalf("expected Explorer failure not to fail distribution triggers, got %v\n%s", result.err, result.output) | ||
| } | ||
| if !strings.Contains(result.output, "WARNING: Endpoint Explorer preview refresh was not requested") { | ||
| t.Fatalf("expected a warning, got:\n%s", result.output) | ||
| } | ||
| } | ||
|
|
||
| func TestDistributionTriggersIgnoreEndpointExplorerTransportFailure(t *testing.T) { | ||
| result := runDistributionTriggers(t, "stable", "000", "28") | ||
|
|
||
| if result.err != nil { | ||
| t.Fatalf("expected Explorer failure not to fail distribution triggers, got %v\n%s", result.err, result.output) | ||
| } | ||
| if !strings.Contains(result.output, "WARNING: Endpoint Explorer stable refresh dispatch failed") { | ||
| t.Fatalf("expected a warning, got:\n%s", result.output) | ||
| } | ||
| } | ||
|
|
||
| func TestDistributionTriggersSkipEndpointExplorerForReleaseCandidate(t *testing.T) { | ||
| result := runDistributionTriggers(t, "rc", "204", "0") | ||
|
|
||
| if result.err != nil { | ||
| t.Fatalf("expected successful distribution triggers, got %v\n%s", result.err, result.output) | ||
| } | ||
| if strings.Contains(result.curlArguments, "endpoint-binary-explorer") { | ||
| t.Fatalf("expected no Explorer refresh for release candidates, got:\n%s", result.curlArguments) | ||
| } | ||
| } | ||
|
|
||
| type distributionTriggerResult struct { | ||
| output string | ||
| curlArguments string | ||
| err error | ||
| } | ||
|
|
||
| func runDistributionTriggers(t *testing.T, channel string, explorerHTTPStatus string, explorerExitStatus string) distributionTriggerResult { | ||
| t.Helper() | ||
|
|
||
| rootDir := t.TempDir() | ||
| releaseScriptsDir := filepath.Join(rootDir, "release-scripts") | ||
| binaryReleasesDir := filepath.Join(rootDir, "binary-releases") | ||
| binDir := filepath.Join(rootDir, "bin") | ||
| for _, directory := range []string{releaseScriptsDir, binaryReleasesDir, binDir} { | ||
| if err := os.MkdirAll(directory, 0755); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| } | ||
|
|
||
| copyTestFile(t, repoPath(t, "release-scripts", "upload-artifacts.sh"), filepath.Join(releaseScriptsDir, "upload-artifacts.sh"), 0755) | ||
| writeTestFile(t, filepath.Join(releaseScriptsDir, "determine-release-channel.sh"), fmt.Sprintf("#!/usr/bin/env bash\necho %s\n", channel), 0755) | ||
| writeTestFile(t, filepath.Join(binaryReleasesDir, "version"), "1.2.3\n", 0644) | ||
| writeTestFile(t, filepath.Join(binaryReleasesDir, "ls-protocol-version-test"), "1\n", 0644) | ||
|
|
||
| curlLog := filepath.Join(rootDir, "curl-arguments") | ||
| mockCurl := `#!/usr/bin/env bash | ||
| printf '%s\n' '--- request ---' "$@" >> "$MOCK_CURL_LOG" | ||
| if [[ "$*" == *"endpoint-binary-explorer/actions/workflows"* ]]; then | ||
| printf '%s' "$MOCK_EXPLORER_HTTP_STATUS" | ||
| exit "$MOCK_EXPLORER_EXIT_STATUS" | ||
| fi | ||
| printf '204' | ||
| ` | ||
| writeTestFile(t, filepath.Join(binDir, "curl"), mockCurl, 0755) | ||
|
|
||
| command := exec.Command("bash", "./release-scripts/upload-artifacts.sh", "trigger-distribution-channels") | ||
| command.Dir = rootDir | ||
| command.Env = environmentWithOverrides(os.Environ(), map[string]string{ | ||
| "HAMMERHEAD_GITHUB_PAT": "test-token", | ||
| "MOCK_CURL_LOG": curlLog, | ||
| "MOCK_EXPLORER_EXIT_STATUS": explorerExitStatus, | ||
| "MOCK_EXPLORER_HTTP_STATUS": explorerHTTPStatus, | ||
| "PATH": binDir + string(os.PathListSeparator) + os.Getenv("PATH"), | ||
| "TMPDIR": rootDir, | ||
| }) | ||
| output, err := command.CombinedOutput() | ||
| curlArguments, readErr := os.ReadFile(curlLog) | ||
| if readErr != nil { | ||
| t.Fatal(readErr) | ||
| } | ||
|
|
||
| return distributionTriggerResult{ | ||
| output: string(output), | ||
| curlArguments: string(curlArguments), | ||
| err: err, | ||
| } | ||
| } | ||
|
|
||
| func copyTestFile(t *testing.T, source string, destination string, mode os.FileMode) { | ||
| t.Helper() | ||
| contents, err := os.ReadFile(source) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| writeTestFile(t, destination, string(contents), mode) | ||
| } | ||
|
|
||
| func writeTestFile(t *testing.T, path string, contents string, mode os.FileMode) { | ||
| t.Helper() | ||
| if err := os.WriteFile(path, []byte(contents), mode); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| } | ||
|
|
||
| func environmentWithOverrides(current []string, overrides map[string]string) []string { | ||
| result := make([]string, 0, len(current)+len(overrides)) | ||
| for _, entry := range current { | ||
| key, _, found := strings.Cut(entry, "=") | ||
| if !found { | ||
| continue | ||
| } | ||
| if _, overridden := overrides[key]; !overridden { | ||
| result = append(result, entry) | ||
| } | ||
| } | ||
| for key, value := range overrides { | ||
| result = append(result, key+"="+value) | ||
| } | ||
| return result | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should also include retries, for example
--retry 2 --retry-connrefused?