Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/prompts/update_catalog_prompt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Review the catalog changes and provide a concise one-line title for a PR, and a summary of the changes to be used as body.
Report field additions, removals, and changes by stream (e.g. 'Added field `name` to stream `customers`').
The stream name is part of the filename in tests/__snapshots__.
The output should have the title on the first line, and the body on subsequent lines, separated by a blank line.
Start the title with 'fix: ' and make sure it is a single line. Use backticks for stream and field names.
Do not add any preamble.
82 changes: 82 additions & 0 deletions .github/workflows/update_catalog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Update Catalog for Hookdeck

on:
workflow_dispatch:
schedule:
# On Fridays
- cron: '0 12 * * 5'

env:
FORCE_COLOR: "1"
# renovate: datasource=pypi depName=llm
LLM_VERSION: 0.29
# renovate: datasource=pypi depName=llm-github-models
LLM_GITHUB_MODELS_VERSION: 0.18.0
# renovate: datasource=pypi depName=uv
UV_VERSION: 0.10.11

jobs:
update_openapi_specification:
name: Update Catalog
runs-on: ubuntu-24.04
permissions:
contents: write # Required by peter-evans/create-pull-request
models: read # Required by llm-github-models
pull-requests: write # Required by peter-evans/create-pull-request
steps:
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: generate-token
with:
app-id: ${{ vars.RESERVOIR_GITHUB_APP_ID }}
private-key: ${{ secrets.RESERVOIR_GITHUB_APP_PKEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0
with:
version: ${{ env.UV_VERSION }}
- run: uv run scripts/update_openapi.py
- run: uv run pytest --snapshot-update tests/test_schema_evolution.py
- id: check_snapshot_changes
continue-on-error: true
run: git diff --quiet tests/__snapshots__
- name: Install LLM with GitHub Models
if: steps.check_snapshot_changes.outcome == 'failure'
run: uv tool install --with llm-github-models==${{ env.LLM_GITHUB_MODELS_VERSION }} --with llm==${{ env.LLM_VERSION }} llm
- name: Review catalog changes
if: steps.check_snapshot_changes.outcome == 'failure'
id: review-catalog-changes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WORKSPACE_PATH: ${{ github.workspace }}
run: |
SYSTEM_PROMPT=$(cat $WORKSPACE_PATH/.github/prompts/update_catalog_prompt.txt)
GENERATED_CONTENT=$(git --no-pager diff -p --no-color HEAD tests/__snapshots__ | llm prompt -m github/gpt-4o-mini -s "$SYSTEM_PROMPT")

PR_TITLE=$(echo "$GENERATED_CONTENT" | head -n 1)
PR_BODY=$(echo "$GENERATED_CONTENT" | tail -n +3)

{
echo 'title<<EOF'
echo "$PR_TITLE"
echo 'EOF'
} >> "$GITHUB_OUTPUT"

{
echo 'body<<EOF'
echo "$PR_BODY"
echo 'EOF'
} >> "$GITHUB_OUTPUT"

{
echo 'commit_message<<EOF'
echo "$PR_TITLE"
echo 'EOF'
} >> "$GITHUB_OUTPUT"
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
if: steps.check_snapshot_changes.outcome == 'failure'
with:
title: ${{ steps.review-catalog-changes.outputs.title }}
commit-message: ${{ steps.review-catalog-changes.outputs.commit_message }}
body: ${{ steps.review-catalog-changes.outputs.body }}
token: ${{ steps.generate-token.outputs.token }}
sign-commits: true
signoff: true
16 changes: 8 additions & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
ci:
autofix_commit_msg: 'chore: pre-commit.ci auto fixes'
autofix_commit_msg: "chore: pre-commit.ci auto fixes"
autofix_prs: true
autoupdate_schedule: monthly
autoupdate_commit_msg: 'chore(deps): pre-commit autoupdate'
autoupdate_commit_msg: "chore(deps): pre-commit autoupdate"

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
Expand Down Expand Up @@ -35,12 +35,12 @@ repos:
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.37.0
hooks:
- id: check-github-workflows
- id: check-meltano
- id: check-renovate
language: python
additional_dependencies:
- pyjson5==2.0.0
- id: check-github-workflows
- id: check-meltano
- id: check-renovate
language: python
additional_dependencies:
- pyjson5==2.0.0

- repo: https://github.com/hukkin/mdformat
rev: 1.0.0
Expand Down
10 changes: 7 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ dynamic = [
"version",
]
dependencies = [
"singer-sdk~=0.54.0a2",
"requests~=2.32",
"singer-sdk~=0.54.0a8",
]
[[project.authors]]
name = "Edgar Ramírez-Mondragón"
Expand All @@ -50,7 +51,7 @@ dev = [
testing = [
"deptry>=0.12",
"pytest>=7.4",
"singer-sdk[testing]~=0.54.0a2",
"singer-sdk[testing]",
"syrupy>=5.1",
]
typing = [
Expand All @@ -62,8 +63,11 @@ typing = [
[tool.hatch.version]
source = "vcs"

[tool.uv.sources]
singer-sdk = { git = "https://github.com/meltano/sdk.git", rev = "main" }

[tool.ruff]
line-length = 100
line-length = 120
preview = true
[tool.ruff.lint]
select = [
Expand Down
41 changes: 41 additions & 0 deletions scripts/update_catalog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env python

"""Update the OpenAPI schema from the Hook API.

Copyright (c) 2026 Edgar Ramírez-Mondragón
"""

from __future__ import annotations

import http
import json
import logging
import pathlib
import sys

import requests

from tap_hookdeck.client import API_VERSION

OPENAPI_URL = f"https://api.hookdeck.com/{API_VERSION}/openapi"
PATH = "tap_hookdeck/openapi.json"

logging.basicConfig(format="%(levelname)s - %(message)s", level=logging.INFO)
logger = logging.getLogger()


def main() -> None:
"""Update the OpenAPI schema from the Hookdeck API."""
logger.info("Updating OpenAPI schema from %s", OPENAPI_URL)
response = requests.get(OPENAPI_URL, timeout=60, allow_redirects=True)
if response.status_code != http.HTTPStatus.OK:
logger.error("Failed to fetch OpenAPI spec: %s", response.reason)
sys.exit(1)

spec = response.json()
content = json.dumps(spec, indent=2) + "\n"
pathlib.Path(PATH).write_text(content, encoding="utf-8")


if __name__ == "__main__":
main()
15 changes: 5 additions & 10 deletions tap_hookdeck/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@
from singer_sdk.helpers.types import Context


API_VERSION = "2025-07-01"


class HookdeckStream(RESTStream[str]):
"""Hookdeck stream class."""

url_base = "https://api.hookdeck.com"
url_base = f"https://api.hookdeck.com/{API_VERSION}"
records_jsonpath = "$.models[*]"
next_page_token_jsonpath = "$.pagination.next" # noqa: S105

Expand All @@ -36,17 +39,9 @@ def authenticator(self) -> APIKeyAuthenticator:
)

@override
def get_url_params(
self,
context: Context | None,
next_page_token: str | None,
) -> dict[str, Any]:
def get_url_params(self, context: Context | None, next_page_token: str | None) -> dict[str, Any]:
"""Get URL query parameters.

Args:
context: Stream sync context.
next_page_token: Next offset.

Returns:
Mapping of URL query parameters.
"""
Expand Down
Loading
Loading