Skip to content

1.10.1#283

Merged
digitalghost-dev merged 22 commits intomainfrom
1.10.1
May 4, 2026
Merged

1.10.1#283
digitalghost-dev merged 22 commits intomainfrom
1.10.1

Conversation

@digitalghost-dev
Copy link
Copy Markdown
Owner

@digitalghost-dev digitalghost-dev commented May 4, 2026

Summary by CodeRabbit

  • New Features

    • Added analytics tracking to the web app with a one-time privacy toast.
    • Enhanced web dashboard with season KPIs and improved tournament visuals.
    • Improved command documentation with interactive workflow details.
  • Bug Fixes

    • Error handling refined so commands return clearer, non-crashing errors.
    • Help output updated (flag descriptions and deprecations) for commands.
  • Documentation

    • Updated installation, command docs, and infrastructure pipeline details.
  • Chores

    • Version bumped to v1.10.1; assorted CI/build/config updates.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 4, 2026

Merging this PR will not alter performance

✅ 12 untouched benchmarks
🆕 41 new benchmarks
⏩ 10 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
🆕 test_build_dataframe_concatenates_all_sets N/A 124.4 ms N/A
🆕 test_pull_product_information_excludes_reverse_holofoil_prices N/A 3.2 ms N/A
🆕 test_pull_product_information_success N/A 3.3 ms N/A
🆕 test_extract_card_name_strip_gold N/A 55.7 µs N/A
🆕 test_get_card_number_no_extended_data N/A 16.7 µs N/A
🆕 test_get_card_number_no_number_field N/A 17.8 µs N/A
🆕 test_pull_product_information_skips_non_cards N/A 3.2 ms N/A
🆕 test_extract_card_name_dash_and_variant_suffix N/A 55.2 µs N/A
🆕 test_extract_series_data_http_error N/A 123 ms N/A
🆕 test_is_card_no_extended_data N/A 24.5 µs N/A
🆕 test_extract_series_data_all_filtered_out N/A 123.4 ms N/A
🆕 test_discord_failure_sensor_handles_request_exception N/A 293.2 µs N/A
🆕 test_discord_success_sensor_posts_webhook N/A 285.1 µs N/A
🆕 test_discord_success_sensor_handles_generic_exception N/A 293.5 µs N/A
🆕 test_discord_failure_sensor_handles_generic_exception N/A 293.2 µs N/A
🆕 test_extract_card_name_strip_reverse_holofoil N/A 57.4 µs N/A
🆕 test_normalize_card_number_double_digit N/A 23.6 µs N/A
🆕 test_get_card_number_no_value_key N/A 17.8 µs N/A
🆕 test_extract_card_name_accented_characters N/A 59.3 µs N/A
🆕 test_pull_product_information_sm_normalizes_card_number N/A 3.2 ms N/A
... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.


Comparing 1.10.1 (9d644c4) with main (a935015)2

Open in CodSpeed

Footnotes

  1. 10 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (702d173) during the generation of this report, so a935015 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5b08b9bd-7d0d-448c-af76-5559d99eb9f8

📥 Commits

Reviewing files that changed from the base of the PR and between ba40a01 and 9d644c4.

📒 Files selected for processing (7)
  • .github/workflows/python_testing.yml
  • card_data/pipelines/poke_cli_dbt/dbt_project.yml
  • testdata/pokemon_image_flag_non-valid_size.golden
  • web/Dockerfile
  • web/analytics.py
  • web/app.py
  • web/app_test.py
💤 Files with no reviewable changes (1)
  • testdata/pokemon_image_flag_non-valid_size.golden
✅ Files skipped from review due to trivial changes (2)
  • card_data/pipelines/poke_cli_dbt/dbt_project.yml
  • web/app_test.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/analytics.py

📝 Walkthrough

Walkthrough

This PR bumps project versions to v1.10.1 across builds/manifests, refactors API/error handling to return structured errors instead of fatals, adds PostHog analytics to the web app, updates docs/help/goldens, and extends CI/ignore/config entries. No broad algorithmic changes beyond error handling and telemetry.

Changes

Version bump (v1.10.1)

