Skip to content

Commit abd94d4

Browse files
committed
update
1 parent 20e3093 commit abd94d4

62 files changed

Lines changed: 17302 additions & 16 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/tagging.yml

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,7 @@ name: tagging
44
on:
55
# Manual dispatch.
66
workflow_dispatch:
7-
inputs:
8-
package:
9-
description: 'Package to tag (leave empty to tag all packages with pending releases).'
10-
required: false
11-
type: string
12-
default: ''
7+
# No inputs are required for the manual dispatch.
138

149
# NOTE: Temporarily disable automated releases.
1510
#
@@ -66,10 +61,12 @@ jobs:
6661
env:
6762
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
6863
GITHUB_REPOSITORY: ${{ github.repository }}
69-
PACKAGE: ${{ inputs.package }}
70-
run: |
71-
if [ -n "$PACKAGE" ]; then
72-
uv run --locked tagging.py --package "$PACKAGE"
73-
else
74-
uv run --locked tagging.py
75-
fi
64+
run: uv run --locked tagging.py
65+
66+
- name: Upload created tags artifact
67+
if: always()
68+
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
69+
with:
70+
name: created-tags
71+
path: created_tags.json
72+
if-no-files-found: ignore

README.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,120 @@
99
> - **Breaking changes may occur at any time**
1010
> - **APIs are experimental and unstable**
1111
> - **Use for development and testing only**
12+
13+
## Design Notes
14+
15+
### FieldMask — Deferred Ergonomics Decisions
16+
17+
The current `FieldMask` implementation validates paths against a per-message
18+
schema inside `FieldMask.build`, throws on mismatch, and stores the
19+
wire-format paths privately so `toString()` produces the server-facing
20+
comma-separated string. Construction entry point today is a **per-message
21+
factory function** generated alongside each message — e.g.
22+
`alertFieldMask('displayName', 'condition.op')` — which supplies the schema
23+
and message name and delegates to `FieldMask.build`. This section records
24+
two refinements we've discussed but deferred; they do not change the
25+
validation semantics, only the call-site shape.
26+
27+
#### Q1 — Call-site ergonomics
28+
29+
**Current (Option C, per-message factory):**
30+
31+
```ts
32+
import {alertFieldMask} from '@databricks/sdk-alerts/v1';
33+
const mask = alertFieldMask('displayName', 'condition.op');
34+
```
35+
36+
- Pros: best discoverability (auto-complete on import), single-argument call,
37+
error messages name the target message, and users never think about
38+
schemas or message names.
39+
- Cons: one generated factory per message (~60+ across the SDK). Each is a
40+
thin one-liner, but they multiply with every new message.
41+
42+
**Option A — raw `FieldMask.build` at the call site:**
43+
44+
```ts
45+
import {FieldMask} from '@databricks/sdk-core/wkt';
46+
import {Alert, alertFieldMaskSchema} from '@databricks/sdk-alerts/v1';
47+
48+
const mask = FieldMask.build<Alert>(
49+
['displayName', 'condition.op'],
50+
alertFieldMaskSchema,
51+
);
52+
```
53+
54+
- Pros: zero helper functions anywhere. Only `FieldMask.build` exists.
55+
- Cons: two-argument low-level call at every usage site. Users must
56+
import the schema explicitly and know which schema pairs with which
57+
type.
58+
59+
**Option B — one generic helper in `sdk-core`:**
60+
61+
```ts
62+
import {fieldMask} from '@databricks/sdk-core/wkt';
63+
import {Alert} from '@databricks/sdk-alerts/v1';
64+
65+
const mask = fieldMask(Alert, 'displayName', 'condition.op');
66+
```
67+
68+
- Pros: a single `fieldMask(...)` replaces the ~60+ per-message factories.
69+
`Alert` supplies both the schema and the message name as properties on
70+
itself, so the call site stays one argument plus paths.
71+
- Cons: requires `Alert` the import to be **both** a TypeScript type and a
72+
runtime descriptor value on the same name. See Q2 below.
73+
74+
#### Q2 — Interface + const declaration merging on the message name
75+
76+
A TypeScript pattern that lets one exported identifier occupy both the
77+
type-space and the value-space:
78+
79+
```ts
80+
// Type — describes instance shape. Zero runtime cost.
81+
export interface Alert {
82+
displayName?: string;
83+
condition?: Condition;
84+
}
85+
86+
// Runtime value — carries the schema under the same name.
87+
export const Alert: MessageDescriptor<Alert> = {
88+
fieldMaskSchema: {
89+
displayName: {wire: 'display_name'},
90+
condition: {wire: 'condition', children: () => Condition.fieldMaskSchema},
91+
},
92+
};
93+
```
94+
95+
Usage after this change:
96+
97+
```ts
98+
const a: Alert = {displayName: 'foo'}; // Alert as a type (literal shape)
99+
const s = Alert.fieldMaskSchema; // Alert as a value (runtime)
100+
const mask = fieldMask(Alert, 'displayName'); // Option B unblocked
101+
```
102+
103+
TypeScript supports this via
104+
[declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html).
105+
`interface X` occupies type-space, `const X` occupies value-space; they do
106+
not collide. The same pattern shows up in `lib.dom.d.ts`, `Promise`, and
107+
various DI libraries.
108+
109+
- Pros: single import, natural `Alert.fieldMaskSchema` access, enables
110+
Option B without asking users to remember a separate `AlertSchema` name.
111+
- Cons: the pattern is less common in everyday TS and can surprise readers
112+
who expect classes for anything with static-like members. The alternative
113+
is to use a distinct name — e.g. `AlertSchema` or `AlertDescriptor` — for
114+
the runtime value, at the cost of one extra identifier to learn per
115+
message.
116+
117+
#### Why we haven't landed Q1/Q2 yet
118+
119+
Both are call-site ergonomics refactors; neither changes the validation
120+
semantics or the per-message schema generation. We want the current
121+
`FieldMask.build` path (validate, translate, store wire paths privately,
122+
`toString()` joins) to settle before adjusting the call-site shape, so
123+
the two axes of change don't churn simultaneously. When we revisit, the
124+
likely landing is **Option B + Option Q2** together — one generic
125+
`fieldMask()` plus the interface+const merge, which most closely matches
126+
what similar TypeScript validation libraries (Zod, Valibot, TypeBox, etc.)
127+
expose while staying consistent with the SDK's existing interface-first
128+
convention for message types.

