Skip to content

Commit a1303ee

Browse files
authored
Merge branch 'main' into dbt-cortex-search-service-20260614
2 parents eb0aa40 + 250c489 commit a1303ee

19 files changed

Lines changed: 501 additions & 101 deletions

.github/pull_request_template.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ Link to your package's repository:
77
## Checklist
88
_This checklist is a cut down version of the [best practices](../blob/main/package-best-practices.md) that we have identified as the package hub has grown. Although meeting these checklist items is not a prerequisite to being added to the Hub, we have found that packages which don't conform provide a worse user experience._
99

10+
### Real world usage
11+
12+
Using coding agents to help you build your package is totally fine, but please don't submit it to the package hub until you've used it in your own production environment for an extended period of time.
13+
14+
- [ ] (Required): I have been using this package in production and am satisfied with its behavior.
15+
1016
### First run experience
1117
- [ ] (Required): The package includes a [licence file detectable by GitHub](https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/adding-a-license-to-a-repository), such as the Apache 2.0 or MIT licence.
1218
- [ ] The package includes a README which explains how to get started with the package and customise its behaviour

.github/workflows/hubcap-scheduler.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ jobs:
6666
HUBCAP_CONFIG: ${{ secrets.HUBCAP_CONFIG }}
6767
INPUT_DRY_RUN: ${{ github.event.inputs.dry_run || (github.event_name == 'pull_request' && 'true') || 'false' }}
6868
ENVIRONMENT: ${{ github.event.inputs.environment || (github.event_name == 'pull_request' && 'test') || 'production' }}
69+
FUSION_BINARY: '/home/runner/.local/bin/dbt'
6970
run: |
7071
echo "Using $ENVIRONMENT environment configuration"
7172
@@ -90,13 +91,16 @@ jobs:
9091
echo "$HUBCAP_CONFIG" > base_config.json
9192
fi
9293
94+
# Add Fusion binary path from env var
95+
jq --arg fusion_path "$FUSION_BINARY" '.fusion_binary_path = $fusion_path' base_config.json > base_config_fusion.json
96+
9397
# Modify config for dry run if requested
9498
if [ "$INPUT_DRY_RUN" = "true" ]; then
9599
echo "Enabling dry-run mode (push_branches = false)"
96-
jq '.push_branches = false' base_config.json > config.json
100+
jq '.push_branches = false' base_config_fusion.json > config.json
97101
else
98102
echo "Running in live mode (push_branches = true)"
99-
cp base_config.json config.json
103+
cp base_config_fusion.json config.json
100104
fi
101105
102106
# Set the CONFIG environment variable for hubcap.py
@@ -115,9 +119,10 @@ jobs:
115119
echo "=== Execution Summary ==="
116120
117121
# Check for errors
118-
if grep -q 'ERROR' hubcap.log; then
122+
# Space after ERROR differentiates error logs from parse errors
123+
if grep -q 'ERROR ' hubcap.log; then
119124
echo "❌ Found ERROR events in execution:"
120-
grep 'ERROR' hubcap.log
125+
grep 'ERROR ' hubcap.log
121126
echo "EXECUTION_STATUS=failed" >> $GITHUB_ENV
122127
else
123128
echo "✅ No ERROR-level log entries found"

CONTRIBUTING.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ Save the token to a secure location. Click the "Configure SSO" button and "Autho
2929
```shell
3030
cp config.example.json config.json
3131

32-
# Add the relevant GitHub username, email address and token
32+
# Add the relevant GitHub username, email address, and token
3333
$EDITOR config.json
3434

3535
# Export the JSON credentials into an environment variable
3636
export CONFIG=$(<config.json)
3737
```
3838

39+
If you have Fusion installed in a location other than the default (`~/.local/bin/dbt`), you will also need to add a line to `config.json` that sets `fusion_binary_path` to the correct path.
40+
3941
## Run in test mode
4042

4143
### Local testing