Layer / File(s) Summary
CI & Build
.github/workflows/ci.yml, .goreleaser.yml, Dockerfile
Updated env VERSION_NUMBER and Go ldflags linking main.version from v1.10.0v1.10.1.
Package Manifests
card_data/pyproject.toml, card_data/pipelines/poke_cli_dbt/dbt_project.yml, nfpm.yaml, web/pyproject.toml
Project/package version fields bumped to v1.10.1.
Docs / Examples
README.md, docs/installation.md
Replaced Docker image tags and examples to reference v1.10.1.
Test Fixture
testdata/main_latest_flag.golden
Updated expected latest-release line to show v1.10.0.

Error-handling refactor (replace fatals with returns & structured errors)

Layer / File(s) Summary
Error formatters
cmd/utils/errors.go
Added exported helpers: FormatNotFoundError, FormatNetworkError, FormatServerError, FormatUnexpectedDataError, FormatFetchError.
HTTP layer
connections/connection.go
Replaced exported FetchEndpoint with unexported generic fetchEndpoint; added HTTPStatusError and formatEndpointError; ApiCallSetup returns HTTPStatusError for non-200; all public API wrappers delegate to fetchEndpoint.
Command callers
cmd/berry/berry.go, cmd/speed/speed.go
Replaced log.Fatalf with returned fmt.Errorf so failures propagate.
Tests
connections/connection_test.go, cmd/utils/errors_test.go, cmd/speed/speed_test.go
Added/updated tests: server error & malformed JSON expectations; TestFormatResourceErrors; invalid SpeedStage case added.

Web analytics and UI changes

Layer / File(s) Summary
Analytics module
web/analytics.py
New PostHog integration: exported POSTHOG_API_KEY, POSTHOG_HOST, init_posthog() cached factory, _truncate_ip(), track_visit() to capture "$pageview" with truncated IP and session de-duplication.
Web app integration
web/app.py
Calls track_visit() from main(); added SeasonKPIs class; refactored SeasonTournamentLocations with TYPE_COLORS and _render_legend(); unique_locations()/tournament_locations() adjusted and tournaments dataset shared between components.
Web deps & Docker
web/pyproject.toml, web/Dockerfile
Added dependency-groups.analytics (posthog==7.14.0) and pinned dev pytest versions; Docker builder includes analytics package and copies analytics.py; CI python-testing uses uv sync --all-groups.
Tests
web/app_test.py
Made tests robust to ordering by locating markdown with flagcdn.com and mapping metrics by label.

Docs, flags, config, ignore updates

Layer / File(s) Summary
Docs & command help
docs/commands.md, card_data/README.md, docs/Infrastructure_Guide/index.md, docs/installation.md, README.md
Added/expanded card docs and speed docs; swapped data architecture image and expanded pipeline steps; updated installation and README tags/roadmap item statuses.
Flags & help text
flags/pokemonflagset.go, cmd/pokemon/pokemon.go
Marked -t, --types as deprecated, added -d, --defense to help output, moved image size validation earlier in ImageFlag.
Ignore & security config
.gitignore, gitleaks.toml, mkdocs.yml
Expanded .gitignore (macOS, coverage, card_data/temp, AI dirs), added phc_... allowlist pattern to gitleaks, changed MkDocs admonition icon.
Golden files
testdata/pokemon_help.golden, testdata/pokemon_image_flag_non-valid_size.golden
Regenerated help golden and adjusted expected formatting/content lines.

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant StreamlitApp
    participant PostHog
    Browser->>StreamlitApp: HTTP request / open page
    StreamlitApp->>StreamlitApp: check st.session_state["ph_visited"]
    alt not visited
        StreamlitApp->>StreamlitApp: ensure st.session_state["ph_distinct_id"]
        StreamlitApp->>StreamlitApp: extract X-Forwarded-For IP
        StreamlitApp->>StreamlitApp: _truncate_ip(ip)
        StreamlitApp->>PostHog: posthog.capture(distinct_id, "$pageview", props incl. $current_url, $ip?)
        StreamlitApp->>StreamlitApp: set st.session_state["ph_visited"]=True
    end
    StreamlitApp->>Browser: render page (SeasonKPIs, map, legend)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • 1.8.1 #211: Related refactor of API-fetch helpers and endpoint error handling in connections/connection.go.
  • 1.10.0 #277: Matches version-bump edits across CI, goreleaser, Docker, and manifests.
  • 1.8.2 #217: Similar release/version metadata updates across CI and build files.

