Skip to content

Commit b47ade8

Browse files
committed
Merge branch 'main' into feat/async-client-search-api
# Conflicts: # leakix/__init__.py # leakix/client.py
2 parents 702b65e + 3d12566 commit b47ade8

18 files changed

Lines changed: 612 additions & 169 deletions
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env bash
2+
# Verify CHANGELOG.md hygiene in pull requests:
3+
# 1. CHANGELOG.md changes must be in their own dedicated commit
4+
# 2. Commit hashes referenced in new changelog entries must exist
5+
# 3. Commit link URLs must match their reference keys
6+
#
7+
# Usage: check-changelog-commit.sh <base-sha>
8+
set -euo pipefail
9+
10+
base="${1:?Usage: check-changelog-commit.sh <base-sha>}"
11+
errors=0
12+
13+
# --- Check 1: CHANGELOG.md must be in dedicated commits ---
14+
15+
for commit in $(git log --format=%H "${base}..HEAD"); do
16+
files=$(git diff-tree --no-commit-id --name-only -r "$commit")
17+
if echo "$files" | grep -q "^CHANGELOG.md$"; then
18+
file_count=$(echo "$files" | wc -l | tr -d ' ')
19+
if [ "$file_count" -gt 1 ]; then
20+
echo "::error::Commit $commit modifies CHANGELOG.md alongside other files."
21+
echo "CHANGELOG.md changes must be in their own dedicated commit."
22+
errors=$((errors + 1))
23+
fi
24+
fi
25+
done
26+
27+
# --- Check 2: Referenced commit hashes must exist ---
28+
29+
changelog_diff=$(git diff "${base}..HEAD" -- CHANGELOG.md \
30+
| grep "^+" | grep -v "^+++" || true)
31+
32+
inline_hashes=$(echo "$changelog_diff" \
33+
| grep -oE '\(\[([0-9a-f]{7,})\]' \
34+
| grep -oE '[0-9a-f]{7,}' | sort -u || true)
35+
36+
for hash in $inline_hashes; do
37+
if ! git cat-file -t "$hash" >/dev/null 2>&1; then
38+
echo "::error::Commit $hash referenced in CHANGELOG.md does not exist."
39+
errors=$((errors + 1))
40+
fi
41+
done
42+
43+
# --- Check 3: Link URLs must match their keys ---
44+
45+
link_lines=$(echo "$changelog_diff" \
46+
| grep -E '^\+\[[0-9a-f]{7,}\]: https://.*commit/' || true)
47+
48+
while IFS= read -r line; do
49+
[ -z "$line" ] && continue
50+
key=$(echo "$line" \
51+
| grep -oE '\[([0-9a-f]{7,})\]' | head -1 \
52+
| tr -d '[]')
53+
url_hash=$(echo "$line" \
54+
| grep -oE 'commit/[0-9a-f]{7,}' \
55+
| sed 's|commit/||')
56+
if [ -n "$key" ] && [ -n "$url_hash" ] && [ "$key" != "$url_hash" ]; then
57+
echo "::error::Link [$key] points to commit/$url_hash but should point to commit/$key"
58+
errors=$((errors + 1))
59+
fi
60+
done <<< "$link_lines"
61+
62+
# --- Summary ---
63+
64+
if [ "$errors" -gt 0 ]; then
65+
echo "Found $errors changelog error(s)."
66+
exit 1
67+
fi
68+
69+
echo "All changelog checks passed."

.github/workflows/changelog.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: CHANGELOG related checks per pull requests
2+
on:
3+
pull_request:
4+
types: [assigned, opened, synchronize, reopened, labeled, unlabeled]
5+
branches:
6+
- main
7+
merge_group:
8+
types: [checks_requested]
9+
10+
jobs:
11+
check-changelog:
12+
name: Check changelog action
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v6
16+
- uses: tarides/changelog-check-action@v3
17+
with:
18+
changelog: CHANGELOG.md
19+
20+
check-changelog-commit:
21+
name: Check changelog is in dedicated commit
22+
runs-on: ubuntu-latest
23+
steps:
24+
- uses: actions/checkout@v6
25+
with:
26+
fetch-depth: 0
27+
- name: Verify CHANGELOG.md changes are in own commit
28+
run: >
29+
.github/scripts/check-changelog-commit.sh
30+
"${{ github.event.pull_request.base.sha }}"
31+
32+
shellcheck:
33+
name: Shellcheck
34+
runs-on: ubuntu-latest
35+
steps:
36+
- uses: actions/checkout@v6
37+
- name: Install shellcheck
38+
run: sudo apt-get install -y shellcheck
39+
- name: Run shellcheck
40+
run: make lint-shell