hub.json

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
"henryupton": [
7373
"dbt-scd2-utils"
7474
],
75+
"kanoniv": [
76+
"dbt-kanoniv"
77+
],
7578
"LewisDavies": [
7679
"upstream-prod"
7780
],
@@ -91,7 +94,8 @@
9194
"dbt-set-similarity",
9295
"dbt-stat-test",
9396
"dbt-cortex-search-service",
94-
"dbt-ml-eval"
97+
"dbt-ml-eval",
98+
"dbt-orphan"
9599
],
96100
"metaplane" : [
97101
"dbt-expectations"
@@ -350,12 +354,17 @@
350354
"dbt_ga4_export",
351355
"dbt_unified_rag",
352356
"dbt_amazon_selling_partner",
353-
"dbt_dynamics_365_crm"
357+
"dbt_dynamics_365_crm",
358+
"dbt_stackadapt"
354359
],
355360
"fullstorydev": [
356361
"dbt_fullstory"
357362
],
363+
"gauthierpiarrette": [
364+
"dbt-timefence"
365+
],
358366
"get-select": [
367+
"dbt-query-tags",
359368
"dbt-snowflake-monitoring",
360369
"dbt-snowflake-query-tags"
361370
],
@@ -426,6 +435,9 @@
426435
"omnata-labs": [
427436
"dbt-ml-preprocessing"
428437
],
438+
"paradime-io": [
439+
"dbt-llm-evals"
440+
],
429441
"pvcy": [
430442
"dbt-privacy"
431443
],
@@ -450,6 +462,9 @@
450462
"sgoley": [
451463
"dbt-postgres-utils"
452464
],
465+
"smithclay": [
466+
"dbt_opentelemetry"
467+
],
453468
"snowplow": [
454469
"dbt-snowplow-utils",
455470
"dbt-snowplow-web",
@@ -482,12 +497,20 @@
482497
"dbt-meta-testing",
483498
"dbt-activity-schema"
484499
],
500+
"tripleaceme": [
501+
"dbt-anomaly-detector",
502+
"dbt-doc-inherit",
503+
"dbt-doc-tracker"
504+
],
485505
"tuva-health": [
486506
"the_tuva_project"
487507
],
488-
"versent-dimensional": [
508+
"versent": [
489509
"dbt_versent_dimensional_automate"
490510
],
511+
"vladimir-vvalov": [
512+
"tbmacro"
513+
],
491514
"windsor-ai": [
492515
"dbt_facebook_ads",
493516
"dbt-bigquery-package-for-salesforce",
@@ -507,5 +530,8 @@
507530
],
508531
"datooine": [
509532
"dbt-buckets"
533+
],
534+
"teoria": [
535+
"dbt-iceberg-utils"
510536
]
511537
}

hubcap/exceptions.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
class GitOperationError(Exception):
2+
"""Custom exception for git operation failures"""
3+
4+
pass
5+
6+
7+
class ConfigurationError(Exception):
8+
"""Custom exception for configuration errors"""
9+
10+
pass
11+
12+
13+
class FileOperationError(Exception):
14+
"""Custom exception for file operation errors"""
15+
16+
pass
17+
18+
19+
class PackageMaintainerError(Exception):
20+
"""Custom exception for package maintainer loading errors"""
21+
22+
pass
23+
24+
25+
class PackageError(Exception):
26+
"""Custom exception for package operation failures"""
27+
28+
pass
29+
30+
31+
class ReleaseCarrierError(Exception):
32+
"""Custom exception for release carrier operation failures"""
33+
34+
pass
35+
36+
37+
class VersionError(Exception):
38+
"""Custom exception for version operation errors"""
39+
40+
pass

hubcap/git_helper.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,23 @@
1010
from git import Repo
1111
from git.exc import GitCommandError
1212
from pathlib import Path
13+
from .exceptions import GitOperationError
1314

1415

15-
class GitOperationError(Exception):
16-
"""Custom exception for git operation failures"""
17-
18-
pass
19-
20-
21-
def run_cmd(cmd, quiet=False):
16+
def run_cmd(cmd: str, quiet=False):
2217
"""Dispatching commands to shell from inside Python needs an exit status wrapper"""
2318
try:
24-
proc = subprocess.run(
19+
proc: subprocess.CompletedProcess[bytes] = subprocess.run(
2520
args=cmd.split(), capture_output=True, timeout=300
2621
) # 5 minute timeout
2722

2823
if proc.returncode:
29-
stderr_output = proc.stderr.decode("utf-8").rstrip()
24+
stderr_output: str = proc.stderr.decode("utf-8").rstrip()
3025
logging.warning(f"Command failed: {cmd}")
3126
logging.warning(f"Error: {stderr_output}")
3227
raise GitOperationError(f"Command failed: {cmd}. Error: {stderr_output}")
3328

34-
output = proc.stdout.decode("utf-8").rstrip()
29+
output: str = proc.stdout.decode("utf-8").rstrip()
3530

3631
if not quiet:
3732
logging.info(output)

hubcap/helper.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,7 @@
88
from typing import Dict, Any, List
99

1010
from pathlib import Path
11-
12-
13-
class ConfigurationError(Exception):
14-
"""Custom exception for configuration errors"""
15-
16-
pass
17-
18-
19-
class FileOperationError(Exception):
20-
"""Custom exception for file operation errors"""
21-
22-
pass
11+
from .exceptions import ConfigurationError, FileOperationError
2312

2413

2514
NOW = int(datetime.datetime.now().timestamp())

hubcap/hubcap.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from hubcap.types import PathLike
23
import sys
34
from pathlib import Path
45

@@ -15,6 +16,9 @@
1516
)
1617
from hubcap.records import IndividualPullRequests, ConsolididatedPullRequest
1718

19+
# Default if no path is specified in config.json
20+
DEFAULT_FUSION_BINARY_PATH = Path.home() / ".local" / "bin" / "dbt"
21+
1822