"I hopped through logs and bumps with care,
Errors now return — no sudden scare,
PostHog listens as visitors come near,
Docs refreshed and versions clear,
A little rabbit cheers: v1.10.1 is here!" 🐇

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title '1.10.1' is extremely vague and generic, providing no meaningful information about the changeset's purpose or primary modification. Use a descriptive title that summarizes the main change, such as 'Bump version to 1.10.1' or 'Release v1.10.1 with error handling improvements'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 1.10.1

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (3)
connections/connection.go (1)

41-71: 🏗️ Heavy lift

Preserve the original cause when you format endpoint errors.

fetchEndpoint now replaces HTTPStatusError, *url.Error, and JSON errors with fresh string-only errors, so downstream callers can no longer use errors.As / errors.Is on the returned error. That undercuts the value of moving from process termination to returned errors.

A small wrapper that exposes the styled message via Error() and the original cause via Unwrap() would keep the current UX without throwing away machine-readable context.

Possible shape
+type formattedEndpointError struct {
+	message string
+	cause   error
+}
+
+func (e formattedEndpointError) Error() string { return e.message }
+func (e formattedEndpointError) Unwrap() error { return e.cause }
+
 func formatEndpointError(resourceType string, err error) error {
 	var statusErr HTTPStatusError
 	if errors.As(err, &statusErr) {
 		switch {
 		case statusErr.StatusCode == http.StatusNotFound:
-			return fmt.Errorf("%s", utils.FormatNotFoundError(resourceType))
+			return formattedEndpointError{message: utils.FormatNotFoundError(resourceType), cause: err}
 		case statusErr.StatusCode >= http.StatusInternalServerError:
-			return fmt.Errorf("%s", utils.FormatServerError(resourceType))
+			return formattedEndpointError{message: utils.FormatServerError(resourceType), cause: err}
 		default:
-			return fmt.Errorf("%s", utils.FormatFetchError(resourceType, err))
+			return formattedEndpointError{message: utils.FormatFetchError(resourceType, err), cause: err}
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@connections/connection.go` around lines 41 - 71, The formatEndpointError
function is discarding the original error types; implement a small wrapper type
(e.g., EndpointError) that stores a formatted message and the original cause,
implements Error() to return the styled message and Unwrap() to return the
cause, then change formatEndpointError to return that wrapper instead of
fmt.Errorf so callers can still use errors.As / errors.Is on HTTPStatusError,
*url.Error, json.SyntaxError, json.UnmarshalTypeError, etc.; use the
utils.Format* helpers for the message and set the cause to the original err in
each branch.
connections/connection_test.go (1)

127-157: ⚡ Quick win

Please add coverage for the remaining new error-mapping branches.

These subtests lock in the 500 and malformed-JSON paths, but formatEndpointError also added behavior for *url.Error and non-404/non-5xx HTTP statuses. Right now a regression in either branch would still slip through the wrapper-level tests.

A single transport failure case and a 403 case here would cover the whole mapping introduced in connections/connection.go.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@connections/connection_test.go` around lines 127 - 157, The tests are missing
coverage for the formatEndpointError branches that handle transport failures
(*url.Error) and non-404/non-5xx HTTP statuses; add two subtests to
connections/connection_test.go alongside the existing ones: one that simulates a
transport error by calling AbilityApiCall with an invalid server URL (or by
using an httptest server that closes connection) and asserts the returned error
contains the formatEndpointError message for a transport/*url.Error case, and
another that makes the server respond with a non-404/non-5xx status (e.g. 403)
and asserts the error contains the mapped message for that status; reference
AbilityApiCall and formatEndpointError when locating where to add these
subtests.
web/analytics.py (1)

6-6: ⚡ Quick win

Store PostHog project token as an environment variable rather than a string literal

PostHog's own docs note that "As a rule of thumb, we do not recommend having API keys or tokens in plaintext. Setting it as an environment variable is best." While phc_ project keys are write-only (no read access), leaking them still allows anyone to pollute your analytics data by ingesting arbitrary events.

♻️ Proposed refactor
+import os
+
 POSTHOG_API_KEY = "phc_qLvoCFJ5U9qgMS4p6LuJPgc3ZcrCRZYBNHLueHE9MU4C"
+POSTHOG_API_KEY = os.environ.get("POSTHOG_API_KEY", "phc_qLvoCFJ5U9qgMS4p6LuJPgc3ZcrCRZYBNHLueHE9MU4C")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/analytics.py` at line 6, The POSTHOG_API_KEY constant is a hard-coded
secret; change its initialization to read from an environment variable (e.g.,
os.environ.get("POSTHOG_API_KEY")) and remove the plaintext token, ensure the
code handles a missing env var by raising a clear exception or logging an error
and failing fast, and update any uses of POSTHOG_API_KEY to rely on this
env-backed value so the secret is no longer stored in source.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@connections/connection.go`:
- Around line 129-130: Change the human-readable label passed into fetchEndpoint
from the type-style "PokémonSpecies" to a natural-language string "Pokémon
species" to make error/CLI messages read better; update the call in
PokemonSpeciesApiCall (which currently invokes
fetchEndpoint[structs.PokemonSpeciesJSONStruct](endpoint, pokemonSpeciesName,
baseURL, "PokémonSpecies")) to pass "Pokémon species" instead.

In `@gitleaks.toml`:
- Around line 9-11: Replace the hardcoded PostHog project API key in
web/analytics.py with an environment variable lookup: find the place where the
literal 'phc_' key is passed to PostHog (e.g., in posthog.init or an
initialize_posthog / get_posthog_client function) and change it to use
os.environ.get('POSTHOG_API_KEY') (or equivalent config accessor), add a clear
error or fallback if the env var is missing, and update any tests or docs that
assumed the hardcoded value.

In `@testdata/main_latest_flag.golden`:
- Line 5: The golden fixture is brittle because the LatestFlag test relies on a
live GitHub API response; change the test to be deterministic by injecting or
mocking the HTTP client used by LatestFlag (or replace the outgoing call with an
httptest server that returns a fixed JSON/body), update the test harness to
point LatestFlag at that mocked server/client, and keep the golden content
static (replace the dynamic version string in the golden fixture with the
expected fixed response used by the mock). Ensure you modify the test setup
where LatestFlag is constructed/called so it accepts the injected client or base
URL and assert against the fixed mock response.

In `@web/analytics.py`:
- Around line 24-30: The code is creating persistent person profiles by always
setting a session-based distinct_id and including $ip in properties; to fix,
gate analytics or make events anonymous: either check a consent flag (e.g.,
st.session_state.get("analytics_consent")) before calling
track_visit()/posthog.capture and skip setting distinct_id/$ip when consent is
false, or explicitly set properties["$process_person_profile"] = False (and
remove $ip) before calling posthog.capture/track_visit so events remain
anonymous; update the block that builds distinct_id and properties (variables
distinct_id, properties) to honor the consent flag or add the
$process_person_profile property.

In `@web/app.py`:
- Around line 92-93: The sum comprehension for total_participants is excluding
tournaments where player_quantity == 0 because it uses a truthy guard; update
the filter to only skip missing/None values instead of falsy zeros (e.g., use
t.get("player_quantity") is not None or "player_quantity" in t) so
total_participants correctly includes zero-valued entries; ensure you still cast
via int(t["player_quantity"]) and preserve behavior when the key is absent or
None.

In `@web/pyproject.toml`:
- Around line 16-18: The posthog package is listed under the optional
dependency-group "analytics" but is imported unconditionally by web/analytics.py
(and transitively by web/app.py), causing runtime failures; update
pyproject.toml by removing "posthog==7.14.0" from the dependency-groups
analytics list and add the same spec to the [project.dependencies] section so
posthog is installed by default; ensure any lock/update commands you use (e.g.,
the project's dependency sync) are run to regenerate the lockfile after moving
the entry.

---

Nitpick comments:
In `@connections/connection_test.go`:
- Around line 127-157: The tests are missing coverage for the
formatEndpointError branches that handle transport failures (*url.Error) and
non-404/non-5xx HTTP statuses; add two subtests to
connections/connection_test.go alongside the existing ones: one that simulates a
transport error by calling AbilityApiCall with an invalid server URL (or by
using an httptest server that closes connection) and asserts the returned error
contains the formatEndpointError message for a transport/*url.Error case, and
another that makes the server respond with a non-404/non-5xx status (e.g. 403)
and asserts the error contains the mapped message for that status; reference
AbilityApiCall and formatEndpointError when locating where to add these
subtests.

In `@connections/connection.go`:
- Around line 41-71: The formatEndpointError function is discarding the original
error types; implement a small wrapper type (e.g., EndpointError) that stores a
formatted message and the original cause, implements Error() to return the
styled message and Unwrap() to return the cause, then change formatEndpointError
to return that wrapper instead of fmt.Errorf so callers can still use errors.As
/ errors.Is on HTTPStatusError, *url.Error, json.SyntaxError,
json.UnmarshalTypeError, etc.; use the utils.Format* helpers for the message and
set the cause to the original err in each branch.

In `@web/analytics.py`:
- Line 6: The POSTHOG_API_KEY constant is a hard-coded secret; change its
initialization to read from an environment variable (e.g.,
os.environ.get("POSTHOG_API_KEY")) and remove the plaintext token, ensure the
code handles a missing env var by raising a clear exception or logging an error
and failing fast, and update any uses of POSTHOG_API_KEY to rely on this
env-backed value so the secret is no longer stored in source.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 107d1cfb-bed7-44ca-852f-9a05caeaea5b

📥 Commits

Reviewing files that changed from the base of the PR and between 702d173 and ba40a01.

⛔ Files ignored due to path filters (5)
  • card_data/data_infrastructure_diagram.png is excluded by !**/*.png
  • card_data/data_infrastructure_v2.png is excluded by !**/*.png
  • docs/assets/card.gif is excluded by !**/*.gif
  • docs/assets/data_infrastructure_diagram.svg is excluded by !**/*.svg
  • web/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (28)
  • .github/workflows/ci.yml
  • .gitignore
  • .goreleaser.yml
  • Dockerfile
  • README.md
  • card_data/README.md
  • card_data/pipelines/poke_cli_dbt/dbt_project.yml
  • card_data/pyproject.toml
  • cmd/berry/berry.go
  • cmd/pokemon/pokemon.go
  • cmd/speed/speed.go
  • cmd/speed/speed_test.go
  • cmd/utils/errors.go
  • cmd/utils/errors_test.go
  • connections/connection.go
  • connections/connection_test.go
  • docs/Infrastructure_Guide/index.md
  • docs/commands.md
  • docs/installation.md
  • flags/pokemonflagset.go
  • gitleaks.toml
  • mkdocs.yml
  • nfpm.yaml
  • testdata/main_latest_flag.golden
  • testdata/pokemon_help.golden
  • web/analytics.py
  • web/app.py
  • web/pyproject.toml

Comment thread connections/connection.go
Comment thread gitleaks.toml
Comment thread testdata/main_latest_flag.golden
Comment thread web/analytics.py
Comment thread web/app.py
Comment thread web/pyproject.toml
@codecov
Copy link
Copy Markdown

codecov Bot commented May 4, 2026

Codecov Report

❌ Patch coverage is 85.45455% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
connections/connection.go 82.75% 4 Missing and 1 partial ⚠️
flags/pokemonflagset.go 80.00% 2 Missing ⚠️
cmd/berry/berry.go 0.00% 1 Missing ⚠️
Files with missing lines Coverage Δ
cmd/pokemon/pokemon.go 85.71% <100.00%> (+0.17%) ⬆️
cmd/speed/speed.go 40.71% <100.00%> (+1.42%) ⬆️
cmd/utils/errors.go 100.00% <100.00%> (ø)
cmd/berry/berry.go 64.46% <0.00%> (ø)
flags/pokemonflagset.go 72.44% <80.00%> (ø)
connections/connection.go 83.54% <82.75%> (-2.90%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@digitalghost-dev digitalghost-dev merged commit a593556 into main May 4, 2026
11 checks passed
@digitalghost-dev digitalghost-dev deleted the 1.10.1 branch May 4, 2026 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant