-
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add skeleton * feat: artifact download implement * docs: add guide of dbt cloud usage * docs: dbt cloud cli ref * test: 96%
- Loading branch information
Showing
9 changed files
with
286 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import os | ||
import json | ||
|
||
import click | ||
import requests | ||
|
||
from dbterd.helpers import file | ||
from dbterd.helpers.log import logger | ||
|
||
|
||
class DbtCloudArtifact: | ||
"""dbt Cloud Artifact class using | ||
dbt CLoud Administrative API | ||
https://docs.getdbt.com/docs/dbt-cloud-apis/admin-cloud-api. | ||
And use Retrieve Run Artifact endpoint, for example, with v2 spec | ||
https://docs.getdbt.com/dbt-cloud/api-v2#/operations/Retrieve%20Run%20Artifact | ||
""" | ||
|
||
def __init__(self, **kwargs) -> None: | ||
"""Initialize the base attributes to interact with API service""" | ||
self.host_url = kwargs.get("dbt_cloud_host_url") | ||
self.service_token = kwargs.get("dbt_cloud_service_token") | ||
self.account_id = kwargs.get("dbt_cloud_account_id") | ||
self.run_id = kwargs.get("dbt_cloud_run_id") | ||
self.api_version = kwargs.get("dbt_cloud_api_version") | ||
|
||
@property | ||
def request_headers(self) -> dict: | ||
"""API Header""" | ||
return {"Authorization": f"Token {self.service_token}"} | ||
|
||
@property | ||
def api_endpoint(self) -> dict: | ||
"""Base API endpoint to a specific artifact object""" | ||
return ( | ||
"https://{host_url}/api/{api_version}/" | ||
"accounts/{account_id}/" | ||
"runs/{run_id}/" | ||
"artifacts/{{path}}" | ||
).format( | ||
host_url=self.host_url, | ||
api_version=self.api_version, | ||
account_id=self.account_id, | ||
run_id=self.run_id, | ||
) | ||
|
||
@property | ||
def manifest_api_endpoint(self) -> dict: | ||
"""Full API endpoint to the `manifest.json` file""" | ||
return self.api_endpoint.format(path="manifest.json") | ||
|
||
@property | ||
def catalog_api_endpoint(self) -> dict: | ||
"""Full API endpoint to the `catalog.json` file""" | ||
return self.api_endpoint.format(path="catalog.json") | ||
|
||
def download_artifact(self, artifact: str, artifacts_dir: str) -> bool: | ||
"""Request API to download the artifact file | ||
Args: | ||
artifact (str): The artifact name e.g. manifest or catalog | ||
Returns: | ||
bool: True is success, False if any errors | ||
""" | ||
artifact_api_endpoint = getattr(self, f"{artifact}_api_endpoint") | ||
logger.info(f"Dowloading...[URL: {artifact_api_endpoint}]") | ||
try: | ||
r = requests.get(url=artifact_api_endpoint, headers=self.request_headers) | ||
logger.info(f"Completed [status: {r.status_code}]") | ||
|
||
if r.status_code != 200: | ||
logger.error(f"Failed to retrieve artifacts [error: {vars(r)}]") | ||
return False | ||
|
||
file.write_json( | ||
data=json.dumps(r.json(), indent=2), | ||
path=f"{artifacts_dir}/{artifact}.json", | ||
) | ||
except click.BadParameter as e: | ||
logger.error(f"Error occurred while downloading [error: {str(e)}]") | ||
return False | ||
|
||
return True | ||
|
||
def get(self, artifacts_dir: str = None) -> bool: | ||
"""Download `manifest.json` and `catalog.json` to the local dir | ||
Args: | ||
artifacts_dir (str, optional): Local dir where the artifacts get downloaded to. Default to CWD/target. | ||
Returns: | ||
bool: True is success, False if any errors | ||
""" | ||
_artifacts_dir = artifacts_dir or f"{os.getcwd()}/target" | ||
r = self.download_artifact(artifact="manifest", artifacts_dir=_artifacts_dir) | ||
if r: | ||
r = self.download_artifact(artifact="catalog", artifacts_dir=_artifacts_dir) | ||
|
||
return r |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
docs/nav/guide/dbt-cloud/download-artifact-from-a-job-run.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# Download artifacts from a Job Run | ||
|
||
This is a guideline on how to download `manifest.json` and `catalog.json` from a Job Run by using [dbt CLoud Administrative API](https://docs.getdbt.com/docs/dbt-cloud-apis/admin-cloud-api), under the [Retrieve Run Artifact](https://docs.getdbt.com/dbt-cloud/api-v2#/operations/Retrieve%20Run%20Artifact) endpoint. Therefore, we don't need to run `dbt docs generate` locally anymore. | ||
|
||
In order to support dbt Cloud users, `dbterd` is now having multiple CLI options starting with `--dbt-cloud` to let us configure the connection to the complete dbt Cloud Job Run. | ||
|
||
!!! note "Prerequisites" | ||
- You have a dbt Cloud account with [Team and Enterprise plans](https://www.getdbt.com/pricing/) 💰 | ||
- You have a job or go create a new job with a single step 🏃 | ||
|
||
```bash | ||
dbt docs generate | ||
``` | ||
- Make sure that you have at least 1 successful run ✅ | ||
|
||
## 1. Prepare the environment variables | ||
|
||
Behind the scene, the API Endpoint will look like: `https://{host_url}/api/{api_version}/accounts/{account_id}/runs/{run_id}/artifacts/{path}`. | ||
|
||
And the dbt Cloud's Job Rub will have the URL constructed as `https://<host_url>/deploy/<account_id>/projects/irrelevant/runs/<run_id>`. | ||
|
||
In the above: | ||
|
||
| URL Part | Environment Variable | CLI Option | Description | | ||
|-------------------|---------------------------------|---------------------------|---------------------------------------------------------------------------| | ||
| `host_url` | `DBTERD_DBT_CLOUD_HOST_URL` | `--dbt-cloud-host-url` | Host URL, also known as [Access URL](https://docs.getdbt.com/docs/cloud/about-cloud/regions-ip-addresses) (Default to `cloud.getdbt.com`) | | ||
| `account_id` | `DBTERD_DBT_CLOUD_ACCOUNT_ID` | `--dbt-cloud-account-id` | dbt Cloud Account ID | | ||
| `run_id` | `DBTERD_DBT_CLOUD_RUN_ID` | `--dbt-cloud-run-id` | dbt Cloud successful job run ID | | ||
| `api_version` | `DBTERD_DBT_CLOUD_API_VERSION` | `--dbt-cloud-api-version` | dbt Cloud API version (Default to `v2`) | | ||
| `path` | `N/A` | `N/A` | Artifact relative file path. You don't need to care about this part as `dbterd` managed it already | | ||
|
||
Besides, we need another one which is very important, the service token: | ||
|
||
- Go to **Account settings** / **Service tokens**. Click _+ New token_ | ||
- Enter _Service token name_ e.g. "ST_dbterd" | ||
- Click _Add_ and select `Job Admin` permission. Optionally, select the right project or all by default | ||
- Click _Save_ | ||
- Copy token & Pass it to the Environment Variable (`DBTERD_DBT_CLOUD_SERVICE_TOKEN`) or the CLI Option (`--dbt-cloud-service-token`) | ||
|
||
Finally, fill in `your_value` and execute the (Linux or Macos) command below: | ||
|
||
```bash | ||
export DBTERD_DBT_CLOUD_SERVICE_TOKEN=your_value | ||
export DBTERD_DBT_CLOUD_HOST_URL=your_value | ||
export DBTERD_DBT_CLOUD_ACCOUNT_ID=your_value | ||
export DBTERD_DBT_CLOUD_RUN_ID=your_value | ||
export DBTERD_DBT_CLOUD_RUN_ID=your_value | ||
``` | ||
|
||
## 2. Genrate ERD file | ||
|
||
We're going to use `--dbt-cloud` option to tell `dbterd` to use dbt Cloud API with all above variables. | ||
|
||
The command will be looks like: | ||
|
||
```bash | ||
dbterd run -s <dbterd selection> --dbt-cloud | ||
``` | ||
|
||
> NOTE: You can not use `--dbt` option together with `--dbt-cloud` | ||
and then, here is the sample console log: | ||
|
||
```log | ||
dbterd - INFO - Run with dbterd==1.0.0 (main.py:54) | ||
dbterd - INFO - Using dbt project dir at: C:\Sources\dbterd (base.py:46) | ||
dbterd - INFO - Dowloading...[URL: https://hidden/api/v2/accounts/hidden/runs/2442752/artifacts/manifest.json] (dbt_cloud.py:68) | ||
dbterd - INFO - Completed [status: 200] (dbt_cloud.py:71) | ||
dbterd - INFO - Dowloading...[URL: https://hidden/api/v2/accounts/hidden/runs/2442752/artifacts/catalog.json] (dbt_cloud.py:68) | ||
dbterd - INFO - Completed [status: 200] (dbt_cloud.py:71) | ||
dbterd - INFO - Using dbt artifact dir at: hidden (base.py:73) | ||
dbterd - INFO - Collected 4 table(s) and 3 relationship(s) (test_relationship.py:59) | ||
dbterd - INFO - C:\Sources\dbterd\target/output.dbml (base.py:170) | ||
``` | ||
|
||
Voila! Happy ERD 🎉! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# from unittest import mock | ||
|
||
# import click | ||
# import pytest | ||
|
||
# from dbterd.adapters.dbt_cloud import DbtCloudArtifact | ||
|
||
|
||
class TestDbtCloudArtifact: | ||
def test_download_artifact(self): | ||
pass | ||
|
||
def test_get(self): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters