mirror of https://github.com/databricks/cli.git
merge
This commit is contained in:
commit
bd231012d1
|
@ -10,19 +10,65 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
publish-to-winget-pkgs:
|
publish-to-winget-pkgs:
|
||||||
runs-on:
|
runs-on:
|
||||||
group: databricks-protected-runner-group
|
group: databricks-deco-testing-runner-group
|
||||||
labels: windows-server-latest
|
labels: ubuntu-latest-deco
|
||||||
|
|
||||||
environment: release
|
environment: release
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: vedantmgoyal2009/winget-releaser@93fd8b606a1672ec3e5c6c3bb19426be68d1a8b0 # v2
|
- name: Checkout repository and submodules
|
||||||
with:
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
identifier: Databricks.DatabricksCLI
|
|
||||||
installers-regex: 'windows_.*-signed\.zip$' # Only signed Windows releases
|
# When updating the version of komac, make sure to update the checksum in the next step.
|
||||||
token: ${{ secrets.ENG_DEV_ECOSYSTEM_BOT_TOKEN }}
|
# Find both at https://github.com/russellbanks/Komac/releases.
|
||||||
fork-user: eng-dev-ecosystem-bot
|
- name: Download komac binary
|
||||||
|
run: |
|
||||||
|
curl -s -L -o $RUNNER_TEMP/komac-2.9.0-x86_64-unknown-linux-gnu.tar.gz https://github.com/russellbanks/Komac/releases/download/v2.9.0/komac-2.9.0-x86_64-unknown-linux-gnu.tar.gz
|
||||||
|
|
||||||
|
- name: Verify komac binary
|
||||||
|
run: |
|
||||||
|
echo "d07a12831ad5418fee715488542a98ce3c0e591d05c850dd149fe78432be8c4c $RUNNER_TEMP/komac-2.9.0-x86_64-unknown-linux-gnu.tar.gz" | sha256sum -c -
|
||||||
|
|
||||||
|
- name: Untar komac binary to temporary path
|
||||||
|
run: |
|
||||||
|
mkdir -p $RUNNER_TEMP/komac
|
||||||
|
tar -xzf $RUNNER_TEMP/komac-2.9.0-x86_64-unknown-linux-gnu.tar.gz -C $RUNNER_TEMP/komac
|
||||||
|
|
||||||
|
- name: Add komac to PATH
|
||||||
|
run: echo "$RUNNER_TEMP/komac" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Confirm komac version
|
||||||
|
run: komac --version
|
||||||
|
|
||||||
# Use the tag from the input, or the ref name if the input is not provided.
|
# Use the tag from the input, or the ref name if the input is not provided.
|
||||||
# The ref name is equal to the tag name when this workflow is triggered by the "sign-cli" command.
|
# The ref name is equal to the tag name when this workflow is triggered by the "sign-cli" command.
|
||||||
release-tag: ${{ inputs.tag || github.ref_name }}
|
- name: Strip "v" prefix from version
|
||||||
|
id: strip_version
|
||||||
|
run: echo "version=$(echo ${{ inputs.tag || github.ref_name }} | sed 's/^v//')" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Get URLs of signed Windows binaries
|
||||||
|
id: get_windows_urls
|
||||||
|
run: |
|
||||||
|
urls=$(
|
||||||
|
gh api https://api.github.com/repos/databricks/cli/releases/tags/${{ inputs.tag || github.ref_name }} | \
|
||||||
|
jq -r .assets[].browser_download_url | \
|
||||||
|
grep -E '_windows_.*-signed\.zip$' | \
|
||||||
|
tr '\n' ' '
|
||||||
|
)
|
||||||
|
if [ -z "$urls" ]; then
|
||||||
|
echo "No signed Windows binaries found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "urls=$urls" >> "$GITHUB_OUTPUT"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Publish to Winget
|
||||||
|
run: |
|
||||||
|
komac update Databricks.DatabricksCLI \
|
||||||
|
--version ${{ steps.strip_version.outputs.version }} \
|
||||||
|
--submit \
|
||||||
|
--urls ${{ steps.get_windows_urls.outputs.urls }} \
|
||||||
|
env:
|
||||||
|
KOMAC_FORK_OWNER: eng-dev-ecosystem-bot
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ENG_DEV_ECOSYSTEM_BOT_TOKEN }}
|
||||||
|
|
|
@ -60,12 +60,6 @@ jobs:
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@887a942a15af3a7626099df99e897a18d9e5ab3a # v5.1.0
|
uses: astral-sh/setup-uv@887a942a15af3a7626099df99e897a18d9e5ab3a # v5.1.0
|
||||||
|
|
||||||
- name: Run ruff
|
|
||||||
uses: astral-sh/ruff-action@31a518504640beb4897d0b9f9e50a2a9196e75ba # v3.0.1
|
|
||||||
with:
|
|
||||||
version: "0.9.1"
|
|
||||||
args: "format --check"
|
|
||||||
|
|
||||||
- name: Set go env
|
- name: Set go env
|
||||||
run: |
|
run: |
|
||||||
echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
|
echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
|
||||||
|
@ -80,7 +74,7 @@ jobs:
|
||||||
- name: Run tests with coverage
|
- name: Run tests with coverage
|
||||||
run: make cover
|
run: make cover
|
||||||
|
|
||||||
golangci:
|
linters:
|
||||||
needs: cleanups
|
needs: cleanups
|
||||||
name: lint
|
name: lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -105,6 +99,11 @@ jobs:
|
||||||
with:
|
with:
|
||||||
version: v1.63.4
|
version: v1.63.4
|
||||||
args: --timeout=15m
|
args: --timeout=15m
|
||||||
|
- name: Run ruff
|
||||||
|
uses: astral-sh/ruff-action@31a518504640beb4897d0b9f9e50a2a9196e75ba # v3.0.1
|
||||||
|
with:
|
||||||
|
version: "0.9.1"
|
||||||
|
args: "format --check"
|
||||||
|
|
||||||
validate-bundle-schema:
|
validate-bundle-schema:
|
||||||
needs: cleanups
|
needs: cleanups
|
||||||
|
|
4
NOTICE
4
NOTICE
|
@ -105,3 +105,7 @@ License - https://github.com/wI2L/jsondiff/blob/master/LICENSE
|
||||||
https://github.com/hexops/gotextdiff
|
https://github.com/hexops/gotextdiff
|
||||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
License - https://github.com/hexops/gotextdiff/blob/main/LICENSE
|
License - https://github.com/hexops/gotextdiff/blob/main/LICENSE
|
||||||
|
|
||||||
|
https://github.com/BurntSushi/toml
|
||||||
|
Copyright (c) 2013 TOML authors
|
||||||
|
https://github.com/BurntSushi/toml/blob/master/COPYING
|
||||||
|
|
|
@ -17,3 +17,5 @@ For more complex tests one can also use:
|
||||||
- `errcode` helper: if the command fails with non-zero code, it appends `Exit code: N` to the output but returns success to caller (bash), allowing continuation of script.
|
- `errcode` helper: if the command fails with non-zero code, it appends `Exit code: N` to the output but returns success to caller (bash), allowing continuation of script.
|
||||||
- `trace` helper: prints the arguments before executing the command.
|
- `trace` helper: prints the arguments before executing the command.
|
||||||
- custom output files: redirect output to custom file (it must start with `out`), e.g. `$CLI bundle validate > out.txt 2> out.error.txt`.
|
- custom output files: redirect output to custom file (it must start with `out`), e.g. `$CLI bundle validate > out.txt 2> out.error.txt`.
|
||||||
|
|
||||||
|
See [selftest](./selftest) for a toy test.
|
||||||
|
|
|
@ -66,12 +66,7 @@ func TestInprocessMode(t *testing.T) {
|
||||||
if InprocessMode {
|
if InprocessMode {
|
||||||
t.Skip("Already tested by TestAccept")
|
t.Skip("Already tested by TestAccept")
|
||||||
}
|
}
|
||||||
if runtime.GOOS == "windows" {
|
require.Equal(t, 1, testAccept(t, true, "selftest"))
|
||||||
// - catalogs A catalog is the first layer of Unity Catalog’s three-level namespace.
|
|
||||||
// + catalogs A catalog is the first layer of Unity Catalog<6F>s three-level namespace.
|
|
||||||
t.Skip("Fails on CI on unicode characters")
|
|
||||||
}
|
|
||||||
require.NotZero(t, testAccept(t, true, "help"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccept(t *testing.T, InprocessMode bool, singleTest string) int {
|
func testAccept(t *testing.T, InprocessMode bool, singleTest string) int {
|
||||||
|
@ -187,6 +182,13 @@ func getTests(t *testing.T) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsContext) {
|
func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsContext) {
|
||||||
|
config, configPath := LoadConfig(t, dir)
|
||||||
|
|
||||||
|
isEnabled, isPresent := config.GOOS[runtime.GOOS]
|
||||||
|
if isPresent && !isEnabled {
|
||||||
|
t.Skipf("Disabled via GOOS.%s setting in %s", runtime.GOOS, configPath)
|
||||||
|
}
|
||||||
|
|
||||||
var tmpDir string
|
var tmpDir string
|
||||||
var err error
|
var err error
|
||||||
if KeepTmp {
|
if KeepTmp {
|
||||||
|
@ -200,6 +202,7 @@ func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsCont
|
||||||
}
|
}
|
||||||
|
|
||||||
repls.SetPathWithParents(tmpDir, "$TMPDIR")
|
repls.SetPathWithParents(tmpDir, "$TMPDIR")
|
||||||
|
repls.Repls = append(repls.Repls, config.Repls...)
|
||||||
|
|
||||||
scriptContents := readMergedScriptContents(t, dir)
|
scriptContents := readMergedScriptContents(t, dir)
|
||||||
testutil.WriteFile(t, filepath.Join(tmpDir, EntryPointScript), scriptContents)
|
testutil.WriteFile(t, filepath.Join(tmpDir, EntryPointScript), scriptContents)
|
||||||
|
@ -250,9 +253,11 @@ func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsCont
|
||||||
server.WriteRequestsToDisk(outRequestsPath)
|
server.WriteRequestsToDisk(outRequestsPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printedRepls := false
|
||||||
|
|
||||||
// Compare expected outputs
|
// Compare expected outputs
|
||||||
for relPath := range outputs {
|
for relPath := range outputs {
|
||||||
doComparison(t, repls, dir, tmpDir, relPath)
|
doComparison(t, repls, dir, tmpDir, relPath, &printedRepls)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure there are not unaccounted for new files
|
// Make sure there are not unaccounted for new files
|
||||||
|
@ -267,12 +272,12 @@ func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsCont
|
||||||
if strings.HasPrefix(relPath, "out") {
|
if strings.HasPrefix(relPath, "out") {
|
||||||
// We have a new file starting with "out"
|
// We have a new file starting with "out"
|
||||||
// Show the contents & support overwrite mode for it:
|
// Show the contents & support overwrite mode for it:
|
||||||
doComparison(t, repls, dir, tmpDir, relPath)
|
doComparison(t, repls, dir, tmpDir, relPath, &printedRepls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func doComparison(t *testing.T, repls testdiff.ReplacementsContext, dirRef, dirNew, relPath string) {
|
func doComparison(t *testing.T, repls testdiff.ReplacementsContext, dirRef, dirNew, relPath string, printedRepls *bool) {
|
||||||
pathRef := filepath.Join(dirRef, relPath)
|
pathRef := filepath.Join(dirRef, relPath)
|
||||||
pathNew := filepath.Join(dirNew, relPath)
|
pathNew := filepath.Join(dirNew, relPath)
|
||||||
bufRef, okRef := readIfExists(t, pathRef)
|
bufRef, okRef := readIfExists(t, pathRef)
|
||||||
|
@ -317,6 +322,15 @@ func doComparison(t *testing.T, repls testdiff.ReplacementsContext, dirRef, dirN
|
||||||
t.Logf("Overwriting existing output file: %s", relPath)
|
t.Logf("Overwriting existing output file: %s", relPath)
|
||||||
testutil.WriteFile(t, pathRef, valueNew)
|
testutil.WriteFile(t, pathRef, valueNew)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !equal && printedRepls != nil && !*printedRepls {
|
||||||
|
*printedRepls = true
|
||||||
|
var items []string
|
||||||
|
for _, item := range repls.Repls {
|
||||||
|
items = append(items, fmt.Sprintf("REPL %s => %s", item.Old, item.New))
|
||||||
|
}
|
||||||
|
t.Log("Available replacements:\n" + strings.Join(items, "\n"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns combined script.prepare (root) + script.prepare (parent) + ... + script + ... + script.cleanup (parent) + ...
|
// Returns combined script.prepare (root) + script.prepare (parent) + ... + script + ... + script.cleanup (parent) + ...
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
bundle:
|
||||||
|
name: git-permerror
|
|
@ -0,0 +1,78 @@
|
||||||
|
=== No permission to access .git. Badness: inferred flag is set to true even though we did not infer branch. bundle_root_path is not correct in subdir case.
|
||||||
|
|
||||||
|
>>> chmod 000 .git
|
||||||
|
|
||||||
|
>>> $CLI bundle validate
|
||||||
|
Error: unable to load repository specific gitconfig: open config: permission denied
|
||||||
|
|
||||||
|
Name: git-permerror
|
||||||
|
Target: default
|
||||||
|
Workspace:
|
||||||
|
User: $USERNAME
|
||||||
|
Path: /Workspace/Users/$USERNAME/.bundle/git-permerror/default
|
||||||
|
|
||||||
|
Found 1 error
|
||||||
|
|
||||||
|
Exit code: 1
|
||||||
|
|
||||||
|
>>> $CLI bundle validate -o json
|
||||||
|
Error: unable to load repository specific gitconfig: open config: permission denied
|
||||||
|
|
||||||
|
|
||||||
|
Exit code: 1
|
||||||
|
{
|
||||||
|
"bundle_root_path": ".",
|
||||||
|
"inferred": true
|
||||||
|
}
|
||||||
|
|
||||||
|
>>> withdir subdir/a/b $CLI bundle validate -o json
|
||||||
|
Error: unable to load repository specific gitconfig: open config: permission denied
|
||||||
|
|
||||||
|
|
||||||
|
Exit code: 1
|
||||||
|
{
|
||||||
|
"bundle_root_path": ".",
|
||||||
|
"inferred": true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
=== No permissions to read .git/HEAD. Badness: warning is not shown. inferred is incorrectly set to true. bundle_root_path is not correct in subdir case.
|
||||||
|
|
||||||
|
>>> chmod 000 .git/HEAD
|
||||||
|
|
||||||
|
>>> $CLI bundle validate -o json
|
||||||
|
{
|
||||||
|
"bundle_root_path": ".",
|
||||||
|
"inferred": true
|
||||||
|
}
|
||||||
|
|
||||||
|
>>> withdir subdir/a/b $CLI bundle validate -o json
|
||||||
|
{
|
||||||
|
"bundle_root_path": ".",
|
||||||
|
"inferred": true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
=== No permissions to read .git/config. Badness: inferred is incorretly set to true. bundle_root_path is not correct is subdir case.
|
||||||
|
|
||||||
|
>>> chmod 000 .git/config
|
||||||
|
|
||||||
|
>>> $CLI bundle validate -o json
|
||||||
|
Error: unable to load repository specific gitconfig: open config: permission denied
|
||||||
|
|
||||||
|
|
||||||
|
Exit code: 1
|
||||||
|
{
|
||||||
|
"bundle_root_path": ".",
|
||||||
|
"inferred": true
|
||||||
|
}
|
||||||
|
|
||||||
|
>>> withdir subdir/a/b $CLI bundle validate -o json
|
||||||
|
Error: unable to load repository specific gitconfig: open config: permission denied
|
||||||
|
|
||||||
|
|
||||||
|
Exit code: 1
|
||||||
|
{
|
||||||
|
"bundle_root_path": ".",
|
||||||
|
"inferred": true
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
mkdir myrepo
|
||||||
|
cd myrepo
|
||||||
|
cp ../databricks.yml .
|
||||||
|
git-repo-init
|
||||||
|
mkdir -p subdir/a/b
|
||||||
|
|
||||||
|
printf "=== No permission to access .git. Badness: inferred flag is set to true even though we did not infer branch. bundle_root_path is not correct in subdir case.\n"
|
||||||
|
trace chmod 000 .git
|
||||||
|
errcode trace $CLI bundle validate
|
||||||
|
errcode trace $CLI bundle validate -o json | jq .bundle.git
|
||||||
|
errcode trace withdir subdir/a/b $CLI bundle validate -o json | jq .bundle.git
|
||||||
|
|
||||||
|
printf "\n\n=== No permissions to read .git/HEAD. Badness: warning is not shown. inferred is incorrectly set to true. bundle_root_path is not correct in subdir case.\n"
|
||||||
|
chmod 700 .git
|
||||||
|
trace chmod 000 .git/HEAD
|
||||||
|
errcode trace $CLI bundle validate -o json | jq .bundle.git
|
||||||
|
errcode trace withdir subdir/a/b $CLI bundle validate -o json | jq .bundle.git
|
||||||
|
|
||||||
|
printf "\n\n=== No permissions to read .git/config. Badness: inferred is incorretly set to true. bundle_root_path is not correct is subdir case.\n"
|
||||||
|
chmod 666 .git/HEAD
|
||||||
|
trace chmod 000 .git/config
|
||||||
|
errcode trace $CLI bundle validate -o json | jq .bundle.git
|
||||||
|
errcode trace withdir subdir/a/b $CLI bundle validate -o json | jq .bundle.git
|
||||||
|
|
||||||
|
rm -fr .git
|
|
@ -0,0 +1,5 @@
|
||||||
|
Badness = "Warning logs not shown; inferred flag is set to true incorrect; bundle_root_path is not correct"
|
||||||
|
|
||||||
|
[GOOS]
|
||||||
|
# This test relies on chmod which does not work on Windows
|
||||||
|
windows = false
|
|
@ -0,0 +1,104 @@
|
||||||
|
package acceptance_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/databricks/cli/libs/testdiff"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
const configFilename = "test.toml"
|
||||||
|
|
||||||
|
var (
|
||||||
|
configCache map[string]TestConfig
|
||||||
|
configMutex sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestConfig struct {
|
||||||
|
// Place to describe what's wrong with this test. Does not affect how the test is run.
|
||||||
|
Badness string
|
||||||
|
|
||||||
|
// Which OSes the test is enabled on. Each string is compared against runtime.GOOS.
|
||||||
|
// If absent, default to true.
|
||||||
|
GOOS map[string]bool
|
||||||
|
|
||||||
|
// List of additional replacements to apply on this test.
|
||||||
|
// Old is a regexp, New is a replacement expression.
|
||||||
|
Repls []testdiff.Replacement
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindConfig finds the closest config file.
|
||||||
|
func FindConfig(t *testing.T, dir string) (string, bool) {
|
||||||
|
shared := false
|
||||||
|
for {
|
||||||
|
path := filepath.Join(dir, configFilename)
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return path, shared
|
||||||
|
}
|
||||||
|
|
||||||
|
shared = true
|
||||||
|
|
||||||
|
if dir == "" || dir == "." {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
dir = filepath.Dir(dir)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Fatalf("Error while reading %s: %s", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Fatal("Config not found: " + configFilename)
|
||||||
|
return "", shared
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadConfig loads the config file. Non-leaf configs are cached.
|
||||||
|
func LoadConfig(t *testing.T, dir string) (TestConfig, string) {
|
||||||
|
path, leafConfig := FindConfig(t, dir)
|
||||||
|
|
||||||
|
if leafConfig {
|
||||||
|
return DoLoadConfig(t, path), path
|
||||||
|
}
|
||||||
|
|
||||||
|
configMutex.Lock()
|
||||||
|
defer configMutex.Unlock()
|
||||||
|
|
||||||
|
if configCache == nil {
|
||||||
|
configCache = make(map[string]TestConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, ok := configCache[path]
|
||||||
|
if ok {
|
||||||
|
return result, path
|
||||||
|
}
|
||||||
|
|
||||||
|
result = DoLoadConfig(t, path)
|
||||||
|
configCache[path] = result
|
||||||
|
return result, path
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoLoadConfig(t *testing.T, path string) TestConfig {
|
||||||
|
bytes, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read config: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var config TestConfig
|
||||||
|
meta, err := toml.Decode(string(bytes), &config)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
keys := meta.Undecoded()
|
||||||
|
if len(keys) > 0 {
|
||||||
|
t.Fatalf("Undecoded keys in %s: %#v", path, keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
|
@ -47,3 +47,14 @@ title() {
|
||||||
local label="$1"
|
local label="$1"
|
||||||
printf "\n=== %s" "$label"
|
printf "\n=== %s" "$label"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
withdir() {
|
||||||
|
local dir="$1"
|
||||||
|
shift
|
||||||
|
local orig_dir="$(pwd)"
|
||||||
|
cd "$dir" || return $?
|
||||||
|
"$@"
|
||||||
|
local exit_code=$?
|
||||||
|
cd "$orig_dir" || return $?
|
||||||
|
return $exit_code
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
HELLO
|
|
@ -0,0 +1,35 @@
|
||||||
|
=== Capturing STDERR
|
||||||
|
>>> python3 -c import sys; sys.stderr.write("STDERR\n")
|
||||||
|
STDERR
|
||||||
|
|
||||||
|
=== Capturing STDOUT
|
||||||
|
>>> python3 -c import sys; sys.stderr.write("STDOUT\n")
|
||||||
|
STDOUT
|
||||||
|
|
||||||
|
=== Capturing exit code
|
||||||
|
>>> errcode python3 -c raise SystemExit(5)
|
||||||
|
|
||||||
|
Exit code: 5
|
||||||
|
|
||||||
|
=== Capturing exit code (alt)
|
||||||
|
>>> python3 -c raise SystemExit(7)
|
||||||
|
|
||||||
|
Exit code: 7
|
||||||
|
|
||||||
|
=== Capturing pwd
|
||||||
|
>>> python3 -c import os; print(os.getcwd())
|
||||||
|
$TMPDIR
|
||||||
|
|
||||||
|
=== Capturing subdir
|
||||||
|
>>> mkdir -p subdir/a/b/c
|
||||||
|
|
||||||
|
>>> withdir subdir/a/b/c python3 -c import os; print(os.getcwd())
|
||||||
|
$TMPDIR/subdir/a/b/c
|
||||||
|
|
||||||
|
=== Custom output files - everything starting with out is captured and compared
|
||||||
|
>>> echo HELLO
|
||||||
|
|
||||||
|
=== Custom regex can be specified in [[Repl]] section
|
||||||
|
1234
|
||||||
|
CUSTOM_NUMBER_REGEX
|
||||||
|
123456
|
|
@ -0,0 +1,26 @@
|
||||||
|
printf "=== Capturing STDERR"
|
||||||
|
trace python3 -c 'import sys; sys.stderr.write("STDERR\n")'
|
||||||
|
|
||||||
|
printf "\n=== Capturing STDOUT"
|
||||||
|
trace python3 -c 'import sys; sys.stderr.write("STDOUT\n")'
|
||||||
|
|
||||||
|
printf "\n=== Capturing exit code"
|
||||||
|
trace errcode python3 -c 'raise SystemExit(5)'
|
||||||
|
|
||||||
|
printf "\n=== Capturing exit code (alt)"
|
||||||
|
errcode trace python3 -c 'raise SystemExit(7)'
|
||||||
|
|
||||||
|
printf "\n=== Capturing pwd"
|
||||||
|
trace python3 -c 'import os; print(os.getcwd())'
|
||||||
|
|
||||||
|
printf "\n=== Capturing subdir"
|
||||||
|
trace mkdir -p subdir/a/b/c
|
||||||
|
trace withdir subdir/a/b/c python3 -c 'import os; print(os.getcwd())'
|
||||||
|
|
||||||
|
printf "\n=== Custom output files - everything starting with out is captured and compared"
|
||||||
|
trace echo HELLO > out.hello.txt
|
||||||
|
|
||||||
|
printf "\n=== Custom regex can be specified in [[Repl]] section\n"
|
||||||
|
echo 1234
|
||||||
|
echo 12345
|
||||||
|
echo 123456
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Badness = "Brief description of what's wrong with the test output, if anything"
|
||||||
|
|
||||||
|
#[GOOS]
|
||||||
|
# Disable on Windows
|
||||||
|
#windows = false
|
||||||
|
|
||||||
|
# Disable on Mac
|
||||||
|
#mac = false
|
||||||
|
|
||||||
|
# Disable on Linux
|
||||||
|
#linux = false
|
||||||
|
|
||||||
|
[[Repls]]
|
||||||
|
Old = '\b[0-9]{5}\b'
|
||||||
|
New = "CUSTOM_NUMBER_REGEX"
|
||||||
|
|
||||||
|
[[Repls]]
|
||||||
|
# Fix path with reverse slashes in the output for Windows.
|
||||||
|
Old = '\$TMPDIR\\subdir\\a\\b\\c'
|
||||||
|
New = '$$TMPDIR/subdir/a/b/c'
|
|
@ -0,0 +1,2 @@
|
||||||
|
# If test directory nor any of its parents do not have test.toml then this file serves as fallback configuration.
|
||||||
|
# The configurations are not merged across parents; the closest one is used fully.
|
1
go.mod
1
go.mod
|
@ -5,6 +5,7 @@ go 1.23
|
||||||
toolchain go1.23.4
|
toolchain go1.23.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/BurntSushi/toml v1.4.0 // MIT
|
||||||
github.com/Masterminds/semver/v3 v3.3.1 // MIT
|
github.com/Masterminds/semver/v3 v3.3.1 // MIT
|
||||||
github.com/briandowns/spinner v1.23.1 // Apache 2.0
|
github.com/briandowns/spinner v1.23.1 // Apache 2.0
|
||||||
github.com/databricks/databricks-sdk-go v0.55.0 // Apache 2.0
|
github.com/databricks/databricks-sdk-go v0.55.0 // Apache 2.0
|
||||||
|
|
|
@ -8,6 +8,8 @@ cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1h
|
||||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||||
|
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
|
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
|
||||||
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||||
|
|
|
@ -79,7 +79,11 @@ func (r *ReplacementsContext) Set(old, new string) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
encodedOld, err := json.Marshal(old)
|
encodedOld, err := json.Marshal(old)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
r.appendLiteral(trimQuotes(string(encodedOld)), trimQuotes(string(encodedNew)))
|
encodedStrNew := trimQuotes(string(encodedNew))
|
||||||
|
encodedStrOld := trimQuotes(string(encodedOld))
|
||||||
|
if encodedStrNew != new || encodedStrOld != old {
|
||||||
|
r.appendLiteral(encodedStrOld, encodedStrNew)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue