From 4b93177f3e513f0363991910379753e48078bfb0 Mon Sep 17 00:00:00 2001 From: Jason Karlavige Date: Thu, 29 Aug 2024 10:37:40 -0400 Subject: [PATCH 01/49] adjust color for blockquotes in alerts --- website/src/css/custom.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/src/css/custom.css b/website/src/css/custom.css index b7c41d44aee..e240a5dfabf 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -705,6 +705,10 @@ html[data-theme="dark"] .alert table { color: var(--ifm-color-gray-900) !important; } +.alert blockquote { + color: inherit; +} + .linkout { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 18 22.5' version='1.1' x='0px' y='0px'%3E%3Ctitle%3Elink%3C/title%3E%3Cdesc%3ECreated with Sketch.%3C/desc%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cpath d='M9.24264069,6.41438508 C8.8521164,6.80490937 8.21895142,6.80490937 7.82842712,6.41438508 C7.43790283,6.02386078 7.43790283,5.39069581 7.82842712,5.00017151 L10.6570258,2.17157288 C12.2191229,0.609475708 14.7517828,0.609475708 16.31388,2.17157288 C17.8759772,3.73367004 17.8759772,6.26632996 16.31388,7.82842712 L13.4854529,10.6568542 C13.0949286,11.0473785 12.4617636,11.0473785 12.0712393,10.6568542 C11.680715,10.26633 11.680715,9.63316498 12.0712393,9.24264069 L14.8996664,6.41421356 C15.680715,5.63316498 15.680715,4.36683502 14.8996664,3.58578644 C14.1186179,2.80473785 12.8522879,2.80473785 12.0712393,3.58578644 L9.24264069,6.41438508 Z M9.2428122,12.0710678 C9.63333649,11.6805435 10.2665015,11.6805435 10.6570258,12.0710678 C11.0475501,12.4615921 11.0475501,13.0947571 10.6570258,13.4852814 L7.82842712,16.31388 C6.26632996,17.8759772 3.73367004,17.8759772 2.17157288,16.31388 C0.609475708,14.7517828 0.609475708,12.2191229 2.17157288,10.6570258 L5,7.82859864 C5.39052429,7.43807435 6.02368927,7.43807435 6.41421356,7.82859864 C6.80473785,8.21912293 6.80473785,8.85228791 6.41421356,9.2428122 L3.58578644,12.0712393 C2.80473785,12.8522879 2.80473785,14.1186179 3.58578644,14.8996664 C4.36683502,15.680715 5.63316498,15.680715 6.41421356,14.8996664 L9.2428122,12.0710678 Z M12.0712393,6.41421356 C12.4617636,6.80473785 12.4617636,7.43790283 12.0712393,7.82842712 L7.82859864,12.0710678 C7.43807435,12.4615921 6.80490937,12.4615921 6.41438508,12.0710678 C6.02386078,11.6805435 6.02386078,11.0473785 6.41438508,10.6568542 L10.6570258,6.41421356 C11.0475501,6.02368927 11.680715,6.02368927 12.0712393,6.41421356 Z' fill='%23000000' fill-rule='nonzero'/%3E%3C/g%3E%3C/svg%3E"); background-size: 2rem 2rem; From 5425b6f9f42eb634ade9fe47d9deece0c0b2c147 Mon Sep 17 00:00:00 2001 From: Jason Karlavige Date: Thu, 29 Aug 2024 10:38:34 -0400 Subject: [PATCH 02/49] add demo admonitions to intro page --- website/docs/docs/introduction.md | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/website/docs/docs/introduction.md b/website/docs/docs/introduction.md index 5301dae396d..013f3b0ab1e 100644 --- a/website/docs/docs/introduction.md +++ b/website/docs/docs/introduction.md @@ -5,6 +5,46 @@ pagination_next: null pagination_prev: null --- +:::note + +Some **content** with _Markdown_ `syntax`. Check [this api](#). + + >After creating (or updating) a workspace, wait until it’s available for using or creating clusters. The workspace status stays at status RUNNING and the VPC change happens immediately. However, you cannot use or create clusters for another 20 minutes. If you create or use clusters before this time interval elapses, clusters do not launch successfully, fail, or could cause other unexpected behavior. + +::: + +:::tip + +Some **content** with _Markdown_ `syntax`. Check [this api](#). + + >After creating (or updating) a workspace, wait until it’s available for using or creating clusters. The workspace status stays at status RUNNING and the VPC change happens immediately. However, you cannot use or create clusters for another 20 minutes. If you create or use clusters before this time interval elapses, clusters do not launch successfully, fail, or could cause other unexpected behavior. + +::: + +:::info + +Some **content** with _Markdown_ `syntax`. Check [this api](#). + + >After creating (or updating) a workspace, wait until it’s available for using or creating clusters. The workspace status stays at status RUNNING and the VPC change happens immediately. However, you cannot use or create clusters for another 20 minutes. If you create or use clusters before this time interval elapses, clusters do not launch successfully, fail, or could cause other unexpected behavior. + +::: + +:::warning + +Some **content** with _Markdown_ `syntax`. Check [this api](#). + + >After creating (or updating) a workspace, wait until it’s available for using or creating clusters. The workspace status stays at status RUNNING and the VPC change happens immediately. However, you cannot use or create clusters for another 20 minutes. If you create or use clusters before this time interval elapses, clusters do not launch successfully, fail, or could cause other unexpected behavior. + +::: + +:::danger + +Some **content** with _Markdown_ `syntax`. Check [this api](#). + + >After creating (or updating) a workspace, wait until it’s available for using or creating clusters. The workspace status stays at status RUNNING and the VPC change happens immediately. However, you cannot use or create clusters for another 20 minutes. If you create or use clusters before this time interval elapses, clusters do not launch successfully, fail, or could cause other unexpected behavior. + +::: + dbt compiles and runs your analytics code against your data platform, enabling you and your team to collaborate on a single source of truth for metrics, insights, and business definitions. This single source of truth, combined with the ability to define tests for your data, reduces errors when logic changes, and alerts you when issues arise. From 469025b5ed9a247166e2acb725f13a8bb739c8c6 Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Thu, 29 Aug 2024 17:27:26 +0100 Subject: [PATCH 03/49] add versionblocks to cumulative metrics doc (#5992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this pr adds versionblocks (1.8 and lower, and 1.9+) to the cumulative metrics doc to differentiate the available parameters. `cumulative_type_params` are only available in “versionless” for dbt-cloud users, which should be mentioned in the documentation. If you’re a dbt-core user, not dbt-cloud, then you can still use the `grain_to_date` & `window` params, but nested under `type_params` instead of `cumulative_type_params`. The `period_agg` param is not available to dbt-core users yet. raised in this internal slack thread and by user in dbt community: https://dbt-labs.slack.com/archives/C02NCQ9483C/p1724944680040759 --- website/docs/docs/build/cumulative-metrics.md | 171 +++++++++++++++++- 1 file changed, 167 insertions(+), 4 deletions(-) diff --git a/website/docs/docs/build/cumulative-metrics.md b/website/docs/docs/build/cumulative-metrics.md index aa2b85aa9c8..056ff79c6eb 100644 --- a/website/docs/docs/build/cumulative-metrics.md +++ b/website/docs/docs/build/cumulative-metrics.md @@ -16,6 +16,8 @@ Note that we use the double colon (::) to indicate whether a parameter is nested ## Parameters + + | Parameter |
Description
| Type | | --------- | ----------- | ---- | | `name` | The name of the metric. | Required | @@ -32,11 +34,33 @@ Note that we use the double colon (::) to indicate whether a parameter is nested | `measure::fill_nulls_with` | Set the value in your metric definition instead of null (such as zero). | Optional | | `measure::join_to_timespine` | Boolean that indicates if the aggregated measure should be joined to the time spine table to fill in missing dates. Default `false`. | Optional | +
+ + + +| Parameter |
Description
| Type | +| --------- | ----------- | ---- | +| `name` | The name of the metric. | Required | +| `description` | The description of the metric. | Optional | +| `type` | The type of the metric (cumulative, derived, ratio, or simple). | Required | +| `label` | Required string that defines the display value in downstream tools. Accepts plain text, spaces, and quotes (such as `orders_total` or `"orders_total"`). | Required | +| `type_params` | The type parameters of the metric. Supports nested parameters indicated by the double colon, such as `type_params::measure`. | Required | +| `window` | The accumulation window, such as 1 month, 7 days, 1 year. This can't be used with `grain_to_date`. | Optional | +| `grain_to_date` | Sets the accumulation grain, such as `month`, which will accumulate data for one month and then restart at the beginning of the next. This can't be used with `window`. | Optional | +| `type_params::measure` | A list of measure inputs | Required | +| `measure:name` | The measure you are referencing. | Optional | +| `measure:fill_nulls_with` | Set the value in your metric definition instead of null (such as zero).| Optional | +| `measure:join_to_timespine` | Boolean that indicates if the aggregated measure should be joined to the time spine table to fill in missing dates. Default `false`. | Optional | + +
+ ### Complete specification The following displays the complete specification for cumulative metrics, along with an example: + + ```yaml metrics: - name: The metric name # Required @@ -54,13 +78,35 @@ metrics: join_to_timespine: true/false # Boolean that indicates if the aggregated measure should be joined to the time spine table to fill in missing dates. Default `false`. # Optional ``` + + + + +```yaml +metrics: + - name: The metric name # Required + description: The metric description # Optional + type: cumulative # Required + label: The value that will be displayed in downstream tools # Required + type_params: # Required + measure: + name: The measure you are referencing # Required + fill_nulls_with: Set the value in your metric definition instead of null (such as zero) # Optional + join_to_timespine: false # Boolean that indicates if the aggregated measure should be joined to the time spine table to fill in missing dates. Default `false`. # Optional + window: 1 month # The accumulation window, such as 1 month, 7 days, 1 year. Optional. Cannot be used with grain_to_date. + grain_to_date: month # Sets the accumulation grain, such as month will accumulate data for one month, then restart at the beginning of the next. Optional. Cannot be used with window. +``` + + ## Cumulative metrics example Cumulative metrics measure data over a given window and consider the window infinite when no window parameter is passed, accumulating the data over all time. -The following example shows how to define cumulative metrics in a YAML file. In this example, we define three cumulative metrics: +The following example shows how to define cumulative metrics in a YAML file: + + - `cumulative_order_total`: Calculates the cumulative order total over all time. Uses `type params` to specify the measure `order_total` to be aggregated. @@ -68,10 +114,23 @@ The following example shows how to define cumulative metrics in a YAML file. In - `cumulative_order_total_mtd`: Calculates the month-to-date cumulative order total, respectively. Uses `cumulative_type_params` to specify a `grain_to_date` of `month`. + + + + +- `cumulative_order_total`: Calculates the cumulative order total over all time. Uses `type params` to specify the measure `order_total` to be aggregated. + +- `cumulative_order_total_l1m`: Calculates the trailing 1-month cumulative order total. Uses `type params` to specify a `window` of 1 month. + +- `cumulative_order_total_mtd`: Calculates the month-to-date cumulative order total, respectively. Uses `type params` to specify a `grain_to_date` of `month`. + + + -```yaml + +```yaml metrics: - name: cumulative_order_total label: Cumulative order total (All-Time) @@ -101,8 +160,44 @@ metrics: cumulative_type_params: grain_to_date: month ``` + + + + +```yaml +metrics: + - name: cumulative_order_total + label: Cumulative order total (All-Time) + description: The cumulative value of all orders + type: cumulative + type_params: + measure: + name: order_total + + - name: cumulative_order_total_l1m + label: Cumulative order total (L1M) + description: Trailing 1-month cumulative order total + type: cumulative + type_params: + measure: + name: order_total + window: 1 month + + - name: cumulative_order_total_mtd + label: Cumulative order total (MTD) + description: The month-to-date value of all orders + type: cumulative + type_params: + measure: + name: order_total + grain_to_date: month +``` + + + + ### Granularity options Use the `period_agg` parameter with `first()`, `last()`, and `average()` functions to aggregate cumulative metrics over the requested period. This is because granularity options for cumulative metrics are different than the options for other metric types. @@ -192,6 +287,8 @@ group by + + ### Window options This section details examples of when to specify and not to specify window options. @@ -218,6 +315,8 @@ measures: We can write a cumulative metric `weekly_customers` as such: + + ``` yaml @@ -240,6 +339,31 @@ From the sample YAML example, note the following: For example, in the `weekly_customers` cumulative metric, MetricFlow takes a sliding 7-day window of relevant customers and applies a count distinct function. +If you remove `window`, the measure will accumulate over all time. + + + + + + +``` yaml +metrics: + - name: weekly_customers # Define the measure and the window. + type: cumulative + type_params: + measure: customers + window: 7 days # Setting the window to 7 days since we want to track weekly active +``` + + + +From the sample YAML example, note the following: + +* `type`: Specify cumulative to indicate the type of metric. +* `type_params`: Configure the cumulative metric by providing a `measure` and optionally add a `window` or `grain_to_date` configuration. + +For example, in the `weekly_customers` cumulative metric, MetricFlow takes a sliding 7-day window of relevant customers and applies a count distinct function. + If you remove `window`, the measure will accumulate over all time. @@ -286,7 +410,6 @@ metrics: ``` - ### Grain to date @@ -310,6 +433,8 @@ We can compare the difference between a 1-month window and a monthly grain to da + + ```yaml metrics: - name: cumulative_order_total_l1m # For this metric, we use a window of 1 month @@ -330,10 +455,33 @@ metrics: grain_to_date: month # Resets at the beginning of each month period_agg: first # Optional. Defaults to first. Accepted values: first|last|average ``` + + + + +```yaml +metrics: + - name: cumulative_order_total_l1m # For this metric, we use a window of 1 month + label: Cumulative order total (L1M) + description: Trailing 1-month cumulative order amount + type: cumulative + type_params: + measure: order_total + window: 1 month # Applies a sliding window of 1 month + - name: cumulative_order_total_mtd # For this metric, we use a monthly grain-to-date + label: Cumulative order total (MTD) + description: The month-to-date value of all orders + type: cumulative + type_params: + measure: order_total + grain_to_date: month # Resets at the beginning of each month +``` + Cumulative metric with grain to date: + ```yaml @@ -390,10 +538,25 @@ order by ``` + + + + + +```yaml +- name: orders_last_month_to_date + label: Orders month to date + type: cumulative + type_params: + measure: order_count + grain_to_date: month +``` + + ## SQL implementation example -To calculate the cumulative value of the metric over a given window, join the timespine table using the primary time dimension. Use the accumulation window in the join to decide which days to include in the calculation. +To calculate the cumulative value of the metric over a given window we do a time range join to a timespine table using the primary time dimension as the join key. We use the accumulation window in the join to decide whether a record should be included on a particular day. The following SQL code produced from an example cumulative metric is provided for reference: To implement cumulative metrics, refer to the SQL code example: From 90981446c270f08302fc485a3160f683b7867bce Mon Sep 17 00:00:00 2001 From: Doug Beatty <44704949+dbeatty10@users.noreply.github.com> Date: Thu, 29 Aug 2024 11:18:16 -0600 Subject: [PATCH 04/49] We currently don't support unit testing models that use the `materialized view` materialization (#5986) [Preview](https://docs-getdbt-com-git-dbeatty10-patch-1-dbt-labs.vercel.app/docs/build/unit-tests#before-you-begin) ## What are you changing in this pull request and why? We currently don't support unit testing models that use the [`materialized view`](https://docs.getdbt.com/docs/build/materializations#materialized-view) materialization= See https://github.com/dbt-labs/dbt-postgres/issues/111 ## Checklist - [x] Review the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. --------- Co-authored-by: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> --- website/docs/docs/build/unit-tests.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/docs/build/unit-tests.md b/website/docs/docs/build/unit-tests.md index 55b35721298..1d7143d7476 100644 --- a/website/docs/docs/build/unit-tests.md +++ b/website/docs/docs/build/unit-tests.md @@ -22,7 +22,8 @@ With dbt Core v1.8 and dbt Cloud environments that have gone versionless by sele - We currently only support unit testing SQL models. - We currently only support adding unit tests to models in your _current_ project. -- We currently *don't* support unit testing models that use recursive SQL. +- We currently _don't_ support unit testing models that use the [`materialized view`](/docs/build/materializations#materialized-view) materialization. +- We currently _don't_ support unit testing models that use recursive SQL. - You must specify all fields in a BigQuery STRUCT in a unit test. You cannot use only a subset of fields in a STRUCT. - If your model has multiple versions, by default the unit test will run on *all* versions of your model. Read [unit testing versioned models](/reference/resource-properties/unit-testing-versions) for more information. - Unit tests must be defined in a YML file in your `models/` directory. From 2b56c4667b0a70253898cea9f8f4bb9a5491e0c3 Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Thu, 29 Aug 2024 20:23:51 +0100 Subject: [PATCH 05/49] consolidate excel gsheets (#5977) this pr adds saved queries and saved selection support for the SL excel integration. it also consolidates the excel and gsheets content into one snippet --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../semantic-layer/excel.md | 2 +- .../semantic-layer/gsheets.md | 14 ++++++++------ website/snippets/_sl-excel-gsheets.md | 18 +++++++----------- .../semantic-layer/gsheets-query-builder.jpg | Bin 53865 -> 0 bytes .../semantic-layer/query-builder.png | Bin 0 -> 112375 bytes 5 files changed, 16 insertions(+), 18 deletions(-) delete mode 100644 website/static/img/docs/dbt-cloud/semantic-layer/gsheets-query-builder.jpg create mode 100644 website/static/img/docs/dbt-cloud/semantic-layer/query-builder.png diff --git a/website/docs/docs/cloud-integrations/semantic-layer/excel.md b/website/docs/docs/cloud-integrations/semantic-layer/excel.md index 4f76bfc5c97..e666bda0e58 100644 --- a/website/docs/docs/cloud-integrations/semantic-layer/excel.md +++ b/website/docs/docs/cloud-integrations/semantic-layer/excel.md @@ -39,9 +39,9 @@ import Tools from '/snippets/_sl-excel-gsheets.md'; type="Microsoft Excel" bullet_1="There's a timeout of 1 minute for queries." bullet_2="If you're using this extension, make sure you're signed into Microsoft with the same Excel profile you used to set up the Add-In. Log in with one profile at a time as using multiple profiles at once might cause issues." +queryBuilder="/img/docs/dbt-cloud/semantic-layer/query-builder.png" /> - ## FAQs diff --git a/website/docs/docs/cloud-integrations/semantic-layer/gsheets.md b/website/docs/docs/cloud-integrations/semantic-layer/gsheets.md index b3931f0f528..f215bee9671 100644 --- a/website/docs/docs/cloud-integrations/semantic-layer/gsheets.md +++ b/website/docs/docs/cloud-integrations/semantic-layer/gsheets.md @@ -40,13 +40,15 @@ import Tools from '/snippets/_sl-excel-gsheets.md'; type="Google Sheets" bullet_1="The custom menu operation has a timeout limit of six (6) minutes." bullet_2="If you're using this extension, make sure you're signed into Chrome with the same Google profile you used to set up the Add-On. Log in with one Google profile at a time as using multiple Google profiles at once might cause issues." -queryBuilder="/img/docs/dbt-cloud/semantic-layer/gsheets-query-builder.jpg" +queryBuilder="/img/docs/dbt-cloud/semantic-layer/query-builder.png" +PrivateSelections="You can also make these selections private or public. Public selections mean your inputs are available in the menu to everyone on the sheet. +Private selections mean your inputs are only visible to you. Note that anyone added to the sheet can still see the data from these private selections, but they won't be able to interact with the selection in the menu or benefit from the automatic refresh." /> - + **Limited use policy disclosure** diff --git a/website/snippets/_sl-excel-gsheets.md b/website/snippets/_sl-excel-gsheets.md index 5179b4be2dc..f6d4678bf6e 100644 --- a/website/snippets/_sl-excel-gsheets.md +++ b/website/snippets/_sl-excel-gsheets.md @@ -65,26 +65,24 @@
  • For time dimensions, you can use the time range selector to filter on presets or custom options. The time range selector applies only to the primary time dimension (metric_time). For all other time dimensions that aren't metric_time, you can use the "Where" option to apply filters.
  • -#### Other settings +#### Other settings -

    If you would like to just query the data values without the headers, you can optionally select the Exclude Column Names box.

    -

    To return your results and keep any previously selected data below it intact, un-select the Exclude Column Names box. By default, we'll clear all trailing rows if there's stale data.

    +

    If you would like to just query the data values without the headers, you can optionally select the Exclude column names box.

    +

    To return your results and keep any previously selected data below it intact, un-select the Clear trailing rows box. By default, we'll clear all trailing rows if there's stale data.

    - - - diff --git a/website/static/img/docs/dbt-cloud/semantic-layer/gsheets-query-builder.jpg b/website/static/img/docs/dbt-cloud/semantic-layer/gsheets-query-builder.jpg deleted file mode 100644 index ef9c5d63c9f588e4000a9f79303f3314a0d633f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53865 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 diff --git a/website/static/img/docs/dbt-cloud/semantic-layer/query-builder.png b/website/static/img/docs/dbt-cloud/semantic-layer/query-builder.png new file mode 100644 index 0000000000000000000000000000000000000000..ae98c0a6c63b141f9c556b98b0e3d8321b5ded57 GIT binary patch literal 112375 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

    W)Wbo@v(RI** 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 literal 0 HcmV?d00001 From ec300fe1375c485818adfef2ce29ff178d0fb131 Mon Sep 17 00:00:00 2001 From: Jason Karlavige Date: Thu, 29 Aug 2024 15:55:13 -0400 Subject: [PATCH 06/49] remove demo alerts from intro page --- website/docs/docs/introduction.md | 40 ------------------------------- 1 file changed, 40 deletions(-) diff --git a/website/docs/docs/introduction.md b/website/docs/docs/introduction.md index 013f3b0ab1e..5301dae396d 100644 --- a/website/docs/docs/introduction.md +++ b/website/docs/docs/introduction.md @@ -5,46 +5,6 @@ pagination_next: null pagination_prev: null --- -:::note - -Some **content** with _Markdown_ `syntax`. Check [this api](#). - - >After creating (or updating) a workspace, wait until it’s available for using or creating clusters. The workspace status stays at status RUNNING and the VPC change happens immediately. However, you cannot use or create clusters for another 20 minutes. If you create or use clusters before this time interval elapses, clusters do not launch successfully, fail, or could cause other unexpected behavior. - -::: - -:::tip - -Some **content** with _Markdown_ `syntax`. Check [this api](#). - - >After creating (or updating) a workspace, wait until it’s available for using or creating clusters. The workspace status stays at status RUNNING and the VPC change happens immediately. However, you cannot use or create clusters for another 20 minutes. If you create or use clusters before this time interval elapses, clusters do not launch successfully, fail, or could cause other unexpected behavior. - -::: - -:::info - -Some **content** with _Markdown_ `syntax`. Check [this api](#). - - >After creating (or updating) a workspace, wait until it’s available for using or creating clusters. The workspace status stays at status RUNNING and the VPC change happens immediately. However, you cannot use or create clusters for another 20 minutes. If you create or use clusters before this time interval elapses, clusters do not launch successfully, fail, or could cause other unexpected behavior. - -::: - -:::warning - -Some **content** with _Markdown_ `syntax`. Check [this api](#). - - >After creating (or updating) a workspace, wait until it’s available for using or creating clusters. The workspace status stays at status RUNNING and the VPC change happens immediately. However, you cannot use or create clusters for another 20 minutes. If you create or use clusters before this time interval elapses, clusters do not launch successfully, fail, or could cause other unexpected behavior. - -::: - -:::danger - -Some **content** with _Markdown_ `syntax`. Check [this api](#). - - >After creating (or updating) a workspace, wait until it’s available for using or creating clusters. The workspace status stays at status RUNNING and the VPC change happens immediately. However, you cannot use or create clusters for another 20 minutes. If you create or use clusters before this time interval elapses, clusters do not launch successfully, fail, or could cause other unexpected behavior. - -::: - dbt compiles and runs your analytics code against your data platform, enabling you and your team to collaborate on a single source of truth for metrics, insights, and business definitions. This single source of truth, combined with the ability to define tests for your data, reduces errors when logic changes, and alerts you when issues arise. From 54610a8883ccbda4e7cb151de6b3b24588a37e44 Mon Sep 17 00:00:00 2001 From: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:57:39 -0400 Subject: [PATCH 07/49] Add athena ref page (#5961) ## What are you changing in this pull request and why? Adding the Amazon Athena /ref page Additionally organized the adapter ref page sidebar in alphabetical order ## Checklist - [ ] Review the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [ ] For [docs versioning](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#about-versioning), review how to [version a whole page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version) and [version a block of content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content). - [ ] Add a checklist item for anything that needs to happen before this PR is merged, such as "needs technical review" or "change base branch." Adding or removing pages (delete if not applicable): - [ ] Add/remove page in `website/sidebars.js` - [ ] Provide a unique filename for new pages - [ ] Add an entry for deleted pages in `website/vercel.json` - [ ] Run link testing locally with `npm run build` to update the links that point to deleted pages --------- Co-authored-by: Ly Nguyen <107218380+nghi-ly@users.noreply.github.com> Co-authored-by: Amy Chen <46451573+amychen1776@users.noreply.github.com> --- .../resource-configs/athena-configs.md | 552 ++++++++++++++++++ website/sidebars.js | 15 +- 2 files changed, 560 insertions(+), 7 deletions(-) create mode 100644 website/docs/reference/resource-configs/athena-configs.md diff --git a/website/docs/reference/resource-configs/athena-configs.md b/website/docs/reference/resource-configs/athena-configs.md new file mode 100644 index 00000000000..f871ede9fab --- /dev/null +++ b/website/docs/reference/resource-configs/athena-configs.md @@ -0,0 +1,552 @@ +--- +title: "Amazon Athena configurations" +description: "Reference article for the Amazon Athena adapter for dbt Core and dbt Cloud." +id: "athena-configs" +--- + +## Models + +### Table configuration + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `external_location` | None | The full S3 path to where the table is saved. It only works with incremental models. It doesn't work with Hive tables with `ha` set to `true`. | +| `partitioned_by` | None | An array list of columns by which the table will be partitioned. Currently limited to 100 partitions. | +| `bucketed_by` | None | An array list of the columns to bucket data. Ignored if using Iceberg. | +| `bucket_count` | None | The number of buckets for bucketing your data. This parameter is ignored if using Iceberg. | +| `table_type` | Hive | The type of table. Supports `hive` or `iceberg`. | +| `ha` | False | Build the table using the high-availability method. Only available for Hive tables. | +| `format` | Parquet | The data format for the table. Supports `ORC`, `PARQUET`, `AVRO`, `JSON`, and `TEXTFILE`. | +| `write_compression` | None | The compression type for any storage format that allows compressions. | +| `field_delimeter` | None | Specify the custom field delimiter to use when the format is set to `TEXTFIRE`. | +| `table_properties` | N/A | The table properties to add to the table. This is only for Iceberg. | +| `native_drop` | N/A | Relation drop operations will be performed with SQL, not direct Glue API calls. No S3 calls will be made to manage data in S3. Data in S3 will only be cleared up for Iceberg tables. See the [AWS docs](https://docs.aws.amazon.com/athena/latest/ug/querying-iceberg-managing-tables.html) for more info. Iceberg DROP TABLE operations may timeout if they take longer than 60 seconds.| +| `seed_by_insert` | False | Creates seeds using an SQL insert statement. Large seed files can't exceed the Athena 262144 bytes limit. | +| `force_batch` | False | Run the table creation directly in batch insert mode. Useful when the standard table creation fails due to partition limitation. | +| `unique_tmp_table_suffix` | False | Replace the "__dbt_tmp table" suffix with a unique UUID for incremental models using insert overwrite on Hive tables. | +| `temp_schema` | None | Defines a schema to hold temporary create statements used in incremental model runs. Scheme will be created in the models target database if it does not exist. | +| `lf_tags_config` | None | [AWS Lake Formation](#aws-lake-formation-integration) tags to associate with the table and columns. Existing tags will be removed.
    * `enabled` (`default=False`) whether LF tags management is enabled for a model
    * `tags` dictionary with tags and their values to assign for the model
    * `tags_columns` dictionary with a tag key, value and list of columns they must be assigned to | +| `lf_inherited_tags` | None | List of the Lake Formation tag keys that are to be inherited from the database level and shouldn't be removed during the assignment of those defined in `ls_tags_config`. | +| `lf_grants` | None | Lake Formation grants config for `data_cell` filters. | + +#### Configuration examples + + + + + + + +```sql +{{ + config( + materialized='incremental', + incremental_strategy='append', + on_schema_change='append_new_columns', + table_type='iceberg', + schema='test_schema', + lf_tags_config={ + 'enabled': true, + 'tags': { + 'tag1': 'value1', + 'tag2': 'value2' + }, + 'tags_columns': { + 'tag1': { + 'value1': ['column1', 'column2'], + 'value2': ['column3', 'column4'] + } + }, + 'inherited_tags': ['tag1', 'tag2'] + } + ) +}} +``` + + + + + + + + +```yaml + +lf_tags_config: + enabled: true + tags: + tag1: value1 + tag2: value2 + tags_columns: + tag1: + value1: [ column1, column2 ] + inherited_tags: [ tag1, tag2 ] +``` + + + + + + + +```python +lf_grants={ + 'data_cell_filters': { + 'enabled': True | False, + 'filters': { + 'filter_name': { + 'row_filter': '', + 'principals': ['principal_arn1', 'principal_arn2'] + } + } + } + } +``` + + + + + +There are some limitations and recommendations that should be considered: + +- `lf_tags` and `lf_tags_columns` configs support only attaching lf tags to corresponding resources. +- We recommend managing LF Tags permissions somewhere outside dbt. For example, [terraform](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lakeformation_permissions) or [aws cdk](https://docs.aws.amazon.com/cdk/api/v1/docs/aws-lakeformation-readme.html). +- `data_cell_filters` management can't be automated outside dbt because the filter can't be attached to the table, which doesn't exist. Once you `enable` this config, dbt will set all filters and their permissions during every dbt run. Such an approach keeps the actual state of row-level security configuration after every dbt run and applies changes if they occur: drop, create, and update filters and their permissions. +- Any tags listed in `lf_inherited_tags` should be strictly inherited from the database level and never overridden at the table and column level. +- Currently, `dbt-athena` does not differentiate between an inherited tag association and an override it made previously. + - For example, If a `lf_tags_config` value overrides an inherited tag in one run, and that override is removed before a subsequent run, the prior override will linger and no longer be encoded anywhere (for example, Terraform where the inherited value is configured nor in the DBT project where the override previously existed but now is gone). + + +### Table location + +The saved location of a table is determined in precedence by the following conditions: + +1. If `external_location` is defined, that value is used. +2. If `s3_data_dir` is defined, the path is determined by that and `s3_data_naming`. +3. If `s3_data_dir` is not defined, data is stored under `s3_staging_dir/tables/`. + +The following options are available for `s3_data_naming`: + +- `unique`: `{s3_data_dir}/{uuid4()}/` +- `table`: `{s3_data_dir}/{table}/` +- `table_unique`: `{s3_data_dir}/{table}/{uuid4()}/` +- `schema_table`: `{s3_data_dir}/{schema}/{table}/` +- `s3_data_naming=schema_table_unique`: `{s3_data_dir}/{schema}/{table}/{uuid4()}/` + +To set the `s3_data_naming` globally in the target profile, overwrite the value in the table config, or set up the value for groups of the models in dbt_project.yml. + +Note: If you're using a workgroup with a default output location configured, `s3_data_naming` ignores any configured buckets and uses the location configured in the workgroup. + +### Incremental models + +The following [incremental models](https://docs.getdbt.com/docs/build/incremental-models) strategies are supported: + +- `insert_overwrite` (default): The insert-overwrite strategy deletes the overlapping partitions from the destination table and then inserts the new records from the source. This strategy depends on the `partitioned_by` keyword! dbt will fall back to the `append` strategy if no partitions are defined. +- `append`: Insert new records without updating, deleting or overwriting any existing data. There might be duplicate data (great for log or historical data). +- `merge`: Conditionally updates, deletes, or inserts rows into an Iceberg table. Used in combination with `unique_key`.It is only available when using Iceberg. + + +### On schema change + +The `on_schema_change` option reflects changes of the schema in incremental models. The values you can set this to are: + +- `ignore` (default) +- `fail` +- `append_new_columns` +- `sync_all_columns` + +To learn more, refer to [What if the columns of my incremental model change](/docs/build/incremental-models#what-if-the-columns-of-my-incremental-model-change). + +### Iceberg + +The adapter supports table materialization for Iceberg. + +For example: + +```sql +{{ config( + materialized='table', + table_type='iceberg', + format='parquet', + partitioned_by=['bucket(user_id, 5)'], + table_properties={ + 'optimize_rewrite_delete_file_threshold': '2' + } +) }} + +select 'A' as user_id, + 'pi' as name, + 'active' as status, + 17.89 as cost, + 1 as quantity, + 100000000 as quantity_big, + current_date as my_date +``` + +Iceberg supports bucketing as hidden partitions. Use the `partitioned_by` config to add specific bucketing +conditions. + +Iceberg supports the `PARQUET`, `AVRO` and `ORC` table formats for data . + +The following are the supported strategies for using Iceberg incrementally: + +- `append`: New records are appended to the table (this can lead to duplicates). +- `merge`: Perform an update and insert (and optional delete) where new and existing records are added. This is only available with Athena engine version 3. + - `unique_key`(required): Columns that define a unique source and target table record. + - `incremental_predicates` (optional): The SQL conditions that enable custom join clauses in the merge statement. This helps improve performance via predicate pushdown on target tables. + - `delete_condition` (optional): SQL condition that identifies records that should be deleted. + - `update_condition` (optional): SQL condition that identifies records that should be updated. + - `insert_condition` (optional): SQL condition that identifies records that should be inserted. + +`incremental_predicates`, `delete_condition`, `update_condition` and `insert_condition` can include any column of the incremental table (`src`) or the final table (`target`). Column names must be prefixed by either `src` or `target` to prevent a `Column is ambiguous` error. + + + + + +```sql +{{ config( + materialized='incremental', + table_type='iceberg', + incremental_strategy='merge', + unique_key='user_id', + incremental_predicates=["src.quantity > 1", "target.my_date >= now() - interval '4' year"], + delete_condition="src.status != 'active' and target.my_date < now() - interval '2' year", + format='parquet' +) }} + +select 'A' as user_id, + 'pi' as name, + 'active' as status, + 17.89 as cost, + 1 as quantity, + 100000000 as quantity_big, + current_date as my_date +``` + + + + + +```sql +{{ config( + materialized='incremental', + incremental_strategy='merge', + unique_key=['id'], + update_condition='target.id > 1', + schema='sandbox' + ) +}} + +{% if is_incremental() %} + +select * from ( + values + (1, 'v1-updated') + , (2, 'v2-updated') +) as t (id, value) + +{% else %} + +select * from ( + values + (-1, 'v-1') + , (0, 'v0') + , (1, 'v1') + , (2, 'v2') +) as t (id, value) + +{% endif %} +``` + + + + + +```sql +{{ config( + materialized='incremental', + incremental_strategy='merge', + unique_key=['id'], + insert_condition='target.status != 0', + schema='sandbox' + ) +}} + +select * from ( + values + (1, 0) + , (2, 1) +) as t (id, status) + +``` + + + + + +### High availability (HA) table + +The current implementation of table materialization can lead to downtime, as the target table is dropped and re-created. For less destructive behavior, you can use the `ha` config on your `table` materialized models. It leverages the table versions feature of the glue catalog, which creates a temporary table and swaps the target table to the location of the temporary table. This materialization is only available for `table_type=hive` and requires using unique locations. For Iceberg, high availability is the default. + +By default, the materialization keeps the last 4 table versions,but you can change it by setting `versions_to_keep`. + +```sql +{{ config( + materialized='table', + ha=true, + format='parquet', + table_type='hive', + partitioned_by=['status'], + s3_data_naming='table_unique' +) }} + +select 'a' as user_id, + 'pi' as user_name, + 'active' as status +union all +select 'b' as user_id, + 'sh' as user_name, + 'disabled' as status +``` + + +#### HA known issues + +- There could be a little downtime when swapping from a table with partitions to a table without (and the other way around). If higher performance is needed, consider bucketing instead of partitions. +- By default, Glue "duplicates" the versions internally, so the last two versions of a table point to the same location. +- It's recommended to set `versions_to_keep` >= 4, as this will avoid having the older location removed. + +### Update glue data catalog + +You can persist your column and model level descriptions to the Glue Data Catalog as [glue table properties](https://docs.aws.amazon.com/glue/latest/dg/tables-described.html#table-properties) and [column parameters](https://docs.aws.amazon.com/glue/latest/webapi/API_Column.html). To enable this, set the configuration to `true` as shown in the following example. By default, documentation persistence is disabled, but it can be enabled for specific resources or groups of resources as needed. + + +For example: + +```yaml +models: + - name: test_deduplicate + description: another value + config: + persist_docs: + relation: true + columns: true + meta: + test: value + columns: + - name: id + meta: + primary_key: true +``` + +Refer to [persist_docs](https://docs.getdbt.com/reference/resource-configs/persist_docs) for more details. + +## Snapshots + +The adapter supports snapshot materialization. It supports both the timestamp and check strategies. To create a snapshot, create a snapshot file in the `snapshots` directory. You'll need to create this directory if it doesn't already exist. + +### Timestamp strategy + + +Refer to [Timestamp strategy](/docs/build/snapshots#timestamp-strategy-recommended) for details on how to use it. + + +### Check strategy + +Refer to [Check strategy](/docs/build/snapshots#check-strategy) for details on how to use it. + +### Hard deletes + +The materialization also supports invalidating hard deletes. For usage details, refer to [Hard deletes](/docs/build/snapshots#hard-deletes-opt-in). + +### Snapshots known issues + +- Incremental Iceberg models - Sync all columns on schema change. Columns used for partitioning can't be removed. From a dbt perspective, the only way is to fully refresh the incremental model. +- Tables, schemas and database names should only be lowercase +- To avoid potential conflicts, make sure [`dbt-athena-adapter`](https://github.com/Tomme/dbt-athena) is not installed in the target environment. +- Snapshot does not support dropping columns from the source table. If you drop a column, make sure to drop the column from the snapshot as well. Another workaround is to NULL the column in the snapshot definition to preserve the history. + +## AWS Lake Formation integration + +The following describes how the adapter implements the AWS Lake Formation tag management: + +- [Enable](#table-configuration) LF tags management with the `lf_tags_config` parameter. By default, it's disabled. +- Once enabled, LF tags are updated on every dbt run. +- First, all lf-tags for columns are removed to avoid inheritance issues. +- Then, all redundant lf-tags are removed from tables and actual tags from table configs are applied. +- Finally, lf-tags for columns are applied. + +It's important to understand the following points: + +- dbt doesn't manage `lf-tags` for databases +- dbt doesn't manage Lake Formation permissions + +That's why it's important to take care of this yourself or use an automation tool such as terraform and AWS CDK. For more details, refer to: + +* [terraform aws_lakeformation_permissions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lakeformation_permissions) +* [terraform aws_lakeformation_resource_lf_tags](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lakeformation_resource_lf_tags) + +## Python models + +The adapter supports Python models using [`spark`](https://docs.aws.amazon.com/athena/latest/ug/notebooks-spark.html). + +### Prerequisites + +- A Spark-enabled workgroup created in Athena. +- Spark execution role granted access to Athena, Glue and S3. +- The Spark workgroup is added to the `~/.dbt/profiles.yml` file and the profile to be used + is referenced in `dbt_project.yml`. + +### Spark-specific table configuration + +| Configuration | Default | Description | +|---------------|---------|--------------| +| `timeout` | 43200 | Time out in seconds for each Python model execution. Defaults to 12 hours/43200 seconds. | +| `spark_encryption` | False | When set to `true,` it encrypts data stored locally by Spark and in transit between Spark nodes. | +| `spark_cross_account_catalog` | False | When using the Spark Athena workgroup, queries can only be made against catalogs on the same AWS account by default. Setting this parameter to true will enable querying external catalogs if you want to query another catalog on an external AWS account.

    Use the syntax `external_catalog_id/database.table` to access the external table on the external catalog (For example, `999999999999/mydatabase.cloudfront_logs` where 999999999999 is the external catalog ID).| +| `spark_requester_pays` | False | When set to true, if an Amazon S3 bucket is configured as `requester pays`, the user account running the query is charged for data access and data transfer fees associated with the query. | + + +### Spark notes + +- A session is created for each unique engine configuration defined in the models that are part of the invocation. +A session's idle timeout is set to 10 minutes. Within the timeout period, if a new calculation (Spark Python model) is ready for execution and the engine configuration matches, the process will reuse the same session. +- The number of Python models running simultaneously depends on the `threads`. The number of sessions created for the entire run depends on the number of unique engine configurations and the availability of sessions to maintain thread concurrency. +- For Iceberg tables, it's recommended to use the `table_properties` configuration to set the `format_version` to `2`. This helps maintain compatibility between the Iceberg tables Trino created and those Spark created. + +### Example models + + + + + +```python +import pandas as pd + + +def model(dbt, session): + dbt.config(materialized="table") + + model_df = pd.DataFrame({"A": [1, 2, 3, 4]}) + + return model_df +``` + + + + + +```python +def model(dbt, spark_session): + dbt.config(materialized="table") + + data = [(1,), (2,), (3,), (4,)] + + df = spark_session.createDataFrame(data, ["A"]) + + return df +``` + + + + +```python +def model(dbt, spark_session): + dbt.config(materialized="incremental") + df = dbt.ref("model") + + if dbt.is_incremental: + max_from_this = ( + f"select max(run_date) from {dbt.this.schema}.{dbt.this.identifier}" + ) + df = df.filter(df.run_date >= spark_session.sql(max_from_this).collect()[0][0]) + + return df +``` + + + + + +```python +def model(dbt, spark_session): + dbt.config( + materialized="table", + engine_config={ + "CoordinatorDpuSize": 1, + "MaxConcurrentDpus": 3, + "DefaultExecutorDpuSize": 1 + }, + spark_encryption=True, + spark_cross_account_catalog=True, + spark_requester_pays=True + polling_interval=15, + timeout=120, + ) + + data = [(1,), (2,), (3,), (4,)] + + df = spark_session.createDataFrame(data, ["A"]) + + return df +``` + + + + + +Using imported external python files: + +```python +def model(dbt, spark_session): + dbt.config( + materialized="incremental", + incremental_strategy="merge", + unique_key="num", + ) + sc = spark_session.sparkContext + sc.addPyFile("s3://athena-dbt/test/file1.py") + sc.addPyFile("s3://athena-dbt/test/file2.py") + + def func(iterator): + from file2 import transform + + return [transform(i) for i in iterator] + + from pyspark.sql.functions import udf + from pyspark.sql.functions import col + + udf_with_import = udf(func) + + data = [(1, "a"), (2, "b"), (3, "c")] + cols = ["num", "alpha"] + df = spark_session.createDataFrame(data, cols) + + return df.withColumn("udf_test_col", udf_with_import(col("alpha"))) +``` + + + + + +### Known issues in Python models + +- Python models can't [reference Athena SQL views](https://docs.aws.amazon.com/athena/latest/ug/notebooks-spark.html). +- You can use third-party Python libraries; however, they must be [included in the pre-installed list][pre-installed list] or [imported manually][imported manually]. +- Python models can only reference or write to tables with names matching the regular expression: `^[0-9a-zA-Z_]+$`. Spark doesn't support dashes or special characters, even though Athena supports them. +- Incremental models don't fully utilize Spark capabilities. They depend partially on existing SQL-based logic that runs on Trino. +- Snapshot materializations are not supported. +- Spark can only reference tables within the same catalog. +- For tables created outside of the dbt tool, be sure to populate the location field, or dbt will throw an error when creating the table. + + +[pre-installed list]: https://docs.aws.amazon.com/athena/latest/ug/notebooks-spark-preinstalled-python-libraries.html +[imported manually]: https://docs.aws.amazon.com/athena/latest/ug/notebooks-import-files-libraries.html + +## Contracts + +The adapter partly supports contract definitions: + +- `data_type` is supported but needs to be adjusted for complex types. Types must be specified entirely (for example, `array`) even though they won't be checked. Indeed, as dbt recommends, we only compare the broader type (array, map, int, varchar). The complete definition is used to check that the data types defined in Athena are ok (pre-flight check). +- The adapter does not support the constraints since Athena has no constraint concept. + diff --git a/website/sidebars.js b/website/sidebars.js index c533975076b..b3b752990dd 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -844,26 +844,27 @@ const sidebarSettings = { type: "category", label: "Platform-specific configs", items: [ + "reference/resource-configs/athena-configs", + "reference/resource-configs/impala-configs", "reference/resource-configs/spark-configs", "reference/resource-configs/bigquery-configs", - "reference/resource-configs/databricks-configs", - "reference/resource-configs/fabric-configs", - "reference/resource-configs/postgres-configs", - "reference/resource-configs/redshift-configs", - "reference/resource-configs/snowflake-configs", - "reference/resource-configs/trino-configs", - "reference/resource-configs/impala-configs", "reference/resource-configs/clickhouse-configs", + "reference/resource-configs/databricks-configs", "reference/resource-configs/doris-configs", "reference/resource-configs/firebolt-configs", "reference/resource-configs/greenplum-configs", "reference/resource-configs/infer-configs", "reference/resource-configs/materialize-configs", "reference/resource-configs/azuresynapse-configs", + "reference/resource-configs/fabric-configs", "reference/resource-configs/mssql-configs", "reference/resource-configs/mindsdb-configs", "reference/resource-configs/oracle-configs", + "reference/resource-configs/postgres-configs", + "reference/resource-configs/redshift-configs", "reference/resource-configs/singlestore-configs", + "reference/resource-configs/snowflake-configs", + "reference/resource-configs/trino-configs", "reference/resource-configs/starrocks-configs", "reference/resource-configs/teradata-configs", "reference/resource-configs/upsolver-configs", From d30270146f9563423f7f7a8865197e03882a0662 Mon Sep 17 00:00:00 2001 From: Doug Beatty <44704949+dbeatty10@users.noreply.github.com> Date: Fri, 30 Aug 2024 03:26:17 -0600 Subject: [PATCH 08/49] Clarify current support level for contracts for materialized views (#5993) [Preview](https://docs-getdbt-com-git-dbeatty10-patch-1-dbt-labs.vercel.app/docs/collaborate/govern/model-contracts#where-are-contracts-supported) ## What are you changing in this pull request and why? - It isn't clear if materialized views have support for model contracts or not. - Also not clear if custom materializations automatically include support for model contracts or not. Context: https://github.com/dbt-labs/dbt-snowflake/issues/888 (`dynamic table` is the Snowflake equivalent of `materialized view` in other data platforms) ## Checklist - [x] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. --- website/docs/docs/collaborate/govern/model-contracts.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/docs/docs/collaborate/govern/model-contracts.md b/website/docs/docs/collaborate/govern/model-contracts.md index 9e59d089e49..e186609b746 100644 --- a/website/docs/docs/collaborate/govern/model-contracts.md +++ b/website/docs/docs/collaborate/govern/model-contracts.md @@ -28,7 +28,8 @@ At present, model contracts are supported for: Model contracts are _not_ supported for: - Python models. -- `ephemeral`-materialized SQL models. +- `materialized view` or `ephemeral`-materialized SQL models. +- Custom materializations (unless added by the author). - Models with recursive 's in BigQuery. - Other resource types, such as `sources`, `seeds`, `snapshots`, and so on. From 995f59e3e5bbc28e0d70c959e2ae3497531d20b1 Mon Sep 17 00:00:00 2001 From: Jessie Obeng Date: Mon, 2 Sep 2024 05:05:01 -0400 Subject: [PATCH 09/49] Update 5-the-rest-of-the-project.md (#5996) Replacing the url for fal, previous page presents a 404 error ## What are you changing in this pull request and why? On the website there is a URL that is broken leading to fal.ai's website. I have replaced it to go to the actual customer's website. ## Checklist - [x] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [x] The topic I'm writing about is for specific dbt version(s) and I have versioned it according to the [version a whole page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version) and/or [version a block of content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content) guidelines. - [x] I have added checklist item(s) to this list for anything anything that needs to happen before this PR is merged, such as "needs technical review" or "change base branch." --- .../how-we-structure/5-the-rest-of-the-project.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/best-practices/how-we-structure/5-the-rest-of-the-project.md b/website/docs/best-practices/how-we-structure/5-the-rest-of-the-project.md index 2dca148a226..21ea6ad4682 100644 --- a/website/docs/best-practices/how-we-structure/5-the-rest-of-the-project.md +++ b/website/docs/best-practices/how-we-structure/5-the-rest-of-the-project.md @@ -105,7 +105,7 @@ We’ve focused heavily thus far on the primary area of action in our dbt projec One important, growing consideration in the analytics engineering ecosystem is how and when to split a codebase into multiple dbt projects. Our present stance on this for most projects, particularly for teams starting out, is straightforward: you should avoid it unless you have no other option or it saves you from an even more complex workaround. If you do have the need to split up your project, it’s completely possible through the use of private packages, but the added complexity and separation is, for most organizations, a hindrance not a help, at present. That said, this is very likely subject to change! [We want to create a world where it’s easy to bring lots of dbt projects together into a cohesive lineage](https://github.com/dbt-labs/dbt-core/discussions/5244). In a world where it’s simple to break up monolithic dbt projects into multiple connected projects, perhaps inside of a modern monorepo, the calculus will be different, and the below situations we recommend against may become totally viable. So watch this space! - ❌ **Business groups or departments.** Conceptual separations within the project are not a good reason to split up your project. Splitting up, for instance, marketing and finance modeling into separate projects will not only add unnecessary complexity, but destroy the unifying effect of collaborating across your organization on cohesive definitions and business logic. -- ❌ **ML vs Reporting use cases.** Similarly to the point above, splitting a project up based on different use cases, particularly more standard BI versus ML features, is a common idea. We tend to discourage it for the time being. As with the previous point, a foundational goal of implementing dbt is to create a single source of truth in your organization. The features you’re providing to your data science teams should be coming from the same marts and metrics that serve reports on executive dashboards. There are a growing number of tools like [fal](https://blog.fal.ai/introducing-fal-dbt/) and [Continual.ai](http://Continual.ai) that make excellent use of this unified viewpoint. +- ❌ **ML vs Reporting use cases.** Similarly to the point above, splitting a project up based on different use cases, particularly more standard BI versus ML features, is a common idea. We tend to discourage it for the time being. As with the previous point, a foundational goal of implementing dbt is to create a single source of truth in your organization. The features you’re providing to your data science teams should be coming from the same marts and metrics that serve reports on executive dashboards. There are a growing number of tools like [fal](https://fal.ai/) and [Continual.ai](http://Continual.ai) that make excellent use of this unified viewpoint. - ✅ **Data governance.** Structural, organizational needs — such as data governance and security — are one of the few worthwhile reasons to split up a project. If, for instance, you work at a healthcare company with only a small team cleared to access raw data with PII in it, you may need to split out your staging models into their own project to preserve those policies. In that case, you would import your staging project into the project that builds on those staging models as a [private package](https://docs.getdbt.com/docs/build/packages/#private-packages). - ✅ **Project size.** At a certain point, your project may grow to have simply too many models to present a viable development experience. If you have 1000s of models, it absolutely makes sense to find a way to split up your project. From 80dcf47c80572367b5a2eeecc12b07399b0d8770 Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:57:56 +0100 Subject: [PATCH 10/49] remove sentence (#5997) this pr removes the last sentence of this guide as they do not apply anymore. refer to internal slack thread: https://dbt-labs.slack.com/archives/C02HE19D51R/p1725268090650929 --- .../how-we-structure/5-the-rest-of-the-project.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/best-practices/how-we-structure/5-the-rest-of-the-project.md b/website/docs/best-practices/how-we-structure/5-the-rest-of-the-project.md index 21ea6ad4682..c7522bf12eb 100644 --- a/website/docs/best-practices/how-we-structure/5-the-rest-of-the-project.md +++ b/website/docs/best-practices/how-we-structure/5-the-rest-of-the-project.md @@ -102,11 +102,11 @@ We’ve focused heavily thus far on the primary area of action in our dbt projec ### Project splitting -One important, growing consideration in the analytics engineering ecosystem is how and when to split a codebase into multiple dbt projects. Our present stance on this for most projects, particularly for teams starting out, is straightforward: you should avoid it unless you have no other option or it saves you from an even more complex workaround. If you do have the need to split up your project, it’s completely possible through the use of private packages, but the added complexity and separation is, for most organizations, a hindrance not a help, at present. That said, this is very likely subject to change! [We want to create a world where it’s easy to bring lots of dbt projects together into a cohesive lineage](https://github.com/dbt-labs/dbt-core/discussions/5244). In a world where it’s simple to break up monolithic dbt projects into multiple connected projects, perhaps inside of a modern monorepo, the calculus will be different, and the below situations we recommend against may become totally viable. So watch this space! +One important, growing consideration in the analytics engineering ecosystem is how and when to split a codebase into multiple dbt projects. Our present stance on this for most projects, particularly for teams starting out, is straightforward: you should avoid it unless you have no other option or it saves you from an even more complex workaround. If you do have the need to split up your project, it’s completely possible through the use of private packages, but the added complexity and separation is, for most organizations, a hindrance, not a help, at present. That said, this is very likely subject to change! [We want to create a world where it’s easy to bring lots of dbt projects together into a cohesive lineage](https://github.com/dbt-labs/dbt-core/discussions/5244). In a world where it’s simple to break up monolithic dbt projects into multiple connected projects, perhaps inside of a modern mono repo, the calculus will be different, and the below situations we recommend against may become totally viable. So watch this space! -- ❌ **Business groups or departments.** Conceptual separations within the project are not a good reason to split up your project. Splitting up, for instance, marketing and finance modeling into separate projects will not only add unnecessary complexity, but destroy the unifying effect of collaborating across your organization on cohesive definitions and business logic. -- ❌ **ML vs Reporting use cases.** Similarly to the point above, splitting a project up based on different use cases, particularly more standard BI versus ML features, is a common idea. We tend to discourage it for the time being. As with the previous point, a foundational goal of implementing dbt is to create a single source of truth in your organization. The features you’re providing to your data science teams should be coming from the same marts and metrics that serve reports on executive dashboards. There are a growing number of tools like [fal](https://fal.ai/) and [Continual.ai](http://Continual.ai) that make excellent use of this unified viewpoint. -- ✅ **Data governance.** Structural, organizational needs — such as data governance and security — are one of the few worthwhile reasons to split up a project. If, for instance, you work at a healthcare company with only a small team cleared to access raw data with PII in it, you may need to split out your staging models into their own project to preserve those policies. In that case, you would import your staging project into the project that builds on those staging models as a [private package](https://docs.getdbt.com/docs/build/packages/#private-packages). +- ❌ **Business groups or departments.** Conceptual separations within the project are not a good reason to split up your project. Splitting up, for instance, marketing and finance modeling into separate projects will not only add unnecessary complexity but destroy the unifying effect of collaborating across your organization on cohesive definitions and business logic. +- ❌ **ML vs Reporting use cases.** Similarly to the point above, splitting a project up based on different use cases, particularly more standard BI versus ML features, is a common idea. We tend to discourage it for the time being. As with the previous point, a foundational goal of implementing dbt is to create a single source of truth in your organization. The features you’re providing to your data science teams should be coming from the same marts and metrics that serve reports on executive dashboards. +- ✅ **Data governance.** Structural, organizational needs — such as data governance and security — are one of the few worthwhile reasons to split up a project. If, for instance, you work at a healthcare company with only a small team cleared to access raw data with PII in it, you may need to split out your staging models into their own projects to preserve those policies. In that case, you would import your staging project into the project that builds on those staging models as a [private package](https://docs.getdbt.com/docs/build/packages/#private-packages). - ✅ **Project size.** At a certain point, your project may grow to have simply too many models to present a viable development experience. If you have 1000s of models, it absolutely makes sense to find a way to split up your project. ## Final considerations From 29578699ab676cc69b5d6a49cb544aea9cbcdbc3 Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Mon, 2 Sep 2024 15:29:02 +0100 Subject: [PATCH 11/49] add file names for clarity (#5998) this pr adds a `` to the code examples or `` --- website/docs/docs/build/metricflow-time-spine.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/website/docs/docs/build/metricflow-time-spine.md b/website/docs/docs/build/metricflow-time-spine.md index 23040459ea4..6ee72e57cc1 100644 --- a/website/docs/docs/build/metricflow-time-spine.md +++ b/website/docs/docs/build/metricflow-time-spine.md @@ -19,7 +19,8 @@ Previously, you were required to create a model called `metricflow_time_spine` i - + + ```yaml models: - name: time_spine_hourly @@ -35,6 +36,7 @@ models: - name: date_day granularity: day # set granularity at column-level for standard_granularity_column ``` + Now, break down the configuration above. It's pointing to a model called `time_spine_daily`. It sets the time spine configurations under the `time_spine` key. The `standard_granularity_column` is the lowest grain of the table, in this case, it's hourly. It needs to reference a column defined under the columns key, in this case, `date_hour`. Use the `standard_granularity_column` as the join key for the time spine table when joining tables in MetricFlow. Here, the granularity of the `standard_granularity_column` is set at the column level, in this case, `hour`. @@ -83,6 +85,8 @@ and date_hour < dateadd(day, 30, current_timestamp()) + + ```sql {{ config( @@ -111,6 +115,7 @@ select * from final where date_day > dateadd(year, -4, current_timestamp()) and date_hour < dateadd(day, 30, current_timestamp()) ``` + @@ -118,8 +123,9 @@ and date_hour < dateadd(day, 30, current_timestamp()) + + ```sql --- filename: metricflow_time_spine.sql -- BigQuery supports DATE() instead of TO_DATE(). Use this model if you're using BigQuery {{config(materialized='table')}} with days as ( @@ -142,13 +148,15 @@ from final where date_day > dateadd(year, -4, current_timestamp()) and date_hour < dateadd(day, 30, current_timestamp()) ``` + + + ```sql --- filename: metricflow_time_spine.sql -- BigQuery supports DATE() instead of TO_DATE(). Use this model if you're using BigQuery {{config(materialized='table')}} with days as ( @@ -171,6 +179,7 @@ from final where date_day > dateadd(year, -4, current_timestamp()) and date_hour < dateadd(day, 30, current_timestamp()) ``` + @@ -178,7 +187,6 @@ and date_hour < dateadd(day, 30, current_timestamp()) ```sql --- filename: metricflow_time_spine_hour.sql {{ config( materialized = 'table', From fb636f1349a86bee79443204416e70f776f88e79 Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Mon, 2 Sep 2024 15:36:19 +0100 Subject: [PATCH 12/49] Update metricflow-time-spine.md fold in natalie's feedback --- website/docs/docs/build/metricflow-time-spine.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/website/docs/docs/build/metricflow-time-spine.md b/website/docs/docs/build/metricflow-time-spine.md index 6ee72e57cc1..ec2d9bf1862 100644 --- a/website/docs/docs/build/metricflow-time-spine.md +++ b/website/docs/docs/build/metricflow-time-spine.md @@ -47,10 +47,10 @@ The example creates a time spine at a daily grain and an hourly grain. A few thi * You can add a time spine for each granularity you intend to use if query efficiency is more important to you than configuration time, or storage constraints. For most engines, the query performance difference should be minimal and transforming your time spine to a coarser grain at query time shouldn't add significant overhead to your queries. * We recommend having a time spine at the finest grain used in any of your dimensions to avoid unexpected errors. i.e., if you have dimensions at an hourly grain, you should have a time spine at an hourly grain. - - + + ```sql {{ config( @@ -80,6 +80,7 @@ select * from final where date_day > dateadd(year, -4, current_timestamp()) and date_hour < dateadd(day, 30, current_timestamp()) ``` + From 51e21083d2a6a9efb9c1591b04ad2f98442572d8 Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:05:51 +0100 Subject: [PATCH 13/49] Update metricflow-time-spine.md (#6000) fix file name position --- .../docs/docs/build/metricflow-time-spine.md | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/website/docs/docs/build/metricflow-time-spine.md b/website/docs/docs/build/metricflow-time-spine.md index ec2d9bf1862..9730313d60d 100644 --- a/website/docs/docs/build/metricflow-time-spine.md +++ b/website/docs/docs/build/metricflow-time-spine.md @@ -47,9 +47,9 @@ The example creates a time spine at a daily grain and an hourly grain. A few thi * You can add a time spine for each granularity you intend to use if query efficiency is more important to you than configuration time, or storage constraints. For most engines, the query performance difference should be minimal and transforming your time spine to a coarser grain at query time shouldn't add significant overhead to your queries. * We recommend having a time spine at the finest grain used in any of your dimensions to avoid unexpected errors. i.e., if you have dimensions at an hourly grain, you should have a time spine at an hourly grain. - + - + ```sql {{ @@ -80,14 +80,11 @@ select * from final where date_day > dateadd(year, -4, current_timestamp()) and date_hour < dateadd(day, 30, current_timestamp()) ``` - - - ```sql {{ config( @@ -116,15 +113,9 @@ select * from final where date_day > dateadd(year, -4, current_timestamp()) and date_hour < dateadd(day, 30, current_timestamp()) ``` - - - - - - ```sql -- BigQuery supports DATE() instead of TO_DATE(). Use this model if you're using BigQuery @@ -149,13 +140,10 @@ from final where date_day > dateadd(year, -4, current_timestamp()) and date_hour < dateadd(day, 30, current_timestamp()) ``` - - - ```sql -- BigQuery supports DATE() instead of TO_DATE(). Use this model if you're using BigQuery @@ -180,9 +168,8 @@ from final where date_day > dateadd(year, -4, current_timestamp()) and date_hour < dateadd(day, 30, current_timestamp()) ``` - - + ## Hourly time spine From ea9f88b4eca4ef409816f0d507d7ed3922f4c244 Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:27:38 +0100 Subject: [PATCH 14/49] adding x proj ref to overview page (#5999) --- website/docs/docs/build/metricflow-time-spine.md | 15 +++++++++++---- .../collaborate/govern/about-model-governance.md | 2 ++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/website/docs/docs/build/metricflow-time-spine.md b/website/docs/docs/build/metricflow-time-spine.md index 9730313d60d..18acf451a12 100644 --- a/website/docs/docs/build/metricflow-time-spine.md +++ b/website/docs/docs/build/metricflow-time-spine.md @@ -115,10 +115,13 @@ and date_hour < dateadd(day, 30, current_timestamp()) ``` + +Use this model if you're using BigQuery. BigQuery supports `DATE()` instead of `TO_DATE()`: + + ```sql --- BigQuery supports DATE() instead of TO_DATE(). Use this model if you're using BigQuery {{config(materialized='table')}} with days as ( {{dbt_utils.date_spine( @@ -140,13 +143,15 @@ from final where date_day > dateadd(year, -4, current_timestamp()) and date_hour < dateadd(day, 30, current_timestamp()) ``` - + - + + + ```sql --- BigQuery supports DATE() instead of TO_DATE(). Use this model if you're using BigQuery + {{config(materialized='table')}} with days as ( {{dbt.date_spine( @@ -168,7 +173,9 @@ from final where date_day > dateadd(year, -4, current_timestamp()) and date_hour < dateadd(day, 30, current_timestamp()) ``` + + ## Hourly time spine diff --git a/website/docs/docs/collaborate/govern/about-model-governance.md b/website/docs/docs/collaborate/govern/about-model-governance.md index a845e941e54..195b1d03caa 100644 --- a/website/docs/docs/collaborate/govern/about-model-governance.md +++ b/website/docs/docs/collaborate/govern/about-model-governance.md @@ -11,3 +11,5 @@ pagination_prev: null [**Model contracts**](model-contracts): Guarantee the shape of a model while it is building to avoid surprises or breaking changes for downstream queries. Explicitly define column names, data types, and constraints (as supported by your data platform). [**Model versions**](model-versions): When a breaking change is unavoidable, provide a smoother upgrade pathway by creating a new version of the model. These model versions share a common reference name and can reuse properties & configurations. + +[**Project dependencies**](/docs/collaborate/govern/project-dependencies): Use cross project dependencies to reference public models across dbt projects using the [two-argument ref](/reference/dbt-jinja-functions/ref#ref-project-specific-models), which includes the project name. From 6eb12f46fc09058621711e49cd993c8938f4ce28 Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:18:48 +0100 Subject: [PATCH 15/49] update callout and clarify title to blog (#6001) this pr updates the title so it's clear it's for dbt core users. and also adds a callout to link to a bitbucket guide for dbt cloud users. [internal slack thread](https://dbt-labs.slack.com/archives/C06V62247K5/p1725345980389369?thread_ts=1725334647.490049&cid=C06V62247K5) --- website/blog/2022-04-14-add-ci-cd-to-bitbucket.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/website/blog/2022-04-14-add-ci-cd-to-bitbucket.md b/website/blog/2022-04-14-add-ci-cd-to-bitbucket.md index 44346e93741..eae8d595ca5 100644 --- a/website/blog/2022-04-14-add-ci-cd-to-bitbucket.md +++ b/website/blog/2022-04-14-add-ci-cd-to-bitbucket.md @@ -1,5 +1,5 @@ --- -title: "Slim CI/CD with Bitbucket Pipelines" +title: "Slim CI/CD with Bitbucket Pipelines for dbt Core" description: "How to set up slim CI/CD outside of dbt Cloud" slug: slim-ci-cd-with-bitbucket-pipelines @@ -12,6 +12,11 @@ date: 2022-05-06 is_featured: true --- + +:::info Set up CI/CD with dbt Cloud +This blog is specifically tailored for dbt Core users. If you're using dbt Cloud and your Git provider doesn't have a native dbt Cloud integration (like BitBucket), follow the [Customizing CI/CD with custom pipelines guide](/guides/custom-cicd-pipelines?step=3) to set up CI/CD. +::: + Continuous Integration (CI) sets the system up to test everyone’s pull request before merging. Continuous Deployment (CD) deploys each approved change to production. “Slim CI” refers to running/testing only the changed code, [thereby saving compute](https://discourse.getdbt.com/t/how-we-sped-up-our-ci-runs-by-10x-using-slim-ci/2603). In summary, CI/CD automates dbt pipeline testing and deployment. [dbt Cloud](https://www.getdbt.com/), a much beloved method of dbt deployment, [supports GitHub- and Gitlab-based CI/CD](https://blog.getdbt.com/adopting-ci-cd-with-dbt-cloud/) out of the box. It doesn’t support Bitbucket, AWS CodeCommit/CodeDeploy, or any number of other services, but you need not give up hope even if you are tethered to an unsupported platform. From 9a869c6ace3338c3ce82202348cf592aabe584ef Mon Sep 17 00:00:00 2001 From: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> Date: Tue, 3 Sep 2024 17:45:19 -0400 Subject: [PATCH 16/49] Updating multi cell migration page (#6002) ## What are you changing in this pull request and why? Updating the migration checklist based on recent changes. Many older manual items are now automated, so customers need to take a minimum of actions. ## Checklist - [ ] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [ ] The topic I'm writing about is for specific dbt version(s) and I have versioned it according to the [version a whole page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version) and/or [version a block of content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content) guidelines. - [ ] I have added checklist item(s) to this list for anything anything that needs to happen before this PR is merged, such as "needs technical review" or "change base branch." --------- Co-authored-by: Leona B. Campbell <3880403+runleonarun@users.noreply.github.com> --- website/docs/docs/cloud/migration.md | 51 +++++++++++++++++----------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/website/docs/docs/cloud/migration.md b/website/docs/docs/cloud/migration.md index 8bdf47eae5a..3aec1956297 100644 --- a/website/docs/docs/cloud/migration.md +++ b/website/docs/docs/cloud/migration.md @@ -7,34 +7,45 @@ pagination_next: null pagination_prev: null --- -dbt Labs is in the process of migrating dbt Cloud to a new _cell-based architecture_. This architecture will be the foundation of dbt Cloud for years to come, and will bring improved scalability, reliability, and security to all customers and users of dbt Cloud. +dbt Labs is in the process of rolling out a new cell-based architecture for dbt Cloud. This architecture provides the foundation of dbt Cloud for years to come, and brings improved reliability, performance, and consistency to users of dbt Cloud. -There is some preparation required to ensure a successful migration. +We're scheduling migrations by account. When we're ready to migrate your account, you will receive a banner or email communication with your migration date. If you have not received this communication, then you don't need to take action at this time. dbt Labs will share information about your migration with you, with appropriate advance notice, when applicable to your account. -Migrations are being scheduled on a per-account basis. _If you haven't received any communication (either with a banner or by email) about a migration date, you don't need to take any action at this time._ dbt Labs will share migration date information with you, with appropriate advance notice, before we complete any migration steps in the dbt Cloud backend. +Your account will be automatically migrated on its scheduled date. However, if you use certain features, you must take action before that date to avoid service disruptions. -This document outlines the steps that you must take to prevent service disruptions before your environment is migrated over to the cell-based architecture. This will impact areas such as login, IP restrictions, and API access. +## Recommended actions -## Pre-migration checklist +We highly recommended you take these actions: -Prior to your migration date, your dbt Cloud account admin will need to make some changes to your account. Most of your configurations will be migrated automatically, but a few will require manual intervention. +- Ensure pending user invitations are accepted or note outstanding invitations. Pending user invitations will be voided during the migration and must be resent after it is complete. +- Commit unsaved changes in the [dbt Cloud IDE](/docs/cloud/dbt-cloud-ide/develop-in-the-cloud). Unsaved changes will be lost during migration. +- Export and download [audit logs](/docs/cloud/manage-access/audit-log) older than 90 days, as they will be lost during migration. If you lose critical logs older than 90 days during the migration, you will have to work with the dbt Labs Customer Support team to recover. -If your account is scheduled for migration, you will see a banner indicating your migration date when you log in. If you don't see a banner, you don't need to take any action. +## Required actions -1. **IP addresses** — dbt Cloud will be using new IPs to access your warehouse after the migration. Make sure to allow inbound traffic from these IPs in your firewall and include it in any database grants. All six of the IPs below should be added to allowlists. - * Old IPs: `52.45.144.63`, `54.81.134.249`, `52.22.161.231` - * New IPs: `52.3.77.232`, `3.214.191.130`, `34.233.79.135` -2. **User invitations** — Any pending user invitations will be invalidated during the migration. You can resend the invitations after the migration is complete. -3. **SSO integrations** — If you've completed the Auth0 migration, your account SSO configurations will be automatically transferred. If you haven't completed the Auth0 migration, dbt Labs recommends doing that before starting the mult-cell migration to avoid service disruptions. -4. **IDE sessions** — Any unsaved changes in the IDE might be lost during migration. dbt Labs _strongly_ recommends committing all changes in the IDE before your scheduled migration time. +These actions are required to prevent users from losing access dbt Cloud: -## Post-migration +- If you still need to, complete [Auth0 migration for SSO](/docs/cloud/manage-access/auth0-migration) before your scheduled migration date to avoid service disruptions. If you've completed the Auth0 migration, your account SSO configurations will be transferred automatically. +- Update your IP allow lists. dbt Cloud will be using new IPs to access your warehouse post-migration. Allow inbound traffic from all of the following new IPs in your firewall and include them in any database grants: -After migration, if you completed all the [Pre-migration checklist](#pre-migration-checklist) items, your dbt Cloud resources and jobs will continue to work as they did before. + - `52.3.77.232` + - `3.214.191.130` + - `34.233.79.135` -You have the option to log in to dbt Cloud at a different URL: - * If you were previously logging in at `cloud.getdbt.com`, you should instead plan to login at `us1.dbt.com`. The original URL will still work, but you’ll have to click through to be redirected upon login. - * You may also log in directly with your account’s unique [access URL](/docs/cloud/about-cloud/access-regions-ip-addresses#accessing-your-account). + Keep the old dbt Cloud IPs listed until the migration is complete. -:::info Login with GitHub -Users who previously used the "Login with GitHub" functionality will no longer be able to use this method to login to dbt Cloud after migration. To continue accessing your account, you can use your existing email and password. +## Post-migration​ + +Complete all of these items to ensure your dbt Cloud resources and jobs will continue working without interruption. + +Use one of these two URL login options: + +- `us1.dbt.com.` If you were previously logging in at `cloud.getdbt.com`, you should instead plan to log in at us1.dbt.com. The original URL will still work, but you’ll have to click through to be redirected upon login. +- `ACCOUNT_PREFIX.us1.dbt.com`: A unique URL specifically for your account. If you belong to multiple accounts, each will have a unique URL available as long as they have been migrated to multi-cell. +Check out [access, regions, and IP addresses](/docs/cloud/about-cloud/access-regions-ip-addresses) for more information. + +Remove the following old IP addresses from your firewall and database grants: + +- `52.45.144.63` +- `54.81.134.249` +- `52.22.161.231` From 331c95a62b932cd6385ae92debf84d20cea6d8c5 Mon Sep 17 00:00:00 2001 From: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> Date: Tue, 3 Sep 2024 19:15:50 -0400 Subject: [PATCH 17/49] Updating beta banner (#6004) ## What are you changing in this pull request and why? Based on some recent changes we've made (and may continue to make) around versions, updating the banner to be more generic and some of the language ## Checklist - [ ] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [ ] The topic I'm writing about is for specific dbt version(s) and I have versioned it according to the [version a whole page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version) and/or [version a block of content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content) guidelines. - [ ] I have added checklist item(s) to this list for anything anything that needs to happen before this PR is merged, such as "needs technical review" or "change base branch." --------- Co-authored-by: Leona B. Campbell <3880403+runleonarun@users.noreply.github.com> --- website/src/theme/DocRoot/Layout/Main/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/theme/DocRoot/Layout/Main/index.js b/website/src/theme/DocRoot/Layout/Main/index.js index 7303e484863..29e7efdc253 100644 --- a/website/src/theme/DocRoot/Layout/Main/index.js +++ b/website/src/theme/DocRoot/Layout/Main/index.js @@ -71,7 +71,7 @@ export default function DocRootLayoutMain({ } else { setPreData({ showisPrereleaseBanner: true, - isPrereleaseBannerText: `You are currently viewing v${dbtVersion}, which is a prerelease of dbt Core. The latest stable version is v${latestStableRelease}`, + isPrereleaseBannerText: `You are viewing the docs for a prerelease version of dbt Core. There may be features described that are still in development, incomplete, or unstable.`, }); } // If EOLDate not set for version, do not show banner From 53227181c9f31d3eceea4cef85186c9a0f982284 Mon Sep 17 00:00:00 2001 From: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:17:49 -0400 Subject: [PATCH 18/49] Update EOL banners (#6009) ## What are you changing in this pull request and why? Updating the EOL banner texts, removing versions and fixing links in the text. ## Checklist - [ ] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [ ] The topic I'm writing about is for specific dbt version(s) and I have versioned it according to the [version a whole page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version) and/or [version a block of content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content) guidelines. - [ ] I have added checklist item(s) to this list for anything anything that needs to happen before this PR is merged, such as "needs technical review" or "change base branch." --------- Co-authored-by: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> --- website/src/theme/DocRoot/Layout/Main/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/theme/DocRoot/Layout/Main/index.js b/website/src/theme/DocRoot/Layout/Main/index.js index 29e7efdc253..458cb9d8716 100644 --- a/website/src/theme/DocRoot/Layout/Main/index.js +++ b/website/src/theme/DocRoot/Layout/Main/index.js @@ -71,7 +71,7 @@ export default function DocRootLayoutMain({ } else { setPreData({ showisPrereleaseBanner: true, - isPrereleaseBannerText: `You are viewing the docs for a prerelease version of dbt Core. There may be features described that are still in development, incomplete, or unstable.`, + isPrereleaseBannerText: `You are viewing the docs for a prerelease version of dbt Core. There may be features described that are still in development, incomplete, or unstable. For the latest generally available features, install the
    latest stable version`, }); } // If EOLDate not set for version, do not show banner @@ -86,12 +86,12 @@ export default function DocRootLayoutMain({ if (new Date() > new Date(EOLDate)) { setEOLData({ showEOLBanner: true, - EOLBannerText: `This version of dbt Core is no longer supported. No patch releases will be made, even for critical security issues. For better performance, improved security, and new features, you should upgrade to ${latestStableRelease}, the latest stable version.`, + EOLBannerText: `This version of dbt Core is no longer supported. There will be no more patches or security fixes. For improved performance, security, and features, upgrade to the latest stable version.`, }); } else if (new Date() > threeMonths) { setEOLData({ showEOLBanner: true, - EOLBannerText: `This version of dbt Core is nearing the end of its critical support period. For better performance, improved security, and new features, you should upgrade to ${latestStableRelease}, the latest stable version.`, + EOLBannerText: `This version of dbt Core is nearing the end of its critical support period. For improved perfomance, security, and features, upgrade to the latest stable version.`, }); } else { setEOLData({ From 54fce192191cca139413b1f8ea265c9ac9c9f329 Mon Sep 17 00:00:00 2001 From: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:17:18 -0400 Subject: [PATCH 19/49] Removing github login (#6010) ## What are you changing in this pull request and why? Removing GitHub login from dbt Cloud - Removed/edited content on the GitHub integration page - Edited links - Added a release note ## Checklist - [ ] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [ ] The topic I'm writing about is for specific dbt version(s) and I have versioned it according to the [version a whole page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version) and/or [version a block of content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content) guidelines. - [ ] I have added checklist item(s) to this list for anything anything that needs to happen before this PR is merged, such as "needs technical review" or "change base branch." --------- Co-authored-by: Ly Nguyen <107218380+nghi-ly@users.noreply.github.com> --- website/docs/docs/cloud/about-cloud/browsers.md | 2 +- website/docs/docs/cloud/git/connect-github.md | 9 ++++----- website/docs/docs/dbt-versions/release-notes.md | 1 + 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/website/docs/docs/cloud/about-cloud/browsers.md b/website/docs/docs/cloud/about-cloud/browsers.md index 12665bc7b72..1e26d3a6d59 100644 --- a/website/docs/docs/cloud/about-cloud/browsers.md +++ b/website/docs/docs/cloud/about-cloud/browsers.md @@ -27,4 +27,4 @@ To improve your experience using dbt Cloud, we suggest that you turn off ad bloc A session is a period of time during which you’re signed in to a dbt Cloud account from a browser. If you close your browser, it will end your session and log you out. You'll need to log in again the next time you try to access dbt Cloud. -If you've logged in using [SSO](/docs/cloud/manage-access/sso-overview) or [OAuth](/docs/cloud/git/connect-github#personally-authenticate-with-github), you can customize your maximum session duration, which might vary depending on your identity provider (IdP). +If you've logged in using [SSO](/docs/cloud/manage-access/sso-overview), you can customize your maximum session duration, which might vary depending on your identity provider (IdP). diff --git a/website/docs/docs/cloud/git/connect-github.md b/website/docs/docs/cloud/git/connect-github.md index 4dc4aaf73e9..f230f70e1f6 100644 --- a/website/docs/docs/cloud/git/connect-github.md +++ b/website/docs/docs/cloud/git/connect-github.md @@ -7,7 +7,6 @@ sidebar_label: "Connect to GitHub" Connecting your GitHub account to dbt Cloud provides convenience and another layer of security to dbt Cloud: -- Log into dbt Cloud using OAuth through GitHub. - Import new GitHub repositories with a couple clicks during dbt Cloud project setup. - Clone repos using HTTPS rather than SSH. - Trigger [Continuous integration](/docs/deploy/continuous-integration)(CI) builds when pull requests are opened in GitHub. @@ -48,15 +47,15 @@ To connect your dbt Cloud account to your GitHub account: - Read and write access to Workflows 6. Once you grant access to the app, you will be redirected back to dbt Cloud and shown a linked account success state. You are now personally authenticated. -7. Ask your team members to [personally authenticate](/docs/cloud/git/connect-github#personally-authenticate-with-github) by connecting their GitHub profiles. +7. Ask your team members to individually authenticate by connecting their [personal GitHub profiles](#authenticate-your-personal-github-account). ## Limiting repository access in GitHub If you are your GitHub organization owner, you can also configure the dbt Cloud GitHub application to have access to only select repositories. This configuration must be done in GitHub, but we provide an easy link in dbt Cloud to start this process. -## Personally authenticate with GitHub +## Authenticate your personal GitHub account -Once the dbt Cloud admin has [set up a connection](/docs/cloud/git/connect-github#installing-dbt-cloud-in-your-github-account) to your organization GitHub account, you need to personally authenticate, which improves the security of dbt Cloud by enabling you to log in using OAuth through GitHub. +After the dbt Cloud administrator [sets up a connection](/docs/cloud/git/connect-github#installing-dbt-cloud-in-your-github-account) to your organization's GitHub account, you need to authenticate using your personal account. You must connect your personal GitHub profile to dbt Cloud to use the [dbt Cloud IDE](/docs/cloud/dbt-cloud-ide/develop-in-the-cloud) and [CLI](/docs/cloud/cloud-cli-installation) and verify your read and write access to the repository. :::info GitHub profile connection @@ -77,7 +76,7 @@ To connect a personal GitHub account: 4. Once you approve authorization, you will be redirected to dbt Cloud, and you should now see your connected account. -The next time you log into dbt Cloud, you will be able to do so via OAuth through GitHub, and if you're on the Enterprise plan, you're ready to use the dbt Cloud IDE or dbt Cloud CLI. +You can now use the dbt Cloud IDE or dbt Cloud CLI. ## FAQs diff --git a/website/docs/docs/dbt-versions/release-notes.md b/website/docs/docs/dbt-versions/release-notes.md index a9db34334ad..57aadba284d 100644 --- a/website/docs/docs/dbt-versions/release-notes.md +++ b/website/docs/docs/dbt-versions/release-notes.md @@ -19,6 +19,7 @@ Release notes are grouped by month for both multi-tenant and virtual private clo \* The official release date for this new format of release notes is May 15th, 2024. Historical release notes for prior dates may not reflect all available features released earlier this year or their tenancy availability. ## August 2024 +- **Behavior change:** GitHub is no longer supported for OAuth login to dbt Cloud. Use a supported [SSO or OAuth provider](/docs/cloud/manage-access/sso-overview) to securely manage access to your dbt Cloud account. - **New**: You can now configure metrics at granularities at finer time grains, such as hour, minute, or even by the second. This is particularly useful for more detailed analysis and for datasets where high-resolution time data is required, such as minute-by-minute event tracking. Refer to [dimensions](/docs/build/dimensions) for more information about time granularity. ## July 2024 From 3b596ebf18e54894134416fbbb41c0be0714a498 Mon Sep 17 00:00:00 2001 From: Lana <100206579+Lana-hl@users.noreply.github.com> Date: Thu, 5 Sep 2024 02:41:19 -0600 Subject: [PATCH 20/49] Update set-up-snowflake-oauth.md (#6015) Adding quotes to `OAUTH_REDIRECT_URI` value as it doesn't work without the quotes ## What are you changing in this pull request and why? ## Checklist - [ ] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [ ] The topic I'm writing about is for specific dbt version(s) and I have versioned it according to the [version a whole page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version) and/or [version a block of content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content) guidelines. - [ ] I have added checklist item(s) to this list for anything anything that needs to happen before this PR is merged, such as "needs technical review" or "change base branch." --- website/docs/docs/cloud/manage-access/set-up-snowflake-oauth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/cloud/manage-access/set-up-snowflake-oauth.md b/website/docs/docs/cloud/manage-access/set-up-snowflake-oauth.md index 3b3b9c2d870..e9c4236438e 100644 --- a/website/docs/docs/cloud/manage-access/set-up-snowflake-oauth.md +++ b/website/docs/docs/cloud/manage-access/set-up-snowflake-oauth.md @@ -43,7 +43,7 @@ CREATE OR REPLACE SECURITY INTEGRATION DBT_CLOUD ENABLED = TRUE OAUTH_CLIENT = CUSTOM OAUTH_CLIENT_TYPE = 'CONFIDENTIAL' - OAUTH_REDIRECT_URI = LOCATED_REDIRECT_URI + OAUTH_REDIRECT_URI = 'LOCATED_REDIRECT_URI' OAUTH_ISSUE_REFRESH_TOKENS = TRUE OAUTH_REFRESH_TOKEN_VALIDITY = 7776000; ``` From a923185b853f5700b364bbeb02451d5d580e59bb Mon Sep 17 00:00:00 2001 From: Doug Beatty <44704949+dbeatty10@users.noreply.github.com> Date: Thu, 5 Sep 2024 02:51:19 -0600 Subject: [PATCH 21/49] Fix config names for hooks for `properties.yml` (#6007) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Preview](https://docs-getdbt-com-git-dbeatty10-patch-1-dbt-labs.vercel.app/reference/seed-configs#general-configurations) - General configurations > Property file ## What are you changing in this pull request and why? Fixes per https://github.com/dbt-labs/dbt-core/issues/10650#issuecomment-2328348338 ## 🎩 image ## Checklist - [x] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [x] The topic I'm writing about applies to all dbt versions Co-authored-by: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> --- website/docs/reference/seed-configs.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/reference/seed-configs.md b/website/docs/reference/seed-configs.md index dd733795eef..5d5c39071d6 100644 --- a/website/docs/reference/seed-configs.md +++ b/website/docs/reference/seed-configs.md @@ -113,8 +113,8 @@ seeds: config: [enabled](/reference/resource-configs/enabled): true | false [tags](/reference/resource-configs/tags): | [] - [pre-hook](/reference/resource-configs/pre-hook-post-hook): | [] - [post-hook](/reference/resource-configs/pre-hook-post-hook): | [] + [pre_hook](/reference/resource-configs/pre-hook-post-hook): | [] + [post_hook](/reference/resource-configs/pre-hook-post-hook): | [] [database](/reference/resource-configs/database): [schema](/reference/resource-properties/schema): [alias](/reference/resource-configs/alias): From 4d1591cd13b9302949e648663ff61ea6052318ed Mon Sep 17 00:00:00 2001 From: Perth Ngarmtrakulchol Date: Thu, 5 Sep 2024 19:01:49 +1000 Subject: [PATCH 22/49] Add a text in docs to prevent using -- for comment. (#6006) The error message (local variable 'connection' referenced before assignment) when using `--` doesn't indicate the actual syntax error. It is also not documented ## What are you changing in this pull request and why? Stumbled upon error from this issue and tried to debug it for few hours until I realised this error. Adding text in the docs to prevent other developers finding the same issue. ## Checklist - [x] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [ ] The topic I'm writing about is for specific dbt version(s) and I have versioned it according to the [version a whole page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version) and/or [version a block of content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content) guidelines. - [x] I have added checklist item(s) to this list for anything anything that needs to happen before this PR is merged, such as "needs technical review" or "change base branch." Co-authored-by: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> --- website/docs/docs/build/jinja-macros.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/docs/build/jinja-macros.md b/website/docs/docs/build/jinja-macros.md index fc4a0cad3e8..bc91e3674c9 100644 --- a/website/docs/docs/build/jinja-macros.md +++ b/website/docs/docs/build/jinja-macros.md @@ -74,7 +74,7 @@ group by 1 You can recognize Jinja based on the delimiters the language uses, which we refer to as "curlies": - **Expressions `{{ ... }}`**: Expressions are used when you want to output a string. You can use expressions to reference [variables](/reference/dbt-jinja-functions/var) and call [macros](/docs/build/jinja-macros#macros). - **Statements `{% ... %}`**: Statements don't output a string. They are used for control flow, for example, to set up `for` loops and `if` statements, to [set](https://jinja.palletsprojects.com/en/3.1.x/templates/#assignments) or [modify](https://jinja.palletsprojects.com/en/3.1.x/templates/#expression-statement) variables, or to define macros. -- **Comments `{# ... #}`**: Jinja comments are used to prevent the text within the comment from executing or outputing a string. +- **Comments `{# ... #}`**: Jinja comments are used to prevent the text within the comment from executing or outputing a string. Don't use `--` for comment. When used in a dbt model, your Jinja needs to compile to a valid query. To check what SQL your Jinja compiles to: * **Using dbt Cloud:** Click the compile button to see the compiled SQL in the Compiled SQL pane From 2399e86f9b279ffad18f307a7be2f893f19110cb Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:21:20 +0100 Subject: [PATCH 23/49] add model paths callout (#6011) adding callout to SL best practices and SL quickstart so users know that sm and metrics should be under the model-path directory. raised in [internal slack thread](https://dbt-labs.slack.com/archives/C05K4R7KZ5Z/p1724945059555389?thread_ts=1724777237.590479&cid=C05K4R7KZ5Z) --- .../semantic-layer-7-semantic-structure.md | 4 ++++ website/docs/guides/sl-snowflake-qs.md | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/website/docs/best-practices/how-we-build-our-metrics/semantic-layer-7-semantic-structure.md b/website/docs/best-practices/how-we-build-our-metrics/semantic-layer-7-semantic-structure.md index 295d86e9c20..5bfbea82dda 100644 --- a/website/docs/best-practices/how-we-build-our-metrics/semantic-layer-7-semantic-structure.md +++ b/website/docs/best-practices/how-we-build-our-metrics/semantic-layer-7-semantic-structure.md @@ -20,6 +20,10 @@ The first thing you need to establish is how you’re going to consistently stru It’s not terribly difficult to shift between these (it can be done with some relatively straightforward shell scripting), and this is purely a decision based on your developers’ preference (i.e. it has no impact on execution or performance), so don’t feel locked in to either path. Just pick the one that feels right and you can always shift down the road if you change your mind. +:::tip +Make sure to save all semantic models and metrics under the directory defined in the [`model-paths`](/reference/project-configs/model-paths) (or a subdirectory of it, like `models/semantic_models/`). If you save them outside of this path, it will result in an empty `semantic_manifest.json` file, and your semantic models or metrics won't be recognized. +::: + ## Naming Next, establish your system for consistent file naming: diff --git a/website/docs/guides/sl-snowflake-qs.md b/website/docs/guides/sl-snowflake-qs.md index 6d9f88ab159..7d42aecabc2 100644 --- a/website/docs/guides/sl-snowflake-qs.md +++ b/website/docs/guides/sl-snowflake-qs.md @@ -619,6 +619,11 @@ select * from final In the following steps, semantic models enable you to define how to interpret the data related to orders. It includes entities (like ID columns serving as keys for joining data), dimensions (for grouping or filtering data), and measures (for data aggregations). 1. In the `metrics` sub-directory, create a new file `fct_orders.yml`. + +:::tip +Make sure to save all semantic models and metrics under the directory defined in the [`model-paths`](/reference/project-configs/model-paths) (or a subdirectory of it, like `models/semantic_models/`). If you save them outside of this path, it will result in an empty `semantic_manifest.json` file, and your semantic models or metrics won't be recognized. +::: + 2. Add the following code to that newly created file: @@ -765,7 +770,11 @@ There are different types of metrics you can configure: Once you've created your semantic models, it's time to start referencing those measures you made to create some metrics: -Add metrics to your `fct_orders.yml` semantic model file: +1. Add metrics to your `fct_orders.yml` semantic model file: + +:::tip +Make sure to save all semantic models and metrics under the directory defined in the [`model-paths`](/reference/project-configs/model-paths) (or a subdirectory of it, like `models/semantic_models/`). If you save them outside of this path, it will result in an empty `semantic_manifest.json` file, and your semantic models or metrics won't be recognized. +::: From a451264d28b67620ab69bf83104f41b6499e525a Mon Sep 17 00:00:00 2001 From: Doug Beatty <44704949+dbeatty10@users.noreply.github.com> Date: Thu, 5 Sep 2024 04:00:10 -0600 Subject: [PATCH 24/49] General examples of calling a macro in a hook (#5972) [Preview: Calling a macro in a hook](https://docs-getdbt-com-git-dbeatty10-patch-2-dbt-labs.vercel.app/docs/build/hooks-operations#calling-a-macro-in-a-hook) [Preview: pre-hook & post-hook ](https://docs-getdbt-com-git-dbeatty10-patch-2-dbt-labs.vercel.app/reference/resource-configs/pre-hook-post-hook) ## What are you changing in this pull request and why? We have a couple concrete examples of calling a macro in a hook (like [here](https://docs.getdbt.com/reference/project-configs/on-run-start-on-run-end#call-a-macro-to-grant-privileges) and [here](https://docs.getdbt.com/reference/resource-configs/pre-hook-post-hook#apache-spark-analyze-tables-after-creation)). But we don't currently have any co-located canonical examples of the different locations where hooks can be configured: 1. SQL model config 1. `properties.yml` \* 1. `dbt_project.yml` \* Calling a macro in a hook within a properties YAML file was fixed in v1.8+ by https://github.com/dbt-labs/dbt-core/pull/10603. ## Other pages to review Once https://github.com/dbt-labs/dbt-core/issues/7128 is resolved, we should also review these pages to ensure they include examples of configs across `dbt_project` YAML files, properties YAML files, and node-level config in SQL files: - https://docs.getdbt.com/reference/resource-configs/pre-hook-post-hook - https://docs.getdbt.com/reference/model-configs#apply-configurations-to-one-model-only - https://docs.getdbt.com/reference/seed-configs#apply-the-schema-configuration-to-one-seed-only ## Additional context Inspired by https://github.com/dbt-labs/dbt-core/issues/10522 ## Checklist - [x] Review the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. --------- Co-authored-by: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> --- website/docs/docs/build/hooks-operations.md | 35 ++++++++++++++++++ .../resource-configs/pre-hook-post-hook.md | 36 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/website/docs/docs/build/hooks-operations.md b/website/docs/docs/build/hooks-operations.md index 9ed20291c34..6cec2a673c0 100644 --- a/website/docs/docs/build/hooks-operations.md +++ b/website/docs/docs/build/hooks-operations.md @@ -72,6 +72,41 @@ You can use hooks to provide database-specific functionality not available out-o You can also use a [macro](/docs/build/jinja-macros#macros) to bundle up hook logic. Check out some of the examples in the reference sections for [on-run-start and on-run-end hooks](/reference/project-configs/on-run-start-on-run-end) and [pre- and post-hooks](/reference/resource-configs/pre-hook-post-hook). + + +```sql +{{ config( + pre_hook=[ + "{{ some_macro() }}" + ] +) }} +``` + + + + + +```yaml +models: + - name: + config: + pre_hook: + - "{{ some_macro() }}" +``` + + + + + +```yaml +models: + : + +pre-hook: + - "{{ some_macro() }}" +``` + + + ## About operations Operations are [macros](/docs/build/jinja-macros#macros) that you can run using the [`run-operation`](/reference/commands/run-operation) command. As such, operations aren't actually a separate resource in your dbt project — they are just a convenient way to invoke a macro without needing to run a model. diff --git a/website/docs/reference/resource-configs/pre-hook-post-hook.md b/website/docs/reference/resource-configs/pre-hook-post-hook.md index bf4375c9490..e1e7d67f02e 100644 --- a/website/docs/reference/resource-configs/pre-hook-post-hook.md +++ b/website/docs/reference/resource-configs/pre-hook-post-hook.md @@ -45,6 +45,18 @@ select ... ``` + + + + +```yml +models: + - name: [] + config: + [pre_hook](/reference/resource-configs/pre-hook-post-hook): | [] + [post_hook](/reference/resource-configs/pre-hook-post-hook): | [] +``` + @@ -66,6 +78,18 @@ seeds: + + +```yml +seeds: + - name: [] + config: + [pre_hook](/reference/resource-configs/pre-hook-post-hook): | [] + [post_hook](/reference/resource-configs/pre-hook-post-hook): | [] +``` + + + @@ -102,6 +126,18 @@ select ... + + +```yml +snapshots: + - name: [] + config: + [pre_hook](/reference/resource-configs/pre-hook-post-hook): | [] + [post_hook](/reference/resource-configs/pre-hook-post-hook): | [] +``` + + + From 9850338758e6c26b4b4f9cd6414efdac91f637fe Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:05:45 +0100 Subject: [PATCH 25/49] add search heavy frontmatter (#5994) adding a search_weight frontmatter option and keywords to the custome ci/cd pipeline page. thisis because this guide isn't listed in the initial search results went searching in algolia. raised in slack channel: https://dbt-labs.slack.com/archives/C02NCQ9483C/p1725010557552679 [notion doc](https://www.notion.so/dbtlabs/DocSearch-Weight-Component-Documentation-58aaa3aca7ff42938887e6159f63e7da) --- website/blog/2022-04-14-add-ci-cd-to-bitbucket.md | 2 ++ website/docs/guides/custom-cicd-pipelines.md | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/website/blog/2022-04-14-add-ci-cd-to-bitbucket.md b/website/blog/2022-04-14-add-ci-cd-to-bitbucket.md index eae8d595ca5..e871687d8cd 100644 --- a/website/blog/2022-04-14-add-ci-cd-to-bitbucket.md +++ b/website/blog/2022-04-14-add-ci-cd-to-bitbucket.md @@ -10,6 +10,8 @@ hide_table_of_contents: false date: 2022-05-06 is_featured: true +keywords: + - dbt core pipeline, slim ci pipeline, slim cd pipeline, bitbucket --- diff --git a/website/docs/guides/custom-cicd-pipelines.md b/website/docs/guides/custom-cicd-pipelines.md index 59a7767c69b..be23524d096 100644 --- a/website/docs/guides/custom-cicd-pipelines.md +++ b/website/docs/guides/custom-cicd-pipelines.md @@ -10,6 +10,9 @@ hide_table_of_contents: true tags: ['dbt Cloud', 'Orchestration', 'CI'] level: 'Intermediate' recently_updated: true +search_weight: "heavy" +keywords: + - bitbucket pipeline, custom pipelines, github, gitlab, azure devops, ci/cd custom pipeline ---

    @@ -19,7 +22,6 @@ One of the core tenets of dbt is that analytic code should be version controlled A note on parlance in this article since each code hosting platform uses different terms for similar concepts. The terms `pull request` (PR) and `merge request` (MR) are used interchangeably to mean the process of merging one branch into another branch. - ### What are pipelines? Pipelines (which are known by many names, such as workflows, actions, or build steps) are a series of pre-defined jobs that are triggered by specific events in your repository (PR created, commit pushed, branch merged, etc). Those jobs can do pretty much anything your heart desires assuming you have the proper security access and coding chops. From 8eceeda49b75e47b065fc5f75fcc306e21732d80 Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:25:48 +0100 Subject: [PATCH 26/49] update ip doc and add clarification (#6020) This PR updates the IP restrictions doc and addresses the issues raised in #5727. Resolves #5727 --- website/docs/docs/cloud/secure/ip-restrictions.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/website/docs/docs/cloud/secure/ip-restrictions.md b/website/docs/docs/cloud/secure/ip-restrictions.md index 034b3a6c144..d39960dab42 100644 --- a/website/docs/docs/cloud/secure/ip-restrictions.md +++ b/website/docs/docs/cloud/secure/ip-restrictions.md @@ -13,7 +13,7 @@ import SetUpPages from '/snippets/_available-tiers-iprestrictions.md'; IP Restrictions help control which IP addresses are allowed to connect to dbt Cloud. IP restrictions allow dbt Cloud customers to meet security and compliance controls by only allowing approved IPs to connect to their dbt Cloud environment. This feature is supported in all regions across NA, Europe, and Asia-Pacific, but contact us if you have questions about availability. -## Configuring IP Restrictions +## Configuring IP restrictions To configure IP restrictions, go to **Account Settings** → **IP Restrictions**. IP restrictions provide two methods for determining which IPs can access dbt Cloud: an allowlist and a blocklist. IPs in the allowlist are allowed to access dbt Cloud, and IPs in the deny list will be blocked from accessing dbt Cloud. IP Restrictions can be used for a range of use cases, including: @@ -29,7 +29,7 @@ For any version control system integrations (Github, Gitlab, ADO, etc.) inbound To add an IP to the allowlist, from the **IP Restrictions** page: -1. Click **edit** +1. Click **Edit** 2. Click **Add Rule** 3. Add name and description for the rule - For example, Corporate VPN CIDR Range @@ -39,7 +39,9 @@ To add an IP to the allowlist, from the **IP Restrictions** page: - You can add multiple ranges in the same rule. 6. Click **Save** -Note that simply adding the IP Ranges will not enforce IP restrictions. For more information, see the section “Enabling Restrictions.” +Add multiple IP ranges by clicking the **Add IP range** button to create a new text field. + +Note that simply adding the IP Ranges will not enforce IP restrictions. For more information, see the [Enabling restrictions](#enabling-restrictions) section. If you only want to allow the IP ranges added to this list and deny all other requests, adding a denylist is not necessary. By default, if only an allow list is added, dbt Cloud will only allow IPs in the allowable range and deny all other IPs. However, you can add a denylist if you want to deny specific IP addresses within your allowlist CIDR range. @@ -65,9 +67,9 @@ It is possible to put an IP range on one list and then a sub-range or IP address ::: -## Enabling Restrictions +## Enabling restrictions -Once you are done adding all your ranges, IP restrictions can be enabled by selecting the **Enable IP restrictions** button and clicking **Save**. If your IP address is in any of the denylist ranges, you won’t be able to save or enable IP restrictions - this is done to prevent accidental account lockouts. If you do get locked out due to IP changes on your end, please reach out to support@dbtlabs.com +Once you are done adding all your ranges, IP restrictions can be enabled by selecting the **Enable IP restrictions** button and clicking **Save**. If your IP address is in any of the denylist ranges, you won’t be able to save or enable IP restrictions - this is done to prevent accidental account lockouts. If you do get locked out due to IP changes on your end, please reach out to support@getdbt.com Once enabled, when someone attempts to access dbt Cloud from a restricted IP, they will encounter one of the following messages depending on whether they use email & password or SSO login. From 9ae02b8713f6f7fdc8b2546549b37061d18bbd3a Mon Sep 17 00:00:00 2001 From: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:19:58 -0400 Subject: [PATCH 27/49] Removing versions (#6021) ## What are you changing in this pull request and why? Now that we have the option for dbt Cloud in the docs, we are removing the v1.9 beta content until the beta is actually out. This removes the whole upgrade guide since the sidebar is autogenerated. ## Checklist - [ ] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [ ] The topic I'm writing about is for specific dbt version(s) and I have versioned it according to the [version a whole page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version) and/or [version a block of content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content) guidelines. - [ ] I have added checklist item(s) to this list for anything anything that needs to happen before this PR is merged, such as "needs technical review" or "change base branch." --- website/dbt-versions.js | 4 --- .../core-upgrade/06-upgrading-to-v1.9.md | 27 ------------------- 2 files changed, 31 deletions(-) delete mode 100644 website/docs/docs/dbt-versions/core-upgrade/06-upgrading-to-v1.9.md diff --git a/website/dbt-versions.js b/website/dbt-versions.js index e5a2b9f4290..0f322100a45 100644 --- a/website/dbt-versions.js +++ b/website/dbt-versions.js @@ -16,10 +16,6 @@ exports.versions = [ version: "1.9.1", customDisplay: "Cloud (Versionless)", }, - { - version: "1.9", - isPrerelease: true, - }, { version: "1.8", EOLDate: "2025-04-15", diff --git a/website/docs/docs/dbt-versions/core-upgrade/06-upgrading-to-v1.9.md b/website/docs/docs/dbt-versions/core-upgrade/06-upgrading-to-v1.9.md deleted file mode 100644 index 544590b18df..00000000000 --- a/website/docs/docs/dbt-versions/core-upgrade/06-upgrading-to-v1.9.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: "Upgrading to v1.9 (beta)" -id: upgrading-to-v1.9 -description: New features and changes in dbt Core v1.9 -displayed_sidebar: "docs" ---- - -## Resources - -- Changelog (coming soon) -- [dbt Core CLI Installation guide](/docs/core/installation-overview) -- [Cloud upgrade guide](/docs/dbt-versions/upgrade-dbt-version-in-cloud) — dbt Cloud is now versionless. dbt v1.9 will not appear in the version dropdown. Select **Versionless** to get all the latest features and functionality in your dbt Cloud account. - -## What to know before upgrading - -dbt Labs is committed to providing backward compatibility for all versions 1.x, except for any changes explicitly mentioned on this page. If you encounter an error upon upgrading, please let us know by [opening an issue](https://github.com/dbt-labs/dbt-core/issues/new). - - -## New and changed features and functionality - -Features and functionality new in dbt v1.9. - -**Coming soon** - -## Quick hits - -**Coming soon** \ No newline at end of file From 03507dd449da1ecb1d6f82fce817266961684c4e Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Thu, 5 Sep 2024 21:24:44 +0200 Subject: [PATCH 28/49] Update "Behavior changes" (#6019) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What are you changing in this pull request and why? - Rename "Legacy behaviors" to "Behavior changes" — this is how we've been referring to them - Add definition of what we consider to be a behavior change, as well as examples of what does / doesn't constitute a behavior change --------- Co-authored-by: nataliefiann <120089939+nataliefiann@users.noreply.github.com> Co-authored-by: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Co-authored-by: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> --- .../core-upgrade/07-upgrading-to-v1.8.md | 8 ++--- .../docs/docs/dbt-versions/release-notes.md | 6 ++-- .../global-configs/about-global-configs.md | 6 ++-- ...egacy-behaviors.md => behavior-changes.md} | 29 ++++++++++++++++--- .../reference/global-configs/project-flags.md | 2 +- website/sidebars.js | 2 +- website/vercel.json | 5 ++++ 7 files changed, 42 insertions(+), 16 deletions(-) rename website/docs/reference/global-configs/{legacy-behaviors.md => behavior-changes.md} (75%) diff --git a/website/docs/docs/dbt-versions/core-upgrade/07-upgrading-to-v1.8.md b/website/docs/docs/dbt-versions/core-upgrade/07-upgrading-to-v1.8.md index dd22329668c..9163047e7e0 100644 --- a/website/docs/docs/dbt-versions/core-upgrade/07-upgrading-to-v1.8.md +++ b/website/docs/docs/dbt-versions/core-upgrade/07-upgrading-to-v1.8.md @@ -98,13 +98,13 @@ The ability for installed packages to override built-in materializations without ### Managing changes to legacy behaviors -dbt Core v1.8 has introduced flags for [managing changes to legacy behaviors](/reference/global-configs/legacy-behaviors). You may opt into recently introduced changes (disabled by default), or opt out of mature changes (enabled by default), by setting `True` / `False` values, respectively, for `flags` in `dbt_project.yml`. +dbt Core v1.8 has introduced flags for [managing changes to legacy behaviors](/reference/global-configs/behavior-changes). You may opt into recently introduced changes (disabled by default), or opt out of mature changes (enabled by default), by setting `True` / `False` values, respectively, for `flags` in `dbt_project.yml`. You can read more about each of these behavior changes in the following links: -- (Mature, enabled by default) [Require explicit package overrides for builtin materializations](/reference/global-configs/legacy-behaviors#require_explicit_package_overrides_for_builtin_materializations) -- (Introduced, disabled by default) [Require resource names without spaces](https://docs.getdbt.com/reference/global-configs/legacy-behaviors#require_resource_names_without_spaces) -- (Introduced, disabled by default) [Run project hooks (`on-run-*`) in the `dbt source freshness` command](/reference/global-configs/legacy-behaviors#source_freshness_run_project_hooks) +- (Mature, enabled by default) [Require explicit package overrides for builtin materializations](/reference/global-configs/behavior-changes#require_explicit_package_overrides_for_builtin_materializations) +- (Introduced, disabled by default) [Require resource names without spaces](/reference/global-configs/behavior-changes#require_resource_names_without_spaces) +- (Introduced, disabled by default) [Run project hooks (`on-run-*`) in the `dbt source freshness` command](/reference/global-configs/behavior-changes#source_freshness_run_project_hooks) ## Quick hits diff --git a/website/docs/docs/dbt-versions/release-notes.md b/website/docs/docs/dbt-versions/release-notes.md index 57aadba284d..1ab09b3839c 100644 --- a/website/docs/docs/dbt-versions/release-notes.md +++ b/website/docs/docs/dbt-versions/release-notes.md @@ -148,7 +148,7 @@ The following features are new or enhanced as part of our [dbt Cloud Launch Show -- **Behavior change:** Introduced the `require_resource_names_without_spaces` flag, opt-in and disabled by default. If set to `True`, dbt will raise an exception if it finds a resource name containing a space in your project or an installed package. This will become the default in a future version of dbt. Read [No spaces in resource names](/reference/global-configs/legacy-behaviors#no-spaces-in-resource-names) for more information. +- **Behavior change:** Introduced the `require_resource_names_without_spaces` flag, opt-in and disabled by default. If set to `True`, dbt will raise an exception if it finds a resource name containing a space in your project or an installed package. This will become the default in a future version of dbt. Read [No spaces in resource names](/reference/global-configs/behavior-changes#no-spaces-in-resource-names) for more information. ## April 2024 @@ -160,7 +160,7 @@ The following features are new or enhanced as part of our [dbt Cloud Launch Show -- **Behavior change:** Introduced the `require_explicit_package_overrides_for_builtin_materializations` flag, opt-in and disabled by default. If set to `True`, dbt will only use built-in materializations defined in the root project or within dbt, rather than implementations in packages. This will become the default in May 2024 (dbt Core v1.8 and "Versionless" dbt Cloud). Read [Package override for built-in materialization](/reference/global-configs/legacy-behaviors#package-override-for-built-in-materialization) for more information. +- **Behavior change:** Introduced the `require_explicit_package_overrides_for_builtin_materializations` flag, opt-in and disabled by default. If set to `True`, dbt will only use built-in materializations defined in the root project or within dbt, rather than implementations in packages. This will become the default in May 2024 (dbt Core v1.8 and "Versionless" dbt Cloud). Read [Package override for built-in materialization](/reference/global-configs/behavior-changes#package-override-for-built-in-materialization) for more information. **dbt Semantic Layer** - **New**: Use Saved selections to [save your query selections](/docs/cloud-integrations/semantic-layer/gsheets#using-saved-selections) within the [Google Sheets application](/docs/cloud-integrations/semantic-layer/gsheets). They can be made private or public and refresh upon loading. @@ -182,7 +182,7 @@ The following features are new or enhanced as part of our [dbt Cloud Launch Show - **Fix:** `dbt parse` no longer shows an error when you use a list of filters (instead of just a string filter) on a metric. - **Fix:** `join_to_timespine` now properly gets applied to conversion metric input measures. - **Fix:** Fixed an issue where exports in Redshift were not always committing to the DWH, which also had the side-effect of leaving table locks open. -- **Behavior change:** Introduced the `source_freshness_run_project_hooks` flag, opt-in and disabled by default. If set to `True`, dbt will include `on-run-*` project hooks in the `source freshness` command. This will become the default in a future version of dbt. Read [Project hooks with source freshness](/reference/global-configs/legacy-behaviors#project-hooks-with-source-freshness) for more information. +- **Behavior change:** Introduced the `source_freshness_run_project_hooks` flag, opt-in and disabled by default. If set to `True`, dbt will include `on-run-*` project hooks in the `source freshness` command. This will become the default in a future version of dbt. Read [Project hooks with source freshness](/reference/global-configs/behavior-changes#project-hooks-with-source-freshness) for more information. ## February 2024 diff --git a/website/docs/reference/global-configs/about-global-configs.md b/website/docs/reference/global-configs/about-global-configs.md index bbbe63ac439..3708b8c96be 100644 --- a/website/docs/reference/global-configs/about-global-configs.md +++ b/website/docs/reference/global-configs/about-global-configs.md @@ -16,7 +16,7 @@ There is a significant overlap between dbt's flags and dbt's command line option ### Setting flags There are multiple ways of setting flags, which depend on the use case: -- **[Project-level `flags` in `dbt_project.yml`](/reference/global-configs/project-flags):** Define version-controlled defaults for everyone running this project. Preserve [legacy behaviors](/reference/global-configs/legacy-behaviors) until their slated deprecation. +- **[Project-level `flags` in `dbt_project.yml`](/reference/global-configs/project-flags):** Define version-controlled defaults for everyone running this project. Also, opt in or opt out of [behavior changes](/reference/global-configs/behavior-changes) to manage your migration off legacy functionality. - **[Environment variables](/reference/global-configs/environment-variable-configs):** Define different behavior in different runtime environments (development vs. production vs. [continuous integration](/docs/deploy/continuous-integration), or different behavior for different users in development (based on personal preferences). - **[CLI options](/reference/global-configs/command-line-options):** Define behavior specific to _this invocation_. Supported for all dbt commands. @@ -41,7 +41,7 @@ dbt run --no-fail-fast # set to False There are two categories of exceptions: 1. **Flags setting file paths:** Flags for file paths that are relevant to runtime execution (for example, `--log-path` or `--state`) cannot be set in `dbt_project.yml`. To override defaults, pass CLI options or set environment variables (`DBT_LOG_PATH`, `DBT_STATE`). Flags that tell dbt where to find project resources (for example, `model-paths`) are set in `dbt_project.yml`, but as a top-level key, outside the `flags` dictionary; these configs are expected to be fully static and never vary based on the command or execution environment. -2. **Opt-in flags:** Flags opting into [legacy dbt behaviors](/reference/global-configs/legacy-behaviors) can _only_ be defined in `dbt_project.yml`. These are intended to be set in version control and migrated via pull/merge request. Their values should not diverge indefinitely across invocations, environments, or users. +2. **Opt-in flags:** Flags opting in or out of [behavior changes](/reference/global-configs/behavior-changes) can _only_ be defined in `dbt_project.yml`. These are intended to be set in version control and migrated via pull/merge request. Their values should not diverge indefinitely across invocations, environments, or users. ### Accessing flags @@ -84,7 +84,7 @@ Because the values of `flags` can differ across invocations, we strongly advise | [quiet](/reference/global-configs/logs#suppress-non-error-logs-in-output) | boolean | False | ❌ | `DBT_QUIET` | `--quiet` | ✅ | | [resource-type](/reference/global-configs/resource-type) (v1.8+) | string | None | ❌ | `DBT_RESOURCE_TYPES`

    `DBT_EXCLUDE_RESOURCE_TYPES` | `--resource-type`

    `--exclude-resource-type` | ✅ | | [send_anonymous_usage_stats](/reference/global-configs/usage-stats) | boolean | True | ✅ | `DBT_SEND_ANONYMOUS_USAGE_STATS` | `--send-anonymous-usage-stats`, `--no-send-anonymous-usage-stats` | ❌ | -| [source_freshness_run_project_hooks](/reference/global-configs/legacy-behaviors#source_freshness_run_project_hooks) | boolean | False | ✅ | ❌ | ❌ | ❌ | +| [source_freshness_run_project_hooks](/reference/global-configs/behavior-changes#source_freshness_run_project_hooks) | boolean | False | ✅ | ❌ | ❌ | ❌ | | [state](/reference/node-selection/defer) | path | none | ❌ | `DBT_STATE`, `DBT_DEFER_STATE` | `--state`, `--defer-state` | ❌ | | [static_parser](/reference/global-configs/parsing#static-parser) | boolean | True | ✅ | `DBT_STATIC_PARSER` | `--static-parser`, `--no-static-parser` | ❌ | | [store_failures](/reference/resource-configs/store_failures) | boolean | False | ✅ (as resource config) | `DBT_STORE_FAILURES` | `--store-failures`, `--no-store-failures` | ✅ | diff --git a/website/docs/reference/global-configs/legacy-behaviors.md b/website/docs/reference/global-configs/behavior-changes.md similarity index 75% rename from website/docs/reference/global-configs/legacy-behaviors.md rename to website/docs/reference/global-configs/behavior-changes.md index 1450fda1459..20f5722b944 100644 --- a/website/docs/reference/global-configs/legacy-behaviors.md +++ b/website/docs/reference/global-configs/behavior-changes.md @@ -1,7 +1,7 @@ --- -title: "Legacy behaviors" -id: "legacy-behaviors" -sidebar: "Legacy behaviors" +title: "Behavior changes" +id: "behavior-changes" +sidebar: "Behavior changes" --- Most flags exist to configure runtime behaviors with multiple valid choices. The right choice may vary based on the environment, user preference, or the specific invocation. @@ -12,10 +12,31 @@ Another category of flags provides existing projects with a migration window for - Providing maintainability of dbt software. Every fork in behavior requires additional testing & cognitive overhead that slows future development. These flags exist to facilitate migration from "current" to "better," not to stick around forever. These flags go through three phases of development: -1. **Introduction (disabled by default):** dbt adds logic to support both 'old' + 'new' behaviors. The 'new' behavior is gated behind a flag, disabled by default, preserving the old behavior. +1. **Introduction (disabled by default):** dbt adds logic to support both 'old' and 'new' behaviors. The 'new' behavior is gated behind a flag, disabled by default, preserving the old behavior. 2. **Maturity (enabled by default):** The default value of the flag is switched, from `false` to `true`, enabling the new behavior by default. Users can preserve the 'old' behavior and opt out of the 'new' behavior by setting the flag to `false` in their projects. They may see deprecation warnings when they do so. 3. **Removal (generally enabled):** After marking the flag for deprecation, we remove it along with the 'old' behavior it supported from the dbt codebases. We aim to support most flags indefinitely, but we're not committed to supporting them forever. If we choose to remove a flag, we'll offer significant advance notice. +## What is a behavior change? + +The same dbt project code and the same dbt commands return one result before the behavior change, and they return a different result after the behavior change. + +Examples of behavior changes: +- dbt begins raising a validation _error_ that it didn't previously. +- dbt changes the signature of a built-in macro. Your project has a custom reimplementation of that macro. This could lead to errors, because your custom reimplementation will be passed arguments it cannot accept. +- A dbt adapter renames or removes a method that was previously available on the `{{ adapter }}` object in the dbt-Jinja context. +- dbt makes a breaking change to contracted metadata artifacts by deleting a required field, changing the name or type of an existing field, or removing the default value of an existing field ([README](https://github.com/dbt-labs/dbt-core/blob/37d382c8e768d1e72acd767e0afdcb1f0dc5e9c5/core/dbt/artifacts/README.md#breaking-changes)). +- dbt removes one of the fields from [structured logs](/reference/events-logging#structured-logging). + +The following are **not** behavior changes: +- Fixing a bug where the previous behavior was defective, undesirable, or undocumented. +- dbt begins raising a _warning_ that it didn't previously. +- dbt updates the language of human-friendly messages in log events. +- dbt makes a non-breaking change to contracted metadata artifacts by adding a new field with a default, or deleting a field with a default ([README](https://github.com/dbt-labs/dbt-core/blob/37d382c8e768d1e72acd767e0afdcb1f0dc5e9c5/core/dbt/artifacts/README.md#non-breaking-changes)). + +The vast majority of changes are not behavior changes. Because introducing these changes does not require any action on the part of users, they are included in continuous releases of dbt Cloud and patch releases of dbt Core. + +By contrast, behavior change migrations happen slowly, over the course of months, facilitated by behavior change flags. The flags are loosely coupled to the specific dbt runtime version. By setting flags, users have control over opting in (and later opting out) of these changes. + ## Behavior change flags These flags _must_ be set in the `flags` dictionary in `dbt_project.yml`. They configure behaviors closely tied to project code, which means they should be defined in version control and modified through pull or merge requests, with the same testing and peer review. diff --git a/website/docs/reference/global-configs/project-flags.md b/website/docs/reference/global-configs/project-flags.md index 896276d9735..cdbe3463b14 100644 --- a/website/docs/reference/global-configs/project-flags.md +++ b/website/docs/reference/global-configs/project-flags.md @@ -17,7 +17,7 @@ flags: Reference the [table of all flags](/reference/global-configs/about-global-configs#available-flags) to see which global configs are available for setting in [`dbt_project.yml`](/reference/dbt_project.yml). -The `flags` dictionary is the _only_ place you can opt out of [behavior changes](/reference/global-configs/legacy-behaviors), while the legacy behavior is still supported. +The `flags` dictionary is the _only_ place you can opt out of [behavior changes](/reference/global-configs/behavior-changes), while the legacy behavior is still supported. diff --git a/website/sidebars.js b/website/sidebars.js index b3b752990dd..69ba286228d 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -1073,6 +1073,7 @@ const sidebarSettings = { }, items: [ "reference/global-configs/about-global-configs", + "reference/global-configs/behavior-changes", { type: "category", label: "Setting flags", @@ -1091,7 +1092,6 @@ const sidebarSettings = { "reference/global-configs/failing-fast", "reference/global-configs/indirect-selection", "reference/global-configs/json-artifacts", - "reference/global-configs/legacy-behaviors", "reference/global-configs/parsing", "reference/global-configs/print-output", "reference/global-configs/record-timing-info", diff --git a/website/vercel.json b/website/vercel.json index 8fdf311e72f..f79fc959187 100644 --- a/website/vercel.json +++ b/website/vercel.json @@ -599,6 +599,11 @@ "destination": "/reference/global-configs/command-line-options", "permanent": true }, + { + "source": "/reference/global-configs/legacy-behaviors", + "destination": "/reference/global-configs/behavior-changes", + "permanent": true + }, { "source": "/reference/global-configs/yaml-configurations", "destination": "/reference/global-configs/project-flags", From 1059f0a39eb3a691bd099b7bb6407659da36d5e9 Mon Sep 17 00:00:00 2001 From: Matt Shaver <60105315+matthewshaver@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:15:51 -0400 Subject: [PATCH 29/49] Adding guidance for custom display (#6022) ## What are you changing in this pull request and why? Adding clarifying text about customDisplay ## Checklist - [ ] I have reviewed the [Content style guide](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/content-style-guide.md) so my content adheres to these guidelines. - [ ] The topic I'm writing about is for specific dbt version(s) and I have versioned it according to the [version a whole page](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#adding-a-new-version) and/or [version a block of content](https://github.com/dbt-labs/docs.getdbt.com/blob/current/contributing/single-sourcing-content.md#versioning-blocks-of-content) guidelines. - [ ] I have added checklist item(s) to this list for anything anything that needs to happen before this PR is merged, such as "needs technical review" or "change base branch." --- website/dbt-versions.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/dbt-versions.js b/website/dbt-versions.js index 0f322100a45..871c3ce601e 100644 --- a/website/dbt-versions.js +++ b/website/dbt-versions.js @@ -10,6 +10,8 @@ * @property {string} EOLDate "End of Life" date which is used to show the EOL banner * @property {boolean} isPrerelease Boolean used for showing the prerelease banner * @property {string} customDisplay Allows setting a custom display name for the current version + * + * customDisplay for dbt Cloud should be a version ahead of latest dbt Core release (GA or beta). */ exports.versions = [ { From 6a1a7bc2b5a18f998f7b8186fbf192bf7da50fb2 Mon Sep 17 00:00:00 2001 From: Mirna Wong <89008547+mirnawong1@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:04:22 +0100 Subject: [PATCH 30/49] needs PM review - update data health tile (#6018) After PM sync, updated [data health tile doc](https://docs.getdbt.com/docs/collaborate/data-tile) to make it clearer users can embed data health tile url or iframe in any tool. turn tableau into example. [ ] Needs PM review --------- Co-authored-by: nataliefiann <120089939+nataliefiann@users.noreply.github.com> --- website/docs/docs/collaborate/data-tile.md | 34 +++++++++++++--------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/website/docs/docs/collaborate/data-tile.md b/website/docs/docs/collaborate/data-tile.md index f40f21ebe18..446922acb92 100644 --- a/website/docs/docs/collaborate/data-tile.md +++ b/website/docs/docs/collaborate/data-tile.md @@ -9,9 +9,11 @@ image: /img/docs/collaborate/dbt-explorer/data-tile-pass.jpg # Embed data health tile in dashboards With data health tiles, stakeholders will get an at-a-glance confirmation on whether the data they’re looking at is stale or degraded. This trust signal allows teams to immediately go back into Explorer to see more details and investigate issues. + :::info Available in beta Data health tile is currently available in open beta. ::: + The data health tile: - Distills trust signals for data consumers. @@ -19,6 +21,8 @@ The data health tile: - Provides richer information and makes it easier to debug. - Revamps the existing, [job-based tiles](#job-based-data-health). +Data health tiles rely on [exposures](/docs/build/exposures) to surface trust signals in your dashboards. When you configure exposures in your dbt project, you are explicitly defining how specific outputs—like dashboards or reports—depend on your data models. + ## Prerequisites @@ -34,43 +38,45 @@ First, be sure to enable [source freshness](/docs/deploy/source-freshness) in 1. Navigate to dbt Explorer by clicking on the **Explore** link in the navigation. 2. In the main **Overview** page, go to the left navigation. -3. Under the **Resources** tab, click on **Exposures** to view the exposures list. +3. Under the **Resources** tab, click on **Exposures** to view the [exposures](/docs/build/exposures) list. 4. Select a dashboard exposure and go to the **General** tab to view the data health information. -5. In this tab, you’ll see: - - Data health status: Data freshness passed, Data quality passed, Data may be stale, Data quality degraded - - Name of the exposure. +5. In this tab, you’ll see: + - Name of the exposure. + - Data health status: Data freshness passed, Data quality passed, Data may be stale, Data quality degraded. - Resource type (model, source, and so on). - Dashboard status: Failure, Pass, Stale. - You can also see the last check completed, the last check time, and the last check duration. -6. You can also click the **Open Dashboard** button on the upper right to immediately view this in your analytics tool. +6. You can click the **Open Dashboard** button on the upper right to immediately view this in your analytics tool. ## Embed in your dashboard -Once you’ve navigated to the auto-exposure in dbt Explorer, you’ll need to set up your dashboard status tile and [service token](/docs/dbt-cloud-apis/service-tokens): +Once you’ve navigated to the auto-exposure in dbt Explorer, you’ll need to set up your data health tile and [service token](/docs/dbt-cloud-apis/service-tokens). You can embed data health tile to any analytics tool that supports URL or iFrame embedding. + +Follow these steps to set up your data health tile: 1. Go to **Account settings** in dbt Cloud. 2. Select **API tokens** in the left sidebar and then **Service tokens**. 3. Click on **Create service token** and give it a name. -4. Select the [**Metadata Only** permission](/docs/dbt-cloud-apis/service-tokens). This token will be used to embed the exposure tile in your dashboard in the later steps. +4. Select the [**Metadata Only**](/docs/dbt-cloud-apis/service-tokens) permission. This token will be used to embed the tile in your dashboard in the later steps. -5. Copy the **Metadata Only token** and save it in a secure location. You'll need it token in the next steps. +5. Copy the **Metadata Only** token and save it in a secure location. You'll need it token in the next steps. 6. Navigate back to dbt Explorer and select an exposure. 7. Below the **Data health** section, expand on the toggle for instructions on how to embed the exposure tile (if you're an account admin with develop permissions). 8. In the expanded toggle, you'll see a text field where you can paste your **Metadata Only token**. -9. Once you’ve pasted your token, you can select either **URL** or **iFrame** depending on which you need to install into your dashboard. +9. Once you’ve pasted your token, you can select either **URL** or **iFrame** depending on which you need to add to your dashboard. If your analytics tool supports iFrames, you can embed the dashboard tile within it. -### Embed data health tile in Tableau -To embed the data health tile in Tableau, follow these steps: +#### Tableau example +Here’s an example with Tableau, where you can embed the iFrame in a web page object: -1. Ensure you've copied the embed iFrame content in dbt Explorer. -2. For the revamped environment-based exposure tile you can insert these fields into the following iFrame, and then embed them with your dashboard. This is the iFrame that is available from the **Exposure details** page in dbt Explorer. +- Ensure you've copied the embed iFrame snippet from the dbt Explorer **Data health** section. +- **For the revamped environment-based exposure tile** — Insert the following fields into the following iFrame. Then embed them with your dashboard. This is the iFrame available from the **Exposure details** page in dbt Explorer. `" + ``` + + -- **For job-based exposure tile** — Insert the following fields into the following iFrame. Then embed them with your dashboard. The next [section](#job-based-data-health) will have more details on the job-based exposure tile. +6. PowerBI desktop doesn't support HTML rendering by default, so you need to install an HTML component from the PowerBI Visuals Store. +7. To do this, go to **Build visuals** and then **Get more visuals**. +8. Login with your PowerBI account. +9. There are several third-party HTML visuals. The one tested for this guide is [HTML content](https://appsource.microsoft.com/en-us/product/power-bi-visuals/WA200001930?tab=Overview). Install it, but please keep in mind it's a third-party plugin not created or supported by dbt Labs. +10. Drag the metric with the iFrame code into the HTML content widget in PowerBI. This should now display your data health tile. - `