packages/abacpolicies/src/v1/model.ts

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// Code generated from API definition by Databricks SDK Generator. DO NOT EDIT.
22

3+
import {FieldMask} from '@databricks/sdk-core/wkt';
4+
import type {FieldMaskSchema} from '@databricks/sdk-core/wkt';
35
import {z} from 'zod';
46

57
export enum PolicyType {
@@ -603,3 +605,235 @@ export const marshalTagValueExtractionSchema: z.ZodType = z
603605
.transform(d => ({
604606
tag_key: d.tagKey,
605607
}));
608+
609+
const columnMaskOptionsFieldMaskSchema: FieldMaskSchema = {
610+
functionName: {wire: 'function_name'},
611+
onColumn: {wire: 'on_column'},
612+
using: {wire: 'using'},
613+
};
614+
615+
export function columnMaskOptionsFieldMask(
616+
...paths: string[]
617+
): FieldMask<ColumnMaskOptions> {
618+
return FieldMask.build<ColumnMaskOptions>(
619+
paths,
620+
columnMaskOptionsFieldMaskSchema
621+
);
622+
}
623+
624+
const columnTagValueExtractionFieldMaskSchema: FieldMaskSchema = {
625+
columnAlias: {wire: 'column_alias'},
626+
tagKey: {wire: 'tag_key'},
627+
};
628+
629+
export function columnTagValueExtractionFieldMask(
630+
...paths: string[]
631+
): FieldMask<ColumnTagValueExtraction> {
632+
return FieldMask.build<ColumnTagValueExtraction>(
633+
paths,
634+
columnTagValueExtractionFieldMaskSchema
635+
);
636+
}
637+
638+
const createPolicyFieldMaskSchema: FieldMaskSchema = {
639+
policyInfo: {wire: 'policy_info', children: () => policyInfoFieldMaskSchema},
640+
};
641+
642+
export function createPolicyFieldMask(
643+
...paths: string[]
644+
): FieldMask<CreatePolicy> {
645+
return FieldMask.build<CreatePolicy>(paths, createPolicyFieldMaskSchema);
646+
}
647+
648+
const deletePolicyFieldMaskSchema: FieldMaskSchema = {
649+
name: {wire: 'name'},
650+
onSecurableFullname: {wire: 'on_securable_fullname'},
651+
onSecurableType: {wire: 'on_securable_type'},
652+
};
653+
654+
export function deletePolicyFieldMask(
655+
...paths: string[]
656+
): FieldMask<DeletePolicy> {
657+
return FieldMask.build<DeletePolicy>(paths, deletePolicyFieldMaskSchema);
658+
}
659+
660+
const denyOptionsFieldMaskSchema: FieldMaskSchema = {
661+
privileges: {wire: 'privileges'},
662+
};
663+
664+
export function denyOptionsFieldMask(
665+
...paths: string[]
666+
): FieldMask<DenyOptions> {
667+
return FieldMask.build<DenyOptions>(paths, denyOptionsFieldMaskSchema);
668+
}
669+
670+
const functionArgumentFieldMaskSchema: FieldMaskSchema = {
671+
alias: {wire: 'alias'},
672+
constant: {wire: 'constant'},
673+
metadataExtraction: {
674+
wire: 'metadata_extraction',
675+
children: () => metadataExtractionExpressionFieldMaskSchema,
676+
},
677+
};
678+
679+
export function functionArgumentFieldMask(
680+
...paths: string[]
681+
): FieldMask<FunctionArgument> {
682+
return FieldMask.build<FunctionArgument>(
683+
paths,
684+
functionArgumentFieldMaskSchema
685+
);
686+
}
687+
688+
const getPolicyFieldMaskSchema: FieldMaskSchema = {
689+
name: {wire: 'name'},
690+
onSecurableFullname: {wire: 'on_securable_fullname'},
691+
onSecurableType: {wire: 'on_securable_type'},
692+
};
693+
694+
export function getPolicyFieldMask(...paths: string[]): FieldMask<GetPolicy> {
695+
return FieldMask.build<GetPolicy>(paths, getPolicyFieldMaskSchema);
696+
}
697+
698+
const grantOptionsFieldMaskSchema: FieldMaskSchema = {
699+
privileges: {wire: 'privileges'},
700+
};
701+
702+
export function grantOptionsFieldMask(
703+
...paths: string[]
704+
): FieldMask<GrantOptions> {
705+
return FieldMask.build<GrantOptions>(paths, grantOptionsFieldMaskSchema);
706+
}
707+
708+
const listPoliciesFieldMaskSchema: FieldMaskSchema = {
709+
includeInherited: {wire: 'include_inherited'},
710+
maxResults: {wire: 'max_results'},
711+
onSecurableFullname: {wire: 'on_securable_fullname'},
712+
onSecurableType: {wire: 'on_securable_type'},
713+
pageToken: {wire: 'page_token'},
714+
};
715+
716+
export function listPoliciesFieldMask(
717+
...paths: string[]
718+
): FieldMask<ListPolicies> {
719+
return FieldMask.build<ListPolicies>(paths, listPoliciesFieldMaskSchema);
720+
}
721+
722+
const listPoliciesResponseFieldMaskSchema: FieldMaskSchema = {
723+
nextPageToken: {wire: 'next_page_token'},
724+
policies: {wire: 'policies'},
725+
};
726+
727+
export function listPoliciesResponseFieldMask(
728+
...paths: string[]
729+
): FieldMask<ListPolicies_Response> {
730+
return FieldMask.build<ListPolicies_Response>(
731+
paths,
732+
listPoliciesResponseFieldMaskSchema
733+
);
734+
}
735+
736+
const matchColumnFieldMaskSchema: FieldMaskSchema = {
737+
alias: {wire: 'alias'},
738+
condition: {wire: 'condition'},
739+
};
740+
741+
export function matchColumnFieldMask(
742+
...paths: string[]
743+
): FieldMask<MatchColumn> {
744+
return FieldMask.build<MatchColumn>(paths, matchColumnFieldMaskSchema);
745+
}
746+
747+
const metadataExtractionExpressionFieldMaskSchema: FieldMaskSchema = {
748+
columnTagValue: {
749+
wire: 'column_tag_value',
750+
children: () => columnTagValueExtractionFieldMaskSchema,
751+
},
752+
tagValue: {
753+
wire: 'tag_value',
754+
children: () => tagValueExtractionFieldMaskSchema,
755+
},
756+
};
757+
758+
export function metadataExtractionExpressionFieldMask(
759+
...paths: string[]
760+
): FieldMask<MetadataExtractionExpression> {
761+
return FieldMask.build<MetadataExtractionExpression>(
762+
paths,
763+
metadataExtractionExpressionFieldMaskSchema
764+
);
765+
}
766+
767+
const policyInfoFieldMaskSchema: FieldMaskSchema = {
768+
columnMask: {
769+
wire: 'column_mask',
770+
children: () => columnMaskOptionsFieldMaskSchema,
771+
},
772+
comment: {wire: 'comment'},
773+
createdAt: {wire: 'created_at'},
774+
createdBy: {wire: 'created_by'},
775+
deny: {wire: 'deny', children: () => denyOptionsFieldMaskSchema},
776+
exceptPrincipals: {wire: 'except_principals'},
777+
forSecurableType: {wire: 'for_securable_type'},
778+
grant: {wire: 'grant', children: () => grantOptionsFieldMaskSchema},
779+
id: {wire: 'id'},
780+
matchColumns: {wire: 'match_columns'},
781+
name: {wire: 'name'},
782+
onSecurableFullname: {wire: 'on_securable_fullname'},
783+
onSecurableType: {wire: 'on_securable_type'},
784+
policyType: {wire: 'policy_type'},
785+
rowFilter: {
786+
wire: 'row_filter',
787+
children: () => rowFilterOptionsFieldMaskSchema,
788+
},
789+
toPrincipals: {wire: 'to_principals'},
790+
updatedAt: {wire: 'updated_at'},
791+
updatedBy: {wire: 'updated_by'},
792+
useSessionIdentity: {wire: 'use_session_identity'},
793+
whenCondition: {wire: 'when_condition'},
794+
};
795+
796+
export function policyInfoFieldMask(...paths: string[]): FieldMask<PolicyInfo> {
797+
return FieldMask.build<PolicyInfo>(paths, policyInfoFieldMaskSchema);
798+
}
799+
800+
const rowFilterOptionsFieldMaskSchema: FieldMaskSchema = {
801+
functionName: {wire: 'function_name'},
802+
using: {wire: 'using'},
803+
};
804+
805+
export function rowFilterOptionsFieldMask(
806+
...paths: string[]
807+
): FieldMask<RowFilterOptions> {
808+
return FieldMask.build<RowFilterOptions>(
809+
paths,
810+
rowFilterOptionsFieldMaskSchema
811+
);
812+
}
813+
814+
const tagValueExtractionFieldMaskSchema: FieldMaskSchema = {
815+
tagKey: {wire: 'tag_key'},
816+
};
817+
818+
export function tagValueExtractionFieldMask(
819+
...paths: string[]
820+
): FieldMask<TagValueExtraction> {
821+
return FieldMask.build<TagValueExtraction>(
822+
paths,
823+
tagValueExtractionFieldMaskSchema
824+
);
825+
}
826+
827+
const updatePolicyFieldMaskSchema: FieldMaskSchema = {
828+
name: {wire: 'name'},
829+
onSecurableFullname: {wire: 'on_securable_fullname'},
830+
onSecurableType: {wire: 'on_securable_type'},
831+
policyInfo: {wire: 'policy_info', children: () => policyInfoFieldMaskSchema},
832+
updateMask: {wire: 'update_mask'},
833+
};
834+
835+
export function updatePolicyFieldMask(
836+
...paths: string[]
837+
): FieldMask<UpdatePolicy> {
838+
return FieldMask.build<UpdatePolicy>(paths, updatePolicyFieldMaskSchema);
839+
}

0 commit comments

Comments
 (0)