CHANGELOG.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,17 @@ and this project adheres to
1212

1313
### Changed
1414

15-
- Updated to Python 3.13+
16-
([65c5121](https://github.com/LeakIX/LeakIXClient-Python/commit/65c5121))
17-
- Updated l9format requirement from 1.3.1a3 to 1.3.2
18-
([0975c1c](https://github.com/LeakIX/LeakIXClient-Python/commit/0975c1c))
19-
- Updated fire requirement from ^0.5.0 to >=0.5,<0.8
20-
([7cb5dae](https://github.com/LeakIX/LeakIXClient-Python/commit/7cb5dae))
21-
- Bumped actions/setup-python from 5 to 6
22-
([b1bc0da](https://github.com/LeakIX/LeakIXClient-Python/commit/b1bc0da))
23-
- Bumped actions/checkout from 4 to 6
24-
([6777ad9](https://github.com/LeakIX/LeakIXClient-Python/commit/6777ad9))
15+
- Updated to Python 3.13+ ([65c5121])
16+
- Updated l9format requirement from 1.3.1a3 to 1.3.2 ([0975c1c])
17+
- Updated fire requirement from ^0.5.0 to >=0.5,<0.8 ([7cb5dae])
18+
- Bumped actions/setup-python from 5 to 6 ([b1bc0da])
19+
- Bumped actions/checkout from 4 to 6 ([6777ad9])
2520

2621
### Infrastructure
2722

28-
- Added pip-audit security scanning to CI
29-
([62550bc](https://github.com/LeakIX/LeakIXClient-Python/commit/62550bc))
23+
- Added pip-audit security scanning to CI ([62550bc])
3024
- Added Dependabot configuration for Python and GitHub Actions
31-
([4dd4948](https://github.com/LeakIX/LeakIXClient-Python/commit/4dd4948))
25+
([4dd4948])
3226

3327
## [0.1.9] - Previous Release
3428

@@ -47,3 +41,12 @@ and this project adheres to
4741
[unreleased]: https://github.com/LeakIX/LeakIXClient-Python/compare/v0.1.10...HEAD
4842
[0.1.10]: https://github.com/LeakIX/LeakIXClient-Python/compare/v0.1.9...v0.1.10
4943
[0.1.9]: https://github.com/LeakIX/LeakIXClient-Python/releases/tag/v0.1.9
44+
45+
<!-- Commit links -->
46+
[65c5121]: https://github.com/LeakIX/LeakIXClient-Python/commit/65c5121
47+
[0975c1c]: https://github.com/LeakIX/LeakIXClient-Python/commit/0975c1c
48+
[7cb5dae]: https://github.com/LeakIX/LeakIXClient-Python/commit/7cb5dae
49+
[b1bc0da]: https://github.com/LeakIX/LeakIXClient-Python/commit/b1bc0da
50+
[6777ad9]: https://github.com/LeakIX/LeakIXClient-Python/commit/6777ad9
51+
[62550bc]: https://github.com/LeakIX/LeakIXClient-Python/commit/62550bc
52+
[4dd4948]: https://github.com/LeakIX/LeakIXClient-Python/commit/4dd4948

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ lint: ## Run ruff linter
3838
lint-fix: ## Run ruff linter with auto-fix
3939
poetry run ruff check --fix leakix/ tests/ example/ executable/
4040

41+
.PHONY: lint-shell
42+
lint-shell: ## Lint shell scripts using shellcheck
43+
shellcheck .github/scripts/*.sh
44+
4145
.PHONY: typecheck
4246
typecheck: ## Run mypy type checker
4347
poetry run mypy leakix/
@@ -53,6 +57,10 @@ check: check-format lint typecheck test ## Run all checks
5357
check-outdated: ## Check for outdated dependencies
5458
poetry show --outdated || true
5559

60+
.PHONY: lint-shell
61+
lint-shell: ## Lint shell scripts using shellcheck
62+
shellcheck .github/scripts/*.sh
63+
5664
.PHONY: clean
5765
clean: ## Clean build artifacts
5866
rm -rf dist/ build/ *.egg-info/ .pytest_cache/ .mypy_cache/ .ruff_cache/

executable/cli.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ def bulk_export_to_json(
2020
before: str | None = None,
2121
after: str | None = None,
2222
):
23-
before_dt = datetime.strptime(before, DATETIME_FORMAT)
24-
after_dt = datetime.strptime(after, DATETIME_FORMAT)
2523
client = Client(api_key=API_KEY)
2624

2725
queries = []
2826
queries.append(RawQuery(query))
2927
if before is not None:
28+
before_dt = datetime.strptime(before, DATETIME_FORMAT)
3029
before_dt_field = UpdateDateField(
3130
before_dt, operator=Operator.StrictlyGreater
3231
)
3332
queries.append(MustQuery(before_dt_field))
3433
if after is not None:
34+
after_dt = datetime.strptime(after, DATETIME_FORMAT)
3535
after_dt_field = UpdateDateField(
3636
after_dt, operator=Operator.StrictlySmaller
3737
)
@@ -46,7 +46,7 @@ def bulk_export_to_json(
4646
else:
4747
raise Exception(
4848
"API error (code = %d, message = %s)"
49-
% (response.status_code, response.json())
49+
% (response.status_code(), response.json())
5050
)
5151

5252

leakix/__init__.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
from importlib.metadata import version
2+
13
from leakix.async_client import AsyncClient as AsyncClient
2-
from leakix.client import __VERSION__ as __VERSION__
34
from leakix.client import Client as Client
45
from leakix.client import HostResult as HostResult
56
from leakix.client import Scope as Scope
7+
from leakix.domain import L9Subdomain as L9Subdomain
68
from leakix.field import (
79
AgeField as AgeField,
810
)
@@ -59,21 +61,21 @@
5961
from leakix.response import (
6062
ErrorResponse as ErrorResponse,
6163
)
62-
from leakix.response import (
63-
R as R,
64-
)
6564
from leakix.response import (
6665
RateLimitResponse as RateLimitResponse,
6766
)
6867
from leakix.response import (
6968
SuccessResponse as SuccessResponse,
7069
)
7170

71+
__version__ = version("leakix")
72+
7273
__all__ = [
73-
"__VERSION__",
74+
"__version__",
7475
"AsyncClient",
7576
"Client",
7677
"HostResult",
78+
"L9Subdomain",
7779
"Scope",
7880
# Fields
7981
"AgeField",
@@ -99,7 +101,6 @@
99101
# Response
100102
"AbstractResponse",
101103
"ErrorResponse",
102-
"R",
103104
"RateLimitResponse",
104105
"SuccessResponse",
105106
]

leakix/async_client.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import asyncio
44
import json
55
from collections.abc import AsyncIterator
6+
from importlib.metadata import version
67

78
import httpx
89
from l9format import l9format
@@ -11,8 +12,6 @@
1112
from leakix.plugin import APIResult
1213
from leakix.query import EmptyQuery, Query, RawQuery
1314

14-
__VERSION__ = "0.2.0"
15-
1615
DEFAULT_URL = "https://leakix.net"
1716
DEFAULT_TIMEOUT = 30.0
1817

@@ -33,7 +32,7 @@ def __init__(
3332
self.timeout = timeout
3433
self.headers = {
3534
"Accept": "application/json",
36-
"User-agent": f"leakix-client-python/{__VERSION__}",
35+
"User-agent": f"leakix-client-python/{version('leakix')}",
3736
}
3837
if api_key:
3938
self.headers["api-key"] = api_key

0 commit comments

Comments
 (0)