Skip to content
Open
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
22 changes: 14 additions & 8 deletions acceptance/bin/print_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
If argument starts with ! then it's a negation filter.

Examples:
print_requests.py //jobs # Show non-GET requests with /jobs in path
print_requests.py --get //jobs # Show all requests with /jobs in path
print_requests.py --sort '^//import-file/' # Show non-GET requests, exclude /import-file/, sort output
print_requests.py --keep //jobs # Show requests and do not delete out.requests.json afterwards
print_requests.py //jobs # Show non-GET requests with /jobs in path
print_requests.py --get //jobs # Show all requests with /jobs in path
print_requests.py --sort '^//import-file/' # Show non-GET requests, exclude /import-file/, sort output
print_requests.py --keep //jobs # Show requests and do not delete out.requests.json afterwards
print_requests.py //api/2.0/repos/snapshots --method DELETE # Show only DELETE to that path

This replaces custom jq wrappers like:
jq --sort-keys 'select(.method != "GET" and (.path | contains("/jobs")))' < out.requests.txt
Expand Down Expand Up @@ -123,7 +124,7 @@ def read_json_many(s):
assert result == [{"method": "GET"}, {"method": "POST"}], result


def filter_requests(requests, path_filters, include_get, should_sort, unique=False):
def filter_requests(requests, path_filters, include_get, should_sort, unique=False, method_filter=None):
"""Filter requests based on method and path filters."""
positive_filters = []
negative_filters = []
Expand All @@ -138,8 +139,12 @@ def filter_requests(requests, path_filters, include_get, should_sort, unique=Fal

filtered_requests = []
for req in requests:
# Skip GET requests unless include_get is True
if req.get("method") == "GET" and not include_get:
if method_filter:
# --method overrides the default GET exclusion
if req.get("method") != method_filter:
continue
elif req.get("method") == "GET" and not include_get:
# Skip GET requests unless include_get is True
continue

# Apply path filters
Expand Down Expand Up @@ -186,6 +191,7 @@ def main():
action="store_true",
help="Collapse consecutive duplicate requests (like uniq), e.g. repeated GET polls",
)
parser.add_argument("--method", metavar="METHOD", help="Only show requests with this HTTP method (e.g. DELETE)")
parser.add_argument("--oneline", action="store_true", help="Print output with one request per line")
parser.add_argument(
"--del-body",
Expand Down Expand Up @@ -217,7 +223,7 @@ def main():
return

requests = read_json_many(data)
filtered_requests = filter_requests(requests, args.path_filters, args.get, args.sort, args.unique)
filtered_requests = filter_requests(requests, args.path_filters, args.get, args.sort, args.unique, args.method)

for req in filtered_requests:
body = req.get("body")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
bundle:
name: test-bundle-immutable-no-artifacts-$UNIQUE_NAME

experimental:
immutable_folder: true

resources:
jobs:
my_job:
name: my job
tasks:
- task_key: spark_python_task
spark_python_task:
python_file: ./src/main.py
environment_key: env
- task_key: notebook_task
notebook_task:
notebook_path: ./src/notebook.py
base_parameters:
path: ${workspace.file_path}/some_path


environments:
- environment_key: env
spec:
environment_version: "4"
3 changes: 3 additions & 0 deletions acceptance/bundle/deploy/immutable-no-artifacts/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions acceptance/bundle/deploy/immutable-no-artifacts/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

>>> [CLI] bundle validate
Name: test-bundle-immutable-no-artifacts-[UNIQUE_NAME]
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle-immutable-no-artifacts-[UNIQUE_NAME]/default

Validation OK!

>>> [CLI] bundle deploy
Uploading immutable bundle snapshot...
Deploying resources...
Updating deployment state...
Deployment complete!

>>> [CLI] jobs get [NUMID]
"/Workspace/Users/[UUID]/.snapshots/[UUID]/[SNAPSHOT_HASH]/src/files/src/main.py"

>>> [CLI] jobs get [NUMID]
"/Workspace/Users/[UUID]/.snapshots/[UUID]/[SNAPSHOT_HASH]/src/files/src/notebook"

>>> [CLI] jobs get [NUMID]
"/Workspace/Users/[UUID]/.snapshots/[UUID]/[SNAPSHOT_HASH]/src/files/some_path"

>>> [CLI] bundle destroy --auto-approve
Comment thread
andrewnester marked this conversation as resolved.
The following resources will be deleted:
delete resources.jobs.my_job

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bundle-immutable-no-artifacts-[UNIQUE_NAME]/default

Deleting files...
Destroy complete!
18 changes: 18 additions & 0 deletions acceptance/bundle/deploy/immutable-no-artifacts/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
envsubst < databricks.yml.tmpl > databricks.yml

cleanup() {
rm -f out.requests.txt
}
trap cleanup EXIT

trace $CLI bundle validate
trace $CLI bundle deploy


# Get a job and check that task paths point into the snapshot
JOB_ID=$($CLI bundle summary -o json | jq -r '.resources.jobs.my_job.id')
trace $CLI jobs get $JOB_ID | jq '.settings.tasks' | jq '.[] | select(.spark_python_task != null) | .spark_python_task.python_file'
trace $CLI jobs get $JOB_ID | jq '.settings.tasks' | jq '.[] | select(.notebook_task != null) | .notebook_task.notebook_path'
trace $CLI jobs get $JOB_ID | jq '.settings.tasks' | jq '.[] | select(.notebook_task != null) | .notebook_task.base_parameters.path'

trace $CLI bundle destroy --auto-approve
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("Hello from Spark Python Task!")
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Databricks notebook source

print("Hello from Notebook Task!")
20 changes: 20 additions & 0 deletions acceptance/bundle/deploy/immutable-no-artifacts/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Local = true
Cloud = true
RecordRequests = true

# immutable_folder only works with the direct engine.
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"]

Ignore = [
"databricks.yml",
".databricks",
".venv",
"script",
"*.pyc",
]

# Normalize the content-addressed snapshot hash so it doesn't need to be
# hardcoded in output.txt and the test stays stable across file changes.
[[Repls]]
Old = '[0-9a-f]{64}'
New = '[SNAPSHOT_HASH]'
34 changes: 34 additions & 0 deletions acceptance/bundle/deploy/immutable/databricks.yml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
bundle:
name: test-bundle-immutable-$UNIQUE_NAME

experimental:
immutable_folder: true

artifacts:
python_artifact:
type: whl
build: uv build --wheel

resources:
jobs:
my_job:
name: my job
tasks:
- task_key: spark_python_task
spark_python_task:
python_file: ./src/main.py
environment_key: env
- task_key: notebook_task
notebook_task:
notebook_path: ./src/notebook.py
- task_key: python_wheel_task
python_wheel_task:
package_name: immutable
entry_point: main
environment_key: env
environments:
- environment_key: env
spec:
environment_version: "4"
dependencies:
- ./dist/*.whl
3 changes: 3 additions & 0 deletions acceptance/bundle/deploy/immutable/out.test.toml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

149 changes: 149 additions & 0 deletions acceptance/bundle/deploy/immutable/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@

>>> [CLI] bundle validate
Name: test-bundle-immutable-[UNIQUE_NAME]
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle-immutable-[UNIQUE_NAME]/default

Validation OK!

>>> [CLI] bundle deploy
Building python_artifact...
Error: build failed python_artifact, error: exit status 2, output: Building wheel...
× Failed to build
│ `[TEST_TMP_DIR]`
├─▶ Failed to resolve requirements from `build-system.requires`
├─▶ No solution found when resolving: `hatchling`
╰─▶ Because only the following versions of hatchling are available:
hatchling==0.8.0
hatchling==0.8.1
hatchling==0.8.2
hatchling==0.9.0
hatchling==0.10.0
hatchling==0.11.0
hatchling==0.11.1
hatchling==0.11.2
hatchling==0.11.3
hatchling==0.12.0
hatchling==0.13.0
hatchling==0.14.0
hatchling==0.15.0
hatchling==0.16.0
hatchling==0.17.0
hatchling==0.18.0
hatchling==0.19.0
hatchling==0.20.0
hatchling==0.20.1
hatchling==0.21.0
hatchling==0.21.1
hatchling==0.22.0
hatchling==0.23.0
hatchling==0.24.0
hatchling==0.25.0
hatchling==0.25.1
hatchling==1.0.0
hatchling==1.1.0
hatchling==1.2.0
hatchling==1.3.0
hatchling==1.3.1
hatchling==1.4.0
hatchling==1.4.1
hatchling==1.5.0
hatchling==1.6.0
hatchling==1.7.0
hatchling==1.7.1
hatchling==1.8.0
hatchling==1.8.1
hatchling==1.9.0
hatchling==1.10.0
hatchling==1.11.0
hatchling==1.11.1
hatchling==1.12.0
hatchling==1.12.1
hatchling==1.12.2
hatchling==1.13.0
hatchling==1.14.0
hatchling==1.14.1
hatchling==1.15.0
hatchling==1.16.0
hatchling==1.16.1
hatchling==1.17.0
hatchling==1.17.1
hatchling==1.18.0
hatchling==1.19.0
hatchling==1.19.1
hatchling==1.20.0
hatchling==1.21.0
hatchling==1.21.1
hatchling==1.22.0
hatchling==1.22.1
hatchling==1.22.2
hatchling==1.22.3
hatchling==1.22.4
hatchling==1.22.5
hatchling==1.23.0
hatchling==1.24.0
hatchling==1.24.1
hatchling==1.24.2
hatchling==1.25.0
hatchling==1.26.0
hatchling==1.26.1
hatchling==1.26.2
hatchling==1.26.3
hatchling==1.27.0
hatchling==1.28.0
hatchling==1.29.0
and hatchling<=1.3.1 needs to be downloaded from a registry, we can
conclude that hatchling<=1.3.1 cannot be used.
And because hatchling==1.4.0 was yanked (reason: Building wheels from
sdists is broken), we can conclude that hatchling<1.4.1 cannot be used.
And because hatchling>=1.4.1,<=1.19.0 needs to be downloaded
from a registry and hatchling==1.19.1 was yanked (reason:
https://github.com/pypa/hatch/issues/1129), we can conclude that
hatchling<1.20.0 cannot be used.
And because hatchling>=1.20.0,<=1.21.1 needs to be downloaded from
a registry and hatchling>=1.22.0,<=1.22.1 was yanked (reason: Broken
builds from sdists), we can conclude that hatchling>=1.22.0,<=1.22.1
cannot be used.
And because hatchling>=1.22.2,<=1.25.0 needs to be downloaded from a
registry and hatchling==1.26.0 was yanked (reason: Incompatible with
currently released Hatch), we can conclude that hatchling<1.26.1 cannot
be used.
And because hatchling>=1.26.1,<=1.26.2 was yanked (reason: Upload
issues) and hatchling>=1.26.3,<=1.28.0 needs to be downloaded from a
registry, we can conclude that hatchling>=1.26.3,<=1.28.0 cannot be
used. (1)

Because only the following versions of tomli{python_full_version <
'3.11'} are available:
tomli{python_full_version < '3.11'}<=1.2.2
tomli{python_full_version < '3.11'}==1.2.3
tomli{python_full_version < '3.11'}==2.0.0
tomli{python_full_version < '3.11'}==2.0.1
tomli{python_full_version < '3.11'}==2.0.2
tomli{python_full_version < '3.11'}==2.1.0
tomli{python_full_version < '3.11'}==2.2.1
tomli{python_full_version < '3.11'}==2.3.0
tomli{python_full_version < '3.11'}==2.3.1
tomli{python_full_version < '3.11'}==2.4.0
tomli{python_full_version < '3.11'}==2.4.1
and tomli>=1.2.2 needs to be downloaded from a registry, we can conclude
that tomli{python_full_version < '3.11'}>=1.2.2,<1.2.3 cannot be used.
And because hatchling==1.29.0 depends on tomli{python_full_version <
'3.11'}>=1.2.2, we can conclude that hatchling==1.29.0 cannot be used.
And because we know from (1) that hatchling>=1.26.3,<=1.28.0 cannot be
used, we can conclude that all versions of hatchling cannot be used.
And because you require hatchling, we can conclude that your
requirements are unsatisfiable.

hint: Packages were unavailable because the network was disabled. When
the network is disabled, registry packages may only be read from the
cache.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this supposed to fail?




>>> [CLI] bundle destroy --auto-approve
No active deployment found to destroy!

Exit code: 1
31 changes: 31 additions & 0 deletions acceptance/bundle/deploy/immutable/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[project]
name = "immutable"
version = "0.0.1"
authors = [{ name = "andrew.nester@databricks.com" }]
requires-python = ">=3.10,<3.13"
dependencies = [
# Any dependencies for jobs and pipelines in this project can be added here
# See also https://docs.databricks.com/dev-tools/bundles/library-dependencies
#
# LIMITATION: for pipelines, dependencies are cached during development;
# add dependencies to the 'environment' section of your pipeline.yml file instead
]

[dependency-groups]
dev = [
"pytest",
"ruff",
"databricks-dlt",
"databricks-connect>=15.4,<15.5",
"ipykernel",
]

[project.scripts]
main = "immutable.main:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.ruff]
line-length = 120
Loading
Loading