1923
def app():
2024
exit_code = main()
@@ -57,6 +61,9 @@ def main():
5761
git_tmp = "target"
5862
TMP_DIR = Path(git_tmp).resolve()
5963
selected_package_maintainers = config.get("selected_package_maintainers")
64+
fusion_binary_path: PathLike = config.get(
65+
"fusion_binary_path", DEFAULT_FUSION_BINARY_PATH.resolve()
66+
)
6067

6168
try:
6269
PACKAGE_MAINTAINERS = package_maintainers.load_package_maintainers()
@@ -156,7 +163,11 @@ def main():
156163
logging.info("collecting the new version tags for packages checked into hub")
157164
try:
158165
update_tasks = package.get_update_tasks(
159-
PACKAGE_MAINTAINERS, HUB_VERSION_INDEX, TMP_DIR, github_repo
166+
PACKAGE_MAINTAINERS,
167+
HUB_VERSION_INDEX,
168+
TMP_DIR,
169+
github_repo,
170+
fusion_binary_path,
160171
)
161172
except Exception as e:
162173
logging.error(f"Error getting update tasks: {str(e)}")

hubcap/package.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,13 @@
66
from typing import List, Dict, Any
77

88
from git import Repo
9+
from hubcap.types import PathLike
910
from pathlib import Path
1011

1112
from hubcap import records
1213
from hubcap import version
1314
from hubcap.git_helper import clone_repo, run_cmd, GitOperationError
14-
15-
16-
class PackageError(Exception):
17-
"""Custom exception for package operation failures"""
18-
19-
pass
15+
from hubcap.exceptions import PackageError
2016

2117

2218
def clone_package_repos(package_maintainer_index, path):
@@ -50,7 +46,7 @@ def clone_package_repos(package_maintainer_index, path):
5046
return failed_repos
5147

5248

53-
def parse_pkg_name(repo_dir) -> str:
49+
def parse_pkg_name(repo_dir: Path) -> str:
5450
"""Parse package name from dbt_project.yml with error handling"""
5551
try:
5652
dbt_project_path = repo_dir / Path("dbt_project.yml")
@@ -160,7 +156,13 @@ def parse_pkgs(repo_dir) -> List[Dict[str, Any]]:
160156
return []
161157

162158

163-
def get_update_tasks(maintainers, version_index, path, hub_repo):
159+
def get_update_tasks(
160+
maintainers: list[records.PackageMaintainer],
161+
version_index,
162+
path: Path,
163+
hub_repo,
164+
fusion_binary_path: PathLike,
165+
):
164166
"""build list of tasks for package version-bump commits"""
165167

166168
def has_dbt_project_yml(package, directory):
@@ -170,10 +172,10 @@ def has_dbt_project_yml(package, directory):
170172
logging.warning(f"{package} has no dbt_project.yml. Skipping...")
171173
return has_yaml
172174

173-
def get_new_tags(repo_path, maintainer_name):
175+
def get_new_tags(repo_path: Path, maintainer_name: str):
174176
# Existing tags are fetched from version index
175177
try:
176-
yml_package_name = parse_pkg_name(repo_path)
178+
yml_package_name: str = parse_pkg_name(repo_path)
177179
logging.info(f"collecting tags for {yml_package_name}")
178180

179181
existing_tags = version.get_existing_tags(
@@ -195,7 +197,7 @@ def get_new_tags(repo_path, maintainer_name):
195197

196198
def build_update_task_tuple(maintainer_name, hub_package_name):
197199
SKIP = None
198-
repo_path = path / Path(f"{maintainer_name}_{hub_package_name}")
200+
repo_path: Path = path / Path(f"{maintainer_name}_{hub_package_name}")
199201

200202
# Check if repo directory exists
201203
if not repo_path.exists():
@@ -226,6 +228,7 @@ def build_update_task_tuple(maintainer_name, hub_package_name):
226228
existing_tags=existing_tags,
227229
new_tags=new_tags,
228230
hub_repo=hub_repo,
231+
fusion_binary_path=fusion_binary_path,
229232
)
230233
# Cannot create update task for package without new tags
231234
else:
@@ -266,7 +269,7 @@ def commit_version_updates_to_hub(
266269

267270
# good house keeping
268271
os.chdir(hub_dir_path)
269-
cmd = f"git checkout {default_branch}"
272+
cmd = f"git checkout --force {default_branch}"
270273
run_cmd(cmd)
271274
except Exception as e:
272275
logging.error(

hubcap/package_maintainers.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,7 @@
44
from pathlib import Path
55

66
from hubcap.records import PackageMaintainer
7-
8-
9-
class PackageMaintainerError(Exception):
10-
"""Custom exception for package maintainer loading errors"""
11-
12-
pass
7+
from hubcap.exceptions import PackageMaintainerError
138

149

1510
def load_package_maintainers() -> List[PackageMaintainer]:

0 commit comments

Comments
 (0)