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
1 change: 1 addition & 0 deletions .nextchanges/bundles/features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Add support for the `features` resource type. ([#6952](https://github.com/databricks/cli/pull/6952))
18 changes: 18 additions & 0 deletions acceptance/bundle/deployment/bind/feature/databricks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
bundle:
name: test-bundle

resources:
features:
feature1:
full_name: main.myschema.boundfeature
description: bound feature
source:
delta_table_source:
full_name: main.myschema.mysource
function:
column_selection:
column: amount
entities:
- name: account_id
timeseries_column:
name: event_ts
2 changes: 2 additions & 0 deletions acceptance/bundle/deployment/bind/feature/out.test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cloud = false
EnvMatrix.DMS = [""]
30 changes: 30 additions & 0 deletions acceptance/bundle/deployment/bind/feature/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

>>> [CLI] bundle deployment bind feature1 main.myschema.boundfeature --auto-approve
Successfully bound feature with an id 'main.myschema.boundfeature'
Run 'bundle deploy' to deploy changes to your workspace

>>> [CLI] bundle summary
Name: test-bundle
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default
Resources:
Features:
feature1:
Name: main.myschema.boundfeature
URL: [DATABRICKS_URL]/explore/data/features/main/myschema/boundfeature?w=[WORKSPACE_ID]

>>> [CLI] bundle deployment unbind feature1

>>> [CLI] bundle summary
Name: test-bundle
Target: default
Workspace:
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default
Resources:
Features:
feature1:
Name: main.myschema.boundfeature
URL: (not deployed)
5 changes: 5 additions & 0 deletions acceptance/bundle/deployment/bind/feature/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
trace $CLI bundle deployment bind feature1 main.myschema.boundfeature --auto-approve
trace $CLI bundle summary

trace $CLI bundle deployment unbind feature1
trace $CLI bundle summary
22 changes: 22 additions & 0 deletions acceptance/bundle/deployment/bind/feature/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Cloud = false

Ignore = [
".databricks",
]

# The bind flow issues a GET to confirm the remote feature exists before binding.
[[Server]]
Pattern = "GET /api/2.0/feature-engineering/features/{full_name}"
Response.Body = '''
{
"full_name": "main.myschema.boundfeature",
"catalog_name": "main",
"schema_name": "myschema",
"name": "boundfeature",
"description": "bound feature",
"source": {"delta_table_source": {"full_name": "main.myschema.mysource"}},
"function": {"column_selection": {"column": "amount"}},
"entities": [{"name": "account_id"}],
"timeseries_column": {"name": "event_ts"}
}
'''
23 changes: 23 additions & 0 deletions acceptance/bundle/invariant/configs/feature.yml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
bundle:
name: test-bundle-$UNIQUE_NAME

resources:
features:
foo:
full_name: main.default.test_feature_$UNIQUE_NAME
description: This is a test feature # CAN_REMOVE
source:
delta_table_source:
full_name: main.default.test_source_$UNIQUE_NAME
function:
aggregation_function:
count_function:
input: value
time_window:
sliding:
window_duration: 604800s
slide_duration: 86400s
entities:
- name: id
timeseries_column:
name: timestamp
27 changes: 27 additions & 0 deletions acceptance/bundle/python/features-support/databricks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
bundle:
name: my_project

sync: {paths: []} # don't need to copy files

python:
resources:
- "resources:load_resources"
mutators:
- "mutators:update_feature"

resources:
features:
my_feature_1:
full_name: main.default.my_feature_1
description: "My Feature"
source:
delta_table_source:
full_name: main.default.my_source_1
function:
aggregation_function:
count_function:
input: value
time_window:
sliding:
window_duration: 604800s
slide_duration: 86400s
11 changes: 11 additions & 0 deletions acceptance/bundle/python/features-support/mutators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from dataclasses import replace

from databricks.bundles.core import feature_mutator
from databricks.bundles.features import Feature


@feature_mutator
def update_feature(feature: Feature) -> Feature:
assert isinstance(feature.description, str)

return replace(feature, description=f"{feature.description} (updated)")
3 changes: 3 additions & 0 deletions acceptance/bundle/python/features-support/out.test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Cloud = false
EnvMatrix.DMS = ["", "true"]
EnvMatrix.PYDAB_VERSION = ["current"]
62 changes: 62 additions & 0 deletions acceptance/bundle/python/features-support/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

>>> uv run [UV_ARGS] -q [CLI] bundle validate --output json
{
"experimental": {
"python": {
"mutators": [
"mutators:update_feature"
],
"resources": [
"resources:load_resources"
]
}
},
"resources": {
"features": {
"my_feature_1": {
"description": "My Feature (updated)",
"full_name": "main.default.my_feature_1",
"function": {
"aggregation_function": {
"count_function": {
"input": "value"
},
"time_window": {
"sliding": {
"slide_duration": "86400s",
"window_duration": "604800s"
}
}
}
},
"source": {
"delta_table_source": {
"full_name": "main.default.my_source_1"
}
}
},
"my_feature_2": {
"description": "My Feature (2) (updated)",
"full_name": "main.default.my_feature_2",
"function": {
"aggregation_function": {
"count_function": {
"input": "value"
},
"time_window": {
"sliding": {
"slide_duration": "86400s",
"window_duration": "604800s"
}
}
}
},
"source": {
"delta_table_source": {
"full_name": "main.default.my_source_2"
}
}
}
}
}
}
29 changes: 29 additions & 0 deletions acceptance/bundle/python/features-support/resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from databricks.bundles.core import Resources


def load_resources() -> Resources:
resources = Resources()

resources.add_feature(
"my_feature_2",
{
"full_name": "main.default.my_feature_2",
"description": "My Feature (2)",
"source": {
"delta_table_source": {"full_name": "main.default.my_source_2"},
},
"function": {
"aggregation_function": {
"count_function": {"input": "value"},
"time_window": {
"sliding": {
"window_duration": "604800s",
"slide_duration": "86400s",
},
},
},
},
},
)

return resources
5 changes: 5 additions & 0 deletions acceptance/bundle/python/features-support/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

trace uv run $UV_ARGS -q $CLI bundle validate --output json | \
jq "pick(.experimental.python, .resources)"

rm -fr .databricks __pycache__
4 changes: 4 additions & 0 deletions acceptance/bundle/python/features-support/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Cloud = false # tests don't interact with APIs

# features are only supported in the current version of the wheel
EnvMatrix.PYDAB_VERSION = ["current"]
Loading
Loading