forked from repo-mirrors/dbt-core
Compare commits
1 Commits
macro-reso
...
adding-sem
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2da925aa25 |
@@ -1,19 +1,13 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 1.8.0a1
|
current_version = 1.5.0a1
|
||||||
parse = (?P<major>[\d]+) # major version number
|
parse = (?P<major>\d+)
|
||||||
\.(?P<minor>[\d]+) # minor version number
|
\.(?P<minor>\d+)
|
||||||
\.(?P<patch>[\d]+) # patch version number
|
\.(?P<patch>\d+)
|
||||||
(?P<prerelease> # optional pre-release - ex: a1, b2, rc25
|
((?P<prekind>a|b|rc)
|
||||||
(?P<prekind>a|b|rc) # pre-release type
|
(?P<pre>\d+) # pre-release version num
|
||||||
(?P<num>[\d]+) # pre-release version number
|
|
||||||
)?
|
)?
|
||||||
( # optional nightly release indicator
|
|
||||||
\.(?P<nightly>dev[0-9]+) # ex: .dev02142023
|
|
||||||
)? # expected matches: `1.15.0`, `1.5.0a11`, `1.5.0a1.dev123`, `1.5.0.dev123457`, expected failures: `1`, `1.5`, `1.5.2-a1`, `text1.5.0`
|
|
||||||
serialize =
|
serialize =
|
||||||
{major}.{minor}.{patch}{prekind}{num}.{nightly}
|
{major}.{minor}.{patch}{prekind}{pre}
|
||||||
{major}.{minor}.{patch}.{nightly}
|
|
||||||
{major}.{minor}.{patch}{prekind}{num}
|
|
||||||
{major}.{minor}.{patch}
|
{major}.{minor}.{patch}
|
||||||
commit = False
|
commit = False
|
||||||
tag = False
|
tag = False
|
||||||
@@ -27,11 +21,9 @@ values =
|
|||||||
rc
|
rc
|
||||||
final
|
final
|
||||||
|
|
||||||
[bumpversion:part:num]
|
[bumpversion:part:pre]
|
||||||
first_value = 1
|
first_value = 1
|
||||||
|
|
||||||
[bumpversion:part:nightly]
|
|
||||||
|
|
||||||
[bumpversion:file:core/setup.py]
|
[bumpversion:file:core/setup.py]
|
||||||
|
|
||||||
[bumpversion:file:core/dbt/version.py]
|
[bumpversion:file:core/dbt/version.py]
|
||||||
|
|||||||
@@ -3,9 +3,6 @@
|
|||||||
For information on prior major and minor releases, see their changelogs:
|
For information on prior major and minor releases, see their changelogs:
|
||||||
|
|
||||||
|
|
||||||
* [1.7](https://github.com/dbt-labs/dbt-core/blob/1.7.latest/CHANGELOG.md)
|
|
||||||
* [1.6](https://github.com/dbt-labs/dbt-core/blob/1.6.latest/CHANGELOG.md)
|
|
||||||
* [1.5](https://github.com/dbt-labs/dbt-core/blob/1.5.latest/CHANGELOG.md)
|
|
||||||
* [1.4](https://github.com/dbt-labs/dbt-core/blob/1.4.latest/CHANGELOG.md)
|
* [1.4](https://github.com/dbt-labs/dbt-core/blob/1.4.latest/CHANGELOG.md)
|
||||||
* [1.3](https://github.com/dbt-labs/dbt-core/blob/1.3.latest/CHANGELOG.md)
|
* [1.3](https://github.com/dbt-labs/dbt-core/blob/1.3.latest/CHANGELOG.md)
|
||||||
* [1.2](https://github.com/dbt-labs/dbt-core/blob/1.2.latest/CHANGELOG.md)
|
* [1.2](https://github.com/dbt-labs/dbt-core/blob/1.2.latest/CHANGELOG.md)
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Breaking Changes
|
|
||||||
body: Remove adapter.get_compiler interface
|
|
||||||
time: 2023-11-27T11:47:57.443202-05:00
|
|
||||||
custom:
|
|
||||||
Author: michelleark
|
|
||||||
Issue: "9148"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Breaking Changes
|
|
||||||
body: Move AdapterLogger to adapters folder
|
|
||||||
time: 2023-11-28T13:43:56.853925-08:00
|
|
||||||
custom:
|
|
||||||
Author: colin-rogers-dbt
|
|
||||||
Issue: "9151"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
kind: Breaking Changes
|
|
||||||
body: move event manager setup back to core, remove ref to global EVENT_MANAGER and
|
|
||||||
clean up event manager functions
|
|
||||||
time: 2023-11-30T13:53:48.645192-08:00
|
|
||||||
custom:
|
|
||||||
Author: colin-rogers-dbt
|
|
||||||
Issue: "9150"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Dependencies
|
|
||||||
body: Begin using DSI 0.4.x
|
|
||||||
time: 2023-10-31T13:19:54.750009-07:00
|
|
||||||
custom:
|
|
||||||
Author: QMalcolm peterallenwebb
|
|
||||||
PR: "8892"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Dependencies
|
|
||||||
body: Update typing-extensions version to >=4.4
|
|
||||||
time: 2023-11-06T13:00:51.062386-08:00
|
|
||||||
custom:
|
|
||||||
Author: tlento
|
|
||||||
PR: "9012"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Docs
|
|
||||||
body: fix get_custom_database docstring
|
|
||||||
time: 2023-11-06T12:31:57.525711Z
|
|
||||||
custom:
|
|
||||||
Author: LeoTheGriff
|
|
||||||
Issue: "9003"
|
|
||||||
6
.changes/unreleased/Features-20230118-134804.yaml
Normal file
6
.changes/unreleased/Features-20230118-134804.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Features
|
||||||
|
body: Adding the entity node
|
||||||
|
time: 2023-01-18T13:48:04.487817-06:00
|
||||||
|
custom:
|
||||||
|
Author: callum-mcdata
|
||||||
|
Issue: "6627"
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Features
|
|
||||||
body: 'Allow adapters to include package logs in dbt standard logging '
|
|
||||||
time: 2023-09-15T12:37:33.862862-07:00
|
|
||||||
custom:
|
|
||||||
Author: colin-rogers-dbt
|
|
||||||
Issue: "7859"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Features
|
|
||||||
body: Add drop_schema_named macro
|
|
||||||
time: 2023-10-17T14:36:20.612289-07:00
|
|
||||||
custom:
|
|
||||||
Author: colin-rogers-dbt
|
|
||||||
Issue: "8025"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Features
|
|
||||||
body: migrate utils to common and adapters folders
|
|
||||||
time: 2023-10-26T11:08:21.458709-07:00
|
|
||||||
custom:
|
|
||||||
Author: colin-rogers-dbt
|
|
||||||
Issue: "8924"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Features
|
|
||||||
body: Move Agate helper client into common
|
|
||||||
time: 2023-10-26T12:35:56.538587-07:00
|
|
||||||
custom:
|
|
||||||
Author: MichelleArk
|
|
||||||
Issue: "8926"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Features
|
|
||||||
body: remove usage of dbt.config.PartialProject from dbt/adapters
|
|
||||||
time: 2023-10-26T12:39:13.904116-07:00
|
|
||||||
custom:
|
|
||||||
Author: MichelleArk
|
|
||||||
Issue: "8928"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Features
|
|
||||||
body: Add exports to SavedQuery spec
|
|
||||||
time: 2023-10-31T13:20:22.448158-07:00
|
|
||||||
custom:
|
|
||||||
Author: QMalcolm peterallenwebb
|
|
||||||
Issue: "8892"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Features
|
|
||||||
body: Remove legacy logger
|
|
||||||
time: 2023-11-07T13:56:35.186648-08:00
|
|
||||||
custom:
|
|
||||||
Author: colin-rogers-dbt
|
|
||||||
Issue: "8027"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Features
|
|
||||||
body: Support setting export configs hierarchically via saved query and project configs
|
|
||||||
time: 2023-11-10T15:42:55.042317-08:00
|
|
||||||
custom:
|
|
||||||
Author: QMalcolm
|
|
||||||
Issue: "8956"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: For packages installed with tarball method, fetch metadata to resolve nested dependencies
|
|
||||||
time: 2023-10-13T13:09:43.188308-04:00
|
|
||||||
custom:
|
|
||||||
Author: adamlopez
|
|
||||||
Issue: "8621"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Fix partial parsing not working for semantic model change
|
|
||||||
time: 2023-10-16T16:39:53.05058-07:00
|
|
||||||
custom:
|
|
||||||
Author: ChenyuLInx
|
|
||||||
Issue: "8859"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Handle unknown `type_code` for model contracts
|
|
||||||
time: 2023-10-24T11:01:51.980781-06:00
|
|
||||||
custom:
|
|
||||||
Author: dbeatty10
|
|
||||||
Issue: 8877 8353
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Add back contract enforcement for temporary tables on postgres
|
|
||||||
time: 2023-10-24T14:55:04.051683-05:00
|
|
||||||
custom:
|
|
||||||
Author: emmyoop
|
|
||||||
Issue: "8857"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Rework get_catalog implementation to retain previous adapter interface semantics
|
|
||||||
time: 2023-10-24T15:54:00.628086-04:00
|
|
||||||
custom:
|
|
||||||
Author: peterallenwebb
|
|
||||||
Issue: "8846"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Add version to fqn when version==0
|
|
||||||
time: 2023-10-26T00:25:36.259356-05:00
|
|
||||||
custom:
|
|
||||||
Author: aranke
|
|
||||||
Issue: "8836"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Fix cased comparison in catalog-retrieval function.
|
|
||||||
time: 2023-10-30T09:37:34.258612-04:00
|
|
||||||
custom:
|
|
||||||
Author: peterallenwebb
|
|
||||||
Issue: "8939"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Catalog queries now assign the correct type to materialized views
|
|
||||||
time: 2023-10-31T00:53:45.486203-04:00
|
|
||||||
custom:
|
|
||||||
Author: mikealfare
|
|
||||||
Issue: "8864"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Fix compilation exception running empty seed file and support new Integer agate data_type
|
|
||||||
time: 2023-10-31T14:48:37.774871-04:00
|
|
||||||
custom:
|
|
||||||
Author: gshank
|
|
||||||
Issue: "8895"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Make relation filtering None-tolerant for maximal flexibility across adapters.
|
|
||||||
time: 2023-11-01T15:58:24.552054-04:00
|
|
||||||
custom:
|
|
||||||
Author: peterallenwebb
|
|
||||||
Issue: "8974"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Update run_results.json from previous versions of dbt to support deferral and
|
|
||||||
rerun from failure
|
|
||||||
time: 2023-11-06T15:59:33.677915-05:00
|
|
||||||
custom:
|
|
||||||
Author: jtcohen6 peterallenwebb
|
|
||||||
Issue: "9010"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Fix git repository with subdirectory for Deps
|
|
||||||
time: 2023-11-07T09:23:58.214271-08:00
|
|
||||||
custom:
|
|
||||||
Author: ChenyuLInx
|
|
||||||
Issue: "9000"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Use MANIFEST.in to recursively include all jinja templates; fixes issue where
|
|
||||||
some templates were not included in the distribution
|
|
||||||
time: 2023-11-07T09:41:30.121733-05:00
|
|
||||||
custom:
|
|
||||||
Author: mikealfare
|
|
||||||
Issue: "9016"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: Fix formatting of tarball information in packages-lock.yml
|
|
||||||
time: 2023-11-13T11:49:56.437007-08:00
|
|
||||||
custom:
|
|
||||||
Author: ChenyuLInx QMalcolm
|
|
||||||
Issue: "9062"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: 'deps: Lock git packages to commit SHA during resolution'
|
|
||||||
time: 2023-11-27T15:43:10.122069+01:00
|
|
||||||
custom:
|
|
||||||
Author: jtcohen6
|
|
||||||
Issue: "9050"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: 'deps: Use PackageRenderer to read package-lock.json'
|
|
||||||
time: 2023-11-27T15:43:47.842423+01:00
|
|
||||||
custom:
|
|
||||||
Author: jtcohen6
|
|
||||||
Issue: "9127"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixes
|
|
||||||
body: 'Get sources working again in dbt docs generate'
|
|
||||||
time: 2023-11-28T15:52:25.738256Z
|
|
||||||
custom:
|
|
||||||
Author: aranke
|
|
||||||
Issue: "9119"
|
|
||||||
6
.changes/unreleased/Under the Hood-20230113-132513.yaml
Normal file
6
.changes/unreleased/Under the Hood-20230113-132513.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Under the Hood
|
||||||
|
body: Fix use of ConnectionReused logging event
|
||||||
|
time: 2023-01-13T13:25:13.023168-05:00
|
||||||
|
custom:
|
||||||
|
Author: gshank
|
||||||
|
Issue: "6168"
|
||||||
6
.changes/unreleased/Under the Hood-20230117-111737.yaml
Normal file
6
.changes/unreleased/Under the Hood-20230117-111737.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Under the Hood
|
||||||
|
body: Update deprecated github action command
|
||||||
|
time: 2023-01-17T11:17:37.046095-06:00
|
||||||
|
custom:
|
||||||
|
Author: davidbloss
|
||||||
|
Issue: "6153"
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Added more type annotations.
|
|
||||||
time: 2023-08-31T16:44:35.737954-04:00
|
|
||||||
custom:
|
|
||||||
Author: peterallenwebb
|
|
||||||
Issue: "8537"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Remove usage of dbt.include.global_project in dbt/adapters
|
|
||||||
time: 2023-10-26T18:49:53.36449-04:00
|
|
||||||
custom:
|
|
||||||
Author: michelleark
|
|
||||||
Issue: "8925"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Add a no-op runner for Saved Qeury
|
|
||||||
time: 2023-10-27T14:00:48.4755-07:00
|
|
||||||
custom:
|
|
||||||
Author: ChenyuLInx
|
|
||||||
Issue: "8893"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: remove dbt.flags.MP_CONTEXT usage in dbt/adapters
|
|
||||||
time: 2023-11-01T10:27:58.790153-04:00
|
|
||||||
custom:
|
|
||||||
Author: michelleark
|
|
||||||
Issue: "8967"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: 'Remove usage of dbt.flags.LOG_CACHE_EVENTS in dbt/adapters'
|
|
||||||
time: 2023-11-01T17:31:24.974093-04:00
|
|
||||||
custom:
|
|
||||||
Author: michelleark
|
|
||||||
Issue: "8969"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Move CatalogRelationTypes test case to the shared test suite to be reused by
|
|
||||||
adapter maintainers
|
|
||||||
time: 2023-11-03T19:52:22.694394-04:00
|
|
||||||
custom:
|
|
||||||
Author: mikealfare
|
|
||||||
Issue: "8952"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Treat SystemExit as an interrupt if raised during node execution.
|
|
||||||
time: 2023-11-06T08:04:22.022179-05:00
|
|
||||||
custom:
|
|
||||||
Author: benmosher
|
|
||||||
Issue: n/a
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Removing unused 'documentable'
|
|
||||||
time: 2023-11-06T10:57:30.694056-08:00
|
|
||||||
custom:
|
|
||||||
Author: QMalcolm
|
|
||||||
Issue: "8871"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Remove use of dbt/core exceptions in dbt/adapter
|
|
||||||
time: 2023-11-07T13:57:28.683727-08:00
|
|
||||||
custom:
|
|
||||||
Author: colin-rogers-dbt MichelleArk
|
|
||||||
Issue: "8920"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Cache dbt plugin modules to improve integration test performance
|
|
||||||
time: 2023-11-07T19:15:46.170151-05:00
|
|
||||||
custom:
|
|
||||||
Author: peterallenwebb
|
|
||||||
Issue: "9029"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Fix test_current_timestamp_matches_utc test; allow for MacOS runner system clock
|
|
||||||
variance
|
|
||||||
time: 2023-11-11T17:53:50.098843-05:00
|
|
||||||
custom:
|
|
||||||
Author: mikealfare
|
|
||||||
Issue: "9057"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Remove usage of dbt.deprecations in dbt/adapters, enable core & adapter-specific
|
|
||||||
event types and protos
|
|
||||||
time: 2023-11-16T17:42:51.005023-05:00
|
|
||||||
custom:
|
|
||||||
Author: michelleark
|
|
||||||
Issue: 8927 8918
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Clean up unused adaptor folders
|
|
||||||
time: 2023-11-20T13:47:35.923794-08:00
|
|
||||||
custom:
|
|
||||||
Author: ChenyuLInx
|
|
||||||
Issue: "9123"
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Move column constraints into common/contracts, removing another dependency of
|
|
||||||
adapters on core.
|
|
||||||
time: 2023-11-20T18:32:14.859503-05:00
|
|
||||||
custom:
|
|
||||||
Author: peterallenwebb
|
|
||||||
Issue: "9024"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Move dbt.semver to dbt.common.semver and update references.
|
|
||||||
time: 2023-11-28T17:07:32.172421-08:00
|
|
||||||
custom:
|
|
||||||
Author: versusfacit
|
|
||||||
Issue: "9039"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Move lowercase utils method to common
|
|
||||||
time: 2023-11-30T13:54:32.561673-08:00
|
|
||||||
custom:
|
|
||||||
Author: colin-rogers-dbt
|
|
||||||
Issue: "9180"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Remove usages of dbt.clients.jinja in dbt/adapters
|
|
||||||
time: 2023-12-05T09:35:44.845352+09:00
|
|
||||||
custom:
|
|
||||||
Author: michelleark
|
|
||||||
Issue: "9205"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Remove usage of dbt.contracts in dbt/adapters
|
|
||||||
time: 2023-12-05T12:05:59.936775+09:00
|
|
||||||
custom:
|
|
||||||
Author: michelleark
|
|
||||||
Issue: "9208"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Remove usage of dbt.contracts.graph.nodes.ResultNode in dbt/adapters
|
|
||||||
time: 2023-12-05T16:58:12.932172+09:00
|
|
||||||
custom:
|
|
||||||
Author: michelleark
|
|
||||||
Issue: "9214"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Under the Hood
|
|
||||||
body: Introduce RelationConfig Protocol, consolidate Relation.create_from
|
|
||||||
time: 2023-12-05T17:07:25.33861+09:00
|
|
||||||
custom:
|
|
||||||
Author: michelleark
|
|
||||||
Issue: "9215"
|
|
||||||
@@ -4,7 +4,6 @@ headerPath: header.tpl.md
|
|||||||
versionHeaderPath: ""
|
versionHeaderPath: ""
|
||||||
changelogPath: CHANGELOG.md
|
changelogPath: CHANGELOG.md
|
||||||
versionExt: md
|
versionExt: md
|
||||||
envPrefix: "CHANGIE_"
|
|
||||||
versionFormat: '## dbt-core {{.Version}} - {{.Time.Format "January 02, 2006"}}'
|
versionFormat: '## dbt-core {{.Version}} - {{.Time.Format "January 02, 2006"}}'
|
||||||
kindFormat: '### {{.Kind}}'
|
kindFormat: '### {{.Kind}}'
|
||||||
changeFormat: |-
|
changeFormat: |-
|
||||||
@@ -88,44 +87,32 @@ custom:
|
|||||||
|
|
||||||
footerFormat: |
|
footerFormat: |
|
||||||
{{- $contributorDict := dict }}
|
{{- $contributorDict := dict }}
|
||||||
{{- /* ensure all names in this list are all lowercase for later matching purposes */}}
|
{{- /* any names added to this list should be all lowercase for later matching purposes */}}
|
||||||
{{- $core_team := splitList " " .Env.CORE_TEAM }}
|
{{- $core_team := list "michelleark" "peterallenwebb" "emmyoop" "nathaniel-may" "gshank" "leahwicz" "chenyulinx" "stu-k" "iknox-fa" "versusfacit" "mcknight-42" "jtcohen6" "aranke" "dependabot[bot]" "snyk-bot" "colin-rogers-dbt" }}
|
||||||
{{- /* ensure we always skip snyk and dependabot in addition to the core team */}}
|
|
||||||
{{- $maintainers := list "dependabot[bot]" "snyk-bot"}}
|
|
||||||
{{- range $team_member := $core_team }}
|
|
||||||
{{- $team_member_lower := lower $team_member }}
|
|
||||||
{{- $maintainers = append $maintainers $team_member_lower }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $change := .Changes }}
|
{{- range $change := .Changes }}
|
||||||
{{- $authorList := splitList " " $change.Custom.Author }}
|
{{- $authorList := splitList " " $change.Custom.Author }}
|
||||||
{{- /* loop through all authors for a single changelog */}}
|
{{- /* loop through all authors for a single changelog */}}
|
||||||
{{- range $author := $authorList }}
|
{{- range $author := $authorList }}
|
||||||
{{- $authorLower := lower $author }}
|
{{- $authorLower := lower $author }}
|
||||||
{{- /* we only want to include non-core team contributors */}}
|
{{- /* we only want to include non-core team contributors */}}
|
||||||
{{- if not (has $authorLower $maintainers)}}
|
{{- if not (has $authorLower $core_team)}}
|
||||||
{{- $changeList := splitList " " $change.Custom.Author }}
|
{{- $changeList := splitList " " $change.Custom.Author }}
|
||||||
{{- $IssueList := list }}
|
{{- /* Docs kind link back to dbt-docs instead of dbt-core issues */}}
|
||||||
{{- $changeLink := $change.Kind }}
|
{{- $changeLink := $change.Kind }}
|
||||||
{{- if or (eq $change.Kind "Dependencies") (eq $change.Kind "Security") }}
|
{{- if or (eq $change.Kind "Dependencies") (eq $change.Kind "Security") }}
|
||||||
{{- $changes := splitList " " $change.Custom.PR }}
|
{{- $changeLink = "[#nbr](https://github.com/dbt-labs/dbt-core/pull/nbr)" | replace "nbr" $change.Custom.PR }}
|
||||||
{{- range $issueNbr := $changes }}
|
{{- else if eq $change.Kind "Docs"}}
|
||||||
{{- $changeLink := "[#nbr](https://github.com/dbt-labs/dbt-core/pull/nbr)" | replace "nbr" $issueNbr }}
|
{{- $changeLink = "[dbt-docs/#nbr](https://github.com/dbt-labs/dbt-docs/issues/nbr)" | replace "nbr" $change.Custom.Issue }}
|
||||||
{{- $IssueList = append $IssueList $changeLink }}
|
|
||||||
{{- end -}}
|
|
||||||
{{- else }}
|
{{- else }}
|
||||||
{{- $changes := splitList " " $change.Custom.Issue }}
|
{{- $changeLink = "[#nbr](https://github.com/dbt-labs/dbt-core/issues/nbr)" | replace "nbr" $change.Custom.Issue }}
|
||||||
{{- range $issueNbr := $changes }}
|
|
||||||
{{- $changeLink := "[#nbr](https://github.com/dbt-labs/dbt-core/issues/nbr)" | replace "nbr" $issueNbr }}
|
|
||||||
{{- $IssueList = append $IssueList $changeLink }}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- /* check if this contributor has other changes associated with them already */}}
|
{{- /* check if this contributor has other changes associated with them already */}}
|
||||||
{{- if hasKey $contributorDict $author }}
|
{{- if hasKey $contributorDict $author }}
|
||||||
{{- $contributionList := get $contributorDict $author }}
|
{{- $contributionList := get $contributorDict $author }}
|
||||||
{{- $contributionList = concat $contributionList $IssueList }}
|
{{- $contributionList = append $contributionList $changeLink }}
|
||||||
{{- $contributorDict := set $contributorDict $author $contributionList }}
|
{{- $contributorDict := set $contributorDict $author $contributionList }}
|
||||||
{{- else }}
|
{{- else }}
|
||||||
{{- $contributionList := $IssueList }}
|
{{- $contributionList := list $changeLink }}
|
||||||
{{- $contributorDict := set $contributorDict $author $contributionList }}
|
{{- $contributorDict := set $contributorDict $author $contributionList }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|||||||
2
.flake8
2
.flake8
@@ -10,5 +10,3 @@ ignore =
|
|||||||
E741
|
E741
|
||||||
E501 # long line checking is done in black
|
E501 # long line checking is done in black
|
||||||
exclude = test/
|
exclude = test/
|
||||||
per-file-ignores =
|
|
||||||
*/__init__.py: F401
|
|
||||||
|
|||||||
6
.gitattributes
vendored
6
.gitattributes
vendored
@@ -1,6 +1,2 @@
|
|||||||
core/dbt/task/docs/index.html binary
|
core/dbt/include/index.html binary
|
||||||
tests/functional/artifacts/data/state/*/manifest.json binary
|
tests/functional/artifacts/data/state/*/manifest.json binary
|
||||||
core/dbt/docs/build/html/searchindex.js binary
|
|
||||||
core/dbt/docs/build/html/index.html binary
|
|
||||||
performance/runner/Cargo.lock binary
|
|
||||||
core/dbt/events/types_pb2.py binary
|
|
||||||
|
|||||||
46
.github/CODEOWNERS
vendored
46
.github/CODEOWNERS
vendored
@@ -11,7 +11,44 @@
|
|||||||
|
|
||||||
# As a default for areas with no assignment,
|
# As a default for areas with no assignment,
|
||||||
# the core team as a whole will be assigned
|
# the core team as a whole will be assigned
|
||||||
* @dbt-labs/core-team
|
* @dbt-labs/core
|
||||||
|
|
||||||
|
# Changes to GitHub configurations including Actions
|
||||||
|
/.github/ @leahwicz
|
||||||
|
|
||||||
|
### LANGUAGE
|
||||||
|
|
||||||
|
# Language core modules
|
||||||
|
/core/dbt/config/ @dbt-labs/core-language
|
||||||
|
/core/dbt/context/ @dbt-labs/core-language
|
||||||
|
/core/dbt/contracts/ @dbt-labs/core-language
|
||||||
|
/core/dbt/deps/ @dbt-labs/core-language
|
||||||
|
/core/dbt/events/ @dbt-labs/core-language # structured logging
|
||||||
|
/core/dbt/parser/ @dbt-labs/core-language
|
||||||
|
|
||||||
|
# Language misc files
|
||||||
|
/core/dbt/dataclass_schema.py @dbt-labs/core-language
|
||||||
|
/core/dbt/hooks.py @dbt-labs/core-language
|
||||||
|
/core/dbt/node_types.py @dbt-labs/core-language
|
||||||
|
/core/dbt/semver.py @dbt-labs/core-language
|
||||||
|
|
||||||
|
|
||||||
|
### EXECUTION
|
||||||
|
|
||||||
|
# Execution core modules
|
||||||
|
/core/dbt/graph/ @dbt-labs/core-execution
|
||||||
|
/core/dbt/task/ @dbt-labs/core-execution
|
||||||
|
|
||||||
|
# Execution misc files
|
||||||
|
/core/dbt/compilation.py @dbt-labs/core-execution
|
||||||
|
/core/dbt/flags.py @dbt-labs/core-execution
|
||||||
|
/core/dbt/lib.py @dbt-labs/core-execution
|
||||||
|
/core/dbt/main.py @dbt-labs/core-execution
|
||||||
|
/core/dbt/profiler.py @dbt-labs/core-execution
|
||||||
|
/core/dbt/selected_resources.py @dbt-labs/core-execution
|
||||||
|
/core/dbt/tracking.py @dbt-labs/core-execution
|
||||||
|
/core/dbt/version.py @dbt-labs/core-execution
|
||||||
|
|
||||||
|
|
||||||
### ADAPTERS
|
### ADAPTERS
|
||||||
|
|
||||||
@@ -23,7 +60,6 @@
|
|||||||
|
|
||||||
# Postgres plugin
|
# Postgres plugin
|
||||||
/plugins/ @dbt-labs/core-adapters
|
/plugins/ @dbt-labs/core-adapters
|
||||||
/plugins/postgres/setup.py @dbt-labs/core-adapters
|
|
||||||
|
|
||||||
# Functional tests for adapter plugins
|
# Functional tests for adapter plugins
|
||||||
/tests/adapter @dbt-labs/core-adapters
|
/tests/adapter @dbt-labs/core-adapters
|
||||||
@@ -35,9 +71,5 @@
|
|||||||
# Perf regression testing framework
|
# Perf regression testing framework
|
||||||
# This excludes the test project files itself since those aren't specific
|
# This excludes the test project files itself since those aren't specific
|
||||||
# framework changes (excluded by not setting an owner next to it- no owner)
|
# framework changes (excluded by not setting an owner next to it- no owner)
|
||||||
/performance @nathaniel-may
|
/performance @nathaniel-may
|
||||||
/performance/projects
|
/performance/projects
|
||||||
|
|
||||||
### ARTIFACTS
|
|
||||||
|
|
||||||
/schemas/dbt @dbt-labs/cloud-artifacts
|
|
||||||
|
|||||||
58
.github/ISSUE_TEMPLATE/implementation-ticket.yml
vendored
58
.github/ISSUE_TEMPLATE/implementation-ticket.yml
vendored
@@ -1,58 +0,0 @@
|
|||||||
name: 🛠️ Implementation
|
|
||||||
description: This is an implementation ticket intended for use by the maintainers of dbt-core
|
|
||||||
title: "[<project>] <title>"
|
|
||||||
labels: ["user docs"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: This is an implementation ticket intended for use by the maintainers of dbt-core
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Housekeeping
|
|
||||||
description: >
|
|
||||||
A couple friendly reminders:
|
|
||||||
1. Remove the `user docs` label if the scope of this work does not require changes to https://docs.getdbt.com/docs: no end-user interface (e.g. yml spec, CLI, error messages, etc) or functional changes
|
|
||||||
2. Link any blocking issues in the "Blocked on" field under the "Core devs & maintainers" project.
|
|
||||||
options:
|
|
||||||
- label: I am a maintainer of dbt-core
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Short description
|
|
||||||
description: |
|
|
||||||
Describe the scope of the ticket, a high-level implementation approach and any tradeoffs to consider
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Acceptance criteria
|
|
||||||
description: |
|
|
||||||
What is the definition of done for this ticket? Include any relevant edge cases and/or test cases
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Impact to Other Teams
|
|
||||||
description: |
|
|
||||||
Will this change impact other teams? Include details of the kinds of changes required (new tests, code changes, related tickets) and _add the relevant `Impact:[team]` label_.
|
|
||||||
placeholder: |
|
|
||||||
Example: This change impacts `dbt-redshift` because the tests will need to be modified. The `Impact:[Adapter]` label has been added.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Will backports be required?
|
|
||||||
description: |
|
|
||||||
Will this change need to be backported to previous versions? Add details, possible blockers to backporting and _add the relevant backport labels `backport 1.x.latest`_
|
|
||||||
placeholder: |
|
|
||||||
Example: Backport to 1.6.latest, 1.5.latest and 1.4.latest. Since 1.4 isn't using click, the backport may be complicated. The `backport 1.6.latest`, `backport 1.5.latest` and `backport 1.4.latest` labels have been added.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Context
|
|
||||||
description: |
|
|
||||||
Provide the "why", motivation, and alternative approaches considered -- linking to previous refinement issues, spikes, Notion docs as appropriate
|
|
||||||
validations:
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
2
.github/_README.md
vendored
2
.github/_README.md
vendored
@@ -197,7 +197,7 @@ ___
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Configure AWS credentials from Test account
|
- name: Configure AWS credentials from Test account
|
||||||
uses: aws-actions/configure-aws-credentials@v2
|
uses: aws-actions/configure-aws-credentials@v1
|
||||||
with:
|
with:
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
|||||||
2
.github/actions/latest-wrangler/README.md
vendored
2
.github/actions/latest-wrangler/README.md
vendored
@@ -35,7 +35,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v1
|
||||||
- name: Wrangle latest tag
|
- name: Wrangle latest tag
|
||||||
id: is_latest
|
id: is_latest
|
||||||
uses: ./.github/actions/latest-wrangler
|
uses: ./.github/actions/latest-wrangler
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v1
|
||||||
- name: Wrangle latest tag
|
- name: Wrangle latest tag
|
||||||
id: is_latest
|
id: is_latest
|
||||||
uses: ./.github/actions/latest-wrangler
|
uses: ./.github/actions/latest-wrangler
|
||||||
|
|||||||
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
@@ -28,10 +28,3 @@ updates:
|
|||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
rebase-strategy: "disabled"
|
rebase-strategy: "disabled"
|
||||||
|
|
||||||
# github dependencies
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
||||||
rebase-strategy: "disabled"
|
|
||||||
|
|||||||
26
.github/pull_request_template.md
vendored
26
.github/pull_request_template.md
vendored
@@ -4,30 +4,20 @@ resolves #
|
|||||||
Include the number of the issue addressed by this PR above if applicable.
|
Include the number of the issue addressed by this PR above if applicable.
|
||||||
PRs for code changes without an associated issue *will not be merged*.
|
PRs for code changes without an associated issue *will not be merged*.
|
||||||
See CONTRIBUTING.md for more information.
|
See CONTRIBUTING.md for more information.
|
||||||
|
|
||||||
Add the `user docs` label to this PR if it will need docs changes. An
|
|
||||||
issue will get opened in docs.getdbt.com upon successful merge of this PR.
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
### Problem
|
### Description
|
||||||
|
|
||||||
<!---
|
<!---
|
||||||
Describe the problem this PR is solving. What is the application state
|
Describe the Pull Request here. Add any references and info to help reviewers
|
||||||
before this PR is merged?
|
understand your changes. Include any tradeoffs you considered.
|
||||||
-->
|
|
||||||
|
|
||||||
### Solution
|
|
||||||
|
|
||||||
<!---
|
|
||||||
Describe the way this PR solves the above problem. Add as much detail as you
|
|
||||||
can to help reviewers understand your changes. Include any alternatives and
|
|
||||||
tradeoffs you considered.
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
### Checklist
|
### Checklist
|
||||||
|
|
||||||
- [ ] I have read [the contributing guide](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md) and understand what's expected of me
|
- [ ] I have read [the contributing guide](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md) and understand what's expected of me
|
||||||
- [ ] I have run this code in development and it appears to resolve the stated issue
|
- [ ] I have signed the [CLA](https://docs.getdbt.com/docs/contributor-license-agreements)
|
||||||
|
- [ ] I have run this code in development and it appears to resolve the stated issue
|
||||||
- [ ] This PR includes tests, or tests are not required/relevant for this PR
|
- [ ] This PR includes tests, or tests are not required/relevant for this PR
|
||||||
- [ ] This PR has no interface changes (e.g. macros, cli, logs, json artifacts, config files, adapter interface, etc) or this PR has already received feedback and approval from Product or DX
|
- [ ] I have [opened an issue to add/update docs](https://github.com/dbt-labs/docs.getdbt.com/issues/new/choose), or docs changes are not required/relevant for this PR
|
||||||
- [ ] This PR includes [type annotations](https://docs.python.org/3/library/typing.html) for new and modified functions
|
- [ ] I have run `changie new` to [create a changelog entry](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md#adding-a-changelog-entry)
|
||||||
|
|||||||
2
.github/workflows/backport.yml
vendored
2
.github/workflows/backport.yml
vendored
@@ -35,6 +35,6 @@ jobs:
|
|||||||
github.event.pull_request.merged
|
github.event.pull_request.merged
|
||||||
&& contains(github.event.label.name, 'backport')
|
&& contains(github.event.label.name, 'backport')
|
||||||
steps:
|
steps:
|
||||||
- uses: tibdex/backport@v2.0.3
|
- uses: tibdex/backport@v2.0.2
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
2
.github/workflows/bot-changelog.yml
vendored
2
.github/workflows/bot-changelog.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
|||||||
- name: Create and commit changelog on bot PR
|
- name: Create and commit changelog on bot PR
|
||||||
if: ${{ contains(github.event.pull_request.labels.*.name, matrix.label) }}
|
if: ${{ contains(github.event.pull_request.labels.*.name, matrix.label) }}
|
||||||
id: bot_changelog
|
id: bot_changelog
|
||||||
uses: emmyoop/changie_bot@v1.1.0
|
uses: emmyoop/changie_bot@v1.0.1
|
||||||
with:
|
with:
|
||||||
GITHUB_TOKEN: ${{ secrets.FISHTOWN_BOT_PAT }}
|
GITHUB_TOKEN: ${{ secrets.FISHTOWN_BOT_PAT }}
|
||||||
commit_author_name: "Github Build Bot"
|
commit_author_name: "Github Build Bot"
|
||||||
|
|||||||
8
.github/workflows/changelog-existence.yml
vendored
8
.github/workflows/changelog-existence.yml
vendored
@@ -2,8 +2,10 @@
|
|||||||
# Checks that a file has been committed under the /.changes directory
|
# Checks that a file has been committed under the /.changes directory
|
||||||
# as a new CHANGELOG entry. Cannot check for a specific filename as
|
# as a new CHANGELOG entry. Cannot check for a specific filename as
|
||||||
# it is dynamically generated by change type and timestamp.
|
# it is dynamically generated by change type and timestamp.
|
||||||
# This workflow runs on pull_request_target because it requires
|
# This workflow should not require any secrets since it runs for PRs
|
||||||
# secrets to post comments.
|
# from forked repos.
|
||||||
|
# By default, secrets are not passed to workflows running from
|
||||||
|
# a forked repo.
|
||||||
|
|
||||||
# **why?**
|
# **why?**
|
||||||
# Ensure code change gets reflected in the CHANGELOG.
|
# Ensure code change gets reflected in the CHANGELOG.
|
||||||
@@ -17,7 +19,7 @@
|
|||||||
name: Check Changelog Entry
|
name: Check Changelog Entry
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request:
|
||||||
types: [opened, reopened, labeled, unlabeled, synchronize]
|
types: [opened, reopened, labeled, unlabeled, synchronize]
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
|||||||
41
.github/workflows/cut-release-branch.yml
vendored
41
.github/workflows/cut-release-branch.yml
vendored
@@ -1,41 +0,0 @@
|
|||||||
# **what?**
|
|
||||||
# Cuts a new `*.latest` branch
|
|
||||||
# Also cleans up all files in `.changes/unreleased` and `.changes/previous verion on
|
|
||||||
# `main` and bumps `main` to the input version.
|
|
||||||
|
|
||||||
# **why?**
|
|
||||||
# Generally reduces the workload of engineers and reduces error. Allow automation.
|
|
||||||
|
|
||||||
# **when?**
|
|
||||||
# This will run when called manually.
|
|
||||||
|
|
||||||
name: Cut new release branch
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version_to_bump_main:
|
|
||||||
description: 'The alpha version main should bump to (ex. 1.6.0a1)'
|
|
||||||
required: true
|
|
||||||
new_branch_name:
|
|
||||||
description: 'The full name of the new branch (ex. 1.5.latest)'
|
|
||||||
required: true
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cut_branch:
|
|
||||||
name: "Cut branch and clean up main for dbt-core"
|
|
||||||
uses: dbt-labs/actions/.github/workflows/cut-release-branch.yml@main
|
|
||||||
with:
|
|
||||||
version_to_bump_main: ${{ inputs.version_to_bump_main }}
|
|
||||||
new_branch_name: ${{ inputs.new_branch_name }}
|
|
||||||
PR_title: "Cleanup main after cutting new ${{ inputs.new_branch_name }} branch"
|
|
||||||
PR_body: "All adapter PRs will fail CI until the dbt-core PR has been merged due to release version conflicts."
|
|
||||||
secrets:
|
|
||||||
FISHTOWN_BOT_PAT: ${{ secrets.FISHTOWN_BOT_PAT }}
|
|
||||||
43
.github/workflows/docs-issue.yml
vendored
43
.github/workflows/docs-issue.yml
vendored
@@ -1,43 +0,0 @@
|
|||||||
# **what?**
|
|
||||||
# Open an issue in docs.getdbt.com when a PR is labeled `user docs`
|
|
||||||
|
|
||||||
# **why?**
|
|
||||||
# To reduce barriers for keeping docs up to date
|
|
||||||
|
|
||||||
# **when?**
|
|
||||||
# When a PR is labeled `user docs` and is merged. Runs on pull_request_target to run off the workflow already merged,
|
|
||||||
# not the workflow that existed on the PR branch. This allows old PRs to get comments.
|
|
||||||
|
|
||||||
|
|
||||||
name: Open issues in docs.getdbt.com repo when a PR is labeled
|
|
||||||
run-name: "Open an issue in docs.getdbt.com for PR #${{ github.event.pull_request.number }}"
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types: [labeled, closed]
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
issues: write # opens new issues
|
|
||||||
pull-requests: write # comments on PRs
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
open_issues:
|
|
||||||
# we only want to run this when the PR has been merged or the label in the labeled event is `user docs`. Otherwise it runs the
|
|
||||||
# risk of duplicaton of issues being created due to merge and label both triggering this workflow to run and neither having
|
|
||||||
# generating the comment before the other runs. This lives here instead of the shared workflow because this is where we
|
|
||||||
# decide if it should run or not.
|
|
||||||
if: |
|
|
||||||
(github.event.pull_request.merged == true) &&
|
|
||||||
((github.event.action == 'closed' && contains( github.event.pull_request.labels.*.name, 'user docs')) ||
|
|
||||||
(github.event.action == 'labeled' && github.event.label.name == 'user docs'))
|
|
||||||
uses: dbt-labs/actions/.github/workflows/open-issue-in-repo.yml@main
|
|
||||||
with:
|
|
||||||
issue_repository: "dbt-labs/docs.getdbt.com"
|
|
||||||
issue_title: "Docs Changes Needed from ${{ github.event.repository.name }} PR #${{ github.event.pull_request.number }}"
|
|
||||||
issue_body: "At a minimum, update body to include a link to the page on docs.getdbt.com requiring updates and what part(s) of the page you would like to see updated."
|
|
||||||
secrets: inherit
|
|
||||||
165
.github/workflows/generate-cli-api-docs.yml
vendored
Normal file
165
.github/workflows/generate-cli-api-docs.yml
vendored
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# **what?**
|
||||||
|
# On push, if anything in core/dbt/docs or core/dbt/cli has been
|
||||||
|
# created or modified, regenerate the CLI API docs using sphinx.
|
||||||
|
|
||||||
|
# **why?**
|
||||||
|
# We watch for changes in core/dbt/cli because the CLI API docs rely on click
|
||||||
|
# and all supporting flags/params to be generated. We watch for changes in
|
||||||
|
# core/dbt/docs since any changes to sphinx configuration or any of the
|
||||||
|
# .rst files there could result in a differently build final index.html file.
|
||||||
|
|
||||||
|
# **when?**
|
||||||
|
# Whenever a change has been pushed to a branch, and only if there is a diff
|
||||||
|
# between the PR branch and main's core/dbt/cli and or core/dbt/docs dirs.
|
||||||
|
|
||||||
|
# TODO: add bot comment to PR informing contributor that the docs have been committed
|
||||||
|
# TODO: figure out why github action triggered pushes cause github to fail to report
|
||||||
|
# the status of jobs
|
||||||
|
|
||||||
|
name: Generate CLI API docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
CLI_DIR: ${{ github.workspace }}/core/dbt/cli
|
||||||
|
DOCS_DIR: ${{ github.workspace }}/core/dbt/docs
|
||||||
|
DOCS_BUILD_DIR: ${{ github.workspace }}/core/dbt/docs/build
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check_gen:
|
||||||
|
name: check if generation needed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.event.pull_request.head.repo.fork == false }}
|
||||||
|
outputs:
|
||||||
|
cli_dir_changed: ${{ steps.check_cli.outputs.cli_dir_changed }}
|
||||||
|
docs_dir_changed: ${{ steps.check_docs.outputs.docs_dir_changed }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: "[DEBUG] print variables"
|
||||||
|
run: |
|
||||||
|
echo "env.CLI_DIR: ${{ env.CLI_DIR }}"
|
||||||
|
echo "env.DOCS_BUILD_DIR: ${{ env.DOCS_BUILD_DIR }}"
|
||||||
|
echo "env.DOCS_DIR: ${{ env.DOCS_DIR }}"
|
||||||
|
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ github.head_ref }}
|
||||||
|
|
||||||
|
- name: set shas
|
||||||
|
id: set_shas
|
||||||
|
run: |
|
||||||
|
THIS_SHA=$(git rev-parse @)
|
||||||
|
LAST_SHA=$(git rev-parse @~1)
|
||||||
|
|
||||||
|
echo "this sha: $THIS_SHA"
|
||||||
|
echo "last sha: $LAST_SHA"
|
||||||
|
|
||||||
|
echo "this_sha=$THIS_SHA" >> $GITHUB_OUTPUT
|
||||||
|
echo "last_sha=$LAST_SHA" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: check for changes in core/dbt/cli
|
||||||
|
id: check_cli
|
||||||
|
run: |
|
||||||
|
CLI_DIR_CHANGES=$(git diff \
|
||||||
|
${{ steps.set_shas.outputs.last_sha }} \
|
||||||
|
${{ steps.set_shas.outputs.this_sha }} \
|
||||||
|
-- ${{ env.CLI_DIR }})
|
||||||
|
|
||||||
|
if [ -n "$CLI_DIR_CHANGES" ]; then
|
||||||
|
echo "changes found"
|
||||||
|
echo $CLI_DIR_CHANGES
|
||||||
|
echo "cli_dir_changed=true" >> $GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "cli_dir_changed=false" >> $GITHUB_OUTPUT
|
||||||
|
echo "no changes found"
|
||||||
|
|
||||||
|
- name: check for changes in core/dbt/docs
|
||||||
|
id: check_docs
|
||||||
|
if: steps.check_cli.outputs.cli_dir_changed == 'false'
|
||||||
|
run: |
|
||||||
|
DOCS_DIR_CHANGES=$(git diff --name-only \
|
||||||
|
${{ steps.set_shas.outputs.last_sha }} \
|
||||||
|
${{ steps.set_shas.outputs.this_sha }} \
|
||||||
|
-- ${{ env.DOCS_DIR }} ':!${{ env.DOCS_BUILD_DIR }}')
|
||||||
|
|
||||||
|
DOCS_BUILD_DIR_CHANGES=$(git diff --name-only \
|
||||||
|
${{ steps.set_shas.outputs.last_sha }} \
|
||||||
|
${{ steps.set_shas.outputs.this_sha }} \
|
||||||
|
-- ${{ env.DOCS_BUILD_DIR }})
|
||||||
|
|
||||||
|
if [ -n "$DOCS_DIR_CHANGES" ] && [ -z "$DOCS_BUILD_DIR_CHANGES" ]; then
|
||||||
|
echo "changes found"
|
||||||
|
echo $DOCS_DIR_CHANGES
|
||||||
|
echo "docs_dir_changed=true" >> $GITHUB_OUTPUT
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "docs_dir_changed=false" >> $GITHUB_OUTPUT
|
||||||
|
echo "no changes found"
|
||||||
|
|
||||||
|
gen_docs:
|
||||||
|
name: generate docs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [check_gen]
|
||||||
|
if: |
|
||||||
|
needs.check_gen.outputs.cli_dir_changed == 'true'
|
||||||
|
|| needs.check_gen.outputs.docs_dir_changed == 'true'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: "[DEBUG] print variables"
|
||||||
|
run: |
|
||||||
|
echo "env.DOCS_DIR: ${{ env.DOCS_DIR }}"
|
||||||
|
echo "github head_ref: ${{ github.head_ref }}"
|
||||||
|
|
||||||
|
- name: git checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: ${{ github.head_ref }}
|
||||||
|
|
||||||
|
- name: install python
|
||||||
|
uses: actions/setup-python@v4.3.0
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
|
||||||
|
- name: install dev requirements
|
||||||
|
run: |
|
||||||
|
python3 -m venv env
|
||||||
|
source env/bin/activate
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r requirements.txt -r dev-requirements.txt
|
||||||
|
|
||||||
|
- name: generate docs
|
||||||
|
run: |
|
||||||
|
source env/bin/activate
|
||||||
|
cd ${{ env.DOCS_DIR }}
|
||||||
|
|
||||||
|
echo "cleaning existing docs"
|
||||||
|
make clean
|
||||||
|
|
||||||
|
echo "creating docs"
|
||||||
|
make html
|
||||||
|
|
||||||
|
- name: debug
|
||||||
|
run: |
|
||||||
|
echo ">>>>> status"
|
||||||
|
git status
|
||||||
|
echo ">>>>> remotes"
|
||||||
|
git remote -v
|
||||||
|
echo ">>>>> branch"
|
||||||
|
git branch -v
|
||||||
|
echo ">>>>> log"
|
||||||
|
git log --pretty=oneline | head -5
|
||||||
|
|
||||||
|
- name: commit docs
|
||||||
|
run: |
|
||||||
|
git config user.name 'Github Build Bot'
|
||||||
|
git config user.email 'buildbot@fishtownanalytics.com'
|
||||||
|
git commit -am "Add generated CLI API docs"
|
||||||
|
git push -u origin ${{ github.head_ref }}
|
||||||
4
.github/workflows/jira-creation.yml
vendored
4
.github/workflows/jira-creation.yml
vendored
@@ -18,8 +18,8 @@ permissions:
|
|||||||
issues: write
|
issues: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
call-creation-action:
|
call-label-action:
|
||||||
uses: dbt-labs/actions/.github/workflows/jira-creation-actions.yml@main
|
uses: dbt-labs/jira-actions/.github/workflows/jira-creation.yml@main
|
||||||
secrets:
|
secrets:
|
||||||
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
||||||
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
||||||
|
|||||||
2
.github/workflows/jira-label.yml
vendored
2
.github/workflows/jira-label.yml
vendored
@@ -19,7 +19,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
call-label-action:
|
call-label-action:
|
||||||
uses: dbt-labs/actions/.github/workflows/jira-label-actions.yml@main
|
uses: dbt-labs/jira-actions/.github/workflows/jira-label.yml@main
|
||||||
secrets:
|
secrets:
|
||||||
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
||||||
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
||||||
|
|||||||
4
.github/workflows/jira-transition.yml
vendored
4
.github/workflows/jira-transition.yml
vendored
@@ -19,8 +19,8 @@ on:
|
|||||||
permissions: read-all
|
permissions: read-all
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
call-transition-action:
|
call-label-action:
|
||||||
uses: dbt-labs/actions/.github/workflows/jira-transition-actions.yml@main
|
uses: dbt-labs/jira-actions/.github/workflows/jira-transition.yml@main
|
||||||
secrets:
|
secrets:
|
||||||
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
||||||
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
||||||
|
|||||||
129
.github/workflows/main.yml
vendored
129
.github/workflows/main.yml
vendored
@@ -33,11 +33,6 @@ defaults:
|
|||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
# top-level adjustments can be made here
|
|
||||||
env:
|
|
||||||
# number of parallel processes to spawn for python integration testing
|
|
||||||
PYTHON_INTEGRATION_TEST_WORKERS: 5
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
code-quality:
|
code-quality:
|
||||||
name: code-quality
|
name: code-quality
|
||||||
@@ -47,10 +42,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the repository
|
- name: Check out the repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: '3.8'
|
python-version: '3.8'
|
||||||
|
|
||||||
@@ -58,8 +53,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python -m pip install --user --upgrade pip
|
python -m pip install --user --upgrade pip
|
||||||
python -m pip --version
|
python -m pip --version
|
||||||
make dev
|
python -m pip install pre-commit
|
||||||
|
pre-commit --version
|
||||||
|
python -m pip install mypy==0.942
|
||||||
mypy --version
|
mypy --version
|
||||||
|
python -m pip install -r requirements.txt
|
||||||
|
python -m pip install -r dev-requirements.txt
|
||||||
dbt --version
|
dbt --version
|
||||||
|
|
||||||
- name: Run pre-commit hooks
|
- name: Run pre-commit hooks
|
||||||
@@ -74,17 +73,18 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.8", "3.9", "3.10", "3.11"]
|
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
TOXENV: "unit"
|
TOXENV: "unit"
|
||||||
|
PYTEST_ADDOPTS: "-v --color=yes --csv unit_results.csv"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the repository
|
- name: Check out the repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
@@ -105,80 +105,43 @@ jobs:
|
|||||||
CURRENT_DATE=$(date +'%Y-%m-%dT%H_%M_%S') # no colons allowed for artifacts
|
CURRENT_DATE=$(date +'%Y-%m-%dT%H_%M_%S') # no colons allowed for artifacts
|
||||||
echo "date=$CURRENT_DATE" >> $GITHUB_OUTPUT
|
echo "date=$CURRENT_DATE" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Upload Unit Test Coverage to Codecov
|
- uses: actions/upload-artifact@v2
|
||||||
if: ${{ matrix.python-version == '3.11' }}
|
if: always()
|
||||||
uses: codecov/codecov-action@v3
|
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
name: unit_results_${{ matrix.python-version }}-${{ steps.date.outputs.date }}.csv
|
||||||
flags: unit
|
path: unit_results.csv
|
||||||
|
|
||||||
integration-metadata:
|
|
||||||
name: integration test metadata generation
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
split-groups: ${{ steps.generate-split-groups.outputs.split-groups }}
|
|
||||||
include: ${{ steps.generate-include.outputs.include }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: generate split-groups
|
|
||||||
id: generate-split-groups
|
|
||||||
run: |
|
|
||||||
MATRIX_JSON="["
|
|
||||||
for B in $(seq 1 ${{ env.PYTHON_INTEGRATION_TEST_WORKERS }}); do
|
|
||||||
MATRIX_JSON+=$(sed 's/^/"/;s/$/"/' <<< "${B}")
|
|
||||||
done
|
|
||||||
MATRIX_JSON="${MATRIX_JSON//\"\"/\", \"}"
|
|
||||||
MATRIX_JSON+="]"
|
|
||||||
echo "split-groups=${MATRIX_JSON}"
|
|
||||||
echo "split-groups=${MATRIX_JSON}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: generate include
|
|
||||||
id: generate-include
|
|
||||||
run: |
|
|
||||||
INCLUDE=('"python-version":"3.8","os":"windows-latest"' '"python-version":"3.8","os":"macos-latest"' )
|
|
||||||
INCLUDE_GROUPS="["
|
|
||||||
for include in ${INCLUDE[@]}; do
|
|
||||||
for group in $(seq 1 ${{ env.PYTHON_INTEGRATION_TEST_WORKERS }}); do
|
|
||||||
INCLUDE_GROUPS+=$(sed 's/$/, /' <<< "{\"split-group\":\"${group}\",${include}}")
|
|
||||||
done
|
|
||||||
done
|
|
||||||
INCLUDE_GROUPS=$(echo $INCLUDE_GROUPS | sed 's/,*$//g')
|
|
||||||
INCLUDE_GROUPS+="]"
|
|
||||||
echo "include=${INCLUDE_GROUPS}"
|
|
||||||
echo "include=${INCLUDE_GROUPS}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
integration:
|
integration:
|
||||||
name: (${{ matrix.split-group }}) integration test / python ${{ matrix.python-version }} / ${{ matrix.os }}
|
name: integration test / python ${{ matrix.python-version }} / ${{ matrix.os }}
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
timeout-minutes: 30
|
timeout-minutes: 45
|
||||||
needs:
|
|
||||||
- integration-metadata
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.8", "3.9", "3.10", "3.11"]
|
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
|
||||||
os: [ubuntu-20.04]
|
os: [ubuntu-20.04]
|
||||||
split-group: ${{ fromJson(needs.integration-metadata.outputs.split-groups) }}
|
include:
|
||||||
include: ${{ fromJson(needs.integration-metadata.outputs.include) }}
|
- python-version: 3.8
|
||||||
|
os: windows-latest
|
||||||
|
- python-version: 3.8
|
||||||
|
os: macos-latest
|
||||||
|
|
||||||
env:
|
env:
|
||||||
TOXENV: integration
|
TOXENV: integration
|
||||||
|
PYTEST_ADDOPTS: "-v --color=yes -n4 --csv integration_results.csv"
|
||||||
DBT_INVOCATION_ENV: github-actions
|
DBT_INVOCATION_ENV: github-actions
|
||||||
DBT_TEST_USER_1: dbt_test_user_1
|
DBT_TEST_USER_1: dbt_test_user_1
|
||||||
DBT_TEST_USER_2: dbt_test_user_2
|
DBT_TEST_USER_2: dbt_test_user_2
|
||||||
DBT_TEST_USER_3: dbt_test_user_3
|
DBT_TEST_USER_3: dbt_test_user_3
|
||||||
DD_CIVISIBILITY_AGENTLESS_ENABLED: true
|
|
||||||
DD_API_KEY: ${{ secrets.DATADOG_API_KEY }}
|
|
||||||
DD_SITE: datadoghq.com
|
|
||||||
DD_ENV: ci
|
|
||||||
DD_SERVICE: ${{ github.event.repository.name }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the repository
|
- name: Check out the repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
@@ -202,9 +165,7 @@ jobs:
|
|||||||
tox --version
|
tox --version
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: tox -- --ddtrace
|
run: tox
|
||||||
env:
|
|
||||||
PYTEST_ADDOPTS: ${{ format('--splits {0} --group {1}', env.PYTHON_INTEGRATION_TEST_WORKERS, matrix.split-group) }}
|
|
||||||
|
|
||||||
- name: Get current date
|
- name: Get current date
|
||||||
if: always()
|
if: always()
|
||||||
@@ -213,35 +174,17 @@ jobs:
|
|||||||
CURRENT_DATE=$(date +'%Y-%m-%dT%H_%M_%S') # no colons allowed for artifacts
|
CURRENT_DATE=$(date +'%Y-%m-%dT%H_%M_%S') # no colons allowed for artifacts
|
||||||
echo "date=$CURRENT_DATE" >> $GITHUB_OUTPUT
|
echo "date=$CURRENT_DATE" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v2
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: logs_${{ matrix.python-version }}_${{ matrix.os }}_${{ steps.date.outputs.date }}
|
name: logs_${{ matrix.python-version }}_${{ matrix.os }}_${{ steps.date.outputs.date }}
|
||||||
path: ./logs
|
path: ./logs
|
||||||
|
|
||||||
- name: Upload Integration Test Coverage to Codecov
|
- uses: actions/upload-artifact@v2
|
||||||
if: ${{ matrix.python-version == '3.11' }}
|
if: always()
|
||||||
uses: codecov/codecov-action@v3
|
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
name: integration_results_${{ matrix.python-version }}_${{ matrix.os }}_${{ steps.date.outputs.date }}.csv
|
||||||
flags: integration
|
path: integration_results.csv
|
||||||
|
|
||||||
integration-report:
|
|
||||||
if: ${{ always() }}
|
|
||||||
name: Integration Test Suite
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: integration
|
|
||||||
steps:
|
|
||||||
- name: "Integration Tests Failed"
|
|
||||||
if: ${{ contains(needs.integration.result, 'failure') || contains(needs.integration.result, 'cancelled') }}
|
|
||||||
# when this is true the next step won't execute
|
|
||||||
run: |
|
|
||||||
echo "::notice title='Integration test suite failed'"
|
|
||||||
exit 1
|
|
||||||
|
|
||||||
- name: "Integration Tests Passed"
|
|
||||||
run: |
|
|
||||||
echo "::notice title='Integration test suite passed'"
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: build packages
|
name: build packages
|
||||||
@@ -250,10 +193,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the repository
|
- name: Check out the repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4.3.0
|
||||||
with:
|
with:
|
||||||
python-version: '3.8'
|
python-version: '3.8'
|
||||||
|
|
||||||
|
|||||||
265
.github/workflows/model_performance.yml
vendored
265
.github/workflows/model_performance.yml
vendored
@@ -1,265 +0,0 @@
|
|||||||
# **what?**
|
|
||||||
# This workflow models the performance characteristics of a point in time in dbt.
|
|
||||||
# It runs specific dbt commands on committed projects multiple times to create and
|
|
||||||
# commit information about the distribution to the current branch. For more information
|
|
||||||
# see the readme in the performance module at /performance/README.md.
|
|
||||||
#
|
|
||||||
# **why?**
|
|
||||||
# When developing new features, we can take quick performance samples and compare
|
|
||||||
# them against the commited baseline measurements produced by this workflow to detect
|
|
||||||
# some performance regressions at development time before they reach users.
|
|
||||||
#
|
|
||||||
# **when?**
|
|
||||||
# This is only run once directly after each release (for non-prereleases). If for some
|
|
||||||
# reason the results of a run are not satisfactory, it can also be triggered manually.
|
|
||||||
|
|
||||||
name: Model Performance Characteristics
|
|
||||||
|
|
||||||
on:
|
|
||||||
# runs after non-prereleases are published.
|
|
||||||
release:
|
|
||||||
types: [released]
|
|
||||||
# run manually from the actions tab
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
release_id:
|
|
||||||
description: 'dbt version to model (must be non-prerelease in Pypi)'
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
RUNNER_CACHE_PATH: performance/runner/target/release/runner
|
|
||||||
|
|
||||||
# both jobs need to write
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
set-variables:
|
|
||||||
name: Setting Variables
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
cache_key: ${{ steps.variables.outputs.cache_key }}
|
|
||||||
release_id: ${{ steps.semver.outputs.base-version }}
|
|
||||||
release_branch: ${{ steps.variables.outputs.release_branch }}
|
|
||||||
steps:
|
|
||||||
|
|
||||||
# explicitly checkout the performance runner from main regardless of which
|
|
||||||
# version we are modeling.
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
|
|
||||||
- name: Parse version into parts
|
|
||||||
id: semver
|
|
||||||
uses: dbt-labs/actions/parse-semver@v1
|
|
||||||
with:
|
|
||||||
version: ${{ github.event.inputs.release_id || github.event.release.tag_name }}
|
|
||||||
|
|
||||||
# collect all the variables that need to be used in subsequent jobs
|
|
||||||
- name: Set variables
|
|
||||||
id: variables
|
|
||||||
run: |
|
|
||||||
# create a cache key that will be used in the next job. without this the
|
|
||||||
# next job would have to checkout from main and hash the files itself.
|
|
||||||
echo "cache_key=${{ runner.os }}-${{ hashFiles('performance/runner/Cargo.toml')}}-${{ hashFiles('performance/runner/src/*') }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
branch_name="${{steps.semver.outputs.major}}.${{steps.semver.outputs.minor}}.latest"
|
|
||||||
echo "release_branch=$branch_name" >> $GITHUB_OUTPUT
|
|
||||||
echo "release branch is inferred to be ${branch_name}"
|
|
||||||
|
|
||||||
latest-runner:
|
|
||||||
name: Build or Fetch Runner
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [set-variables]
|
|
||||||
env:
|
|
||||||
RUSTFLAGS: "-D warnings"
|
|
||||||
steps:
|
|
||||||
- name: '[DEBUG] print variables'
|
|
||||||
run: |
|
|
||||||
echo "all variables defined in set-variables"
|
|
||||||
echo "cache_key: ${{ needs.set-variables.outputs.cache_key }}"
|
|
||||||
echo "release_id: ${{ needs.set-variables.outputs.release_id }}"
|
|
||||||
echo "release_branch: ${{ needs.set-variables.outputs.release_branch }}"
|
|
||||||
|
|
||||||
# explicitly checkout the performance runner from main regardless of which
|
|
||||||
# version we are modeling.
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
|
|
||||||
# attempts to access a previously cached runner
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
id: cache
|
|
||||||
with:
|
|
||||||
path: ${{ env.RUNNER_CACHE_PATH }}
|
|
||||||
key: ${{ needs.set-variables.outputs.cache_key }}
|
|
||||||
|
|
||||||
- name: Fetch Rust Toolchain
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
profile: minimal
|
|
||||||
toolchain: stable
|
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: Add fmt
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
run: rustup component add rustfmt
|
|
||||||
|
|
||||||
- name: Cargo fmt
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: fmt
|
|
||||||
args: --manifest-path performance/runner/Cargo.toml --all -- --check
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: test
|
|
||||||
args: --manifest-path performance/runner/Cargo.toml
|
|
||||||
|
|
||||||
- name: Build (optimized)
|
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: build
|
|
||||||
args: --release --manifest-path performance/runner/Cargo.toml
|
|
||||||
# the cache action automatically caches this binary at the end of the job
|
|
||||||
|
|
||||||
model:
|
|
||||||
# depends on `latest-runner` as a separate job so that failures in this job do not prevent
|
|
||||||
# a successfully tested and built binary from being cached.
|
|
||||||
needs: [set-variables, latest-runner]
|
|
||||||
name: Model a release
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: '[DEBUG] print variables'
|
|
||||||
run: |
|
|
||||||
echo "all variables defined in set-variables"
|
|
||||||
echo "cache_key: ${{ needs.set-variables.outputs.cache_key }}"
|
|
||||||
echo "release_id: ${{ needs.set-variables.outputs.release_id }}"
|
|
||||||
echo "release_branch: ${{ needs.set-variables.outputs.release_branch }}"
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: "3.8"
|
|
||||||
|
|
||||||
- name: Install dbt
|
|
||||||
run: pip install dbt-postgres==${{ needs.set-variables.outputs.release_id }}
|
|
||||||
|
|
||||||
- name: Install Hyperfine
|
|
||||||
run: wget https://github.com/sharkdp/hyperfine/releases/download/v1.11.0/hyperfine_1.11.0_amd64.deb && sudo dpkg -i hyperfine_1.11.0_amd64.deb
|
|
||||||
|
|
||||||
# explicitly checkout main to get the latest project definitions
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
|
|
||||||
# this was built in the previous job so it will be there.
|
|
||||||
- name: Fetch Runner
|
|
||||||
uses: actions/cache@v3
|
|
||||||
id: cache
|
|
||||||
with:
|
|
||||||
path: ${{ env.RUNNER_CACHE_PATH }}
|
|
||||||
key: ${{ needs.set-variables.outputs.cache_key }}
|
|
||||||
|
|
||||||
- name: Move Runner
|
|
||||||
run: mv performance/runner/target/release/runner performance/app
|
|
||||||
|
|
||||||
- name: Change Runner Permissions
|
|
||||||
run: chmod +x ./performance/app
|
|
||||||
|
|
||||||
- name: '[DEBUG] ls baseline directory before run'
|
|
||||||
run: ls -R performance/baselines/
|
|
||||||
|
|
||||||
# `${{ github.workspace }}` is used to pass the absolute path
|
|
||||||
- name: Create directories
|
|
||||||
run: |
|
|
||||||
mkdir ${{ github.workspace }}/performance/tmp/
|
|
||||||
mkdir -p performance/baselines/${{ needs.set-variables.outputs.release_id }}/
|
|
||||||
|
|
||||||
# Run modeling with taking 20 samples
|
|
||||||
- name: Run Measurement
|
|
||||||
run: |
|
|
||||||
performance/app model -v ${{ needs.set-variables.outputs.release_id }} -b ${{ github.workspace }}/performance/baselines/ -p ${{ github.workspace }}/performance/projects/ -t ${{ github.workspace }}/performance/tmp/ -n 20
|
|
||||||
|
|
||||||
- name: '[DEBUG] ls baseline directory after run'
|
|
||||||
run: ls -R performance/baselines/
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: baseline
|
|
||||||
path: performance/baselines/${{ needs.set-variables.outputs.release_id }}/
|
|
||||||
|
|
||||||
create-pr:
|
|
||||||
name: Open PR for ${{ matrix.base-branch }}
|
|
||||||
|
|
||||||
# depends on `model` as a separate job so that the baseline can be committed to more than one branch
|
|
||||||
# i.e. release branch and main
|
|
||||||
needs: [set-variables, latest-runner, model]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- base-branch: refs/heads/main
|
|
||||||
target-branch: performance-bot/main_${{ needs.set-variables.outputs.release_id }}_${{GITHUB.RUN_ID}}
|
|
||||||
- base-branch: refs/heads/${{ needs.set-variables.outputs.release_branch }}
|
|
||||||
target-branch: performance-bot/release_${{ needs.set-variables.outputs.release_id }}_${{GITHUB.RUN_ID}}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: '[DEBUG] print variables'
|
|
||||||
run: |
|
|
||||||
echo "all variables defined in set-variables"
|
|
||||||
echo "cache_key: ${{ needs.set-variables.outputs.cache_key }}"
|
|
||||||
echo "release_id: ${{ needs.set-variables.outputs.release_id }}"
|
|
||||||
echo "release_branch: ${{ needs.set-variables.outputs.release_branch }}"
|
|
||||||
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: ${{ matrix.base-branch }}
|
|
||||||
|
|
||||||
- name: Create PR branch
|
|
||||||
run: |
|
|
||||||
git checkout -b ${{ matrix.target-branch }}
|
|
||||||
git push origin ${{ matrix.target-branch }}
|
|
||||||
git branch --set-upstream-to=origin/${{ matrix.target-branch }} ${{ matrix.target-branch }}
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: baseline
|
|
||||||
path: performance/baselines/${{ needs.set-variables.outputs.release_id }}
|
|
||||||
|
|
||||||
- name: '[DEBUG] ls baselines after artifact download'
|
|
||||||
run: ls -R performance/baselines/
|
|
||||||
|
|
||||||
- name: Commit baseline
|
|
||||||
uses: EndBug/add-and-commit@v9
|
|
||||||
with:
|
|
||||||
add: 'performance/baselines/*'
|
|
||||||
author_name: 'Github Build Bot'
|
|
||||||
author_email: 'buildbot@fishtownanalytics.com'
|
|
||||||
message: 'adding performance baseline for ${{ needs.set-variables.outputs.release_id }}'
|
|
||||||
push: 'origin origin/${{ matrix.target-branch }}'
|
|
||||||
|
|
||||||
- name: Create Pull Request
|
|
||||||
uses: peter-evans/create-pull-request@v5
|
|
||||||
with:
|
|
||||||
author: 'Github Build Bot <buildbot@fishtownanalytics.com>'
|
|
||||||
base: ${{ matrix.base-branch }}
|
|
||||||
branch: '${{ matrix.target-branch }}'
|
|
||||||
title: 'Adding performance modeling for ${{needs.set-variables.outputs.release_id}} to ${{ matrix.base-branch }}'
|
|
||||||
body: 'Committing perf results for tracking for the ${{needs.set-variables.outputs.release_id}}'
|
|
||||||
labels: |
|
|
||||||
Skip Changelog
|
|
||||||
Performance
|
|
||||||
109
.github/workflows/nightly-release.yml
vendored
109
.github/workflows/nightly-release.yml
vendored
@@ -1,109 +0,0 @@
|
|||||||
# **what?**
|
|
||||||
# Nightly releases to GitHub and PyPI. This workflow produces the following outcome:
|
|
||||||
# - generate and validate data for night release (commit SHA, version number, release branch);
|
|
||||||
# - pass data to release workflow;
|
|
||||||
# - night release will be pushed to GitHub as a draft release;
|
|
||||||
# - night build will be pushed to test PyPI;
|
|
||||||
#
|
|
||||||
# **why?**
|
|
||||||
# Ensure an automated and tested release process for nightly builds
|
|
||||||
#
|
|
||||||
# **when?**
|
|
||||||
# This workflow runs on schedule or can be run manually on demand.
|
|
||||||
|
|
||||||
name: Nightly Test Release to GitHub and PyPI
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch: # for manual triggering
|
|
||||||
schedule:
|
|
||||||
- cron: 0 9 * * *
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write # this is the permission that allows creating a new release
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
env:
|
|
||||||
RELEASE_BRANCH: "main"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
aggregate-release-data:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
outputs:
|
|
||||||
commit_sha: ${{ steps.resolve-commit-sha.outputs.release_commit }}
|
|
||||||
version_number: ${{ steps.nightly-release-version.outputs.number }}
|
|
||||||
release_branch: ${{ steps.release-branch.outputs.name }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: "Checkout ${{ github.repository }} Branch ${{ env.RELEASE_BRANCH }}"
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: ${{ env.RELEASE_BRANCH }}
|
|
||||||
|
|
||||||
- name: "Resolve Commit To Release"
|
|
||||||
id: resolve-commit-sha
|
|
||||||
run: |
|
|
||||||
commit_sha=$(git rev-parse HEAD)
|
|
||||||
echo "release_commit=$commit_sha" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: "Get Current Version Number"
|
|
||||||
id: version-number-sources
|
|
||||||
run: |
|
|
||||||
current_version=`awk -F"current_version = " '{print $2}' .bumpversion.cfg | tr '\n' ' '`
|
|
||||||
echo "current_version=$current_version" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: "Audit Version And Parse Into Parts"
|
|
||||||
id: semver
|
|
||||||
uses: dbt-labs/actions/parse-semver@v1.1.0
|
|
||||||
with:
|
|
||||||
version: ${{ steps.version-number-sources.outputs.current_version }}
|
|
||||||
|
|
||||||
- name: "Get Current Date"
|
|
||||||
id: current-date
|
|
||||||
run: echo "date=$(date +'%m%d%Y')" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: "Generate Nightly Release Version Number"
|
|
||||||
id: nightly-release-version
|
|
||||||
run: |
|
|
||||||
number="${{ steps.semver.outputs.version }}.dev${{ steps.current-date.outputs.date }}"
|
|
||||||
echo "number=$number" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: "Audit Nightly Release Version And Parse Into Parts"
|
|
||||||
uses: dbt-labs/actions/parse-semver@v1.1.0
|
|
||||||
with:
|
|
||||||
version: ${{ steps.nightly-release-version.outputs.number }}
|
|
||||||
|
|
||||||
- name: "Set Release Branch"
|
|
||||||
id: release-branch
|
|
||||||
run: |
|
|
||||||
echo "name=${{ env.RELEASE_BRANCH }}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
log-outputs-aggregate-release-data:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [aggregate-release-data]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: "[DEBUG] Log Outputs"
|
|
||||||
run: |
|
|
||||||
echo commit_sha : ${{ needs.aggregate-release-data.outputs.commit_sha }}
|
|
||||||
echo version_number: ${{ needs.aggregate-release-data.outputs.version_number }}
|
|
||||||
echo release_branch: ${{ needs.aggregate-release-data.outputs.release_branch }}
|
|
||||||
|
|
||||||
release-github-pypi:
|
|
||||||
needs: [aggregate-release-data]
|
|
||||||
|
|
||||||
uses: ./.github/workflows/release.yml
|
|
||||||
with:
|
|
||||||
sha: ${{ needs.aggregate-release-data.outputs.commit_sha }}
|
|
||||||
target_branch: ${{ needs.aggregate-release-data.outputs.release_branch }}
|
|
||||||
version_number: ${{ needs.aggregate-release-data.outputs.version_number }}
|
|
||||||
build_script_path: "scripts/build-dist.sh"
|
|
||||||
env_setup_script_path: "scripts/env-setup.sh"
|
|
||||||
s3_bucket_name: "core-team-artifacts"
|
|
||||||
package_test_command: "dbt --version"
|
|
||||||
test_run: true
|
|
||||||
nightly_release: true
|
|
||||||
secrets: inherit
|
|
||||||
43
.github/workflows/release-branch-tests.yml
vendored
43
.github/workflows/release-branch-tests.yml
vendored
@@ -1,7 +1,11 @@
|
|||||||
# **what?**
|
# **what?**
|
||||||
# The purpose of this workflow is to trigger CI to run for each
|
# The purpose of this workflow is to trigger CI to run for each
|
||||||
# release branch and main branch on a regular cadence. If the CI workflow
|
# release branch and main branch on a regular cadence. If the CI workflow
|
||||||
# fails for a branch, it will post to #dev-core-alerts to raise awareness.
|
# fails for a branch, it will post to dev-core-alerts to raise awareness.
|
||||||
|
# The 'aurelien-baudet/workflow-dispatch' Action triggers the existing
|
||||||
|
# CI worklow file on the given branch to run so that even if we change the
|
||||||
|
# CI workflow file in the future, the one that is tailored for the given
|
||||||
|
# release branch will be used.
|
||||||
|
|
||||||
# **why?**
|
# **why?**
|
||||||
# Ensures release branches and main are always shippable and not broken.
|
# Ensures release branches and main are always shippable and not broken.
|
||||||
@@ -24,8 +28,35 @@ on:
|
|||||||
permissions: read-all
|
permissions: read-all
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run_tests:
|
kick-off-ci:
|
||||||
uses: dbt-labs/actions/.github/workflows/release-branch-tests.yml@main
|
name: Kick-off CI
|
||||||
with:
|
runs-on: ubuntu-latest
|
||||||
workflows_to_run: '["main.yml"]'
|
|
||||||
secrets: inherit
|
strategy:
|
||||||
|
# must run CI 1 branch at a time b/c the workflow-dispatch Action polls for
|
||||||
|
# latest run for results and it gets confused when we kick off multiple runs
|
||||||
|
# at once. There is a race condition so we will just run in sequential order.
|
||||||
|
max-parallel: 1
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
branch: [1.0.latest, 1.1.latest, 1.2.latest, 1.3.latest, main]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Call CI workflow for ${{ matrix.branch }} branch
|
||||||
|
id: trigger-step
|
||||||
|
uses: aurelien-baudet/workflow-dispatch@v2.1.1
|
||||||
|
with:
|
||||||
|
workflow: main.yml
|
||||||
|
ref: ${{ matrix.branch }}
|
||||||
|
token: ${{ secrets.FISHTOWN_BOT_PAT }}
|
||||||
|
|
||||||
|
- name: Post failure to Slack
|
||||||
|
uses: ravsamhq/notify-slack-action@v1
|
||||||
|
if: ${{ always() && !contains(steps.trigger-step.outputs.workflow-conclusion,'success') }}
|
||||||
|
with:
|
||||||
|
status: ${{ job.status }}
|
||||||
|
notification_title: 'dbt-core scheduled run of "${{ matrix.branch }}" branch not successful'
|
||||||
|
message_format: ':x: CI on branch "${{ matrix.branch }}" ${{ steps.trigger-step.outputs.workflow-conclusion }}'
|
||||||
|
footer: 'Linked failed CI run ${{ steps.trigger-step.outputs.workflow-url }}'
|
||||||
|
env:
|
||||||
|
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_DEV_CORE_ALERTS }}
|
||||||
|
|||||||
12
.github/workflows/release-docker.yml
vendored
12
.github/workflows/release-docker.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
|||||||
latest: ${{ steps.latest.outputs.latest }}
|
latest: ${{ steps.latest.outputs.latest }}
|
||||||
minor_latest: ${{ steps.latest.outputs.minor_latest }}
|
minor_latest: ${{ steps.latest.outputs.minor_latest }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v1
|
||||||
- name: Split version
|
- name: Split version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
needs: [get_version_meta]
|
needs: [get_version_meta]
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v1
|
||||||
|
|
||||||
build_and_push:
|
build_and_push:
|
||||||
name: Build images and push to GHCR
|
name: Build images and push to GHCR
|
||||||
@@ -76,14 +76,14 @@ jobs:
|
|||||||
echo "build_arg_value=$BUILD_ARG_VALUE" >> $GITHUB_OUTPUT
|
echo "build_arg_value=$BUILD_ARG_VALUE" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Log in to the GHCR
|
- name: Log in to the GHCR
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v1
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push MAJOR.MINOR.PATCH tag
|
- name: Build and push MAJOR.MINOR.PATCH tag
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
file: docker/Dockerfile
|
file: docker/Dockerfile
|
||||||
push: True
|
push: True
|
||||||
@@ -94,7 +94,7 @@ jobs:
|
|||||||
ghcr.io/dbt-labs/${{ github.event.inputs.package }}:${{ github.event.inputs.version_number }}
|
ghcr.io/dbt-labs/${{ github.event.inputs.package }}:${{ github.event.inputs.version_number }}
|
||||||
|
|
||||||
- name: Build and push MINOR.latest tag
|
- name: Build and push MINOR.latest tag
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v2
|
||||||
if: ${{ needs.get_version_meta.outputs.minor_latest == 'True' }}
|
if: ${{ needs.get_version_meta.outputs.minor_latest == 'True' }}
|
||||||
with:
|
with:
|
||||||
file: docker/Dockerfile
|
file: docker/Dockerfile
|
||||||
@@ -106,7 +106,7 @@ jobs:
|
|||||||
ghcr.io/dbt-labs/${{ github.event.inputs.package }}:${{ needs.get_version_meta.outputs.major }}.${{ needs.get_version_meta.outputs.minor }}.latest
|
ghcr.io/dbt-labs/${{ github.event.inputs.package }}:${{ needs.get_version_meta.outputs.major }}.${{ needs.get_version_meta.outputs.minor }}.latest
|
||||||
|
|
||||||
- name: Build and push latest tag
|
- name: Build and push latest tag
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v2
|
||||||
if: ${{ needs.get_version_meta.outputs.latest == 'True' }}
|
if: ${{ needs.get_version_meta.outputs.latest == 'True' }}
|
||||||
with:
|
with:
|
||||||
file: docker/Dockerfile
|
file: docker/Dockerfile
|
||||||
|
|||||||
341
.github/workflows/release.yml
vendored
341
.github/workflows/release.yml
vendored
@@ -1,110 +1,24 @@
|
|||||||
# **what?**
|
# **what?**
|
||||||
# Release workflow provides the following steps:
|
# Take the given commit, run unit tests specifically on that sha, build and
|
||||||
# - checkout the given commit;
|
# package it, and then release to GitHub and PyPi with that specific build
|
||||||
# - validate version in sources and changelog file for given version;
|
|
||||||
# - bump the version and generate a changelog if needed;
|
|
||||||
# - merge all changes to the target branch if needed;
|
|
||||||
# - run unit and integration tests against given commit;
|
|
||||||
# - build and package that SHA;
|
|
||||||
# - release it to GitHub and PyPI with that specific build;
|
|
||||||
#
|
|
||||||
# **why?**
|
# **why?**
|
||||||
# Ensure an automated and tested release process
|
# Ensure an automated and tested release process
|
||||||
#
|
|
||||||
# **when?**
|
|
||||||
# This workflow can be run manually on demand or can be called by other workflows
|
|
||||||
|
|
||||||
name: Release to GitHub and PyPI
|
# **when?**
|
||||||
|
# This will only run manually with a given sha and version
|
||||||
|
|
||||||
|
name: Release to GitHub and PyPi
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
sha:
|
sha:
|
||||||
description: "The last commit sha in the release"
|
description: 'The last commit sha in the release'
|
||||||
type: string
|
required: true
|
||||||
required: true
|
|
||||||
target_branch:
|
|
||||||
description: "The branch to release from"
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
version_number:
|
version_number:
|
||||||
description: "The release version number (i.e. 1.0.0b1)"
|
description: 'The release version number (i.e. 1.0.0b1)'
|
||||||
type: string
|
required: true
|
||||||
required: true
|
|
||||||
build_script_path:
|
|
||||||
description: "Build script path"
|
|
||||||
type: string
|
|
||||||
default: "scripts/build-dist.sh"
|
|
||||||
required: true
|
|
||||||
env_setup_script_path:
|
|
||||||
description: "Environment setup script path"
|
|
||||||
type: string
|
|
||||||
default: "scripts/env-setup.sh"
|
|
||||||
required: false
|
|
||||||
s3_bucket_name:
|
|
||||||
description: "AWS S3 bucket name"
|
|
||||||
type: string
|
|
||||||
default: "core-team-artifacts"
|
|
||||||
required: true
|
|
||||||
package_test_command:
|
|
||||||
description: "Package test command"
|
|
||||||
type: string
|
|
||||||
default: "dbt --version"
|
|
||||||
required: true
|
|
||||||
test_run:
|
|
||||||
description: "Test run (Publish release as draft)"
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
required: false
|
|
||||||
nightly_release:
|
|
||||||
description: "Nightly release to dev environment"
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
required: false
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
sha:
|
|
||||||
description: "The last commit sha in the release"
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
target_branch:
|
|
||||||
description: "The branch to release from"
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
version_number:
|
|
||||||
description: "The release version number (i.e. 1.0.0b1)"
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
build_script_path:
|
|
||||||
description: "Build script path"
|
|
||||||
type: string
|
|
||||||
default: "scripts/build-dist.sh"
|
|
||||||
required: true
|
|
||||||
env_setup_script_path:
|
|
||||||
description: "Environment setup script path"
|
|
||||||
type: string
|
|
||||||
default: "scripts/env-setup.sh"
|
|
||||||
required: false
|
|
||||||
s3_bucket_name:
|
|
||||||
description: "AWS S3 bucket name"
|
|
||||||
type: string
|
|
||||||
default: "core-team-artifacts"
|
|
||||||
required: true
|
|
||||||
package_test_command:
|
|
||||||
description: "Package test command"
|
|
||||||
type: string
|
|
||||||
default: "dbt --version"
|
|
||||||
required: true
|
|
||||||
test_run:
|
|
||||||
description: "Test run (Publish release as draft)"
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
required: false
|
|
||||||
nightly_release:
|
|
||||||
description: "Nightly release to dev environment"
|
|
||||||
type: boolean
|
|
||||||
default: false
|
|
||||||
required: false
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write # this is the permission that allows creating a new release
|
contents: write # this is the permission that allows creating a new release
|
||||||
@@ -114,116 +28,175 @@ defaults:
|
|||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
log-inputs:
|
unit:
|
||||||
name: Log Inputs
|
name: Unit test
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
TOXENV: "unit"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: "[DEBUG] Print Variables"
|
- name: Check out the repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
ref: ${{ github.event.inputs.sha }}
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
|
||||||
|
- name: Install python dependencies
|
||||||
run: |
|
run: |
|
||||||
echo The last commit sha in the release: ${{ inputs.sha }}
|
pip install --user --upgrade pip
|
||||||
echo The branch to release from: ${{ inputs.target_branch }}
|
pip install tox
|
||||||
echo The release version number: ${{ inputs.version_number }}
|
pip --version
|
||||||
echo Build script path: ${{ inputs.build_script_path }}
|
tox --version
|
||||||
echo Environment setup script path: ${{ inputs.env_setup_script_path }}
|
|
||||||
echo AWS S3 bucket name: ${{ inputs.s3_bucket_name }}
|
|
||||||
echo Package test command: ${{ inputs.package_test_command }}
|
|
||||||
echo Test run: ${{ inputs.test_run }}
|
|
||||||
echo Nightly release: ${{ inputs.nightly_release }}
|
|
||||||
|
|
||||||
bump-version-generate-changelog:
|
- name: Run tox
|
||||||
name: Bump package version, Generate changelog
|
run: tox
|
||||||
|
|
||||||
uses: dbt-labs/dbt-release/.github/workflows/release-prep.yml@main
|
build:
|
||||||
|
name: build packages
|
||||||
with:
|
|
||||||
sha: ${{ inputs.sha }}
|
|
||||||
version_number: ${{ inputs.version_number }}
|
|
||||||
target_branch: ${{ inputs.target_branch }}
|
|
||||||
env_setup_script_path: ${{ inputs.env_setup_script_path }}
|
|
||||||
test_run: ${{ inputs.test_run }}
|
|
||||||
nightly_release: ${{ inputs.nightly_release }}
|
|
||||||
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
log-outputs-bump-version-generate-changelog:
|
|
||||||
name: "[Log output] Bump package version, Generate changelog"
|
|
||||||
if: ${{ !failure() && !cancelled() }}
|
|
||||||
|
|
||||||
needs: [bump-version-generate-changelog]
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Print variables
|
- name: Check out the repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
ref: ${{ github.event.inputs.sha }}
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
|
||||||
|
- name: Install python dependencies
|
||||||
run: |
|
run: |
|
||||||
echo Final SHA : ${{ needs.bump-version-generate-changelog.outputs.final_sha }}
|
pip install --user --upgrade pip
|
||||||
echo Changelog path: ${{ needs.bump-version-generate-changelog.outputs.changelog_path }}
|
pip install --upgrade setuptools wheel twine check-wheel-contents
|
||||||
|
pip --version
|
||||||
|
|
||||||
build-test-package:
|
- name: Build distributions
|
||||||
name: Build, Test, Package
|
run: ./scripts/build-dist.sh
|
||||||
if: ${{ !failure() && !cancelled() }}
|
|
||||||
needs: [bump-version-generate-changelog]
|
|
||||||
|
|
||||||
uses: dbt-labs/dbt-release/.github/workflows/build.yml@main
|
- name: Show distributions
|
||||||
|
run: ls -lh dist/
|
||||||
|
|
||||||
with:
|
- name: Check distribution descriptions
|
||||||
sha: ${{ needs.bump-version-generate-changelog.outputs.final_sha }}
|
run: |
|
||||||
version_number: ${{ inputs.version_number }}
|
twine check dist/*
|
||||||
changelog_path: ${{ needs.bump-version-generate-changelog.outputs.changelog_path }}
|
|
||||||
build_script_path: ${{ inputs.build_script_path }}
|
|
||||||
s3_bucket_name: ${{ inputs.s3_bucket_name }}
|
|
||||||
package_test_command: ${{ inputs.package_test_command }}
|
|
||||||
test_run: ${{ inputs.test_run }}
|
|
||||||
nightly_release: ${{ inputs.nightly_release }}
|
|
||||||
|
|
||||||
secrets:
|
- name: Check wheel contents
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
run: |
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
check-wheel-contents dist/*.whl --ignore W007,W008
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: |
|
||||||
|
dist/
|
||||||
|
!dist/dbt-${{github.event.inputs.version_number}}.tar.gz
|
||||||
|
|
||||||
|
test-build:
|
||||||
|
name: verify packages
|
||||||
|
|
||||||
|
needs: [build, unit]
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
|
||||||
|
- name: Install python dependencies
|
||||||
|
run: |
|
||||||
|
pip install --user --upgrade pip
|
||||||
|
pip install --upgrade wheel
|
||||||
|
pip --version
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: dist/
|
||||||
|
|
||||||
|
- name: Show distributions
|
||||||
|
run: ls -lh dist/
|
||||||
|
|
||||||
|
- name: Install wheel distributions
|
||||||
|
run: |
|
||||||
|
find ./dist/*.whl -maxdepth 1 -type f | xargs pip install --force-reinstall --find-links=dist/
|
||||||
|
|
||||||
|
- name: Check wheel distributions
|
||||||
|
run: |
|
||||||
|
dbt --version
|
||||||
|
|
||||||
|
- name: Install source distributions
|
||||||
|
run: |
|
||||||
|
find ./dist/*.gz -maxdepth 1 -type f | xargs pip install --force-reinstall --find-links=dist/
|
||||||
|
|
||||||
|
- name: Check source distributions
|
||||||
|
run: |
|
||||||
|
dbt --version
|
||||||
|
|
||||||
github-release:
|
github-release:
|
||||||
name: GitHub Release
|
name: GitHub Release
|
||||||
if: ${{ !failure() && !cancelled() }}
|
|
||||||
|
|
||||||
needs: [bump-version-generate-changelog, build-test-package]
|
needs: test-build
|
||||||
|
|
||||||
uses: dbt-labs/dbt-release/.github/workflows/github-release.yml@main
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
with:
|
steps:
|
||||||
sha: ${{ needs.bump-version-generate-changelog.outputs.final_sha }}
|
- uses: actions/download-artifact@v2
|
||||||
version_number: ${{ inputs.version_number }}
|
with:
|
||||||
changelog_path: ${{ needs.bump-version-generate-changelog.outputs.changelog_path }}
|
name: dist
|
||||||
test_run: ${{ inputs.test_run }}
|
path: '.'
|
||||||
|
|
||||||
|
# Need to set an output variable because env variables can't be taken as input
|
||||||
|
# This is needed for the next step with releasing to GitHub
|
||||||
|
- name: Find release type
|
||||||
|
id: release_type
|
||||||
|
env:
|
||||||
|
IS_PRERELEASE: ${{ contains(github.event.inputs.version_number, 'rc') || contains(github.event.inputs.version_number, 'b') }}
|
||||||
|
run: |
|
||||||
|
echo "isPrerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Creating GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
name: dbt-core v${{github.event.inputs.version_number}}
|
||||||
|
tag_name: v${{github.event.inputs.version_number}}
|
||||||
|
prerelease: ${{ steps.release_type.outputs.isPrerelease }}
|
||||||
|
target_commitish: ${{github.event.inputs.sha}}
|
||||||
|
body: |
|
||||||
|
[Release notes](https://github.com/dbt-labs/dbt-core/blob/main/CHANGELOG.md)
|
||||||
|
files: |
|
||||||
|
dbt_postgres-${{github.event.inputs.version_number}}-py3-none-any.whl
|
||||||
|
dbt_core-${{github.event.inputs.version_number}}-py3-none-any.whl
|
||||||
|
dbt-postgres-${{github.event.inputs.version_number}}.tar.gz
|
||||||
|
dbt-core-${{github.event.inputs.version_number}}.tar.gz
|
||||||
|
|
||||||
pypi-release:
|
pypi-release:
|
||||||
name: PyPI Release
|
name: Pypi release
|
||||||
|
|
||||||
needs: [github-release]
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
uses: dbt-labs/dbt-release/.github/workflows/pypi-release.yml@main
|
needs: github-release
|
||||||
|
|
||||||
with:
|
environment: PypiProd
|
||||||
version_number: ${{ inputs.version_number }}
|
steps:
|
||||||
test_run: ${{ inputs.test_run }}
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: 'dist'
|
||||||
|
|
||||||
secrets:
|
- name: Publish distribution to PyPI
|
||||||
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
uses: pypa/gh-action-pypi-publish@v1.4.2
|
||||||
TEST_PYPI_API_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
with:
|
||||||
|
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||||
slack-notification:
|
|
||||||
name: Slack Notification
|
|
||||||
if: ${{ failure() && (!inputs.test_run || inputs.nightly_release) }}
|
|
||||||
|
|
||||||
needs:
|
|
||||||
[
|
|
||||||
bump-version-generate-changelog,
|
|
||||||
build-test-package,
|
|
||||||
github-release,
|
|
||||||
pypi-release,
|
|
||||||
]
|
|
||||||
|
|
||||||
uses: dbt-labs/dbt-release/.github/workflows/slack-post-notification.yml@main
|
|
||||||
with:
|
|
||||||
status: "failure"
|
|
||||||
|
|
||||||
secrets:
|
|
||||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_DEV_CORE_ALERTS }}
|
|
||||||
|
|||||||
30
.github/workflows/repository-cleanup.yml
vendored
30
.github/workflows/repository-cleanup.yml
vendored
@@ -1,30 +0,0 @@
|
|||||||
# **what?**
|
|
||||||
# Cleanup branches left over from automation and testing. Also cleanup
|
|
||||||
# draft releases from release testing.
|
|
||||||
|
|
||||||
# **why?**
|
|
||||||
# The automations are leaving behind branches and releases that clutter
|
|
||||||
# the repository. Sometimes we need them to debug processes so we don't
|
|
||||||
# want them immediately deleted. Running on Saturday to avoid running
|
|
||||||
# at the same time as an actual release to prevent breaking a release
|
|
||||||
# mid-release.
|
|
||||||
|
|
||||||
# **when?**
|
|
||||||
# Mainly on a schedule of 12:00 Saturday.
|
|
||||||
# Manual trigger can also run on demand
|
|
||||||
|
|
||||||
name: Repository Cleanup
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 12 * * SAT' # At 12:00 on Saturday - details in `why` above
|
|
||||||
|
|
||||||
workflow_dispatch: # for manual triggering
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cleanup-repo:
|
|
||||||
uses: dbt-labs/actions/.github/workflows/repository-cleanup.yml@main
|
|
||||||
secrets: inherit
|
|
||||||
8
.github/workflows/schema-check.yml
vendored
8
.github/workflows/schema-check.yml
vendored
@@ -37,17 +37,17 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.8
|
python-version: 3.8
|
||||||
|
|
||||||
- name: Checkout dbt repo
|
- name: Checkout dbt repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2.3.4
|
||||||
with:
|
with:
|
||||||
path: ${{ env.DBT_REPO_DIRECTORY }}
|
path: ${{ env.DBT_REPO_DIRECTORY }}
|
||||||
|
|
||||||
- name: Checkout schemas.getdbt.com repo
|
- name: Checkout schemas.getdbt.com repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2.3.4
|
||||||
with:
|
with:
|
||||||
repository: dbt-labs/schemas.getdbt.com
|
repository: dbt-labs/schemas.getdbt.com
|
||||||
ref: 'main'
|
ref: 'main'
|
||||||
@@ -83,7 +83,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload schema diff
|
- name: Upload schema diff
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v2.2.4
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
with:
|
with:
|
||||||
name: 'schema_schanges.txt'
|
name: 'schema_schanges.txt'
|
||||||
|
|||||||
@@ -18,41 +18,11 @@ on:
|
|||||||
|
|
||||||
permissions: read-all
|
permissions: read-all
|
||||||
|
|
||||||
# top-level adjustments can be made here
|
|
||||||
env:
|
|
||||||
# number of parallel processes to spawn for python testing
|
|
||||||
PYTHON_INTEGRATION_TEST_WORKERS: 5
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
integration-metadata:
|
|
||||||
name: integration test metadata generation
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
split-groups: ${{ steps.generate-split-groups.outputs.split-groups }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: generate split-groups
|
|
||||||
id: generate-split-groups
|
|
||||||
run: |
|
|
||||||
MATRIX_JSON="["
|
|
||||||
for B in $(seq 1 ${{ env.PYTHON_INTEGRATION_TEST_WORKERS }}); do
|
|
||||||
MATRIX_JSON+=$(sed 's/^/"/;s/$/"/' <<< "${B}")
|
|
||||||
done
|
|
||||||
MATRIX_JSON="${MATRIX_JSON//\"\"/\", \"}"
|
|
||||||
MATRIX_JSON+="]"
|
|
||||||
echo "split-groups=${MATRIX_JSON}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# run the performance measurements on the current or default branch
|
# run the performance measurements on the current or default branch
|
||||||
test-schema:
|
test-schema:
|
||||||
name: Test Log Schema
|
name: Test Log Schema
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
timeout-minutes: 30
|
|
||||||
needs:
|
|
||||||
- integration-metadata
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
split-group: ${{ fromJson(needs.integration-metadata.outputs.split-groups) }}
|
|
||||||
env:
|
env:
|
||||||
# turns warnings into errors
|
# turns warnings into errors
|
||||||
RUSTFLAGS: "-D warnings"
|
RUSTFLAGS: "-D warnings"
|
||||||
@@ -60,8 +30,6 @@ jobs:
|
|||||||
LOG_DIR: "/home/runner/work/dbt-core/dbt-core/logs"
|
LOG_DIR: "/home/runner/work/dbt-core/dbt-core/logs"
|
||||||
# tells integration tests to output into json format
|
# tells integration tests to output into json format
|
||||||
DBT_LOG_FORMAT: "json"
|
DBT_LOG_FORMAT: "json"
|
||||||
# tell eventmgr to convert logging events into bytes
|
|
||||||
DBT_TEST_BINARY_SERIALIZATION: "true"
|
|
||||||
# Additional test users
|
# Additional test users
|
||||||
DBT_TEST_USER_1: dbt_test_user_1
|
DBT_TEST_USER_1: dbt_test_user_1
|
||||||
DBT_TEST_USER_2: dbt_test_user_2
|
DBT_TEST_USER_2: dbt_test_user_2
|
||||||
@@ -69,12 +37,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: checkout dev
|
- name: checkout dev
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2.2.2
|
||||||
with:
|
with:
|
||||||
python-version: "3.8"
|
python-version: "3.8"
|
||||||
|
|
||||||
@@ -95,14 +63,3 @@ jobs:
|
|||||||
# we actually care if these pass, because the normal test run doesn't usually include many json log outputs
|
# we actually care if these pass, because the normal test run doesn't usually include many json log outputs
|
||||||
- name: Run integration tests
|
- name: Run integration tests
|
||||||
run: tox -e integration -- -nauto
|
run: tox -e integration -- -nauto
|
||||||
env:
|
|
||||||
PYTEST_ADDOPTS: ${{ format('--splits {0} --group {1}', env.PYTHON_INTEGRATION_TEST_WORKERS, matrix.split-group) }}
|
|
||||||
|
|
||||||
test-schema-report:
|
|
||||||
name: Log Schema Test Suite
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: test-schema
|
|
||||||
steps:
|
|
||||||
- name: "[Notification] Log test suite passes"
|
|
||||||
run: |
|
|
||||||
echo "::notice title="Log test suite passes""
|
|
||||||
|
|||||||
155
.github/workflows/test-repeater.yml
vendored
155
.github/workflows/test-repeater.yml
vendored
@@ -1,155 +0,0 @@
|
|||||||
# **what?**
|
|
||||||
# This workflow will test all test(s) at the input path given number of times to determine if it's flaky or not. You can test with any supported OS/Python combination.
|
|
||||||
# This is batched in 10 to allow more test iterations faster.
|
|
||||||
|
|
||||||
# **why?**
|
|
||||||
# Testing if a test is flaky and if a previously flaky test has been fixed. This allows easy testing on supported python versions and OS combinations.
|
|
||||||
|
|
||||||
# **when?**
|
|
||||||
# This is triggered manually from dbt-core.
|
|
||||||
|
|
||||||
name: Flaky Tester
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
branch:
|
|
||||||
description: 'Branch to check out'
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
default: 'main'
|
|
||||||
test_path:
|
|
||||||
description: 'Path to single test to run (ex: tests/functional/retry/test_retry.py::TestRetry::test_fail_fast)'
|
|
||||||
type: string
|
|
||||||
required: true
|
|
||||||
default: 'tests/functional/...'
|
|
||||||
python_version:
|
|
||||||
description: 'Version of Python to Test Against'
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- '3.8'
|
|
||||||
- '3.9'
|
|
||||||
- '3.10'
|
|
||||||
- '3.11'
|
|
||||||
os:
|
|
||||||
description: 'OS to run test in'
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- 'ubuntu-latest'
|
|
||||||
- 'macos-latest'
|
|
||||||
- 'windows-latest'
|
|
||||||
num_runs_per_batch:
|
|
||||||
description: 'Max number of times to run the test per batch. We always run 10 batches.'
|
|
||||||
type: number
|
|
||||||
required: true
|
|
||||||
default: '50'
|
|
||||||
|
|
||||||
permissions: read-all
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
debug:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: "[DEBUG] Output Inputs"
|
|
||||||
run: |
|
|
||||||
echo "Branch: ${{ inputs.branch }}"
|
|
||||||
echo "test_path: ${{ inputs.test_path }}"
|
|
||||||
echo "python_version: ${{ inputs.python_version }}"
|
|
||||||
echo "os: ${{ inputs.os }}"
|
|
||||||
echo "num_runs_per_batch: ${{ inputs.num_runs_per_batch }}"
|
|
||||||
|
|
||||||
pytest:
|
|
||||||
runs-on: ${{ inputs.os }}
|
|
||||||
strategy:
|
|
||||||
# run all batches, even if one fails. This informs how flaky the test may be.
|
|
||||||
fail-fast: false
|
|
||||||
# using a matrix to speed up the jobs since the matrix will run in parallel when runners are available
|
|
||||||
matrix:
|
|
||||||
batch: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
|
|
||||||
env:
|
|
||||||
PYTEST_ADDOPTS: "-v --color=yes -n4 --csv integration_results.csv"
|
|
||||||
DBT_TEST_USER_1: dbt_test_user_1
|
|
||||||
DBT_TEST_USER_2: dbt_test_user_2
|
|
||||||
DBT_TEST_USER_3: dbt_test_user_3
|
|
||||||
DD_CIVISIBILITY_AGENTLESS_ENABLED: true
|
|
||||||
DD_API_KEY: ${{ secrets.DATADOG_API_KEY }}
|
|
||||||
DD_SITE: datadoghq.com
|
|
||||||
DD_ENV: ci
|
|
||||||
DD_SERVICE: ${{ github.event.repository.name }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: "Checkout code"
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
ref: ${{ inputs.branch }}
|
|
||||||
|
|
||||||
- name: "Setup Python"
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: "${{ inputs.python_version }}"
|
|
||||||
|
|
||||||
- name: "Setup Dev Environment"
|
|
||||||
run: make dev
|
|
||||||
|
|
||||||
- name: "Set up postgres (linux)"
|
|
||||||
if: inputs.os == 'ubuntu-latest'
|
|
||||||
run: make setup-db
|
|
||||||
|
|
||||||
# mac and windows don't use make due to limitations with docker with those runners in GitHub
|
|
||||||
- name: "Set up postgres (macos)"
|
|
||||||
if: inputs.os == 'macos-latest'
|
|
||||||
uses: ./.github/actions/setup-postgres-macos
|
|
||||||
|
|
||||||
- name: "Set up postgres (windows)"
|
|
||||||
if: inputs.os == 'windows-latest'
|
|
||||||
uses: ./.github/actions/setup-postgres-windows
|
|
||||||
|
|
||||||
- name: "Test Command"
|
|
||||||
id: command
|
|
||||||
run: |
|
|
||||||
test_command="python -m pytest ${{ inputs.test_path }}"
|
|
||||||
echo "test_command=$test_command" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: "Run test ${{ inputs.num_runs_per_batch }} times"
|
|
||||||
id: pytest
|
|
||||||
run: |
|
|
||||||
set +e
|
|
||||||
for ((i=1; i<=${{ inputs.num_runs_per_batch }}; i++))
|
|
||||||
do
|
|
||||||
echo "Running pytest iteration $i..."
|
|
||||||
python -m pytest --ddtrace ${{ inputs.test_path }}
|
|
||||||
exit_code=$?
|
|
||||||
|
|
||||||
if [[ $exit_code -eq 0 ]]; then
|
|
||||||
success=$((success + 1))
|
|
||||||
echo "Iteration $i: Success"
|
|
||||||
else
|
|
||||||
failure=$((failure + 1))
|
|
||||||
echo "Iteration $i: Failure"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "==========================="
|
|
||||||
echo "Successful runs: $success"
|
|
||||||
echo "Failed runs: $failure"
|
|
||||||
echo "==========================="
|
|
||||||
echo
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "failure=$failure" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: "Success and Failure Summary: ${{ inputs.os }}/Python ${{ inputs.python_version }}"
|
|
||||||
run: |
|
|
||||||
echo "Batch: ${{ matrix.batch }}"
|
|
||||||
echo "Successful runs: ${{ steps.pytest.outputs.success }}"
|
|
||||||
echo "Failed runs: ${{ steps.pytest.outputs.failure }}"
|
|
||||||
|
|
||||||
- name: "Error for Failures"
|
|
||||||
if: ${{ steps.pytest.outputs.failure }}
|
|
||||||
run: |
|
|
||||||
echo "Batch ${{ matrix.batch }} failed ${{ steps.pytest.outputs.failure }} of ${{ inputs.num_runs_per_batch }} tests"
|
|
||||||
exit 1
|
|
||||||
12
.github/workflows/triage-labels.yml
vendored
12
.github/workflows/triage-labels.yml
vendored
@@ -24,8 +24,10 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
triage_label:
|
triage_label:
|
||||||
if: contains(github.event.issue.labels.*.name, 'awaiting_response')
|
if: contains(github.event.issue.labels.*.name, 'awaiting_response')
|
||||||
uses: dbt-labs/actions/.github/workflows/swap-labels.yml@main
|
runs-on: ubuntu-latest
|
||||||
with:
|
steps:
|
||||||
add_label: "triage"
|
- name: initial labeling
|
||||||
remove_label: "awaiting_response"
|
uses: andymckay/labeler@master
|
||||||
secrets: inherit
|
with:
|
||||||
|
add-labels: "triage"
|
||||||
|
remove-labels: "awaiting_response"
|
||||||
|
|||||||
107
.github/workflows/version-bump.yml
vendored
107
.github/workflows/version-bump.yml
vendored
@@ -20,9 +20,106 @@ on:
|
|||||||
description: 'The version number to bump to (ex. 1.2.0, 1.3.0b1)'
|
description: 'The version number to bump to (ex. 1.2.0, 1.3.0b1)'
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
version_bump_and_changie:
|
bump:
|
||||||
uses: dbt-labs/actions/.github/workflows/version-bump.yml@main
|
runs-on: ubuntu-latest
|
||||||
with:
|
steps:
|
||||||
version_number: ${{ inputs.version_number }}
|
- name: "[DEBUG] Print Variables"
|
||||||
secrets: inherit # ok since what we are calling is internally maintained
|
run: |
|
||||||
|
echo "all variables defined as inputs"
|
||||||
|
echo The version_number: ${{ github.event.inputs.version_number }}
|
||||||
|
|
||||||
|
- name: Check out the repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: "3.8"
|
||||||
|
|
||||||
|
- name: Install python dependencies
|
||||||
|
run: |
|
||||||
|
python3 -m venv env
|
||||||
|
source env/bin/activate
|
||||||
|
pip install --upgrade pip
|
||||||
|
|
||||||
|
- name: Add Homebrew to PATH
|
||||||
|
run: |
|
||||||
|
echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Install Homebrew packages
|
||||||
|
run: |
|
||||||
|
brew install pre-commit
|
||||||
|
brew tap miniscruff/changie https://github.com/miniscruff/changie
|
||||||
|
brew install changie
|
||||||
|
|
||||||
|
- name: Audit Version and Parse Into Parts
|
||||||
|
id: semver
|
||||||
|
uses: dbt-labs/actions/parse-semver@v1
|
||||||
|
with:
|
||||||
|
version: ${{ github.event.inputs.version_number }}
|
||||||
|
|
||||||
|
- name: Set branch value
|
||||||
|
id: variables
|
||||||
|
run: |
|
||||||
|
echo "BRANCH_NAME=prep-release/${{ github.event.inputs.version_number }}_$GITHUB_RUN_ID" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Create PR branch
|
||||||
|
run: |
|
||||||
|
git checkout -b ${{ steps.variables.outputs.BRANCH_NAME }}
|
||||||
|
git push origin ${{ steps.variables.outputs.BRANCH_NAME }}
|
||||||
|
git branch --set-upstream-to=origin/${{ steps.variables.outputs.BRANCH_NAME }} ${{ steps.variables.outputs.BRANCH_NAME }}
|
||||||
|
|
||||||
|
- name: Bump version
|
||||||
|
run: |
|
||||||
|
source env/bin/activate
|
||||||
|
pip install -r dev-requirements.txt
|
||||||
|
env/bin/bumpversion --allow-dirty --new-version ${{ github.event.inputs.version_number }} major
|
||||||
|
git status
|
||||||
|
|
||||||
|
- name: Run changie
|
||||||
|
run: |
|
||||||
|
if [[ ${{ steps.semver.outputs.is-pre-release }} -eq 1 ]]
|
||||||
|
then
|
||||||
|
changie batch ${{ steps.semver.outputs.base-version }} --move-dir '${{ steps.semver.outputs.base-version }}' --prerelease '${{ steps.semver.outputs.pre-release }}'
|
||||||
|
else
|
||||||
|
changie batch ${{ steps.semver.outputs.base-version }} --include '${{ steps.semver.outputs.base-version }}' --remove-prereleases
|
||||||
|
fi
|
||||||
|
changie merge
|
||||||
|
git status
|
||||||
|
|
||||||
|
# this step will fail on whitespace errors but also correct them
|
||||||
|
- name: Remove trailing whitespace
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
pre-commit run trailing-whitespace --files .bumpversion.cfg CHANGELOG.md .changes/*
|
||||||
|
git status
|
||||||
|
|
||||||
|
# this step will fail on newline errors but also correct them
|
||||||
|
- name: Removing extra newlines
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
pre-commit run end-of-file-fixer --files .bumpversion.cfg CHANGELOG.md .changes/*
|
||||||
|
git status
|
||||||
|
|
||||||
|
- name: Commit version bump to branch
|
||||||
|
uses: EndBug/add-and-commit@v7
|
||||||
|
with:
|
||||||
|
author_name: 'Github Build Bot'
|
||||||
|
author_email: 'buildbot@fishtownanalytics.com'
|
||||||
|
message: 'Bumping version to ${{ github.event.inputs.version_number }} and generate CHANGELOG'
|
||||||
|
branch: '${{ steps.variables.outputs.BRANCH_NAME }}'
|
||||||
|
push: 'origin origin/${{ steps.variables.outputs.BRANCH_NAME }}'
|
||||||
|
|
||||||
|
- name: Create Pull Request
|
||||||
|
uses: peter-evans/create-pull-request@v3
|
||||||
|
with:
|
||||||
|
author: 'Github Build Bot <buildbot@fishtownanalytics.com>'
|
||||||
|
base: ${{github.ref}}
|
||||||
|
title: 'Bumping version to ${{ github.event.inputs.version_number }} and generate changelog'
|
||||||
|
branch: '${{ steps.variables.outputs.BRANCH_NAME }}'
|
||||||
|
labels: |
|
||||||
|
Skip Changelog
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -11,7 +11,6 @@ __pycache__/
|
|||||||
env*/
|
env*/
|
||||||
dbt_env/
|
dbt_env/
|
||||||
build/
|
build/
|
||||||
!tests/functional/build
|
|
||||||
!core/dbt/docs/build
|
!core/dbt/docs/build
|
||||||
develop-eggs/
|
develop-eggs/
|
||||||
dist/
|
dist/
|
||||||
@@ -29,8 +28,6 @@ var/
|
|||||||
.mypy_cache/
|
.mypy_cache/
|
||||||
.dmypy.json
|
.dmypy.json
|
||||||
logs/
|
logs/
|
||||||
.user.yml
|
|
||||||
profiles.yml
|
|
||||||
|
|
||||||
# PyInstaller
|
# PyInstaller
|
||||||
# Usually these files are written by a python script from a template
|
# Usually these files are written by a python script from a template
|
||||||
@@ -54,7 +51,6 @@ coverage.xml
|
|||||||
*,cover
|
*,cover
|
||||||
.hypothesis/
|
.hypothesis/
|
||||||
test.env
|
test.env
|
||||||
makefile.test.env
|
|
||||||
*.pytest_cache/
|
*.pytest_cache/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
# Configuration for pre-commit hooks (see https://pre-commit.com/).
|
# Configuration for pre-commit hooks (see https://pre-commit.com/).
|
||||||
# Eventually the hooks described here will be run as tests before merging each PR.
|
# Eventually the hooks described here will be run as tests before merging each PR.
|
||||||
|
|
||||||
exclude: ^(core/dbt/docs/build/|core/dbt/common/events/types_pb2.py|core/dbt/events/core_types_pb2.py|core/dbt/adapters/events/adapter_types_pb2.py)
|
# TODO: remove global exclusion of tests when testing overhaul is complete
|
||||||
|
exclude: ^(test/|core/dbt/docs/build/)
|
||||||
|
|
||||||
# Force all unspecified python hooks to run python 3.8
|
# Force all unspecified python hooks to run python 3.8
|
||||||
default_language_version:
|
default_language_version:
|
||||||
@@ -37,7 +38,7 @@ repos:
|
|||||||
alias: flake8-check
|
alias: flake8-check
|
||||||
stages: [manual]
|
stages: [manual]
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v1.4.1
|
rev: v0.942
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
# N.B.: Mypy is... a bit fragile.
|
# N.B.: Mypy is... a bit fragile.
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Legacy tests are found in the 'test' directory:
|
|||||||
|
|
||||||
The "tasks" map to top-level dbt commands. So `dbt run` => task.run.RunTask, etc. Some are more like abstract base classes (GraphRunnableTask, for example) but all the concrete types outside of task should map to tasks. Currently one executes at a time. The tasks kick off their “Runners” and those do execute in parallel. The parallelism is managed via a thread pool, in GraphRunnableTask.
|
The "tasks" map to top-level dbt commands. So `dbt run` => task.run.RunTask, etc. Some are more like abstract base classes (GraphRunnableTask, for example) but all the concrete types outside of task should map to tasks. Currently one executes at a time. The tasks kick off their “Runners” and those do execute in parallel. The parallelism is managed via a thread pool, in GraphRunnableTask.
|
||||||
|
|
||||||
core/dbt/task/docs/index.html
|
core/dbt/include/index.html
|
||||||
This is the docs website code. It comes from the dbt-docs repository, and is generated when a release is packaged.
|
This is the docs website code. It comes from the dbt-docs repository, and is generated when a release is packaged.
|
||||||
|
|
||||||
## Adapters
|
## Adapters
|
||||||
|
|||||||
@@ -10,9 +10,6 @@
|
|||||||
For information on prior major and minor releases, see their changelogs:
|
For information on prior major and minor releases, see their changelogs:
|
||||||
|
|
||||||
|
|
||||||
* [1.7](https://github.com/dbt-labs/dbt-core/blob/1.7.latest/CHANGELOG.md)
|
|
||||||
* [1.6](https://github.com/dbt-labs/dbt-core/blob/1.6.latest/CHANGELOG.md)
|
|
||||||
* [1.5](https://github.com/dbt-labs/dbt-core/blob/1.5.latest/CHANGELOG.md)
|
|
||||||
* [1.4](https://github.com/dbt-labs/dbt-core/blob/1.4.latest/CHANGELOG.md)
|
* [1.4](https://github.com/dbt-labs/dbt-core/blob/1.4.latest/CHANGELOG.md)
|
||||||
* [1.3](https://github.com/dbt-labs/dbt-core/blob/1.3.latest/CHANGELOG.md)
|
* [1.3](https://github.com/dbt-labs/dbt-core/blob/1.3.latest/CHANGELOG.md)
|
||||||
* [1.2](https://github.com/dbt-labs/dbt-core/blob/1.2.latest/CHANGELOG.md)
|
* [1.2](https://github.com/dbt-labs/dbt-core/blob/1.2.latest/CHANGELOG.md)
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
1. [About this document](#about-this-document)
|
1. [About this document](#about-this-document)
|
||||||
2. [Getting the code](#getting-the-code)
|
2. [Getting the code](#getting-the-code)
|
||||||
3. [Setting up an environment](#setting-up-an-environment)
|
3. [Setting up an environment](#setting-up-an-environment)
|
||||||
4. [Running dbt-core in development](#running-dbt-core-in-development)
|
4. [Running `dbt` in development](#running-dbt-core-in-development)
|
||||||
5. [Testing dbt-core](#testing)
|
5. [Testing dbt-core](#testing)
|
||||||
6. [Debugging](#debugging)
|
6. [Debugging](#debugging)
|
||||||
7. [Adding or modifying a changelog entry](#adding-or-modifying-a-changelog-entry)
|
7. [Adding a changelog entry](#adding-a-changelog-entry)
|
||||||
8. [Submitting a Pull Request](#submitting-a-pull-request)
|
8. [Submitting a Pull Request](#submitting-a-pull-request)
|
||||||
|
|
||||||
## About this document
|
## About this document
|
||||||
@@ -56,7 +56,7 @@ There are some tools that will be helpful to you in developing locally. While th
|
|||||||
|
|
||||||
These are the tools used in `dbt-core` development and testing:
|
These are the tools used in `dbt-core` development and testing:
|
||||||
|
|
||||||
- [`tox`](https://tox.readthedocs.io/en/latest/) to manage virtualenvs across python versions. We currently target the latest patch releases for Python 3.8, 3.9, 3.10 and 3.11
|
- [`tox`](https://tox.readthedocs.io/en/latest/) to manage virtualenvs across python versions. We currently target the latest patch releases for Python 3.7, 3.8, 3.9, 3.10 and 3.11
|
||||||
- [`pytest`](https://docs.pytest.org/en/latest/) to define, discover, and run tests
|
- [`pytest`](https://docs.pytest.org/en/latest/) to define, discover, and run tests
|
||||||
- [`flake8`](https://flake8.pycqa.org/en/latest/) for code linting
|
- [`flake8`](https://flake8.pycqa.org/en/latest/) for code linting
|
||||||
- [`black`](https://github.com/psf/black) for code formatting
|
- [`black`](https://github.com/psf/black) for code formatting
|
||||||
@@ -113,7 +113,7 @@ When installed in this way, any changes you make to your local copy of the sourc
|
|||||||
|
|
||||||
With your virtualenv activated, the `dbt` script should point back to the source code you've cloned on your machine. You can verify this by running `which dbt`. This command should show you a path to an executable in your virtualenv.
|
With your virtualenv activated, the `dbt` script should point back to the source code you've cloned on your machine. You can verify this by running `which dbt`. This command should show you a path to an executable in your virtualenv.
|
||||||
|
|
||||||
Configure your [profile](https://docs.getdbt.com/docs/configure-your-profile) as necessary to connect to your target databases. It may be a good idea to add a new profile pointing to a local Postgres instance, or a specific test sandbox within your data warehouse if appropriate. Make sure to create a profile before running integration tests.
|
Configure your [profile](https://docs.getdbt.com/docs/configure-your-profile) as necessary to connect to your target databases. It may be a good idea to add a new profile pointing to a local Postgres instance, or a specific test sandbox within your data warehouse if appropriate.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ suites.
|
|||||||
|
|
||||||
#### `tox`
|
#### `tox`
|
||||||
|
|
||||||
[`tox`](https://tox.readthedocs.io/en/latest/) takes care of managing virtualenvs and install dependencies in order to run tests. You can also run tests in parallel, for example, you can run unit tests for Python 3.8, Python 3.9, Python 3.10 and Python 3.11 checks in parallel with `tox -p`. Also, you can run unit tests for specific python versions with `tox -e py38`. The configuration for these tests in located in `tox.ini`.
|
[`tox`](https://tox.readthedocs.io/en/latest/) takes care of managing virtualenvs and install dependencies in order to run tests. You can also run tests in parallel, for example, you can run unit tests for Python 3.7, Python 3.8, Python 3.9, Python 3.10 and Python 3.11 checks in parallel with `tox -p`. Also, you can run unit tests for specific python versions with `tox -e py37`. The configuration for these tests in located in `tox.ini`.
|
||||||
|
|
||||||
#### `pytest`
|
#### `pytest`
|
||||||
|
|
||||||
@@ -171,10 +171,12 @@ Finally, you can also run a specific test or group of tests using [`pytest`](htt
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
# run all unit tests in a file
|
# run all unit tests in a file
|
||||||
python3 -m pytest tests/unit/test_graph.py
|
python3 -m pytest test/unit/test_graph.py
|
||||||
# run a specific unit test
|
# run a specific unit test
|
||||||
python3 -m pytest tests/unit/test_graph.py::GraphTest::test__dependency_list
|
python3 -m pytest test/unit/test_graph.py::GraphTest::test__dependency_list
|
||||||
# run specific Postgres functional tests
|
# run specific Postgres integration tests (old way)
|
||||||
|
python3 -m pytest -m profile_postgres test/integration/074_postgres_unlogged_table_tests
|
||||||
|
# run specific Postgres integration tests (new way)
|
||||||
python3 -m pytest tests/functional/sources
|
python3 -m pytest tests/functional/sources
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -183,8 +185,9 @@ python3 -m pytest tests/functional/sources
|
|||||||
### Unit, Integration, Functional?
|
### Unit, Integration, Functional?
|
||||||
|
|
||||||
Here are some general rules for adding tests:
|
Here are some general rules for adding tests:
|
||||||
* unit tests (`tests/unit`) don’t need to access a database; "pure Python" tests should be written as unit tests
|
* unit tests (`test/unit` & `tests/unit`) don’t need to access a database; "pure Python" tests should be written as unit tests
|
||||||
* functional tests (`tests/functional`) cover anything that interacts with a database, namely adapter
|
* functional tests (`test/integration` & `tests/functional`) cover anything that interacts with a database, namely adapter
|
||||||
|
* *everything in* `test/*` *is being steadily migrated to* `tests/*`
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ ENV DEBIAN_FRONTEND noninteractive
|
|||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
software-properties-common gpg-agent \
|
software-properties-common \
|
||||||
&& add-apt-repository ppa:git-core/ppa -y \
|
&& add-apt-repository ppa:git-core/ppa -y \
|
||||||
&& apt-get dist-upgrade -y \
|
&& apt-get dist-upgrade -y \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
@@ -30,9 +30,16 @@ RUN apt-get update \
|
|||||||
unixodbc-dev \
|
unixodbc-dev \
|
||||||
&& add-apt-repository ppa:deadsnakes/ppa \
|
&& add-apt-repository ppa:deadsnakes/ppa \
|
||||||
&& apt-get install -y \
|
&& apt-get install -y \
|
||||||
python-is-python3 \
|
python \
|
||||||
python-dev-is-python3 \
|
python-dev \
|
||||||
python3-pip \
|
python3-pip \
|
||||||
|
python3.6 \
|
||||||
|
python3.6-dev \
|
||||||
|
python3-pip \
|
||||||
|
python3.6-venv \
|
||||||
|
python3.7 \
|
||||||
|
python3.7-dev \
|
||||||
|
python3.7-venv \
|
||||||
python3.8 \
|
python3.8 \
|
||||||
python3.8-dev \
|
python3.8-dev \
|
||||||
python3.8-venv \
|
python3.8-venv \
|
||||||
|
|||||||
50
Makefile
50
Makefile
@@ -6,51 +6,29 @@ ifeq ($(USE_DOCKER),true)
|
|||||||
DOCKER_CMD := docker-compose run --rm test
|
DOCKER_CMD := docker-compose run --rm test
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#
|
LOGS_DIR := ./logs
|
||||||
# To override CI_flags, create a file at this repo's root dir named `makefile.test.env`. Fill it
|
|
||||||
# with any ENV_VAR overrides required by your test environment, e.g.
|
|
||||||
# DBT_TEST_USER_1=user
|
|
||||||
# LOG_DIR="dir with a space in it"
|
|
||||||
#
|
|
||||||
# Warn: Restrict each line to one variable only.
|
|
||||||
#
|
|
||||||
ifeq (./makefile.test.env,$(wildcard ./makefile.test.env))
|
|
||||||
include ./makefile.test.env
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
# Optional flag to invoke tests using our CI env.
|
||||||
|
# But we always want these active for structured
|
||||||
|
# log testing.
|
||||||
CI_FLAGS =\
|
CI_FLAGS =\
|
||||||
DBT_TEST_USER_1=$(if $(DBT_TEST_USER_1),$(DBT_TEST_USER_1),dbt_test_user_1)\
|
DBT_TEST_USER_1=dbt_test_user_1\
|
||||||
DBT_TEST_USER_2=$(if $(DBT_TEST_USER_2),$(DBT_TEST_USER_2),dbt_test_user_2)\
|
DBT_TEST_USER_2=dbt_test_user_2\
|
||||||
DBT_TEST_USER_3=$(if $(DBT_TEST_USER_3),$(DBT_TEST_USER_3),dbt_test_user_3)\
|
DBT_TEST_USER_3=dbt_test_user_3\
|
||||||
RUSTFLAGS=$(if $(RUSTFLAGS),$(RUSTFLAGS),"-D warnings")\
|
RUSTFLAGS="-D warnings"\
|
||||||
LOG_DIR=$(if $(LOG_DIR),$(LOG_DIR),./logs)\
|
LOG_DIR=./logs\
|
||||||
DBT_LOG_FORMAT=$(if $(DBT_LOG_FORMAT),$(DBT_LOG_FORMAT),json)
|
DBT_LOG_FORMAT=json
|
||||||
|
|
||||||
|
|
||||||
.PHONY: dev_req
|
.PHONY: dev_req
|
||||||
dev_req: ## Installs dbt-* packages in develop mode along with only development dependencies.
|
dev_req: ## Installs dbt-* packages in develop mode along with only development dependencies.
|
||||||
@\
|
@\
|
||||||
pip install -r dev-requirements.txt
|
pip install -r dev-requirements.txt -r editable-requirements.txt
|
||||||
pip install -r editable-requirements.txt
|
|
||||||
|
|
||||||
.PHONY: dev
|
.PHONY: dev
|
||||||
dev: dev_req ## Installs dbt-* packages in develop mode along with development dependencies and pre-commit.
|
dev: dev_req ## Installs dbt-* packages in develop mode along with development dependencies and pre-commit.
|
||||||
@\
|
@\
|
||||||
pre-commit install
|
pre-commit install
|
||||||
|
|
||||||
.PHONY: proto_types
|
|
||||||
proto_types: ## generates google protobuf python file from types.proto
|
|
||||||
protoc -I=./core/dbt/common/events --python_out=./core/dbt/common/events ./core/dbt/common/events/types.proto
|
|
||||||
|
|
||||||
.PHONY: core_proto_types
|
|
||||||
core_proto_types: ## generates google protobuf python file from core_types.proto
|
|
||||||
protoc -I=./core/dbt/events --python_out=./core/dbt/events ./core/dbt/events/core_types.proto
|
|
||||||
|
|
||||||
.PHONY: adapter_proto_types
|
|
||||||
adapter_proto_types: ## generates google protobuf python file from core_types.proto
|
|
||||||
protoc -I=./core/dbt/adapters/events --python_out=./core/dbt/adapters/events ./core/dbt/adapters/events/adapter_types.proto
|
|
||||||
|
|
||||||
|
|
||||||
.PHONY: mypy
|
.PHONY: mypy
|
||||||
mypy: .env ## Runs mypy against staged changes for static type checking.
|
mypy: .env ## Runs mypy against staged changes for static type checking.
|
||||||
@\
|
@\
|
||||||
@@ -88,7 +66,7 @@ test: .env ## Runs unit tests with py and code checks against staged changes.
|
|||||||
.PHONY: integration
|
.PHONY: integration
|
||||||
integration: .env ## Runs postgres integration tests with py-integration
|
integration: .env ## Runs postgres integration tests with py-integration
|
||||||
@\
|
@\
|
||||||
$(CI_FLAGS) $(DOCKER_CMD) tox -e py-integration -- -nauto
|
$(if $(USE_CI_FLAGS), $(CI_FLAGS)) $(DOCKER_CMD) tox -e py-integration -- -nauto
|
||||||
|
|
||||||
.PHONY: integration-fail-fast
|
.PHONY: integration-fail-fast
|
||||||
integration-fail-fast: .env ## Runs postgres integration tests with py-integration in "fail fast" mode.
|
integration-fail-fast: .env ## Runs postgres integration tests with py-integration in "fail fast" mode.
|
||||||
@@ -98,9 +76,9 @@ integration-fail-fast: .env ## Runs postgres integration tests with py-integrati
|
|||||||
.PHONY: interop
|
.PHONY: interop
|
||||||
interop: clean
|
interop: clean
|
||||||
@\
|
@\
|
||||||
mkdir $(LOG_DIR) && \
|
mkdir $(LOGS_DIR) && \
|
||||||
$(CI_FLAGS) $(DOCKER_CMD) tox -e py-integration -- -nauto && \
|
$(CI_FLAGS) $(DOCKER_CMD) tox -e py-integration -- -nauto && \
|
||||||
LOG_DIR=$(LOG_DIR) cargo run --manifest-path test/interop/log_parsing/Cargo.toml
|
LOG_DIR=$(LOGS_DIR) cargo run --manifest-path test/interop/log_parsing/Cargo.toml
|
||||||
|
|
||||||
.PHONY: setup-db
|
.PHONY: setup-db
|
||||||
setup-db: ## Setup Postgres database with docker-compose for system testing.
|
setup-db: ## Setup Postgres database with docker-compose for system testing.
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ These select statements, or "models", form a dbt project. Models frequently buil
|
|||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
- [Install dbt](https://docs.getdbt.com/docs/get-started/installation)
|
- [Install dbt](https://docs.getdbt.com/docs/installation)
|
||||||
- Read the [introduction](https://docs.getdbt.com/docs/introduction/) and [viewpoint](https://docs.getdbt.com/docs/about/viewpoint/)
|
- Read the [introduction](https://docs.getdbt.com/docs/introduction/) and [viewpoint](https://docs.getdbt.com/docs/about/viewpoint/)
|
||||||
|
|
||||||
## Join the dbt Community
|
## Join the dbt Community
|
||||||
|
|||||||
13
codecov.yml
13
codecov.yml
@@ -1,13 +0,0 @@
|
|||||||
ignore:
|
|
||||||
- ".github"
|
|
||||||
- ".changes"
|
|
||||||
coverage:
|
|
||||||
status:
|
|
||||||
project:
|
|
||||||
default:
|
|
||||||
target: auto
|
|
||||||
threshold: 0.1% # Reduce noise by ignoring rounding errors in coverage drops
|
|
||||||
patch:
|
|
||||||
default:
|
|
||||||
target: auto
|
|
||||||
threshold: 80%
|
|
||||||
@@ -1,19 +1,14 @@
|
|||||||
# these are all just exports, #noqa them so flake8 will be happy
|
# these are all just exports, #noqa them so flake8 will be happy
|
||||||
|
|
||||||
# TODO: Should we still include this in the `adapters` namespace?
|
# TODO: Should we still include this in the `adapters` namespace?
|
||||||
from dbt.adapters.contracts.connection import Credentials # noqa: F401
|
from dbt.contracts.connection import Credentials # noqa
|
||||||
from dbt.adapters.base.meta import available # noqa: F401
|
from dbt.adapters.base.meta import available # noqa
|
||||||
from dbt.adapters.base.connections import BaseConnectionManager # noqa: F401
|
from dbt.adapters.base.connections import BaseConnectionManager # noqa
|
||||||
from dbt.adapters.base.relation import ( # noqa: F401
|
from dbt.adapters.base.relation import ( # noqa
|
||||||
BaseRelation,
|
BaseRelation,
|
||||||
RelationType,
|
RelationType,
|
||||||
SchemaSearchMap,
|
SchemaSearchMap,
|
||||||
)
|
)
|
||||||
from dbt.adapters.base.column import Column # noqa: F401
|
from dbt.adapters.base.column import Column # noqa
|
||||||
from dbt.adapters.base.impl import ( # noqa: F401
|
from dbt.adapters.base.impl import AdapterConfig, BaseAdapter, PythonJobHelper # noqa
|
||||||
AdapterConfig,
|
from dbt.adapters.base.plugin import AdapterPlugin # noqa
|
||||||
BaseAdapter,
|
|
||||||
PythonJobHelper,
|
|
||||||
ConstraintSupport,
|
|
||||||
)
|
|
||||||
from dbt.adapters.base.plugin import AdapterPlugin # noqa: F401
|
|
||||||
|
|||||||
@@ -2,17 +2,17 @@ from dataclasses import dataclass
|
|||||||
import re
|
import re
|
||||||
from typing import Dict, ClassVar, Any, Optional
|
from typing import Dict, ClassVar, Any, Optional
|
||||||
|
|
||||||
from dbt.common.exceptions import DbtRuntimeError
|
from dbt.exceptions import DbtRuntimeError
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Column:
|
class Column:
|
||||||
# Note: This is automatically used by contract code
|
|
||||||
# No-op conversions (INTEGER => INT) have been removed.
|
|
||||||
# Any adapter that wants to take advantage of "translate_type"
|
|
||||||
# should create a ClassVar with the appropriate conversions.
|
|
||||||
TYPE_LABELS: ClassVar[Dict[str, str]] = {
|
TYPE_LABELS: ClassVar[Dict[str, str]] = {
|
||||||
"STRING": "TEXT",
|
"STRING": "TEXT",
|
||||||
|
"TIMESTAMP": "TIMESTAMP",
|
||||||
|
"FLOAT": "FLOAT",
|
||||||
|
"INTEGER": "INT",
|
||||||
|
"BOOLEAN": "BOOLEAN",
|
||||||
}
|
}
|
||||||
column: str
|
column: str
|
||||||
dtype: str
|
dtype: str
|
||||||
@@ -60,7 +60,6 @@ class Column:
|
|||||||
"float",
|
"float",
|
||||||
"double precision",
|
"double precision",
|
||||||
"float8",
|
"float8",
|
||||||
"double",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def is_integer(self) -> bool:
|
def is_integer(self) -> bool:
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import traceback
|
|||||||
|
|
||||||
# multiprocessing.RLock is a function returning this type
|
# multiprocessing.RLock is a function returning this type
|
||||||
from multiprocessing.synchronize import RLock
|
from multiprocessing.synchronize import RLock
|
||||||
from multiprocessing.context import SpawnContext
|
|
||||||
from threading import get_ident
|
from threading import get_ident
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
@@ -24,9 +23,8 @@ from typing import (
|
|||||||
|
|
||||||
import agate
|
import agate
|
||||||
|
|
||||||
import dbt.adapters.exceptions
|
import dbt.exceptions
|
||||||
import dbt.common.exceptions.base
|
from dbt.contracts.connection import (
|
||||||
from dbt.adapters.contracts.connection import (
|
|
||||||
Connection,
|
Connection,
|
||||||
Identifier,
|
Identifier,
|
||||||
ConnectionState,
|
ConnectionState,
|
||||||
@@ -38,9 +36,9 @@ from dbt.contracts.graph.manifest import Manifest
|
|||||||
from dbt.adapters.base.query_headers import (
|
from dbt.adapters.base.query_headers import (
|
||||||
MacroQueryStringSetter,
|
MacroQueryStringSetter,
|
||||||
)
|
)
|
||||||
from dbt.adapters.events.logging import AdapterLogger
|
from dbt.events import AdapterLogger
|
||||||
from dbt.common.events.functions import fire_event
|
from dbt.events.functions import fire_event
|
||||||
from dbt.adapters.events.types import (
|
from dbt.events.types import (
|
||||||
NewConnection,
|
NewConnection,
|
||||||
ConnectionReused,
|
ConnectionReused,
|
||||||
ConnectionLeftOpenInCleanup,
|
ConnectionLeftOpenInCleanup,
|
||||||
@@ -50,8 +48,9 @@ from dbt.adapters.events.types import (
|
|||||||
Rollback,
|
Rollback,
|
||||||
RollbackFailed,
|
RollbackFailed,
|
||||||
)
|
)
|
||||||
from dbt.common.events.contextvars import get_node_info
|
from dbt.events.contextvars import get_node_info
|
||||||
from dbt.common.utils import cast_to_str
|
from dbt import flags
|
||||||
|
from dbt.utils import cast_to_str
|
||||||
|
|
||||||
SleepTime = Union[int, float] # As taken by time.sleep.
|
SleepTime = Union[int, float] # As taken by time.sleep.
|
||||||
AdapterHandle = Any # Adapter connection handle objects can be any class.
|
AdapterHandle = Any # Adapter connection handle objects can be any class.
|
||||||
@@ -73,10 +72,10 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
|
|
||||||
TYPE: str = NotImplemented
|
TYPE: str = NotImplemented
|
||||||
|
|
||||||
def __init__(self, profile: AdapterRequiredConfig, mp_context: SpawnContext) -> None:
|
def __init__(self, profile: AdapterRequiredConfig):
|
||||||
self.profile = profile
|
self.profile = profile
|
||||||
self.thread_connections: Dict[Hashable, Connection] = {}
|
self.thread_connections: Dict[Hashable, Connection] = {}
|
||||||
self.lock: RLock = mp_context.RLock()
|
self.lock: RLock = flags.MP_CONTEXT.RLock()
|
||||||
self.query_header: Optional[MacroQueryStringSetter] = None
|
self.query_header: Optional[MacroQueryStringSetter] = None
|
||||||
|
|
||||||
def set_query_header(self, manifest: Manifest) -> None:
|
def set_query_header(self, manifest: Manifest) -> None:
|
||||||
@@ -92,15 +91,13 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
key = self.get_thread_identifier()
|
key = self.get_thread_identifier()
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if key not in self.thread_connections:
|
if key not in self.thread_connections:
|
||||||
raise dbt.adapters.exceptions.InvalidConnectionError(
|
raise dbt.exceptions.InvalidConnectionError(key, list(self.thread_connections))
|
||||||
key, list(self.thread_connections)
|
|
||||||
)
|
|
||||||
return self.thread_connections[key]
|
return self.thread_connections[key]
|
||||||
|
|
||||||
def set_thread_connection(self, conn: Connection) -> None:
|
def set_thread_connection(self, conn: Connection) -> None:
|
||||||
key = self.get_thread_identifier()
|
key = self.get_thread_identifier()
|
||||||
if key in self.thread_connections:
|
if key in self.thread_connections:
|
||||||
raise dbt.common.exceptions.DbtInternalError(
|
raise dbt.exceptions.DbtInternalError(
|
||||||
"In set_thread_connection, existing connection exists for {}"
|
"In set_thread_connection, existing connection exists for {}"
|
||||||
)
|
)
|
||||||
self.thread_connections[key] = conn
|
self.thread_connections[key] = conn
|
||||||
@@ -140,13 +137,13 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
:return: A context manager that handles exceptions raised by the
|
:return: A context manager that handles exceptions raised by the
|
||||||
underlying database.
|
underlying database.
|
||||||
"""
|
"""
|
||||||
raise dbt.common.exceptions.base.NotImplementedError(
|
raise dbt.exceptions.NotImplementedError(
|
||||||
"`exception_handler` is not implemented for this adapter!"
|
"`exception_handler` is not implemented for this adapter!"
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_connection_name(self, name: Optional[str] = None) -> Connection:
|
def set_connection_name(self, name: Optional[str] = None) -> Connection:
|
||||||
"""Called by 'acquire_connection' in BaseAdapter, which is called by
|
"""Called by 'acquire_connection' in BaseAdapter, which is called by
|
||||||
'connection_named'.
|
'connection_named', called by 'connection_for(node)'.
|
||||||
Creates a connection for this thread if one doesn't already
|
Creates a connection for this thread if one doesn't already
|
||||||
exist, and will rename an existing connection."""
|
exist, and will rename an existing connection."""
|
||||||
|
|
||||||
@@ -223,14 +220,14 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
:param int _attempts: Parameter used to keep track of the number of attempts in calling the
|
:param int _attempts: Parameter used to keep track of the number of attempts in calling the
|
||||||
connect function across recursive calls. Passed as an argument to retry_timeout if it
|
connect function across recursive calls. Passed as an argument to retry_timeout if it
|
||||||
is a Callable. This parameter should not be set by the initial caller.
|
is a Callable. This parameter should not be set by the initial caller.
|
||||||
:raises dbt.adapters.exceptions.FailedToConnectError: Upon exhausting all retry attempts without
|
:raises dbt.exceptions.FailedToConnectError: Upon exhausting all retry attempts without
|
||||||
successfully acquiring a handle.
|
successfully acquiring a handle.
|
||||||
:return: The given connection with its appropriate state and handle attributes set
|
:return: The given connection with its appropriate state and handle attributes set
|
||||||
depending on whether we successfully acquired a handle or not.
|
depending on whether we successfully acquired a handle or not.
|
||||||
"""
|
"""
|
||||||
timeout = retry_timeout(_attempts) if callable(retry_timeout) else retry_timeout
|
timeout = retry_timeout(_attempts) if callable(retry_timeout) else retry_timeout
|
||||||
if timeout < 0:
|
if timeout < 0:
|
||||||
raise dbt.adapters.exceptions.FailedToConnectError(
|
raise dbt.exceptions.FailedToConnectError(
|
||||||
"retry_timeout cannot be negative or return a negative time."
|
"retry_timeout cannot be negative or return a negative time."
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -238,7 +235,7 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
# This guard is not perfect others may add to the recursion limit (e.g. built-ins).
|
# This guard is not perfect others may add to the recursion limit (e.g. built-ins).
|
||||||
connection.handle = None
|
connection.handle = None
|
||||||
connection.state = ConnectionState.FAIL
|
connection.state = ConnectionState.FAIL
|
||||||
raise dbt.adapters.exceptions.FailedToConnectError("retry_limit cannot be negative")
|
raise dbt.exceptions.FailedToConnectError("retry_limit cannot be negative")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
connection.handle = connect()
|
connection.handle = connect()
|
||||||
@@ -249,7 +246,7 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
if retry_limit <= 0:
|
if retry_limit <= 0:
|
||||||
connection.handle = None
|
connection.handle = None
|
||||||
connection.state = ConnectionState.FAIL
|
connection.state = ConnectionState.FAIL
|
||||||
raise dbt.adapters.exceptions.FailedToConnectError(str(e))
|
raise dbt.exceptions.FailedToConnectError(str(e))
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Got a retryable error when attempting to open a {cls.TYPE} connection.\n"
|
f"Got a retryable error when attempting to open a {cls.TYPE} connection.\n"
|
||||||
@@ -271,12 +268,12 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
connection.handle = None
|
connection.handle = None
|
||||||
connection.state = ConnectionState.FAIL
|
connection.state = ConnectionState.FAIL
|
||||||
raise dbt.adapters.exceptions.FailedToConnectError(str(e))
|
raise dbt.exceptions.FailedToConnectError(str(e))
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def cancel_open(self) -> Optional[List[str]]:
|
def cancel_open(self) -> Optional[List[str]]:
|
||||||
"""Cancel all open connections on the adapter. (passable)"""
|
"""Cancel all open connections on the adapter. (passable)"""
|
||||||
raise dbt.common.exceptions.base.NotImplementedError(
|
raise dbt.exceptions.NotImplementedError(
|
||||||
"`cancel_open` is not implemented for this adapter!"
|
"`cancel_open` is not implemented for this adapter!"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -291,9 +288,7 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
This should be thread-safe, or hold the lock if necessary. The given
|
This should be thread-safe, or hold the lock if necessary. The given
|
||||||
connection should not be in either in_use or available.
|
connection should not be in either in_use or available.
|
||||||
"""
|
"""
|
||||||
raise dbt.common.exceptions.base.NotImplementedError(
|
raise dbt.exceptions.NotImplementedError("`open` is not implemented for this adapter!")
|
||||||
"`open` is not implemented for this adapter!"
|
|
||||||
)
|
|
||||||
|
|
||||||
def release(self) -> None:
|
def release(self) -> None:
|
||||||
with self.lock:
|
with self.lock:
|
||||||
@@ -325,16 +320,12 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def begin(self) -> None:
|
def begin(self) -> None:
|
||||||
"""Begin a transaction. (passable)"""
|
"""Begin a transaction. (passable)"""
|
||||||
raise dbt.common.exceptions.base.NotImplementedError(
|
raise dbt.exceptions.NotImplementedError("`begin` is not implemented for this adapter!")
|
||||||
"`begin` is not implemented for this adapter!"
|
|
||||||
)
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def commit(self) -> None:
|
def commit(self) -> None:
|
||||||
"""Commit a transaction. (passable)"""
|
"""Commit a transaction. (passable)"""
|
||||||
raise dbt.common.exceptions.base.NotImplementedError(
|
raise dbt.exceptions.NotImplementedError("`commit` is not implemented for this adapter!")
|
||||||
"`commit` is not implemented for this adapter!"
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _rollback_handle(cls, connection: Connection) -> None:
|
def _rollback_handle(cls, connection: Connection) -> None:
|
||||||
@@ -370,7 +361,7 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
def _rollback(cls, connection: Connection) -> None:
|
def _rollback(cls, connection: Connection) -> None:
|
||||||
"""Roll back the given connection."""
|
"""Roll back the given connection."""
|
||||||
if connection.transaction_open is False:
|
if connection.transaction_open is False:
|
||||||
raise dbt.common.exceptions.DbtInternalError(
|
raise dbt.exceptions.DbtInternalError(
|
||||||
f"Tried to rollback transaction on connection "
|
f"Tried to rollback transaction on connection "
|
||||||
f'"{connection.name}", but it does not have one open!'
|
f'"{connection.name}", but it does not have one open!'
|
||||||
)
|
)
|
||||||
@@ -409,7 +400,7 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def execute(
|
def execute(
|
||||||
self, sql: str, auto_begin: bool = False, fetch: bool = False, limit: Optional[int] = None
|
self, sql: str, auto_begin: bool = False, fetch: bool = False
|
||||||
) -> Tuple[AdapterResponse, agate.Table]:
|
) -> Tuple[AdapterResponse, agate.Table]:
|
||||||
"""Execute the given SQL.
|
"""Execute the given SQL.
|
||||||
|
|
||||||
@@ -417,30 +408,7 @@ class BaseConnectionManager(metaclass=abc.ABCMeta):
|
|||||||
:param bool auto_begin: If set, and dbt is not currently inside a
|
:param bool auto_begin: If set, and dbt is not currently inside a
|
||||||
transaction, automatically begin one.
|
transaction, automatically begin one.
|
||||||
:param bool fetch: If set, fetch results.
|
:param bool fetch: If set, fetch results.
|
||||||
:param int limit: If set, limits the result set
|
|
||||||
:return: A tuple of the query status and results (empty if fetch=False).
|
:return: A tuple of the query status and results (empty if fetch=False).
|
||||||
:rtype: Tuple[AdapterResponse, agate.Table]
|
:rtype: Tuple[AdapterResponse, agate.Table]
|
||||||
"""
|
"""
|
||||||
raise dbt.common.exceptions.base.NotImplementedError(
|
raise dbt.exceptions.NotImplementedError("`execute` is not implemented for this adapter!")
|
||||||
"`execute` is not implemented for this adapter!"
|
|
||||||
)
|
|
||||||
|
|
||||||
def add_select_query(self, sql: str) -> Tuple[Connection, Any]:
|
|
||||||
"""
|
|
||||||
This was added here because base.impl.BaseAdapter.get_column_schema_from_query expects it to be here.
|
|
||||||
That method wouldn't work unless the adapter used sql.impl.SQLAdapter, sql.connections.SQLConnectionManager
|
|
||||||
or defined this method on <Adapter>ConnectionManager before passing it in to <Adapter>Adapter.
|
|
||||||
|
|
||||||
See https://github.com/dbt-labs/dbt-core/issues/8396 for more information.
|
|
||||||
"""
|
|
||||||
raise dbt.common.exceptions.base.NotImplementedError(
|
|
||||||
"`add_select_query` is not implemented for this adapter!"
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def data_type_code_to_name(cls, type_code: Union[int, str]) -> str:
|
|
||||||
"""Get the string representation of the data type from the type_code."""
|
|
||||||
# https://peps.python.org/pep-0249/#type-objects
|
|
||||||
raise dbt.common.exceptions.base.NotImplementedError(
|
|
||||||
"`data_type_code_to_name` is not implemented for this adapter!"
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -2,80 +2,61 @@ import abc
|
|||||||
from concurrent.futures import as_completed, Future
|
from concurrent.futures import as_completed, Future
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
|
||||||
import time
|
import time
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Optional,
|
||||||
|
Tuple,
|
||||||
Callable,
|
Callable,
|
||||||
|
Iterable,
|
||||||
|
Type,
|
||||||
Dict,
|
Dict,
|
||||||
Iterator,
|
Any,
|
||||||
List,
|
List,
|
||||||
Mapping,
|
Mapping,
|
||||||
Optional,
|
Iterator,
|
||||||
Set,
|
Set,
|
||||||
Tuple,
|
|
||||||
Type,
|
|
||||||
TypedDict,
|
|
||||||
Union,
|
|
||||||
)
|
)
|
||||||
from multiprocessing.context import SpawnContext
|
|
||||||
|
|
||||||
from dbt.adapters.capability import Capability, CapabilityDict
|
|
||||||
from dbt.common.contracts.constraints import (
|
|
||||||
ColumnLevelConstraint,
|
|
||||||
ConstraintType,
|
|
||||||
ModelLevelConstraint,
|
|
||||||
)
|
|
||||||
from dbt.adapters.contracts.macros import MacroResolver
|
|
||||||
|
|
||||||
import agate
|
import agate
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from dbt.adapters.exceptions import (
|
from dbt.exceptions import (
|
||||||
SnapshotTargetIncompleteError,
|
|
||||||
SnapshotTargetNotSnapshotTableError,
|
|
||||||
NullRelationDropAttemptedError,
|
|
||||||
NullRelationCacheAttemptedError,
|
|
||||||
RelationReturnedMultipleResultsError,
|
|
||||||
UnexpectedNonTimestampError,
|
|
||||||
RenameToNoneAttemptedError,
|
|
||||||
QuoteConfigTypeError,
|
|
||||||
)
|
|
||||||
|
|
||||||
from dbt.common.exceptions import (
|
|
||||||
NotImplementedError,
|
|
||||||
DbtInternalError,
|
DbtInternalError,
|
||||||
DbtRuntimeError,
|
|
||||||
DbtValidationError,
|
|
||||||
UnexpectedNullError,
|
|
||||||
MacroArgTypeError,
|
MacroArgTypeError,
|
||||||
MacroResultError,
|
MacroResultError,
|
||||||
|
QuoteConfigTypeError,
|
||||||
|
NotImplementedError,
|
||||||
|
NullRelationCacheAttemptedError,
|
||||||
|
NullRelationDropAttemptedError,
|
||||||
|
RelationReturnedMultipleResultsError,
|
||||||
|
RenameToNoneAttemptedError,
|
||||||
|
DbtRuntimeError,
|
||||||
|
SnapshotTargetIncompleteError,
|
||||||
|
SnapshotTargetNotSnapshotTableError,
|
||||||
|
UnexpectedNullError,
|
||||||
|
UnexpectedNonTimestampError,
|
||||||
)
|
)
|
||||||
|
|
||||||
from dbt.adapters.protocol import AdapterConfig
|
from dbt.adapters.protocol import (
|
||||||
from dbt.common.clients.agate_helper import (
|
AdapterConfig,
|
||||||
empty_table,
|
ConnectionManagerProtocol,
|
||||||
get_column_value_uncased,
|
|
||||||
merge_tables,
|
|
||||||
table_from_rows,
|
|
||||||
Integer,
|
|
||||||
)
|
)
|
||||||
from dbt.common.clients.jinja import CallableMacroGenerator
|
from dbt.clients.agate_helper import empty_table, merge_tables, table_from_rows
|
||||||
from dbt.contracts.graph.manifest import Manifest
|
from dbt.clients.jinja import MacroGenerator
|
||||||
from dbt.common.events.functions import fire_event, warn_or_error
|
from dbt.contracts.graph.manifest import Manifest, MacroManifest
|
||||||
from dbt.adapters.events.types import (
|
from dbt.contracts.graph.nodes import ResultNode
|
||||||
|
from dbt.events.functions import fire_event, warn_or_error
|
||||||
|
from dbt.events.types import (
|
||||||
CacheMiss,
|
CacheMiss,
|
||||||
ListRelations,
|
ListRelations,
|
||||||
CodeExecution,
|
CodeExecution,
|
||||||
CodeExecutionStatus,
|
CodeExecutionStatus,
|
||||||
CatalogGenerationError,
|
CatalogGenerationError,
|
||||||
ConstraintNotSupported,
|
|
||||||
ConstraintNotEnforced,
|
|
||||||
)
|
)
|
||||||
from dbt.common.utils import filter_null_values, executor, cast_to_str, AttrDict
|
from dbt.utils import filter_null_values, executor, cast_to_str
|
||||||
|
|
||||||
from dbt.adapters.base.connections import Connection, AdapterResponse, BaseConnectionManager
|
from dbt.adapters.base.connections import Connection, AdapterResponse
|
||||||
from dbt.adapters.base.meta import AdapterMeta, available
|
from dbt.adapters.base.meta import AdapterMeta, available
|
||||||
from dbt.adapters.base.relation import (
|
from dbt.adapters.base.relation import (
|
||||||
ComponentName,
|
ComponentName,
|
||||||
@@ -85,20 +66,11 @@ from dbt.adapters.base.relation import (
|
|||||||
)
|
)
|
||||||
from dbt.adapters.base import Column as BaseColumn
|
from dbt.adapters.base import Column as BaseColumn
|
||||||
from dbt.adapters.base import Credentials
|
from dbt.adapters.base import Credentials
|
||||||
from dbt.adapters.cache import RelationsCache, _make_ref_key_dict
|
from dbt.adapters.cache import RelationsCache, _make_ref_key_msg
|
||||||
from dbt.adapters.events.types import CollectFreshnessReturnSignature
|
|
||||||
|
|
||||||
|
|
||||||
GET_CATALOG_MACRO_NAME = "get_catalog"
|
GET_CATALOG_MACRO_NAME = "get_catalog"
|
||||||
GET_CATALOG_RELATIONS_MACRO_NAME = "get_catalog_relations"
|
|
||||||
FRESHNESS_MACRO_NAME = "collect_freshness"
|
FRESHNESS_MACRO_NAME = "collect_freshness"
|
||||||
GET_RELATION_LAST_MODIFIED_MACRO_NAME = "get_relation_last_modified"
|
|
||||||
|
|
||||||
|
|
||||||
class ConstraintSupport(str, Enum):
|
|
||||||
ENFORCED = "enforced"
|
|
||||||
NOT_ENFORCED = "not_enforced"
|
|
||||||
NOT_SUPPORTED = "not_supported"
|
|
||||||
|
|
||||||
|
|
||||||
def _expect_row_value(key: str, row: agate.Row):
|
def _expect_row_value(key: str, row: agate.Row):
|
||||||
@@ -127,7 +99,7 @@ def _catalog_filter_schemas(manifest: Manifest) -> Callable[[agate.Row], bool]:
|
|||||||
return test
|
return test
|
||||||
|
|
||||||
|
|
||||||
def _utc(dt: Optional[datetime], source: Optional[BaseRelation], field_name: str) -> datetime:
|
def _utc(dt: Optional[datetime], source: BaseRelation, field_name: str) -> datetime:
|
||||||
"""If dt has a timezone, return a new datetime that's in UTC. Otherwise,
|
"""If dt has a timezone, return a new datetime that's in UTC. Otherwise,
|
||||||
assume the datetime is already for UTC and add the timezone.
|
assume the datetime is already for UTC and add the timezone.
|
||||||
"""
|
"""
|
||||||
@@ -179,12 +151,6 @@ class PythonJobHelper:
|
|||||||
raise NotImplementedError("PythonJobHelper submit function is not implemented yet")
|
raise NotImplementedError("PythonJobHelper submit function is not implemented yet")
|
||||||
|
|
||||||
|
|
||||||
class FreshnessResponse(TypedDict):
|
|
||||||
max_loaded_at: datetime
|
|
||||||
snapshotted_at: datetime
|
|
||||||
age: float # age in seconds
|
|
||||||
|
|
||||||
|
|
||||||
class BaseAdapter(metaclass=AdapterMeta):
|
class BaseAdapter(metaclass=AdapterMeta):
|
||||||
"""The BaseAdapter provides an abstract base class for adapters.
|
"""The BaseAdapter provides an abstract base class for adapters.
|
||||||
|
|
||||||
@@ -211,7 +177,6 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
- truncate_relation
|
- truncate_relation
|
||||||
- rename_relation
|
- rename_relation
|
||||||
- get_columns_in_relation
|
- get_columns_in_relation
|
||||||
- get_column_schema_from_query
|
|
||||||
- expand_column_types
|
- expand_column_types
|
||||||
- list_relations_without_caching
|
- list_relations_without_caching
|
||||||
- is_cancelable
|
- is_cancelable
|
||||||
@@ -232,42 +197,17 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
|
|
||||||
Relation: Type[BaseRelation] = BaseRelation
|
Relation: Type[BaseRelation] = BaseRelation
|
||||||
Column: Type[BaseColumn] = BaseColumn
|
Column: Type[BaseColumn] = BaseColumn
|
||||||
ConnectionManager: Type[BaseConnectionManager]
|
ConnectionManager: Type[ConnectionManagerProtocol]
|
||||||
|
|
||||||
# A set of clobber config fields accepted by this adapter
|
# A set of clobber config fields accepted by this adapter
|
||||||
# for use in materializations
|
# for use in materializations
|
||||||
AdapterSpecificConfigs: Type[AdapterConfig] = AdapterConfig
|
AdapterSpecificConfigs: Type[AdapterConfig] = AdapterConfig
|
||||||
|
|
||||||
CONSTRAINT_SUPPORT = {
|
def __init__(self, config):
|
||||||
ConstraintType.check: ConstraintSupport.NOT_SUPPORTED,
|
|
||||||
ConstraintType.not_null: ConstraintSupport.ENFORCED,
|
|
||||||
ConstraintType.unique: ConstraintSupport.NOT_ENFORCED,
|
|
||||||
ConstraintType.primary_key: ConstraintSupport.NOT_ENFORCED,
|
|
||||||
ConstraintType.foreign_key: ConstraintSupport.ENFORCED,
|
|
||||||
}
|
|
||||||
|
|
||||||
# This static member variable can be overriden in concrete adapter
|
|
||||||
# implementations to indicate adapter support for optional capabilities.
|
|
||||||
_capabilities = CapabilityDict({})
|
|
||||||
|
|
||||||
def __init__(self, config, mp_context: SpawnContext) -> None:
|
|
||||||
self.config = config
|
self.config = config
|
||||||
self.cache = RelationsCache(log_cache_events=config.log_cache_events)
|
self.cache = RelationsCache()
|
||||||
self.connections = self.ConnectionManager(config, mp_context)
|
self.connections = self.ConnectionManager(config)
|
||||||
self._macro_resolver: Optional[MacroResolver] = None
|
self._macro_manifest_lazy: Optional[MacroManifest] = None
|
||||||
|
|
||||||
###
|
|
||||||
# Methods to set / access a macro resolver
|
|
||||||
###
|
|
||||||
def set_macro_resolver(self, macro_resolver: MacroResolver) -> None:
|
|
||||||
self._macro_resolver = macro_resolver
|
|
||||||
|
|
||||||
def get_macro_resolver(self) -> Optional[MacroResolver]:
|
|
||||||
return self._macro_resolver
|
|
||||||
|
|
||||||
def clear_macro_resolver(self) -> None:
|
|
||||||
if self._macro_resolver is not None:
|
|
||||||
self._macro_resolver = None
|
|
||||||
|
|
||||||
###
|
###
|
||||||
# Methods that pass through to the connection manager
|
# Methods that pass through to the connection manager
|
||||||
@@ -297,10 +237,10 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
return conn.name
|
return conn.name
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def connection_named(self, name: str, query_header_context: Any = None) -> Iterator[None]:
|
def connection_named(self, name: str, node: Optional[ResultNode] = None) -> Iterator[None]:
|
||||||
try:
|
try:
|
||||||
if self.connections.query_header is not None:
|
if self.connections.query_header is not None:
|
||||||
self.connections.query_header.set(name, query_header_context)
|
self.connections.query_header.set(name, node)
|
||||||
self.acquire_connection(name)
|
self.acquire_connection(name)
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
@@ -308,9 +248,14 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
if self.connections.query_header is not None:
|
if self.connections.query_header is not None:
|
||||||
self.connections.query_header.reset()
|
self.connections.query_header.reset()
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def connection_for(self, node: ResultNode) -> Iterator[None]:
|
||||||
|
with self.connection_named(node.unique_id, node):
|
||||||
|
yield
|
||||||
|
|
||||||
@available.parse(lambda *a, **k: ("", empty_table()))
|
@available.parse(lambda *a, **k: ("", empty_table()))
|
||||||
def execute(
|
def execute(
|
||||||
self, sql: str, auto_begin: bool = False, fetch: bool = False, limit: Optional[int] = None
|
self, sql: str, auto_begin: bool = False, fetch: bool = False
|
||||||
) -> Tuple[AdapterResponse, agate.Table]:
|
) -> Tuple[AdapterResponse, agate.Table]:
|
||||||
"""Execute the given SQL. This is a thin wrapper around
|
"""Execute the given SQL. This is a thin wrapper around
|
||||||
ConnectionManager.execute.
|
ConnectionManager.execute.
|
||||||
@@ -319,53 +264,21 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
:param bool auto_begin: If set, and dbt is not currently inside a
|
:param bool auto_begin: If set, and dbt is not currently inside a
|
||||||
transaction, automatically begin one.
|
transaction, automatically begin one.
|
||||||
:param bool fetch: If set, fetch results.
|
:param bool fetch: If set, fetch results.
|
||||||
:param Optional[int] limit: If set, only fetch n number of rows
|
|
||||||
:return: A tuple of the query status and results (empty if fetch=False).
|
:return: A tuple of the query status and results (empty if fetch=False).
|
||||||
:rtype: Tuple[AdapterResponse, agate.Table]
|
:rtype: Tuple[AdapterResponse, agate.Table]
|
||||||
"""
|
"""
|
||||||
return self.connections.execute(sql=sql, auto_begin=auto_begin, fetch=fetch, limit=limit)
|
return self.connections.execute(sql=sql, auto_begin=auto_begin, fetch=fetch)
|
||||||
|
|
||||||
def validate_sql(self, sql: str) -> AdapterResponse:
|
|
||||||
"""Submit the given SQL to the engine for validation, but not execution.
|
|
||||||
|
|
||||||
This should throw an appropriate exception if the input SQL is invalid, although
|
|
||||||
in practice that will generally be handled by delegating to an existing method
|
|
||||||
for execution and allowing the error handler to take care of the rest.
|
|
||||||
|
|
||||||
:param str sql: The sql to validate
|
|
||||||
"""
|
|
||||||
raise NotImplementedError("`validate_sql` is not implemented for this adapter!")
|
|
||||||
|
|
||||||
@available.parse(lambda *a, **k: [])
|
|
||||||
def get_column_schema_from_query(self, sql: str) -> List[BaseColumn]:
|
|
||||||
"""Get a list of the Columns with names and data types from the given sql."""
|
|
||||||
_, cursor = self.connections.add_select_query(sql)
|
|
||||||
columns = [
|
|
||||||
self.Column.create(
|
|
||||||
column_name, self.connections.data_type_code_to_name(column_type_code)
|
|
||||||
)
|
|
||||||
# https://peps.python.org/pep-0249/#description
|
|
||||||
for column_name, column_type_code, *_ in cursor.description
|
|
||||||
]
|
|
||||||
return columns
|
|
||||||
|
|
||||||
@available.parse(lambda *a, **k: ("", empty_table()))
|
@available.parse(lambda *a, **k: ("", empty_table()))
|
||||||
def get_partitions_metadata(self, table: str) -> Tuple[agate.Table]:
|
def get_partitions_metadata(self, table: str) -> Tuple[agate.Table]:
|
||||||
"""
|
"""Obtain partitions metadata for a BigQuery partitioned table.
|
||||||
TODO: Can we move this to dbt-bigquery?
|
|
||||||
Obtain partitions metadata for a BigQuery partitioned table.
|
|
||||||
|
|
||||||
:param str table: a partitioned table id, in standard SQL format.
|
:param str table_id: a partitioned table id, in standard SQL format.
|
||||||
:return: a partition metadata tuple, as described in
|
:return: a partition metadata tuple, as described in
|
||||||
https://cloud.google.com/bigquery/docs/creating-partitioned-tables#getting_partition_metadata_using_meta_tables.
|
https://cloud.google.com/bigquery/docs/creating-partitioned-tables#getting_partition_metadata_using_meta_tables.
|
||||||
:rtype: agate.Table
|
:rtype: agate.Table
|
||||||
"""
|
"""
|
||||||
if hasattr(self.connections, "get_partitions_metadata"):
|
return self.connections.get_partitions_metadata(table=table)
|
||||||
return self.connections.get_partitions_metadata(table=table)
|
|
||||||
else:
|
|
||||||
raise NotImplementedError(
|
|
||||||
"`get_partitions_metadata` is not implemented for this adapter!"
|
|
||||||
)
|
|
||||||
|
|
||||||
###
|
###
|
||||||
# Methods that should never be overridden
|
# Methods that should never be overridden
|
||||||
@@ -380,6 +293,39 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
"""
|
"""
|
||||||
return cls.ConnectionManager.TYPE
|
return cls.ConnectionManager.TYPE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _macro_manifest(self) -> MacroManifest:
|
||||||
|
if self._macro_manifest_lazy is None:
|
||||||
|
return self.load_macro_manifest()
|
||||||
|
return self._macro_manifest_lazy
|
||||||
|
|
||||||
|
def check_macro_manifest(self) -> Optional[MacroManifest]:
|
||||||
|
"""Return the internal manifest (used for executing macros) if it's
|
||||||
|
been initialized, otherwise return None.
|
||||||
|
"""
|
||||||
|
return self._macro_manifest_lazy
|
||||||
|
|
||||||
|
def load_macro_manifest(self, base_macros_only=False) -> MacroManifest:
|
||||||
|
# base_macros_only is for the test framework
|
||||||
|
if self._macro_manifest_lazy is None:
|
||||||
|
# avoid a circular import
|
||||||
|
from dbt.parser.manifest import ManifestLoader
|
||||||
|
|
||||||
|
manifest = ManifestLoader.load_macros(
|
||||||
|
self.config,
|
||||||
|
self.connections.set_query_header,
|
||||||
|
base_macros_only=base_macros_only,
|
||||||
|
)
|
||||||
|
# TODO CT-211
|
||||||
|
self._macro_manifest_lazy = manifest # type: ignore[assignment]
|
||||||
|
# TODO CT-211
|
||||||
|
return self._macro_manifest_lazy # type: ignore[return-value]
|
||||||
|
|
||||||
|
def clear_macro_manifest(self):
|
||||||
|
if self._macro_manifest_lazy is not None:
|
||||||
|
self._macro_manifest_lazy = None
|
||||||
|
|
||||||
|
###
|
||||||
# Caching methods
|
# Caching methods
|
||||||
###
|
###
|
||||||
def _schema_is_cached(self, database: Optional[str], schema: str) -> bool:
|
def _schema_is_cached(self, database: Optional[str], schema: str) -> bool:
|
||||||
@@ -403,9 +349,9 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
"""
|
"""
|
||||||
# the cache only cares about executable nodes
|
# the cache only cares about executable nodes
|
||||||
return {
|
return {
|
||||||
self.Relation.create_from(self.config, node).without_identifier() # type: ignore[arg-type]
|
self.Relation.create_from(self.config, node).without_identifier()
|
||||||
for node in manifest.nodes.values()
|
for node in manifest.nodes.values()
|
||||||
if (node.is_relational and not node.is_ephemeral_model and not node.is_external_node)
|
if (node.is_relational and not node.is_ephemeral_model)
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_catalog_schemas(self, manifest: Manifest) -> SchemaSearchMap:
|
def _get_catalog_schemas(self, manifest: Manifest) -> SchemaSearchMap:
|
||||||
@@ -418,30 +364,7 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
lowercase strings.
|
lowercase strings.
|
||||||
"""
|
"""
|
||||||
info_schema_name_map = SchemaSearchMap()
|
info_schema_name_map = SchemaSearchMap()
|
||||||
relations = self._get_catalog_relations(manifest)
|
nodes: Iterator[ResultNode] = chain(
|
||||||
for relation in relations:
|
|
||||||
info_schema_name_map.add(relation)
|
|
||||||
# result is a map whose keys are information_schema Relations without
|
|
||||||
# identifiers that have appropriate database prefixes, and whose values
|
|
||||||
# are sets of lowercase schema names that are valid members of those
|
|
||||||
# databases
|
|
||||||
return info_schema_name_map
|
|
||||||
|
|
||||||
def _get_catalog_relations_by_info_schema(
|
|
||||||
self, relations
|
|
||||||
) -> Dict[InformationSchema, List[BaseRelation]]:
|
|
||||||
relations_by_info_schema: Dict[InformationSchema, List[BaseRelation]] = dict()
|
|
||||||
for relation in relations:
|
|
||||||
info_schema = relation.information_schema_only()
|
|
||||||
if info_schema not in relations_by_info_schema:
|
|
||||||
relations_by_info_schema[info_schema] = []
|
|
||||||
relations_by_info_schema[info_schema].append(relation)
|
|
||||||
|
|
||||||
return relations_by_info_schema
|
|
||||||
|
|
||||||
def _get_catalog_relations(self, manifest: Manifest) -> List[BaseRelation]:
|
|
||||||
|
|
||||||
nodes = chain(
|
|
||||||
[
|
[
|
||||||
node
|
node
|
||||||
for node in manifest.nodes.values()
|
for node in manifest.nodes.values()
|
||||||
@@ -449,12 +372,17 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
],
|
],
|
||||||
manifest.sources.values(),
|
manifest.sources.values(),
|
||||||
)
|
)
|
||||||
|
for node in nodes:
|
||||||
relations = [self.Relation.create_from(self.config, n) for n in nodes] # type: ignore[arg-type]
|
relation = self.Relation.create_from(self.config, node)
|
||||||
return relations
|
info_schema_name_map.add(relation)
|
||||||
|
# result is a map whose keys are information_schema Relations without
|
||||||
|
# identifiers that have appropriate database prefixes, and whose values
|
||||||
|
# are sets of lowercase schema names that are valid members of those
|
||||||
|
# databases
|
||||||
|
return info_schema_name_map
|
||||||
|
|
||||||
def _relations_cache_for_schemas(
|
def _relations_cache_for_schemas(
|
||||||
self, manifest: Manifest, cache_schemas: Optional[Set[BaseRelation]] = None
|
self, manifest: Manifest, cache_schemas: Set[BaseRelation] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Populate the relations cache for the given schemas. Returns an
|
"""Populate the relations cache for the given schemas. Returns an
|
||||||
iterable of the schemas populated, as strings.
|
iterable of the schemas populated, as strings.
|
||||||
@@ -481,17 +409,16 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
# it's possible that there were no relations in some schemas. We want
|
# it's possible that there were no relations in some schemas. We want
|
||||||
# to insert the schemas we query into the cache's `.schemas` attribute
|
# to insert the schemas we query into the cache's `.schemas` attribute
|
||||||
# so we can check it later
|
# so we can check it later
|
||||||
cache_update: Set[Tuple[Optional[str], str]] = set()
|
cache_update: Set[Tuple[Optional[str], Optional[str]]] = set()
|
||||||
for relation in cache_schemas:
|
for relation in cache_schemas:
|
||||||
if relation.schema:
|
cache_update.add((relation.database, relation.schema))
|
||||||
cache_update.add((relation.database, relation.schema))
|
|
||||||
self.cache.update_schemas(cache_update)
|
self.cache.update_schemas(cache_update)
|
||||||
|
|
||||||
def set_relations_cache(
|
def set_relations_cache(
|
||||||
self,
|
self,
|
||||||
manifest: Manifest,
|
manifest: Manifest,
|
||||||
clear: bool = False,
|
clear: bool = False,
|
||||||
required_schemas: Optional[Set[BaseRelation]] = None,
|
required_schemas: Set[BaseRelation] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Run a query that gets a populated cache of the relations in the
|
"""Run a query that gets a populated cache of the relations in the
|
||||||
database and set the cache on this adapter.
|
database and set the cache on this adapter.
|
||||||
@@ -777,23 +704,11 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
# we can't build the relations cache because we don't have a
|
# we can't build the relations cache because we don't have a
|
||||||
# manifest so we can't run any operations.
|
# manifest so we can't run any operations.
|
||||||
relations = self.list_relations_without_caching(schema_relation)
|
relations = self.list_relations_without_caching(schema_relation)
|
||||||
|
|
||||||
# if the cache is already populated, add this schema in
|
|
||||||
# otherwise, skip updating the cache and just ignore
|
|
||||||
if self.cache:
|
|
||||||
for relation in relations:
|
|
||||||
self.cache.add(relation)
|
|
||||||
if not relations:
|
|
||||||
# it's possible that there were no relations in some schemas. We want
|
|
||||||
# to insert the schemas we query into the cache's `.schemas` attribute
|
|
||||||
# so we can check it later
|
|
||||||
self.cache.update_schemas([(database, schema)])
|
|
||||||
|
|
||||||
fire_event(
|
fire_event(
|
||||||
ListRelations(
|
ListRelations(
|
||||||
database=cast_to_str(database),
|
database=cast_to_str(database),
|
||||||
schema=schema,
|
schema=schema,
|
||||||
relations=[_make_ref_key_dict(x) for x in relations],
|
relations=[_make_ref_key_msg(x) for x in relations],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -825,6 +740,7 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
schema: str,
|
schema: str,
|
||||||
identifier: str,
|
identifier: str,
|
||||||
) -> List[BaseRelation]:
|
) -> List[BaseRelation]:
|
||||||
|
|
||||||
matches = []
|
matches = []
|
||||||
|
|
||||||
search = self._make_match_kwargs(database, schema, identifier)
|
search = self._make_match_kwargs(database, schema, identifier)
|
||||||
@@ -946,17 +862,6 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError("`convert_number_type` is not implemented for this adapter!")
|
raise NotImplementedError("`convert_number_type` is not implemented for this adapter!")
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def convert_integer_type(cls, agate_table: agate.Table, col_idx: int) -> str:
|
|
||||||
"""Return the type in the database that best maps to the agate.Number
|
|
||||||
type for the given agate table and column index.
|
|
||||||
|
|
||||||
:param agate_table: The table
|
|
||||||
:param col_idx: The index into the agate table for the column.
|
|
||||||
:return: The name of the type in the database
|
|
||||||
"""
|
|
||||||
return "integer"
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def convert_boolean_type(cls, agate_table: agate.Table, col_idx: int) -> str:
|
def convert_boolean_type(cls, agate_table: agate.Table, col_idx: int) -> str:
|
||||||
@@ -1014,7 +919,6 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
def convert_agate_type(cls, agate_table: agate.Table, col_idx: int) -> Optional[str]:
|
def convert_agate_type(cls, agate_table: agate.Table, col_idx: int) -> Optional[str]:
|
||||||
agate_type: Type = agate_table.column_types[col_idx]
|
agate_type: Type = agate_table.column_types[col_idx]
|
||||||
conversions: List[Tuple[Type, Callable[..., str]]] = [
|
conversions: List[Tuple[Type, Callable[..., str]]] = [
|
||||||
(Integer, cls.convert_integer_type),
|
|
||||||
(agate.Text, cls.convert_text_type),
|
(agate.Text, cls.convert_text_type),
|
||||||
(agate.Number, cls.convert_number_type),
|
(agate.Number, cls.convert_number_type),
|
||||||
(agate.Boolean, cls.convert_boolean_type),
|
(agate.Boolean, cls.convert_boolean_type),
|
||||||
@@ -1034,11 +938,12 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
def execute_macro(
|
def execute_macro(
|
||||||
self,
|
self,
|
||||||
macro_name: str,
|
macro_name: str,
|
||||||
macro_resolver: Optional[MacroResolver] = None,
|
manifest: Optional[Manifest] = None,
|
||||||
project: Optional[str] = None,
|
project: Optional[str] = None,
|
||||||
context_override: Optional[Dict[str, Any]] = None,
|
context_override: Optional[Dict[str, Any]] = None,
|
||||||
kwargs: Optional[Dict[str, Any]] = None,
|
kwargs: Dict[str, Any] = None,
|
||||||
) -> AttrDict:
|
text_only_columns: Optional[Iterable[str]] = None,
|
||||||
|
) -> agate.Table:
|
||||||
"""Look macro_name up in the manifest and execute its results.
|
"""Look macro_name up in the manifest and execute its results.
|
||||||
|
|
||||||
:param macro_name: The name of the macro to execute.
|
:param macro_name: The name of the macro to execute.
|
||||||
@@ -1057,11 +962,13 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
if context_override is None:
|
if context_override is None:
|
||||||
context_override = {}
|
context_override = {}
|
||||||
|
|
||||||
resolver = macro_resolver or self._macro_resolver
|
if manifest is None:
|
||||||
if resolver is None:
|
# TODO CT-211
|
||||||
raise DbtInternalError("macro resolver was None when calling execute_macro!")
|
manifest = self._macro_manifest # type: ignore[assignment]
|
||||||
|
# TODO CT-211
|
||||||
macro = resolver.find_macro_by_name(macro_name, self.config.project_name, project)
|
macro = manifest.find_macro_by_name( # type: ignore[union-attr]
|
||||||
|
macro_name, self.config.project_name, project
|
||||||
|
)
|
||||||
if macro is None:
|
if macro is None:
|
||||||
if project is None:
|
if project is None:
|
||||||
package_name = "any package"
|
package_name = "any package"
|
||||||
@@ -1081,12 +988,12 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
# TODO CT-211
|
# TODO CT-211
|
||||||
macro=macro,
|
macro=macro,
|
||||||
config=self.config,
|
config=self.config,
|
||||||
manifest=resolver, # type: ignore[arg-type]
|
manifest=manifest, # type: ignore[arg-type]
|
||||||
package_name=project,
|
package_name=project,
|
||||||
)
|
)
|
||||||
macro_context.update(context_override)
|
macro_context.update(context_override)
|
||||||
|
|
||||||
macro_function = CallableMacroGenerator(macro, macro_context)
|
macro_function = MacroGenerator(macro, macro_context)
|
||||||
|
|
||||||
with self.connections.exception_handler(f"macro {macro_name}"):
|
with self.connections.exception_handler(f"macro {macro_name}"):
|
||||||
result = macro_function(**kwargs)
|
result = macro_function(**kwargs)
|
||||||
@@ -1111,119 +1018,37 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
schemas: Set[str],
|
schemas: Set[str],
|
||||||
manifest: Manifest,
|
manifest: Manifest,
|
||||||
) -> agate.Table:
|
) -> agate.Table:
|
||||||
|
|
||||||
kwargs = {"information_schema": information_schema, "schemas": schemas}
|
kwargs = {"information_schema": information_schema, "schemas": schemas}
|
||||||
table = self.execute_macro(
|
table = self.execute_macro(
|
||||||
GET_CATALOG_MACRO_NAME,
|
GET_CATALOG_MACRO_NAME,
|
||||||
kwargs=kwargs,
|
kwargs=kwargs,
|
||||||
# pass in the full manifest so we get any local project
|
# pass in the full manifest so we get any local project
|
||||||
# overrides
|
# overrides
|
||||||
macro_resolver=manifest,
|
manifest=manifest,
|
||||||
)
|
)
|
||||||
|
|
||||||
results = self._catalog_filter_table(table, manifest) # type: ignore[arg-type]
|
results = self._catalog_filter_table(table, manifest)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def _get_one_catalog_by_relations(
|
|
||||||
self,
|
|
||||||
information_schema: InformationSchema,
|
|
||||||
relations: List[BaseRelation],
|
|
||||||
manifest: Manifest,
|
|
||||||
) -> agate.Table:
|
|
||||||
|
|
||||||
kwargs = {
|
|
||||||
"information_schema": information_schema,
|
|
||||||
"relations": relations,
|
|
||||||
}
|
|
||||||
table = self.execute_macro(
|
|
||||||
GET_CATALOG_RELATIONS_MACRO_NAME,
|
|
||||||
kwargs=kwargs,
|
|
||||||
# pass in the full manifest, so we get any local project
|
|
||||||
# overrides
|
|
||||||
macro_resolver=manifest,
|
|
||||||
)
|
|
||||||
|
|
||||||
results = self._catalog_filter_table(table, manifest) # type: ignore[arg-type]
|
|
||||||
return results
|
|
||||||
|
|
||||||
def get_filtered_catalog(
|
|
||||||
self, manifest: Manifest, relations: Optional[Set[BaseRelation]] = None
|
|
||||||
):
|
|
||||||
catalogs: agate.Table
|
|
||||||
if (
|
|
||||||
relations is None
|
|
||||||
or len(relations) > 100
|
|
||||||
or not self.supports(Capability.SchemaMetadataByRelations)
|
|
||||||
):
|
|
||||||
# Do it the traditional way. We get the full catalog.
|
|
||||||
catalogs, exceptions = self.get_catalog(manifest)
|
|
||||||
else:
|
|
||||||
# Do it the new way. We try to save time by selecting information
|
|
||||||
# only for the exact set of relations we are interested in.
|
|
||||||
catalogs, exceptions = self.get_catalog_by_relations(manifest, relations)
|
|
||||||
|
|
||||||
if relations and catalogs:
|
|
||||||
relation_map = {
|
|
||||||
(
|
|
||||||
r.database.casefold() if r.database else None,
|
|
||||||
r.schema.casefold() if r.schema else None,
|
|
||||||
r.identifier.casefold() if r.identifier else None,
|
|
||||||
)
|
|
||||||
for r in relations
|
|
||||||
}
|
|
||||||
|
|
||||||
def in_map(row: agate.Row):
|
|
||||||
d = _expect_row_value("table_database", row)
|
|
||||||
s = _expect_row_value("table_schema", row)
|
|
||||||
i = _expect_row_value("table_name", row)
|
|
||||||
d = d.casefold() if d is not None else None
|
|
||||||
s = s.casefold() if s is not None else None
|
|
||||||
i = i.casefold() if i is not None else None
|
|
||||||
return (d, s, i) in relation_map
|
|
||||||
|
|
||||||
catalogs = catalogs.where(in_map)
|
|
||||||
|
|
||||||
return catalogs, exceptions
|
|
||||||
|
|
||||||
def row_matches_relation(self, row: agate.Row, relations: Set[BaseRelation]):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_catalog(self, manifest: Manifest) -> Tuple[agate.Table, List[Exception]]:
|
def get_catalog(self, manifest: Manifest) -> Tuple[agate.Table, List[Exception]]:
|
||||||
|
schema_map = self._get_catalog_schemas(manifest)
|
||||||
|
|
||||||
with executor(self.config) as tpe:
|
with executor(self.config) as tpe:
|
||||||
futures: List[Future[agate.Table]] = []
|
futures: List[Future[agate.Table]] = []
|
||||||
schema_map: SchemaSearchMap = self._get_catalog_schemas(manifest)
|
|
||||||
for info, schemas in schema_map.items():
|
for info, schemas in schema_map.items():
|
||||||
if len(schemas) == 0:
|
if len(schemas) == 0:
|
||||||
continue
|
continue
|
||||||
name = ".".join([str(info.database), "information_schema"])
|
name = ".".join([str(info.database), "information_schema"])
|
||||||
|
|
||||||
fut = tpe.submit_connected(
|
fut = tpe.submit_connected(
|
||||||
self, name, self._get_one_catalog, info, schemas, manifest
|
self, name, self._get_one_catalog, info, schemas, manifest
|
||||||
)
|
)
|
||||||
futures.append(fut)
|
futures.append(fut)
|
||||||
|
|
||||||
catalogs, exceptions = catch_as_completed(futures)
|
|
||||||
return catalogs, exceptions
|
|
||||||
|
|
||||||
def get_catalog_by_relations(
|
|
||||||
self, manifest: Manifest, relations: Set[BaseRelation]
|
|
||||||
) -> Tuple[agate.Table, List[Exception]]:
|
|
||||||
with executor(self.config) as tpe:
|
|
||||||
futures: List[Future[agate.Table]] = []
|
|
||||||
relations_by_schema = self._get_catalog_relations_by_info_schema(relations)
|
|
||||||
for info_schema in relations_by_schema:
|
|
||||||
name = ".".join([str(info_schema.database), "information_schema"])
|
|
||||||
relations = set(relations_by_schema[info_schema])
|
|
||||||
fut = tpe.submit_connected(
|
|
||||||
self,
|
|
||||||
name,
|
|
||||||
self._get_one_catalog_by_relations,
|
|
||||||
info_schema,
|
|
||||||
relations,
|
|
||||||
manifest,
|
|
||||||
)
|
|
||||||
futures.append(fut)
|
|
||||||
|
|
||||||
catalogs, exceptions = catch_as_completed(futures)
|
catalogs, exceptions = catch_as_completed(futures)
|
||||||
return catalogs, exceptions
|
|
||||||
|
return catalogs, exceptions
|
||||||
|
|
||||||
def cancel_open_connections(self):
|
def cancel_open_connections(self):
|
||||||
"""Cancel all open connections."""
|
"""Cancel all open connections."""
|
||||||
@@ -1235,7 +1060,7 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
loaded_at_field: str,
|
loaded_at_field: str,
|
||||||
filter: Optional[str],
|
filter: Optional[str],
|
||||||
manifest: Optional[Manifest] = None,
|
manifest: Optional[Manifest] = None,
|
||||||
) -> Tuple[Optional[AdapterResponse], FreshnessResponse]:
|
) -> Dict[str, Any]:
|
||||||
"""Calculate the freshness of sources in dbt, and return it"""
|
"""Calculate the freshness of sources in dbt, and return it"""
|
||||||
kwargs: Dict[str, Any] = {
|
kwargs: Dict[str, Any] = {
|
||||||
"source": source,
|
"source": source,
|
||||||
@@ -1244,19 +1069,7 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# run the macro
|
# run the macro
|
||||||
# in older versions of dbt-core, the 'collect_freshness' macro returned the table of results directly
|
table = self.execute_macro(FRESHNESS_MACRO_NAME, kwargs=kwargs, manifest=manifest)
|
||||||
# starting in v1.5, by default, we return both the table and the adapter response (metadata about the query)
|
|
||||||
result: Union[
|
|
||||||
AttrDict, # current: contains AdapterResponse + agate.Table
|
|
||||||
agate.Table, # previous: just table
|
|
||||||
]
|
|
||||||
result = self.execute_macro(FRESHNESS_MACRO_NAME, kwargs=kwargs, macro_resolver=manifest)
|
|
||||||
if isinstance(result, agate.Table):
|
|
||||||
warn_or_error(CollectFreshnessReturnSignature())
|
|
||||||
adapter_response = None
|
|
||||||
table = result
|
|
||||||
else:
|
|
||||||
adapter_response, table = result.response, result.table # type: ignore[attr-defined]
|
|
||||||
# now we have a 1-row table of the maximum `loaded_at_field` value and
|
# now we have a 1-row table of the maximum `loaded_at_field` value and
|
||||||
# the current time according to the db.
|
# the current time according to the db.
|
||||||
if len(table) != 1 or len(table[0]) != 2:
|
if len(table) != 1 or len(table[0]) != 2:
|
||||||
@@ -1270,51 +1083,11 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
|
|
||||||
snapshotted_at = _utc(table[0][1], source, loaded_at_field)
|
snapshotted_at = _utc(table[0][1], source, loaded_at_field)
|
||||||
age = (snapshotted_at - max_loaded_at).total_seconds()
|
age = (snapshotted_at - max_loaded_at).total_seconds()
|
||||||
freshness: FreshnessResponse = {
|
return {
|
||||||
"max_loaded_at": max_loaded_at,
|
"max_loaded_at": max_loaded_at,
|
||||||
"snapshotted_at": snapshotted_at,
|
"snapshotted_at": snapshotted_at,
|
||||||
"age": age,
|
"age": age,
|
||||||
}
|
}
|
||||||
return adapter_response, freshness
|
|
||||||
|
|
||||||
def calculate_freshness_from_metadata(
|
|
||||||
self,
|
|
||||||
source: BaseRelation,
|
|
||||||
manifest: Optional[Manifest] = None,
|
|
||||||
) -> Tuple[Optional[AdapterResponse], FreshnessResponse]:
|
|
||||||
kwargs: Dict[str, Any] = {
|
|
||||||
"information_schema": source.information_schema_only(),
|
|
||||||
"relations": [source],
|
|
||||||
}
|
|
||||||
result = self.execute_macro(
|
|
||||||
GET_RELATION_LAST_MODIFIED_MACRO_NAME, kwargs=kwargs, macro_resolver=manifest
|
|
||||||
)
|
|
||||||
adapter_response, table = result.response, result.table # type: ignore[attr-defined]
|
|
||||||
|
|
||||||
try:
|
|
||||||
row = table[0]
|
|
||||||
last_modified_val = get_column_value_uncased("last_modified", row)
|
|
||||||
snapshotted_at_val = get_column_value_uncased("snapshotted_at", row)
|
|
||||||
except Exception:
|
|
||||||
raise MacroResultError(GET_RELATION_LAST_MODIFIED_MACRO_NAME, table)
|
|
||||||
|
|
||||||
if last_modified_val is None:
|
|
||||||
# Interpret missing value as "infinitely long ago"
|
|
||||||
max_loaded_at = datetime(1, 1, 1, 0, 0, 0, tzinfo=pytz.UTC)
|
|
||||||
else:
|
|
||||||
max_loaded_at = _utc(last_modified_val, None, "last_modified")
|
|
||||||
|
|
||||||
snapshotted_at = _utc(snapshotted_at_val, None, "snapshotted_at")
|
|
||||||
|
|
||||||
age = (snapshotted_at - max_loaded_at).total_seconds()
|
|
||||||
|
|
||||||
freshness: FreshnessResponse = {
|
|
||||||
"max_loaded_at": max_loaded_at,
|
|
||||||
"snapshotted_at": snapshotted_at,
|
|
||||||
"age": age,
|
|
||||||
}
|
|
||||||
|
|
||||||
return adapter_response, freshness
|
|
||||||
|
|
||||||
def pre_model_hook(self, config: Mapping[str, Any]) -> Any:
|
def pre_model_hook(self, config: Mapping[str, Any]) -> Any:
|
||||||
"""A hook for running some operation before the model materialization
|
"""A hook for running some operation before the model materialization
|
||||||
@@ -1341,6 +1114,11 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def get_compiler(self):
|
||||||
|
from dbt.compilation import Compiler
|
||||||
|
|
||||||
|
return Compiler(self.config)
|
||||||
|
|
||||||
# Methods used in adapter tests
|
# Methods used in adapter tests
|
||||||
def update_column_sql(
|
def update_column_sql(
|
||||||
self,
|
self,
|
||||||
@@ -1460,7 +1238,7 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
|
|
||||||
strategy = strategy.replace("+", "_")
|
strategy = strategy.replace("+", "_")
|
||||||
macro_name = f"get_incremental_{strategy}_sql"
|
macro_name = f"get_incremental_{strategy}_sql"
|
||||||
# The model_context should have callable objects for all macros
|
# The model_context should have MacroGenerator callable objects for all macros
|
||||||
if macro_name not in model_context:
|
if macro_name not in model_context:
|
||||||
raise DbtRuntimeError(
|
raise DbtRuntimeError(
|
||||||
'dbt could not find an incremental strategy macro with the name "{}" in {}'.format(
|
'dbt could not find an incremental strategy macro with the name "{}" in {}'.format(
|
||||||
@@ -1471,127 +1249,6 @@ class BaseAdapter(metaclass=AdapterMeta):
|
|||||||
# This returns a callable macro
|
# This returns a callable macro
|
||||||
return model_context[macro_name]
|
return model_context[macro_name]
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse_column_constraint(cls, raw_constraint: Dict[str, Any]) -> ColumnLevelConstraint:
|
|
||||||
try:
|
|
||||||
ColumnLevelConstraint.validate(raw_constraint)
|
|
||||||
return ColumnLevelConstraint.from_dict(raw_constraint)
|
|
||||||
except Exception:
|
|
||||||
raise DbtValidationError(f"Could not parse constraint: {raw_constraint}")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def render_column_constraint(cls, constraint: ColumnLevelConstraint) -> Optional[str]:
|
|
||||||
"""Render the given constraint as DDL text. Should be overriden by adapters which need custom constraint
|
|
||||||
rendering."""
|
|
||||||
constraint_expression = constraint.expression or ""
|
|
||||||
|
|
||||||
rendered_column_constraint = None
|
|
||||||
if constraint.type == ConstraintType.check and constraint_expression:
|
|
||||||
rendered_column_constraint = f"check ({constraint_expression})"
|
|
||||||
elif constraint.type == ConstraintType.not_null:
|
|
||||||
rendered_column_constraint = f"not null {constraint_expression}"
|
|
||||||
elif constraint.type == ConstraintType.unique:
|
|
||||||
rendered_column_constraint = f"unique {constraint_expression}"
|
|
||||||
elif constraint.type == ConstraintType.primary_key:
|
|
||||||
rendered_column_constraint = f"primary key {constraint_expression}"
|
|
||||||
elif constraint.type == ConstraintType.foreign_key and constraint_expression:
|
|
||||||
rendered_column_constraint = f"references {constraint_expression}"
|
|
||||||
elif constraint.type == ConstraintType.custom and constraint_expression:
|
|
||||||
rendered_column_constraint = constraint_expression
|
|
||||||
|
|
||||||
if rendered_column_constraint:
|
|
||||||
rendered_column_constraint = rendered_column_constraint.strip()
|
|
||||||
|
|
||||||
return rendered_column_constraint
|
|
||||||
|
|
||||||
@available
|
|
||||||
@classmethod
|
|
||||||
def render_raw_columns_constraints(cls, raw_columns: Dict[str, Dict[str, Any]]) -> List:
|
|
||||||
rendered_column_constraints = []
|
|
||||||
|
|
||||||
for v in raw_columns.values():
|
|
||||||
col_name = cls.quote(v["name"]) if v.get("quote") else v["name"]
|
|
||||||
rendered_column_constraint = [f"{col_name} {v['data_type']}"]
|
|
||||||
for con in v.get("constraints", None):
|
|
||||||
constraint = cls._parse_column_constraint(con)
|
|
||||||
c = cls.process_parsed_constraint(constraint, cls.render_column_constraint)
|
|
||||||
if c is not None:
|
|
||||||
rendered_column_constraint.append(c)
|
|
||||||
rendered_column_constraints.append(" ".join(rendered_column_constraint))
|
|
||||||
|
|
||||||
return rendered_column_constraints
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def process_parsed_constraint(
|
|
||||||
cls, parsed_constraint: Union[ColumnLevelConstraint, ModelLevelConstraint], render_func
|
|
||||||
) -> Optional[str]:
|
|
||||||
if (
|
|
||||||
parsed_constraint.warn_unsupported
|
|
||||||
and cls.CONSTRAINT_SUPPORT[parsed_constraint.type] == ConstraintSupport.NOT_SUPPORTED
|
|
||||||
):
|
|
||||||
warn_or_error(
|
|
||||||
ConstraintNotSupported(constraint=parsed_constraint.type.value, adapter=cls.type())
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
parsed_constraint.warn_unenforced
|
|
||||||
and cls.CONSTRAINT_SUPPORT[parsed_constraint.type] == ConstraintSupport.NOT_ENFORCED
|
|
||||||
):
|
|
||||||
warn_or_error(
|
|
||||||
ConstraintNotEnforced(constraint=parsed_constraint.type.value, adapter=cls.type())
|
|
||||||
)
|
|
||||||
if cls.CONSTRAINT_SUPPORT[parsed_constraint.type] != ConstraintSupport.NOT_SUPPORTED:
|
|
||||||
return render_func(parsed_constraint)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _parse_model_constraint(cls, raw_constraint: Dict[str, Any]) -> ModelLevelConstraint:
|
|
||||||
try:
|
|
||||||
ModelLevelConstraint.validate(raw_constraint)
|
|
||||||
c = ModelLevelConstraint.from_dict(raw_constraint)
|
|
||||||
return c
|
|
||||||
except Exception:
|
|
||||||
raise DbtValidationError(f"Could not parse constraint: {raw_constraint}")
|
|
||||||
|
|
||||||
@available
|
|
||||||
@classmethod
|
|
||||||
def render_raw_model_constraints(cls, raw_constraints: List[Dict[str, Any]]) -> List[str]:
|
|
||||||
return [c for c in map(cls.render_raw_model_constraint, raw_constraints) if c is not None]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def render_raw_model_constraint(cls, raw_constraint: Dict[str, Any]) -> Optional[str]:
|
|
||||||
constraint = cls._parse_model_constraint(raw_constraint)
|
|
||||||
return cls.process_parsed_constraint(constraint, cls.render_model_constraint)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def render_model_constraint(cls, constraint: ModelLevelConstraint) -> Optional[str]:
|
|
||||||
"""Render the given constraint as DDL text. Should be overriden by adapters which need custom constraint
|
|
||||||
rendering."""
|
|
||||||
constraint_prefix = f"constraint {constraint.name} " if constraint.name else ""
|
|
||||||
column_list = ", ".join(constraint.columns)
|
|
||||||
if constraint.type == ConstraintType.check and constraint.expression:
|
|
||||||
return f"{constraint_prefix}check ({constraint.expression})"
|
|
||||||
elif constraint.type == ConstraintType.unique:
|
|
||||||
constraint_expression = f" {constraint.expression}" if constraint.expression else ""
|
|
||||||
return f"{constraint_prefix}unique{constraint_expression} ({column_list})"
|
|
||||||
elif constraint.type == ConstraintType.primary_key:
|
|
||||||
constraint_expression = f" {constraint.expression}" if constraint.expression else ""
|
|
||||||
return f"{constraint_prefix}primary key{constraint_expression} ({column_list})"
|
|
||||||
elif constraint.type == ConstraintType.foreign_key and constraint.expression:
|
|
||||||
return f"{constraint_prefix}foreign key ({column_list}) references {constraint.expression}"
|
|
||||||
elif constraint.type == ConstraintType.custom and constraint.expression:
|
|
||||||
return f"{constraint_prefix}{constraint.expression}"
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def capabilities(cls) -> CapabilityDict:
|
|
||||||
return cls._capabilities
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def supports(cls, capability: Capability) -> bool:
|
|
||||||
return bool(cls.capabilities()[capability])
|
|
||||||
|
|
||||||
|
|
||||||
COLUMNS_EQUAL_SQL = """
|
COLUMNS_EQUAL_SQL = """
|
||||||
with diff_count as (
|
with diff_count as (
|
||||||
@@ -1625,6 +1282,7 @@ join diff_count using (id)
|
|||||||
def catch_as_completed(
|
def catch_as_completed(
|
||||||
futures, # typing: List[Future[agate.Table]]
|
futures, # typing: List[Future[agate.Table]]
|
||||||
) -> Tuple[agate.Table, List[Exception]]:
|
) -> Tuple[agate.Table, List[Exception]]:
|
||||||
|
|
||||||
# catalogs: agate.Table = agate.Table(rows=[])
|
# catalogs: agate.Table = agate.Table(rows=[])
|
||||||
tables: List[agate.Table] = []
|
tables: List[agate.Table] = []
|
||||||
exceptions: List[Exception] = []
|
exceptions: List[Exception] = []
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user