feat: SDK Doctor MVP / Beta (#38886)
Co-authored-by: Patricio <patricio@posthog.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Rafa Audibert <rafael@posthog.com>
@@ -13,5 +13,8 @@
|
||||
"MD028": false,
|
||||
"MD045": false,
|
||||
"MD029": false
|
||||
}
|
||||
},
|
||||
"ignores": [
|
||||
"**/fixtures/**"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -14,5 +14,6 @@ load_from:
|
||||
# These dags are loaded in local dev
|
||||
- python_module: dags.locations.analytics_platform
|
||||
- python_module: dags.locations.experiments
|
||||
- python_module: dags.locations.growth
|
||||
- python_module: dags.locations.max_ai
|
||||
- python_module: dags.locations.web_analytics
|
||||
|
||||
@@ -8,6 +8,7 @@ from posthog.clickhouse import query_tagging
|
||||
from posthog.clickhouse.cluster import ClickhouseCluster, ExponentialBackoff, RetryPolicy, get_cluster
|
||||
from posthog.clickhouse.custom_metrics import MetricsClient
|
||||
from posthog.clickhouse.query_tagging import DagsterTags
|
||||
from posthog.redis import get_client, redis
|
||||
|
||||
|
||||
class JobOwners(str, Enum):
|
||||
@@ -62,6 +63,16 @@ class ClickhouseClusterResource(dagster.ConfigurableResource):
|
||||
)
|
||||
|
||||
|
||||
class RedisResource(dagster.ConfigurableResource):
|
||||
"""
|
||||
A Redis resource that can be used to store and retrieve data.
|
||||
"""
|
||||
|
||||
def create_resource(self, context: dagster.InitResourceContext) -> redis.Redis:
|
||||
client = get_client()
|
||||
return client
|
||||
|
||||
|
||||
def report_job_status_metric(
|
||||
context: dagster.RunStatusSensorContext, cluster: dagster.ResourceParam[ClickhouseCluster]
|
||||
) -> None:
|
||||
|
||||
@@ -5,7 +5,7 @@ import dagster_slack
|
||||
from dagster_aws.s3.io_manager import s3_pickle_io_manager
|
||||
from dagster_aws.s3.resources import S3Resource
|
||||
|
||||
from dags.common import ClickhouseClusterResource
|
||||
from dags.common import ClickhouseClusterResource, RedisResource
|
||||
|
||||
# Define resources for different environments
|
||||
resources_by_env = {
|
||||
@@ -14,6 +14,7 @@ resources_by_env = {
|
||||
"io_manager": s3_pickle_io_manager.configured(
|
||||
{"s3_bucket": settings.DAGSTER_S3_BUCKET, "s3_prefix": "dag-storage"}
|
||||
),
|
||||
"redis_client": RedisResource(),
|
||||
"s3": S3Resource(),
|
||||
# Using EnvVar instead of the Django setting to ensure that the token is not leaked anywhere in the Dagster UI
|
||||
"slack": dagster_slack.SlackResource(token=dagster.EnvVar("SLACK_TOKEN")),
|
||||
@@ -21,12 +22,13 @@ resources_by_env = {
|
||||
"local": {
|
||||
"cluster": ClickhouseClusterResource.configure_at_launch(),
|
||||
"io_manager": dagster.fs_io_manager,
|
||||
"slack": dagster.ResourceDefinition.none_resource(description="Dummy Slack resource for local development"),
|
||||
"redis_client": RedisResource(),
|
||||
"s3": S3Resource(
|
||||
endpoint_url=settings.OBJECT_STORAGE_ENDPOINT,
|
||||
aws_access_key_id=settings.OBJECT_STORAGE_ACCESS_KEY_ID,
|
||||
aws_secret_access_key=settings.OBJECT_STORAGE_SECRET_ACCESS_KEY,
|
||||
),
|
||||
"slack": dagster.ResourceDefinition.none_resource(description="Dummy Slack resource for local development"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
import dagster
|
||||
|
||||
from dags import oauth
|
||||
from dags.sdk_doctor import github_sdk_versions, team_sdk_versions
|
||||
|
||||
from . import resources
|
||||
|
||||
defs = dagster.Definitions(
|
||||
jobs=[
|
||||
oauth.oauth_clear_expired_oauth_tokens_job,
|
||||
github_sdk_versions.cache_github_sdk_versions_job,
|
||||
team_sdk_versions.cache_all_team_sdk_versions_job,
|
||||
],
|
||||
schedules=[
|
||||
oauth.oauth_clear_expired_oauth_tokens_schedule,
|
||||
github_sdk_versions.cache_github_sdk_versions_schedule,
|
||||
team_sdk_versions.cache_all_team_sdk_versions_schedule,
|
||||
],
|
||||
resources=resources,
|
||||
)
|
||||
|
||||
0
dags/sdk_doctor/__init__.py
Normal file
421
dags/sdk_doctor/github_sdk_versions.py
Normal file
@@ -0,0 +1,421 @@
|
||||
import re
|
||||
import json
|
||||
import time
|
||||
from collections.abc import Callable
|
||||
from typing import Any, Literal, Optional, cast
|
||||
|
||||
import dagster
|
||||
import requests
|
||||
import structlog
|
||||
|
||||
from posthog.exceptions_capture import capture_exception
|
||||
|
||||
from dags.common import JobOwners, redis
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
CACHE_EXPIRY = 60 * 60 * 24 * 3 # 3 days
|
||||
MAX_REQUEST_RETRIES = 3
|
||||
INITIAL_RETRIES_BACKOFF = 1 # in seconds
|
||||
|
||||
SdkTypes = Literal[
|
||||
"web",
|
||||
"posthog-ios",
|
||||
"posthog-android",
|
||||
"posthog-node",
|
||||
"posthog-python",
|
||||
"posthog-php",
|
||||
"posthog-ruby",
|
||||
"posthog-go",
|
||||
"posthog-flutter",
|
||||
"posthog-react-native",
|
||||
"posthog-dotnet",
|
||||
"posthog-elixir",
|
||||
]
|
||||
SDK_TYPES: list[SdkTypes] = [
|
||||
"web",
|
||||
"posthog-ios",
|
||||
"posthog-android",
|
||||
"posthog-node",
|
||||
"posthog-python",
|
||||
"posthog-php",
|
||||
"posthog-ruby",
|
||||
"posthog-go",
|
||||
"posthog-flutter",
|
||||
"posthog-react-native",
|
||||
"posthog-dotnet",
|
||||
"posthog-elixir",
|
||||
]
|
||||
|
||||
|
||||
# Using lambda here to be able to define this before defining the functions
|
||||
SDK_FETCH_FUNCTIONS: dict[SdkTypes, Callable[[], Optional[dict[str, Any]]]] = {
|
||||
"web": lambda: fetch_web_sdk_data(),
|
||||
"posthog-python": lambda: fetch_python_sdk_data(),
|
||||
"posthog-node": lambda: fetch_node_sdk_data(),
|
||||
"posthog-react-native": lambda: fetch_react_native_sdk_data(),
|
||||
"posthog-flutter": lambda: fetch_flutter_sdk_data(),
|
||||
"posthog-ios": lambda: fetch_ios_sdk_data(),
|
||||
"posthog-android": lambda: fetch_android_sdk_data(),
|
||||
"posthog-go": lambda: fetch_go_sdk_data(),
|
||||
"posthog-php": lambda: fetch_php_sdk_data(),
|
||||
"posthog-ruby": lambda: fetch_ruby_sdk_data(),
|
||||
"posthog-elixir": lambda: fetch_elixir_sdk_data(),
|
||||
"posthog-dotnet": lambda: fetch_dotnet_sdk_data(),
|
||||
}
|
||||
|
||||
|
||||
def fetch_github_data_for_sdk(lib_name: str) -> Optional[dict[str, Any]]:
|
||||
"""Fetch GitHub data for specific SDK type using ClickHouse $lib value."""
|
||||
fetch_fn = SDK_FETCH_FUNCTIONS.get(cast(SdkTypes, lib_name))
|
||||
if fetch_fn:
|
||||
return fetch_fn()
|
||||
return None
|
||||
|
||||
|
||||
def fetch_sdk_data_from_releases(repo: str, tag_prefix: str = "") -> Optional[dict[str, Any]]:
|
||||
"""Helper function to fetch SDK data from GitHub releases API."""
|
||||
try:
|
||||
response = requests.get(f"https://api.github.com/repos/{repo}/releases", timeout=10)
|
||||
if not response.ok:
|
||||
logger.error(f"[SDK Doctor] Failed to fetch releases for {repo}", status_code=response.status_code)
|
||||
return None
|
||||
|
||||
releases = response.json()
|
||||
if not releases:
|
||||
return None
|
||||
|
||||
latest_version = None
|
||||
release_dates = {}
|
||||
|
||||
for release in releases:
|
||||
if release.get("draft") or release.get("prerelease"):
|
||||
continue
|
||||
|
||||
tag = release.get("tag_name", "")
|
||||
|
||||
# If tag_prefix is specified, only process tags that match
|
||||
if tag_prefix:
|
||||
if not tag.startswith(tag_prefix):
|
||||
continue
|
||||
version = tag[len(tag_prefix) :]
|
||||
elif tag.startswith("v"):
|
||||
version = tag[1:]
|
||||
elif tag.startswith("android-v"):
|
||||
version = tag[9:]
|
||||
else:
|
||||
version = tag
|
||||
|
||||
if version:
|
||||
if latest_version is None:
|
||||
latest_version = version
|
||||
published_at = release.get("published_at")
|
||||
if published_at:
|
||||
release_dates[version] = published_at
|
||||
|
||||
if not latest_version:
|
||||
return None
|
||||
|
||||
return {"latestVersion": latest_version, "releaseDates": release_dates}
|
||||
except Exception as e:
|
||||
logger.exception(f"[SDK Doctor] Failed to fetch SDK data from releases for {repo}")
|
||||
capture_exception(e)
|
||||
return None
|
||||
|
||||
|
||||
def fetch_web_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch Web SDK data from GitHub releases API"""
|
||||
return fetch_sdk_data_from_releases("PostHog/posthog-js", tag_prefix="posthog-js@")
|
||||
|
||||
|
||||
def fetch_python_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch Python SDK data from GitHub releases API"""
|
||||
return fetch_sdk_data_from_releases("PostHog/posthog-python", tag_prefix="v")
|
||||
|
||||
|
||||
def fetch_node_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch Node.js SDK data from GitHub releases API"""
|
||||
return fetch_sdk_data_from_releases("PostHog/posthog-js", tag_prefix="posthog-node@")
|
||||
|
||||
|
||||
def fetch_react_native_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch React Native SDK data from GitHub releases API"""
|
||||
return fetch_sdk_data_from_releases("PostHog/posthog-js", tag_prefix="posthog-react-native@")
|
||||
|
||||
|
||||
def fetch_flutter_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch Flutter SDK data from GitHub releases API"""
|
||||
return fetch_sdk_data_from_releases("PostHog/posthog-flutter")
|
||||
|
||||
|
||||
def fetch_ios_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch iOS SDK data from GitHub releases API"""
|
||||
return fetch_sdk_data_from_releases("PostHog/posthog-ios")
|
||||
|
||||
|
||||
def fetch_android_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch Android SDK data from GitHub releases API"""
|
||||
return fetch_sdk_data_from_releases("PostHog/posthog-android", tag_prefix="android-v")
|
||||
|
||||
|
||||
def fetch_go_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch Go SDK data from GitHub releases API"""
|
||||
return fetch_sdk_data_from_releases("PostHog/posthog-go", tag_prefix="v")
|
||||
|
||||
|
||||
def fetch_php_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch PHP SDK data from History.md with release dates"""
|
||||
try:
|
||||
changelog_response = requests.get(
|
||||
"https://raw.githubusercontent.com/PostHog/posthog-php/master/History.md", timeout=10
|
||||
)
|
||||
if not changelog_response.ok:
|
||||
return None
|
||||
|
||||
changelog_content = changelog_response.text
|
||||
version_pattern = re.compile(r"^(\d+\.\d+\.\d+) / (\d{4}-\d{2}-\d{2})", re.MULTILINE)
|
||||
matches = version_pattern.findall(changelog_content)
|
||||
|
||||
if not matches:
|
||||
return None
|
||||
|
||||
latest_version = matches[0][0]
|
||||
release_dates = {}
|
||||
for version, date in matches:
|
||||
release_dates[version] = f"{date}T00:00:00Z"
|
||||
|
||||
return {"latestVersion": latest_version, "releaseDates": release_dates}
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def fetch_ruby_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch Ruby SDK data from CHANGELOG.md with release dates"""
|
||||
try:
|
||||
changelog_response = requests.get(
|
||||
"https://raw.githubusercontent.com/PostHog/posthog-ruby/main/CHANGELOG.md", timeout=10
|
||||
)
|
||||
if not changelog_response.ok:
|
||||
return None
|
||||
|
||||
changelog_content = changelog_response.text
|
||||
version_pattern = re.compile(r"^## (\d+\.\d+\.\d+) - (\d{4}-\d{2}-\d{2})", re.MULTILINE)
|
||||
matches = version_pattern.findall(changelog_content)
|
||||
|
||||
if not matches:
|
||||
return None
|
||||
|
||||
latest_version = matches[0][0]
|
||||
release_dates = {}
|
||||
for version, date in matches:
|
||||
release_dates[version] = f"{date}T00:00:00Z"
|
||||
|
||||
return {"latestVersion": latest_version, "releaseDates": release_dates}
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def fetch_elixir_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch Elixir SDK data from CHANGELOG.md with release dates"""
|
||||
try:
|
||||
changelog_response = requests.get(
|
||||
"https://raw.githubusercontent.com/PostHog/posthog-elixir/master/CHANGELOG.md", timeout=10
|
||||
)
|
||||
if not changelog_response.ok:
|
||||
return None
|
||||
|
||||
changelog_content = changelog_response.text
|
||||
version_pattern = re.compile(r"^## (\d+\.\d+\.\d+) - (\d{4}-\d{2}-\d{2})", re.MULTILINE)
|
||||
matches = version_pattern.findall(changelog_content)
|
||||
|
||||
if not matches:
|
||||
return None
|
||||
|
||||
latest_version = matches[0][0]
|
||||
release_dates = {}
|
||||
for version, date in matches:
|
||||
release_dates[version] = f"{date}T00:00:00Z"
|
||||
|
||||
return {"latestVersion": latest_version, "releaseDates": release_dates}
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def fetch_dotnet_sdk_data() -> Optional[dict[str, Any]]:
|
||||
"""Fetch .NET SDK data from GitHub releases API"""
|
||||
return fetch_sdk_data_from_releases("PostHog/posthog-dotnet", tag_prefix="v")
|
||||
|
||||
|
||||
def fetch_github_release_dates(repo: str) -> dict[str, str]:
|
||||
"""Fetch release dates from GitHub releases API with exponential backoff."""
|
||||
for attempt in range(MAX_REQUEST_RETRIES):
|
||||
try:
|
||||
response = requests.get(f"https://api.github.com/repos/{repo}/releases?per_page=100", timeout=10)
|
||||
|
||||
if response.status_code in [403, 429]:
|
||||
if attempt < MAX_REQUEST_RETRIES - 1:
|
||||
backoff_time = INITIAL_RETRIES_BACKOFF * (2**attempt)
|
||||
logger.warning(
|
||||
f"[SDK Doctor] GitHub API rate limit hit for {repo} (status {response.status_code}), retrying in {backoff_time}s (attempt {attempt + 1}/{MAX_REQUEST_RETRIES})"
|
||||
)
|
||||
time.sleep(backoff_time)
|
||||
continue
|
||||
else:
|
||||
logger.error(
|
||||
f"[SDK Doctor] GitHub API rate limit exceeded for {repo} after {MAX_REQUEST_RETRIES} attempts (status {response.status_code})"
|
||||
)
|
||||
return {}
|
||||
|
||||
if not response.ok:
|
||||
logger.warning(f"[SDK Doctor] GitHub API error for {repo}: {response.status_code}")
|
||||
return {}
|
||||
|
||||
releases = response.json()
|
||||
release_dates = {}
|
||||
|
||||
for release in releases:
|
||||
tag_name = release.get("tag_name", "")
|
||||
published_at = release.get("published_at", "")
|
||||
|
||||
if not tag_name or not published_at:
|
||||
continue
|
||||
|
||||
if repo == "PostHog/posthog-js":
|
||||
if "@" in tag_name:
|
||||
version = tag_name.split("@")[1]
|
||||
release_dates[version] = published_at
|
||||
elif repo in [
|
||||
"PostHog/posthog-python",
|
||||
"PostHog/posthog-flutter",
|
||||
"PostHog/posthog-ios",
|
||||
"PostHog/posthog-go",
|
||||
"PostHog/posthog-dotnet",
|
||||
]:
|
||||
if tag_name.startswith("v"):
|
||||
version = tag_name[1:]
|
||||
release_dates[version] = published_at
|
||||
elif repo == "PostHog/posthog-android":
|
||||
if tag_name.startswith("android-v"):
|
||||
version = tag_name[9:]
|
||||
release_dates[version] = published_at
|
||||
|
||||
return release_dates
|
||||
except Exception as e:
|
||||
if attempt < MAX_REQUEST_RETRIES - 1:
|
||||
backoff_time = INITIAL_RETRIES_BACKOFF * (2**attempt)
|
||||
logger.warning(
|
||||
f"[SDK Doctor] Error fetching GitHub releases for {repo}, retrying in {backoff_time}s: {str(e)}"
|
||||
)
|
||||
time.sleep(backoff_time)
|
||||
continue
|
||||
else:
|
||||
logger.exception(
|
||||
f"[SDK Doctor] Failed to fetch GitHub releases for {repo} after {MAX_REQUEST_RETRIES} attempts"
|
||||
)
|
||||
return {}
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
# ---- Dagster defs
|
||||
retry_policy = dagster.RetryPolicy(
|
||||
max_retries=3,
|
||||
delay=1,
|
||||
backoff=dagster.Backoff.EXPONENTIAL,
|
||||
jitter=dagster.Jitter.FULL,
|
||||
)
|
||||
|
||||
|
||||
@dagster.op(retry_policy=retry_policy)
|
||||
def fetch_github_sdk_versions_op(context: dagster.OpExecutionContext) -> dict[str, Optional[dict[str, Any]]]:
|
||||
"""Fetch GitHub SDK version data for all SDK types."""
|
||||
sdk_data = {}
|
||||
fetched_count = 0
|
||||
failed_count = 0
|
||||
|
||||
for lib_name in SDK_TYPES:
|
||||
try:
|
||||
context.log.info(f"Fetching {lib_name} SDK data from GitHub")
|
||||
github_data = fetch_github_data_for_sdk(lib_name)
|
||||
|
||||
if github_data:
|
||||
sdk_data[lib_name] = github_data
|
||||
fetched_count += 1
|
||||
context.log.info(f"Successfully fetched {lib_name} SDK data")
|
||||
else:
|
||||
failed_count += 1
|
||||
context.log.warning(f"No data received from GitHub for {lib_name}")
|
||||
except Exception as e:
|
||||
failed_count += 1
|
||||
context.log.exception(f"Failed to fetch {lib_name} SDK data")
|
||||
capture_exception(e)
|
||||
|
||||
context.log.info(f"Fetched {fetched_count} SDK versions")
|
||||
context.log.info(f"Failed to fetch {failed_count} SDK versions")
|
||||
context.log.info(f"Total SDKs: {len(SDK_TYPES)}")
|
||||
context.log.info(f"SDK data: {sdk_data}")
|
||||
|
||||
context.add_output_metadata(
|
||||
{
|
||||
"fetched_count": dagster.MetadataValue.int(fetched_count),
|
||||
"failed_count": dagster.MetadataValue.int(failed_count),
|
||||
"total_sdks": dagster.MetadataValue.int(len(SDK_TYPES)),
|
||||
}
|
||||
)
|
||||
|
||||
return sdk_data # type: ignore
|
||||
|
||||
|
||||
@dagster.op(retry_policy=retry_policy)
|
||||
def cache_github_sdk_versions_op(
|
||||
context: dagster.OpExecutionContext,
|
||||
sdk_data: dict[str, Optional[dict[str, Any]]],
|
||||
redis_client: dagster.ResourceParam[redis.Redis],
|
||||
) -> None:
|
||||
"""Cache GitHub SDK version data to Redis."""
|
||||
cached_count = 0
|
||||
skipped_count = 0
|
||||
|
||||
for lib_name, github_data in sdk_data.items():
|
||||
if github_data is None:
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
cache_key = f"github:sdk_versions:{lib_name}"
|
||||
try:
|
||||
redis_client.setex(cache_key, CACHE_EXPIRY, json.dumps(github_data))
|
||||
cached_count += 1
|
||||
context.log.info(f"Successfully cached {lib_name} SDK data")
|
||||
except Exception as e:
|
||||
context.log.exception(f"Failed to cache {lib_name} SDK data")
|
||||
capture_exception(e)
|
||||
|
||||
context.log.info(f"Cached {cached_count} SDK versions")
|
||||
context.log.info(f"Skipped {skipped_count} SDK versions")
|
||||
context.log.info(f"Total SDKs: {len(sdk_data)}")
|
||||
context.log.info(f"SDK data: {sdk_data}")
|
||||
|
||||
context.add_output_metadata(
|
||||
{
|
||||
"cached_count": dagster.MetadataValue.int(cached_count),
|
||||
"skipped_count": dagster.MetadataValue.int(skipped_count),
|
||||
"total_sdks": dagster.MetadataValue.int(len(sdk_data)),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@dagster.job(
|
||||
description="Queries GitHub for most recent SDK versions and caches them in Redis",
|
||||
tags={"owner": JobOwners.TEAM_GROWTH.value},
|
||||
)
|
||||
def cache_github_sdk_versions_job():
|
||||
sdk_data = fetch_github_sdk_versions_op()
|
||||
cache_github_sdk_versions_op(sdk_data)
|
||||
|
||||
|
||||
cache_github_sdk_versions_schedule = dagster.ScheduleDefinition(
|
||||
job=cache_github_sdk_versions_job,
|
||||
cron_schedule="0 */6 * * *", # Every 6 hours
|
||||
execution_timezone="UTC",
|
||||
name="cache_github_sdk_versions_schedule",
|
||||
)
|
||||
223
dags/sdk_doctor/team_sdk_versions.py
Normal file
@@ -0,0 +1,223 @@
|
||||
import json
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Literal, Optional
|
||||
|
||||
import dagster
|
||||
import structlog
|
||||
|
||||
from posthog.hogql import ast
|
||||
from posthog.hogql.parser import parse_select
|
||||
from posthog.hogql.query import execute_hogql_query
|
||||
|
||||
from posthog.exceptions_capture import capture_exception
|
||||
from posthog.models import Team
|
||||
|
||||
from dags.common import JobOwners, redis
|
||||
from dags.sdk_doctor.github_sdk_versions import SDK_TYPES
|
||||
|
||||
default_logger = structlog.get_logger(__name__)
|
||||
|
||||
CACHE_EXPIRY = 60 * 60 * 24 * 3 # 3 days
|
||||
|
||||
|
||||
def get_sdk_versions_for_team(
|
||||
team_id: int,
|
||||
*,
|
||||
logger=default_logger,
|
||||
) -> Optional[dict[str, list[dict[str, Any]]]]:
|
||||
"""
|
||||
Query ClickHouse for events in the last 7 days and extract SDK usage.
|
||||
Returns dict of SDK versions with minimal data, grouped by lib type.
|
||||
"""
|
||||
try:
|
||||
team = Team.objects.get(id=team_id)
|
||||
|
||||
# TODO: Extract the semVer sorting below to either a Clickhouse UDF/HogQL function.
|
||||
# Source: https://clickhouse.com/blog/semantic-versioning-udf
|
||||
query = parse_select(
|
||||
"""
|
||||
SELECT
|
||||
properties.$lib AS lib,
|
||||
properties.$lib_version AS lib_version,
|
||||
MAX(timestamp) AS max_timestamp,
|
||||
COUNT(*) AS event_count
|
||||
FROM events
|
||||
WHERE
|
||||
timestamp >= now() - INTERVAL 7 DAY
|
||||
AND lib IS NOT NULL
|
||||
AND lib_version IS NOT NULL
|
||||
GROUP BY lib, lib_version
|
||||
ORDER BY
|
||||
lib,
|
||||
arrayMap(x -> toIntOrZero(x), splitByChar('.', extract(assumeNotNull(lib_version), {regex}))) DESC,
|
||||
event_count DESC
|
||||
""",
|
||||
placeholders={"regex": ast.Constant(value="(\\d+(\\.\\d+)+)")}, # Matches number.number.number.number.<...>
|
||||
)
|
||||
|
||||
response = execute_hogql_query(query, team, query_type="sdk_versions_for_team")
|
||||
|
||||
output = defaultdict(list)
|
||||
for lib, lib_version, max_timestamp, event_count in response.results:
|
||||
if lib in SDK_TYPES:
|
||||
output[lib].append(
|
||||
{
|
||||
"lib_version": lib_version,
|
||||
"max_timestamp": str(max_timestamp),
|
||||
"count": event_count,
|
||||
}
|
||||
)
|
||||
|
||||
return dict(output)
|
||||
except Team.DoesNotExist:
|
||||
logger.exception(f"[SDK Doctor] Team {team_id} not found")
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.exception(f"[SDK Doctor] Error querying events for team {team_id}")
|
||||
capture_exception(e)
|
||||
return None
|
||||
|
||||
|
||||
def get_and_cache_team_sdk_versions(
|
||||
team_id: int,
|
||||
redis_client: redis.Redis,
|
||||
*,
|
||||
logger=default_logger,
|
||||
) -> Optional[dict[str, list[dict[str, Any]]]]:
|
||||
"""
|
||||
Query ClickHouse for team SDK versions and cache the result.
|
||||
Shared function used by both API and Dagster job.
|
||||
Returns the response data dict or None if failed.
|
||||
"""
|
||||
try:
|
||||
sdk_versions = get_sdk_versions_for_team(team_id, logger=logger)
|
||||
if sdk_versions is not None:
|
||||
payload = json.dumps(sdk_versions)
|
||||
cache_key = f"sdk_versions:team:{team_id}"
|
||||
redis_client.setex(cache_key, CACHE_EXPIRY, payload)
|
||||
logger.info(f"[SDK Doctor] Team {team_id} SDK versions cached successfully")
|
||||
|
||||
return sdk_versions
|
||||
else:
|
||||
logger.error(f"[SDK Doctor] No data received from ClickHouse for team {team_id}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.exception(f"[SDK Doctor] Failed to get and cache SDK versions for team {team_id}")
|
||||
capture_exception(e)
|
||||
return None
|
||||
|
||||
|
||||
@dagster.op(
|
||||
out=dagster.DynamicOut(int),
|
||||
config_schema={
|
||||
"team_ids": dagster.Field(
|
||||
dagster.Array(dagster.Int),
|
||||
default_value=[],
|
||||
is_required=False,
|
||||
description="Specific team IDs to process. If empty, processes all teams.",
|
||||
)
|
||||
},
|
||||
)
|
||||
def get_all_team_ids_op(context: dagster.OpExecutionContext):
|
||||
"""Fetch all team IDs to process."""
|
||||
override_team_ids = context.op_config["team_ids"]
|
||||
|
||||
if override_team_ids:
|
||||
team_ids = override_team_ids
|
||||
context.log.info(f"Processing {len(team_ids)} configured teams: {team_ids}")
|
||||
else:
|
||||
team_ids = list(Team.objects.values_list("id", flat=True))
|
||||
context.log.info(f"Processing all {len(team_ids)} teams")
|
||||
|
||||
for team_id in team_ids:
|
||||
yield dagster.DynamicOutput(team_id, mapping_key=str(team_id))
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class CacheTeamSdkVersionsResult:
|
||||
team_id: int
|
||||
sdk_count: int
|
||||
status: Literal["success", "empty", "failed", "error"]
|
||||
|
||||
|
||||
@dagster.op
|
||||
def cache_team_sdk_versions_for_team_op(
|
||||
context: dagster.OpExecutionContext,
|
||||
redis_client: dagster.ResourceParam[redis.Redis],
|
||||
team_id: int,
|
||||
) -> CacheTeamSdkVersionsResult:
|
||||
"""Fetch and cache SDK versions for a single team."""
|
||||
try:
|
||||
sdk_versions = get_and_cache_team_sdk_versions(team_id, redis_client, logger=context.log)
|
||||
|
||||
sdk_count = 0 if sdk_versions is None else len(sdk_versions)
|
||||
context.add_output_metadata(
|
||||
{
|
||||
"team_id": dagster.MetadataValue.int(team_id),
|
||||
"sdk_count": dagster.MetadataValue.int(sdk_count),
|
||||
}
|
||||
)
|
||||
|
||||
status: Literal["success", "empty", "failed", "error"] = "error"
|
||||
if sdk_versions is not None:
|
||||
if len(sdk_versions) == 0:
|
||||
context.log.debug(f"Team {team_id} has no SDK versions")
|
||||
status = "empty"
|
||||
else:
|
||||
context.log.info(f"Cached {sdk_count} SDK types for team {team_id}")
|
||||
status = "success"
|
||||
else:
|
||||
context.log.warning(f"Failed to get SDK versions for team {team_id}")
|
||||
status = "failed"
|
||||
|
||||
return CacheTeamSdkVersionsResult(team_id=team_id, sdk_count=sdk_count, status=status)
|
||||
except Exception as e:
|
||||
context.log.exception(f"Failed to process SDK versions for team {team_id}")
|
||||
capture_exception(e)
|
||||
return CacheTeamSdkVersionsResult(team_id=team_id, sdk_count=0, status="error")
|
||||
|
||||
|
||||
@dagster.op
|
||||
def aggregate_results_op(context: dagster.OpExecutionContext, results: list[CacheTeamSdkVersionsResult]) -> None:
|
||||
"""Aggregate results from all team processing ops."""
|
||||
total_teams = len(results)
|
||||
cached_count = sum(1 for r in results if r.status == "success")
|
||||
empty_count = sum(1 for r in results if r.status == "empty")
|
||||
failed_count = sum(1 for r in results if r.status in ("failed", "error"))
|
||||
|
||||
context.log.info(
|
||||
f"Completed processing {total_teams} teams: {cached_count} cached, {empty_count} empty, {failed_count} failed"
|
||||
)
|
||||
|
||||
context.add_output_metadata(
|
||||
{
|
||||
"total_teams": dagster.MetadataValue.int(total_teams),
|
||||
"cached_count": dagster.MetadataValue.int(cached_count),
|
||||
"empty_count": dagster.MetadataValue.int(empty_count),
|
||||
"failed_count": dagster.MetadataValue.int(failed_count),
|
||||
}
|
||||
)
|
||||
|
||||
if failed_count > 0:
|
||||
failed_team_ids = [r.team_id for r in results if r.status in ("failed", "error")]
|
||||
raise Exception(f"Failed to cache SDK versions for {failed_count} teams: {failed_team_ids}")
|
||||
|
||||
|
||||
@dagster.job(
|
||||
description="Queries ClickHouse for recent SDK versions and caches them in Redis",
|
||||
executor_def=dagster.multiprocess_executor.configured({"max_concurrent": 2}), # Do this slowly, 2 teams at a time
|
||||
tags={"owner": JobOwners.TEAM_GROWTH.value},
|
||||
)
|
||||
def cache_all_team_sdk_versions_job():
|
||||
team_ids = get_all_team_ids_op()
|
||||
results = team_ids.map(cache_team_sdk_versions_for_team_op)
|
||||
aggregate_results_op(results.collect())
|
||||
|
||||
|
||||
cache_all_team_sdk_versions_schedule = dagster.ScheduleDefinition(
|
||||
job=cache_all_team_sdk_versions_job,
|
||||
cron_schedule="0 */6 * * *", # Every 6 hours
|
||||
execution_timezone="UTC",
|
||||
name="cache_all_team_sdk_versions_schedule",
|
||||
)
|
||||
82
dags/tests/fixtures/changelogs/elixir_changelog.md
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
## 2.0.0 - 2025-09-30
|
||||
|
||||
### Major Release
|
||||
|
||||
`posthog-elixir` was fully reworked. Check [migration guide](MIGRATION.md#v1-v2)
|
||||
for some tips on how to upgrade.
|
||||
|
||||
Huge thanks to community member [@martosaur](https://github.com/martosaur) for contributing this new version.
|
||||
|
||||
### What's new
|
||||
|
||||
- Elixir v1.17+ required
|
||||
- Event capture is now offloaded to background workers with automatic batching
|
||||
- [Context](README.md#context) mechanism for easier property propagation
|
||||
- [Error Tracking](README.md#error-tracking) support
|
||||
- New `PostHog.FeatureFlags` module for working with feature flags
|
||||
- [Test mode](`PostHog.Test`) for easier testing
|
||||
- Customizable [HTTP client](`PostHog.API.Client`) with Req as the default
|
||||
- [Plug integration](`PostHog.Integrations.Plug`) for automatically capturing common HTTP properties
|
||||
|
||||
## 1.1.0 - 2025-07-01
|
||||
|
||||
- Expose `capture/2` `b077aba849126c63f1c7a82b6ad9d21945871a4a`
|
||||
|
||||
## 1.0.3 - 2025-06-02
|
||||
|
||||
- Fix implementation for structs `2cdc6f578a192fd751ce105018a7f78b7ed8f852`
|
||||
|
||||
## 1.0.2 - 2025-04-17
|
||||
|
||||
- More small changes to docs `147795c21a58e2308fbd43b571d9ba978c8a8a3b`
|
||||
|
||||
## 1.0.1 - 2025-04-17
|
||||
|
||||
- Small changes to docs `f3578a7006fb8d6cb19f36e19b1387243a12bd21`
|
||||
|
||||
## 1.0.0 - 2025-04-17
|
||||
|
||||
### Big Release
|
||||
|
||||
`posthog-elixir` is now officially stable and running on v1. There are some breaking changes and some general improvements. Check [MIGRATION.md](./MIGRATION.md#v0-v1) for a guide on how to migrate.
|
||||
|
||||
### What's changed
|
||||
|
||||
- Elixir v1.14+ is now a requirement
|
||||
- Feature Flags now return a key called `payload` rather than `value` to better align with the other SDKs
|
||||
- PostHog now requires you to initialize `Posthog.Application` alongside your supervisor tree. This is required because of our `Cachex` system to properly track your FF usage.
|
||||
- We'll also include local evaluation in the near term, which will also require a GenServer, therefore, requiring us to use a Supervisor.
|
||||
- Added `enabled_capture` configuration option to disable PostHog tracking in development/test environments
|
||||
- `PostHog.capture` now requires `distinct_id` as a required second argument
|
||||
|
||||
## 0.4.4 - 2025-04-14
|
||||
|
||||
Fix inconsistent docs for properties - [#13]
|
||||
|
||||
## 0.4.3 - 2025-04-14
|
||||
|
||||
Improve docs setup - [#12]
|
||||
|
||||
## 0.4.2 - 2025-03-27
|
||||
|
||||
Allow `atom()` property keys - [#11]
|
||||
|
||||
## 0.4.1 - 2025-03-12
|
||||
|
||||
Fix feature flags broken implementation - [#10]
|
||||
|
||||
## 0.4.0 - 2025-02-11
|
||||
|
||||
Documentation + OTP/Elixir version bumps
|
||||
|
||||
## 0.3.0 - 2025-01-09
|
||||
|
||||
- Initial feature flags implementation (#7)
|
||||
|
||||
## 0.2.0 - 2024-05-04
|
||||
|
||||
- Allow extra headers (#3)
|
||||
|
||||
## 0.1.0 - 2020-06-06
|
||||
|
||||
- Initial release
|
||||
257
dags/tests/fixtures/changelogs/php_changelog.md
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
3.7.1 / 2025-09-26
|
||||
==================
|
||||
|
||||
* fix: don't sort condition sets with variant overrides to the top (#85)
|
||||
|
||||
|
||||
3.7.0 / 2025-08-26
|
||||
==================
|
||||
|
||||
* feat(flags): Implement local evaluation of flag dependencies (#84)
|
||||
* fix: Ignore new `flag` filter type in local evaluation (#80)
|
||||
* chore: Add feature flags project board workflow (#79)
|
||||
|
||||
3.6.0 / 2025-04-30
|
||||
==================
|
||||
|
||||
* chore(flags): use new `/flags` endpoint instead of `/decide` (#76)
|
||||
|
||||
3.5.0 / 2025-04-17
|
||||
==================
|
||||
|
||||
* feat: Add request id, version, id, and evaluation reason to $feature_flag_called events (#75)
|
||||
* Bump version to 3.4.0 (#74)
|
||||
3.4.0 / 2025-04-15
|
||||
==================
|
||||
|
||||
* feat(flags): Add getFeatureFlagPayload method (#53)
|
||||
|
||||
3.3.5 / 2025-03-26
|
||||
==================
|
||||
|
||||
* Fix version updating in Makefile (#72)
|
||||
|
||||
3.3.4 / 2025-03-11
|
||||
==================
|
||||
|
||||
* Add support for 'verify_batch_events_request=>false' (#70)
|
||||
* Run GitHub actions on all supported PHP versions (#67)
|
||||
|
||||
3.3.3 / 2025-02-28
|
||||
==================
|
||||
|
||||
* Fix PHP 8.4 deprecation on Client.php constructor (Backwards Compatible) (#66)
|
||||
|
||||
|
||||
3.3.2 / 2024-04-03
|
||||
==================
|
||||
|
||||
* Make the feature flag fetch optional on initialisation (#65)
|
||||
|
||||
3.3.1 / 2024-03-22
|
||||
==================
|
||||
|
||||
* fix(flags): Handle bool value matching (#64)
|
||||
* Fixes a bug with local evaluation where passing in true and false values for a property wouldn't match correctly.
|
||||
|
||||
3.3.0 / 2024-03-13
|
||||
==================
|
||||
|
||||
* feat(flags): Locally evaluate all cohorts (#63)
|
||||
|
||||
3.2.2 / 2024-03-11
|
||||
==================
|
||||
|
||||
* feat(flags): Add specific timeout for feature flags (#62)
|
||||
* Adds a new `feature_flag_request_timeout_ms` timeout parameter for feature flags which defaults to 3 seconds, updated from the default 10s for all other API calls.
|
||||
|
||||
3.2.1 / 2024-01-26
|
||||
==================
|
||||
|
||||
* fix(flags): Update relative date op names (#61)
|
||||
* Remove new relative date operators, combine into regular date operators
|
||||
|
||||
3.2.0 / 2024-01-10
|
||||
==================
|
||||
|
||||
* feat(flags): Add local props and flags to all calls (#60)
|
||||
* When local evaluation is enabled, we automatically add flag information to all events sent to PostHog, whenever possible. This makes it easier to use these events in experiments.
|
||||
|
||||
3.1.0 / 2024-01-10
|
||||
==================
|
||||
|
||||
* feat(flags): Add relative date operator and fix numeric ops (#58)
|
||||
* Numeric property handling for feature flags now does the expected: When passed in a number, we do a numeric comparison. When passed in a string, we do a string comparison. Previously, we always did a string comparison.
|
||||
* Add support for relative date operators for local evaluation.
|
||||
* Fixes issue with regex matching for local evaluation.
|
||||
|
||||
3.0.8 / 2023-09-25
|
||||
==================
|
||||
|
||||
* fix(flags): Safe access flags in decide v2 (#55)
|
||||
|
||||
3.0.7 / 2023-08-31
|
||||
==================
|
||||
|
||||
* PHP 8.1+ Support + Fix Errors When API/Internet Connection Down (#54)
|
||||
|
||||
3.0.6 / 2023-07-04
|
||||
==================
|
||||
|
||||
* Fix typehint (#52)
|
||||
|
||||
3.0.5 / 2023-06-16
|
||||
==================
|
||||
|
||||
* Prevent "Undefined array key" warning in isFeatureEnabled() (#51)
|
||||
|
||||
3.0.4 / 2023-05-19
|
||||
==================
|
||||
|
||||
* fix(flags): Handle no rollout percentage condition (#49)
|
||||
|
||||
3.0.3 / 2023-03-21
|
||||
==================
|
||||
|
||||
* Merge branch 'master' into groups-fix
|
||||
* Make timeout configurable (#44)
|
||||
* format
|
||||
* fix(groups): actually add groups support for capture
|
||||
|
||||
3.0.2 / 2023-03-08
|
||||
==================
|
||||
|
||||
* update version 3.0.2
|
||||
* Allow to configure the HttpClient maximumBackoffDuration (#33)
|
||||
|
||||
3.0.1 / 2022-12-09
|
||||
==================
|
||||
|
||||
* feat(flags): Add support for variant overrides (#39)
|
||||
* Update history (#37)
|
||||
|
||||
3.0.0 / 2022-08-15
|
||||
==================
|
||||
|
||||
|
||||
* Requires posthog 1.38
|
||||
* Local Evaluation: isFeatureEnabled and getFeatureFlag accept group and person properties now which will evaluate relevant flags locally.
|
||||
* isFeatureEnabled and getFeatureFlag also have new parameters:
|
||||
onlyEvaluateLocally (bool) - turns on and off local evaluation
|
||||
sendFeatureFlagEvents (bool) - turns on and off $feature_flag_called events
|
||||
* Removes default parameter from isFeatureEnabled and getFeatureFlag. Returns null instead
|
||||
|
||||
2.1.1 / 2022-01-21
|
||||
==================
|
||||
|
||||
* more sensible default timeout for requests
|
||||
* Merge pull request #29 from PostHog/group-analytics-flags
|
||||
* Add groups feature flags support
|
||||
* Test default behavior
|
||||
* Release 2.1.0
|
||||
* Merge pull request #26 from PostHog/group-analytics-support
|
||||
* Add basic group analytics support
|
||||
* Fix bin/posthog help text
|
||||
* Allow bypassing ssl in bin/ command
|
||||
* Solve linter issues
|
||||
|
||||
2.1.0 / 2021-10-28
|
||||
==================
|
||||
|
||||
* Add basic group analytics support
|
||||
* Fix bin/posthog help text
|
||||
* Allow bypassing ssl in bin/ command
|
||||
|
||||
2.0.6 / 2021-10-05
|
||||
==================
|
||||
|
||||
* Separate timeout from maxBackoffDuration
|
||||
* Set the timeout config for HttpClient curl
|
||||
|
||||
2.0.5 / 2021-07-13
|
||||
==================
|
||||
|
||||
* Merge pull request #23 from joesaunderson/bugfix/send-user-agent
|
||||
* Send user agent with decide request
|
||||
|
||||
2.0.5 / 2021-07-13
|
||||
==================
|
||||
|
||||
|
||||
|
||||
2.0.4 / 2021-07-08
|
||||
==================
|
||||
|
||||
* Release 2.0.3
|
||||
* Merge pull request #21 from joesaunderson/bugfix/optional-apikey
|
||||
* API key is optional
|
||||
* Merge pull request #20 from imhmdb/patch-1
|
||||
* Fix calling error handler Closure function stored in class properties
|
||||
|
||||
2.0.3 / 2021-07-08
|
||||
==================
|
||||
|
||||
* Merge pull request #21 from joesaunderson/bugfix/optional-apikey
|
||||
* API key is optional
|
||||
* Merge pull request #20 from imhmdb/patch-1
|
||||
* Fix calling error handler Closure function stored in class properties
|
||||
|
||||
2.0.2 / 2021-07-08
|
||||
==================
|
||||
|
||||
* Merge pull request #19 from PostHog/handle-host
|
||||
* fix tests for good
|
||||
* check if host exists before operating on it
|
||||
* undefined check
|
||||
* fix tests
|
||||
* Allow hosts with protocol specified
|
||||
* Merge pull request #18 from PostHog/feature-flags
|
||||
* remove useless comment
|
||||
* have env var as the secondary option
|
||||
* bump version
|
||||
* bring back destruct
|
||||
* remove feature flags
|
||||
* simplify everything
|
||||
* Cleanup isFeatureEnabled docblock
|
||||
* Fix user agent undefined array key
|
||||
* Merge pull request #17 from PostHog/releasing-update
|
||||
* Note `git-extras` in RELEASING.md
|
||||
* Add test case for isFeatureEnabled with the simple flag in the mocked response
|
||||
* Fix: make rolloutPercentage nullable in isSimpleFlagEnabled
|
||||
* Merge remote-tracking branch 'upstream/master'
|
||||
* Fix is_simple_flag tests by mocking response
|
||||
* Use LONG_SCALE const
|
||||
* Implement isSimpleFlagEnabled
|
||||
* Don't set payload on get requests
|
||||
* (WIP) Rework feature flags based on spec `https://github.com/PostHog/posthog.com/pull/1455`
|
||||
* Extract http client functionalities
|
||||
* Remove extra line
|
||||
* Change default host to app.posthog.com
|
||||
* Feature/support feature flags decide API
|
||||
* Upgrade phplint
|
||||
2.0.1 / 2021-06-11
|
||||
==================
|
||||
|
||||
* Allow for setup via environment variables POSTHOG_API_KEY and POSTHOG_HOST
|
||||
* Make code adhere to PSR-4 and PSR-12
|
||||
|
||||
2.0.0 / 2021-05-22
|
||||
==================
|
||||
|
||||
* fix sed command for macos
|
||||
* Merge pull request #9 from adrienbrault/psr-4
|
||||
* Finish psr-4 refactoring
|
||||
* PostHog/posthog-php#3: Update composer.json to support PSR-4
|
||||
* Update README.md
|
||||
* Merge pull request #6 from chuva-inc/document_property
|
||||
* Merge pull request #5 from chuva-inc/issue_4
|
||||
* Posthog/posthog-php#3: Document the customer property
|
||||
* PostHog/posthog-php#4: Removes \n from beginning of the file
|
||||
* Update README.md
|
||||
* fix infinite loop on error 0 from libcurl
|
||||
* fix error when including https:// in host
|
||||
* fix tests for php 7.1, phpunit 8.5
|
||||
* upgrade phpunit and switch php to >=7.1
|
||||
* Update README.md
|
||||
* make tests pass
|
||||
* first commit
|
||||
156
dags/tests/fixtures/changelogs/ruby_changelog.md
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
## 3.3.2 - 2025-09-26
|
||||
|
||||
1. fix: don't sort condition sets with variant overrides to top ([#78](https://github.com/PostHog/posthog-ruby/pull/78))
|
||||
|
||||
## 3.3.1 - 2025-09-26
|
||||
|
||||
Not used
|
||||
|
||||
## 3.3.0 - 2025-09-23
|
||||
|
||||
1. feat: add exception capture ([#77](https://github.com/PostHog/posthog-ruby/pull/77))
|
||||
|
||||
## 3.2.0 - 2025-08-26
|
||||
|
||||
1. feat: Add support for local evaluation of flags that depend on other flags ([#75](https://github.com/PostHog/posthog-ruby/pull/75))
|
||||
|
||||
## 3.1.2 - 2025-08-26
|
||||
|
||||
1. fix: Add cohort evaluation support for local feature flag evaluation ([#74](https://github.com/PostHog/posthog-ruby/pull/74))
|
||||
|
||||
## 3.1.1 - 2025-08-06
|
||||
|
||||
1. fix: Pass project API key in `remote_config` requests ([#72](https://github.com/PostHog/posthog-ruby/pull/72))
|
||||
|
||||
## 3.1.0 - 2025-08-06
|
||||
|
||||
1. feat: make the `send_feature_flags` parameter more declarative and ergonomic
|
||||
|
||||
## 3.0.1 - 2025-05-20
|
||||
|
||||
1. fix: was warning on absent UUID when capturing ([#67](https://github.com/PostHog/posthog-ruby/pull/67))
|
||||
|
||||
## 3.0.0 - 2025-05-20
|
||||
|
||||
1. Drops support for Ruby 2.x ([#63](https://github.com/PostHog/posthog-ruby/pull/63))
|
||||
|
||||
Version 3.0 of the Ruby SDK drops support for Ruby 2.x. The minimum supported version is now Ruby 3.2.
|
||||
|
||||
In previous version `FeatureFlags` was added as a top-level class and was causing conflicts for other folk's applications.
|
||||
|
||||
In this change we have properly namespaced all classes within a `PostHog` module. See [#60](https://github.com/PostHog/posthog-ruby/issues/60)
|
||||
|
||||
## 2.11.0 – 2025-05-20
|
||||
|
||||
1. feat: add before_send function ([#64](https://github.com/PostHog/posthog-ruby/pull/64))
|
||||
|
||||
## 2.10.0 – 2025-05-20
|
||||
|
||||
1. chore: fix all rubocop errors ([#61](https://github.com/PostHog/posthog-ruby/pull/61))
|
||||
2. fix: add UUID capture option to capture ([#58](https://github.com/PostHog/posthog-ruby/pull/58))
|
||||
|
||||
## 2.9.0 – 2025-04-30
|
||||
|
||||
1. Use new `/flags` service to power feature flag evaluation.
|
||||
|
||||
## 2.8.1 – 2025-04-18
|
||||
|
||||
1. Fix `condition_index` can be null in `/decide` requests
|
||||
|
||||
## 2.8.0 – 2025-04-07
|
||||
|
||||
1. Add more information to `$feature_flag_called` events for `/decide` requests such as flag id, version, reason, and the request id.
|
||||
|
||||
## 2.7.2 – 2025-03-14
|
||||
|
||||
1. Fix invocation of shell by ` character
|
||||
|
||||
## 2.7.0 – 2025-02-26
|
||||
|
||||
1. Add support for quota-limited feature flags
|
||||
|
||||
## 2.6.0 - 2025-02-13
|
||||
|
||||
1. Add method for fetching decrypted remote config flag payload
|
||||
|
||||
## 2.5.1 - 2024-12-19
|
||||
|
||||
1. Adds a new, optional `distinct_id` parameter to group identify calls which allows specifying the Distinct ID for the event.
|
||||
|
||||
## 2.5.0 - 2024-03-15
|
||||
|
||||
1. Adds a new `feature_flag_request_timeout_seconds` timeout parameter for feature flags which defaults to 3 seconds, updated from the default 10s for all other API calls.
|
||||
|
||||
## 2.4.3 - 2024-02-29
|
||||
|
||||
1. Fix memory leak in PostHog::Client.new
|
||||
|
||||
## 2.4.2 - 2024-01-26
|
||||
|
||||
1. Remove new relative date operators, combine into regular date operators
|
||||
|
||||
# 2.4.1 - 2024-01-09
|
||||
|
||||
1. Add default properties for feature flags local evaluation, to target flags by distinct id & group keys.
|
||||
|
||||
# 2.4.0 - 2024-01-09
|
||||
|
||||
1. Numeric property handling for feature flags now does the expected: When passed in a number, we do a numeric comparison. When passed in a string, we do a string comparison. Previously, we always did a string comparison.
|
||||
2. Add support for relative date operators for local evaluation.
|
||||
|
||||
# 2.3.1 - 2023-08-14
|
||||
|
||||
1. Update option doc string to show personal API Key as an option
|
||||
|
||||
# 2.3.0 - 2023-02-15
|
||||
|
||||
1. Add support for feature flag payloads
|
||||
|
||||
# 2.2.0 - 2023-02-08
|
||||
|
||||
1. Remove concurrent gem dependency version limitation
|
||||
|
||||
# 2.1.0 - 2022-11-14
|
||||
|
||||
1. Add support for datetime operators for local feature flag evaluation
|
||||
2. Add support for variant overrides for local feature flag evaluation
|
||||
|
||||
# 2.0.0 - 2022-08-12
|
||||
|
||||
Breaking changes:
|
||||
|
||||
1. Minimum PostHog version requirement: 1.38
|
||||
2. Regular feature flag evaluation (i.e. by requesting from your PostHog servers) doesn't require a personal API key.
|
||||
3. `Client` initialisation doesn't take the `api_host` parameter anymore. Instead, it takes the `host` parameter, which needs to be fully qualified. For example: `https://api.posthog.com` is valid, while `api.posthog.com` is not valid.
|
||||
4. The log level by default is set to WARN. You can change it to DEBUG if you want to debug the client by running `client.logger.level = Logger::DEBUG`, where client is your initialized `PostHog::Client` instance.
|
||||
5. Default polling interval for feature flags is now set at 30 seconds. If you don't want local evaluation, don't set a personal API key in the library.
|
||||
6. Feature flag defaults are no more. Now, if a flag fails to compute for whatever reason, it will return `nil`. Otherwise, it returns either true or false. In case of `get_feature_flag`, it may also return a string variant value.
|
||||
|
||||
New Changes:
|
||||
|
||||
1. You can now evaluate feature flags locally (i.e. without sending a request to your PostHog servers) by setting a personal API key, and passing in groups and person properties to `is_feature_enabled` and `get_feature_flag` calls.
|
||||
2. Introduces a `get_all_flags` method that returns all feature flags. This is useful for when you want to seed your frontend with some initial flags, given a user ID.
|
||||
|
||||
# 1.3.0 - 2022-06-24
|
||||
|
||||
- Add support for running the client in "No-op" mode for testing (https://github.com/PostHog/posthog-ruby/pull/15)
|
||||
|
||||
# 1.2.4 - 2022-05-30
|
||||
|
||||
- Fix `create_alias` call (https://github.com/PostHog/posthog-ruby/pull/14)
|
||||
|
||||
# 1.2.3 - 2022-01-18
|
||||
|
||||
- Fix `present?` call (https://github.com/PostHog/posthog-ruby/pull/12)
|
||||
|
||||
# 1.2.2 - 2021-11-22
|
||||
|
||||
- Add ability to disable SSL verification by passing `skip_ssl_verification` (https://github.com/PostHog/posthog-ruby/pull/11)
|
||||
|
||||
# 1.2.1 - 2021-11-19
|
||||
|
||||
- Add concurrent-ruby gem dependency (fixes #8)
|
||||
|
||||
# 1.1.0 - 2020-12-15
|
||||
|
||||
- Change default domain from `t.posthog.com` to `app.posthog.com`
|
||||
512
dags/tests/fixtures/releases/dotnet_releases.json
vendored
Normal file
@@ -0,0 +1,512 @@
|
||||
[
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/250610402",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/250610402/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-dotnet/releases/250610402/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-dotnet/releases/tag/v2.0.1",
|
||||
"id": 250610402,
|
||||
"author": {
|
||||
"login": "andyzzhao",
|
||||
"id": 34008309,
|
||||
"node_id": "MDQ6VXNlcjM0MDA4MzA5",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/34008309?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/andyzzhao",
|
||||
"html_url": "https://github.com/andyzzhao",
|
||||
"followers_url": "https://api.github.com/users/andyzzhao/followers",
|
||||
"following_url": "https://api.github.com/users/andyzzhao/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/andyzzhao/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/andyzzhao/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/andyzzhao/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/andyzzhao/orgs",
|
||||
"repos_url": "https://api.github.com/users/andyzzhao/repos",
|
||||
"events_url": "https://api.github.com/users/andyzzhao/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/andyzzhao/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDONqSrH84O8ALi",
|
||||
"tag_name": "v2.0.1",
|
||||
"target_commitish": "main",
|
||||
"name": "v2.0.1",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-28T19:35:41Z",
|
||||
"updated_at": "2025-09-28T19:40:53Z",
|
||||
"published_at": "2025-09-28T19:40:53Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/tarball/v2.0.1",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/zipball/v2.0.1",
|
||||
"body": "## What's Changed\r\n* feat: allow capture to override timestamp with datetime or datetimeoffset by @darkopia in https://github.com/PostHog/posthog-dotnet/pull/101\r\n* Use `pull_request_target` by @haacked in https://github.com/PostHog/posthog-dotnet/pull/103\r\n* chore: Add MIT license by @haacked in https://github.com/PostHog/posthog-dotnet/pull/106\r\n* fix: don't sort condition sets with variant overrides to top by @andyzzhao in https://github.com/PostHog/posthog-dotnet/pull/107\r\n* fix: test discovery warning for netcoreapp3.1 by @haacked in https://github.com/PostHog/posthog-dotnet/pull/109\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-dotnet/compare/v2.0.0...v2.0.1",
|
||||
"reactions": {
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/250610402/reactions",
|
||||
"total_count": 1,
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"laugh": 0,
|
||||
"hooray": 0,
|
||||
"confused": 0,
|
||||
"heart": 0,
|
||||
"rocket": 1,
|
||||
"eyes": 0
|
||||
},
|
||||
"mentions_count": 3
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/242717803",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/242717803/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-dotnet/releases/242717803/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-dotnet/releases/tag/v2.0.0",
|
||||
"id": 242717803,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDONqSrH84Od5Rr",
|
||||
"tag_name": "v2.0.0",
|
||||
"target_commitish": "main",
|
||||
"name": "v2.0.0 - It Depends Edition",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-26T22:17:55Z",
|
||||
"updated_at": "2025-08-26T22:21:03Z",
|
||||
"published_at": "2025-08-26T22:21:03Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/tarball/v2.0.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/zipball/v2.0.0",
|
||||
"body": "This version targets .net 8.0 instead of .net 9.0 which should make it usable by a larger population.\r\n\r\n## What's Changed\r\n* feat: allow custom timestamps on .net by @darkopia in https://github.com/PostHog/posthog-dotnet/pull/98\r\n* feat(flags): Implement local evaluation of flag dependencies by @haacked in https://github.com/PostHog/posthog-dotnet/pull/97\r\n* feat(flags): use .net 8 packages by @haacked in https://github.com/PostHog/posthog-dotnet/pull/99\r\n\r\n## New Contributors\r\n* @darkopia made their first contribution in https://github.com/PostHog/posthog-dotnet/pull/98\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-dotnet/compare/v1.0.8...v2.0.0",
|
||||
"reactions": {
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/242717803/reactions",
|
||||
"total_count": 1,
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"laugh": 0,
|
||||
"hooray": 0,
|
||||
"confused": 0,
|
||||
"heart": 0,
|
||||
"rocket": 1,
|
||||
"eyes": 0
|
||||
},
|
||||
"mentions_count": 2
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/238450298",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/238450298/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-dotnet/releases/238450298/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-dotnet/releases/tag/v1.0.8",
|
||||
"id": 238450298,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDONqSrH84ONnZ6",
|
||||
"tag_name": "v1.0.8",
|
||||
"target_commitish": "main",
|
||||
"name": "v1.0.8 - Deterministic Requests are the Best Requests Edition",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-07T22:17:53Z",
|
||||
"updated_at": "2025-08-07T22:20:48Z",
|
||||
"published_at": "2025-08-07T22:20:48Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/tarball/v1.0.8",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/zipball/v1.0.8",
|
||||
"body": "## What's Changed\r\n* Prepare v1.0.7 release by @haacked in https://github.com/PostHog/posthog-dotnet/pull/89\r\n* fix: Pass project API key in `remote_config` and `local_evaluation` requests by @haacked in https://github.com/PostHog/posthog-dotnet/pull/93\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-dotnet/compare/v1.0.7...v1.0.8",
|
||||
"reactions": {
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/238450298/reactions",
|
||||
"total_count": 1,
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"laugh": 0,
|
||||
"hooray": 0,
|
||||
"confused": 0,
|
||||
"heart": 0,
|
||||
"rocket": 1,
|
||||
"eyes": 0
|
||||
},
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/233958922",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/233958922/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-dotnet/releases/233958922/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-dotnet/releases/tag/v1.0.7",
|
||||
"id": 233958922,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDONqSrH84N8e4K",
|
||||
"tag_name": "v1.0.7",
|
||||
"target_commitish": "main",
|
||||
"name": "v1.0.7 - The Boy Scout Edition",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-07-18T21:38:06Z",
|
||||
"updated_at": "2025-07-21T15:27:43Z",
|
||||
"published_at": "2025-07-21T15:27:43Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/tarball/v1.0.7",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/zipball/v1.0.7",
|
||||
"body": "## What's Changed\r\n* fix: boolean value handling in `PropertyFilterValue` by @haacked in https://github.com/PostHog/posthog-dotnet/pull/88\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-dotnet/compare/v1.0.6...v1.0.7",
|
||||
"reactions": {
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/233958922/reactions",
|
||||
"total_count": 1,
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"laugh": 0,
|
||||
"hooray": 0,
|
||||
"confused": 0,
|
||||
"heart": 0,
|
||||
"rocket": 1,
|
||||
"eyes": 0
|
||||
},
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/231607122",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/231607122/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-dotnet/releases/231607122/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-dotnet/releases/tag/v1.0.6",
|
||||
"id": 231607122,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDONqSrH84NzgtS",
|
||||
"tag_name": "v1.0.6",
|
||||
"target_commitish": "main",
|
||||
"name": "v1.0.6 - Load All The Flags Edition",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-07-10T21:00:56Z",
|
||||
"updated_at": "2025-07-10T21:07:11Z",
|
||||
"published_at": "2025-07-10T21:07:11Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/tarball/v1.0.6",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/zipball/v1.0.6",
|
||||
"body": "## What's Changed\r\n* Add unit test for null condition index by @haacked in https://github.com/PostHog/posthog-dotnet/pull/73\r\n* Remove token from local_evaluation API call by @haacked in https://github.com/PostHog/posthog-dotnet/pull/76\r\n* chore: Add workflow to call Flags Project Board by @haacked in https://github.com/PostHog/posthog-dotnet/pull/78\r\n* feat: Add LoadFeatureFlagsAsync method for manual feature flag reloading by @haacked in https://github.com/PostHog/posthog-dotnet/pull/85\r\n* fix: Ensure serialization doesn't fail when encountering flag dependencies by @haacked in https://github.com/PostHog/posthog-dotnet/pull/86\r\n* chore: Bump version to 1.0.6 by @haacked in https://github.com/PostHog/posthog-dotnet/pull/87\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-dotnet/compare/v1.0.5...v1.0.6",
|
||||
"reactions": {
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/231607122/reactions",
|
||||
"total_count": 1,
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"laugh": 0,
|
||||
"hooray": 0,
|
||||
"confused": 0,
|
||||
"heart": 0,
|
||||
"rocket": 1,
|
||||
"eyes": 0
|
||||
},
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/210475057",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/210475057/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-dotnet/releases/210475057/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-dotnet/releases/tag/v1.0.5",
|
||||
"id": 210475057,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDONqSrH84Mi5gx",
|
||||
"tag_name": "v1.0.5",
|
||||
"target_commitish": "main",
|
||||
"name": "v1.0.5 - The Indecision Edition",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-04-04T21:34:11Z",
|
||||
"updated_at": "2025-04-04T21:35:05Z",
|
||||
"published_at": "2025-04-04T21:35:05Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/tarball/v1.0.5",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/zipball/v1.0.5",
|
||||
"body": "## What's Changed\r\n\r\n* chore(flags): Decide v4 support - adds version, id, reason, and requestId to `$feature_flag_called` events by @haacked in https://github.com/PostHog/posthog-dotnet/pull/71\r\n* Make less decide requests when enriching events by @haacked in https://github.com/PostHog/posthog-dotnet/pull/72\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-dotnet/compare/v1.0.4...v1.0.5",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/207975707",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/207975707/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-dotnet/releases/207975707/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-dotnet/releases/tag/v1.0.4",
|
||||
"id": 207975707,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDONqSrH84MZXUb",
|
||||
"tag_name": "v1.0.4",
|
||||
"target_commitish": "main",
|
||||
"name": "v1.0.4 - Gotta Catch Them All Edition",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-03-24T21:58:01Z",
|
||||
"updated_at": "2025-03-24T21:59:52Z",
|
||||
"published_at": "2025-03-24T21:59:52Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/tarball/v1.0.4",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/zipball/v1.0.4",
|
||||
"body": "## What's Changed\r\n* Show whether we're using local eval or not by @haacked in https://github.com/PostHog/posthog-dotnet/pull/65\r\n* Add requestId to the `$feature_flag_called` event. by @haacked in https://github.com/PostHog/posthog-dotnet/pull/66\r\n* feat(flags): Allow specifying flags to evaluate by @haacked in https://github.com/PostHog/posthog-dotnet/pull/67\r\n* Catch and log all exceptions by @haacked in https://github.com/PostHog/posthog-dotnet/pull/68\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-dotnet/compare/v1.0.3...v1.0.4",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/203983615",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/203983615/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-dotnet/releases/203983615/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-dotnet/releases/tag/v1.0.3",
|
||||
"id": 203983615,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDONqSrH84MKIr_",
|
||||
"tag_name": "v1.0.3",
|
||||
"target_commitish": "main",
|
||||
"name": "v1.0.3 - Hide The Dirty Laundry Edition",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-03-05T23:40:51Z",
|
||||
"updated_at": "2025-03-24T21:59:38Z",
|
||||
"published_at": "2025-03-05T23:41:51Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/tarball/v1.0.3",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/zipball/v1.0.3",
|
||||
"body": "## What's Changed\r\n* Remove internal method from IPostHogClient interface by @haacked in https://github.com/PostHog/posthog-dotnet/pull/61\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-dotnet/compare/v1.0.2...v1.0.3",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/203748121",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/203748121/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-dotnet/releases/203748121/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-dotnet/releases/tag/v1.0.2",
|
||||
"id": 203748121,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDONqSrH84MJPMZ",
|
||||
"tag_name": "v1.0.2",
|
||||
"target_commitish": "main",
|
||||
"name": "v1.0.2 - Let Those Not Disposed Cast The First Stone Edition",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-03-05T02:42:02Z",
|
||||
"updated_at": "2025-03-24T21:59:28Z",
|
||||
"published_at": "2025-03-05T02:43:18Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/tarball/v1.0.2",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/zipball/v1.0.2",
|
||||
"body": "## What's Changed\r\n* Fix unhandled object disposed exception by @haacked in https://github.com/PostHog/posthog-dotnet/pull/59\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-dotnet/compare/v1.0.1...v1.0.2",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/202880735",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-dotnet/releases/202880735/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-dotnet/releases/202880735/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-dotnet/releases/tag/v1.0.1",
|
||||
"id": 202880735,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDONqSrH84MF7bf",
|
||||
"tag_name": "v1.0.1",
|
||||
"target_commitish": "main",
|
||||
"name": "v1.0.1 - The Lay Down The Law Edition",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-02-27T00:26:15Z",
|
||||
"updated_at": "2025-02-27T19:33:13Z",
|
||||
"published_at": "2025-02-27T19:33:13Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/tarball/v1.0.1",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-dotnet/zipball/v1.0.1",
|
||||
"body": "## What's Changed\r\n* chore(flags): update quota-limited logs by @dmarticus in https://github.com/PostHog/posthog-dotnet/pull/58\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-dotnet/compare/v1.0.0...v1.0.1",
|
||||
"mentions_count": 1
|
||||
}
|
||||
]
|
||||
442
dags/tests/fixtures/releases/posthog_android_releases.json
vendored
Normal file
@@ -0,0 +1,442 @@
|
||||
[
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-android/releases/252352498",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-android/releases/252352498/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-android/releases/252352498/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-android/releases/tag/android-v3.23.0",
|
||||
"id": 252352498,
|
||||
"author": {
|
||||
"login": "marandaneto",
|
||||
"id": 5731772,
|
||||
"node_id": "MDQ6VXNlcjU3MzE3NzI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5731772?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/marandaneto",
|
||||
"html_url": "https://github.com/marandaneto",
|
||||
"followers_url": "https://api.github.com/users/marandaneto/followers",
|
||||
"following_url": "https://api.github.com/users/marandaneto/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/marandaneto/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/marandaneto/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/marandaneto/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/marandaneto/orgs",
|
||||
"repos_url": "https://api.github.com/users/marandaneto/repos",
|
||||
"events_url": "https://api.github.com/users/marandaneto/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/marandaneto/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD32IJM4PCpfy",
|
||||
"tag_name": "android-v3.23.0",
|
||||
"target_commitish": "main",
|
||||
"name": "android-v3.23.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-10-06T09:12:35Z",
|
||||
"updated_at": "2025-10-06T09:13:27Z",
|
||||
"published_at": "2025-10-06T09:13:27Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-android/tarball/android-v3.23.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-android/zipball/android-v3.23.0",
|
||||
"body": "- feat: Android surveys use the new response question id format ([#289](https://github.com/PostHog/posthog-android/pull/289))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-android/releases/252068643",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-android/releases/252068643/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-android/releases/252068643/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-android/releases/tag/server-v1.1.0",
|
||||
"id": 252068643,
|
||||
"author": {
|
||||
"login": "dustinbyrne",
|
||||
"id": 8737782,
|
||||
"node_id": "MDQ6VXNlcjg3Mzc3ODI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8737782?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/dustinbyrne",
|
||||
"html_url": "https://github.com/dustinbyrne",
|
||||
"followers_url": "https://api.github.com/users/dustinbyrne/followers",
|
||||
"following_url": "https://api.github.com/users/dustinbyrne/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/dustinbyrne/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/dustinbyrne/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/dustinbyrne/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/dustinbyrne/orgs",
|
||||
"repos_url": "https://api.github.com/users/dustinbyrne/repos",
|
||||
"events_url": "https://api.github.com/users/dustinbyrne/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/dustinbyrne/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD32IJM4PBkMj",
|
||||
"tag_name": "server-v1.1.0",
|
||||
"target_commitish": "main",
|
||||
"name": "server-v1.1.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-10-03T17:48:05Z",
|
||||
"updated_at": "2025-10-03T17:48:47Z",
|
||||
"published_at": "2025-10-03T17:48:47Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-android/tarball/server-v1.1.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-android/zipball/server-v1.1.0",
|
||||
"body": "- feat: `timestamp` can now be overridden when capturing an event ([#297](https://github.com/PostHog/posthog-android/issues/297))\r\n- feat: Add `groups`, `groupProperties`, `personProperties` overrides to feature flag methods ([#298](https://github.com/PostHog/posthog-android/issues/298))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-android/releases/252065173",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-android/releases/252065173/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-android/releases/252065173/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-android/releases/tag/core-v4.0.0",
|
||||
"id": 252065173,
|
||||
"author": {
|
||||
"login": "dustinbyrne",
|
||||
"id": 8737782,
|
||||
"node_id": "MDQ6VXNlcjg3Mzc3ODI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8737782?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/dustinbyrne",
|
||||
"html_url": "https://github.com/dustinbyrne",
|
||||
"followers_url": "https://api.github.com/users/dustinbyrne/followers",
|
||||
"following_url": "https://api.github.com/users/dustinbyrne/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/dustinbyrne/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/dustinbyrne/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/dustinbyrne/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/dustinbyrne/orgs",
|
||||
"repos_url": "https://api.github.com/users/dustinbyrne/repos",
|
||||
"events_url": "https://api.github.com/users/dustinbyrne/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/dustinbyrne/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD32IJM4PBjWV",
|
||||
"tag_name": "core-v4.0.0",
|
||||
"target_commitish": "main",
|
||||
"name": "core-v4.0.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-10-03T17:31:44Z",
|
||||
"updated_at": "2025-10-03T17:33:27Z",
|
||||
"published_at": "2025-10-03T17:33:27Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-android/tarball/core-v4.0.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-android/zipball/core-v4.0.0",
|
||||
"body": "- feat: Stateless client can override event `timestamp` when capturing an event ([#297](https://github.com/PostHog/posthog-android/issues/297))\r\n- feat: Alter the stateless client interface to support parameterized feature flags groups, group properties and person properties ([#298](https://github.com/PostHog/posthog-android/issues/298))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-android/releases/251589073",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-android/releases/251589073/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-android/releases/251589073/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-android/releases/tag/server-v1.0.3",
|
||||
"id": 251589073,
|
||||
"author": {
|
||||
"login": "dustinbyrne",
|
||||
"id": 8737782,
|
||||
"node_id": "MDQ6VXNlcjg3Mzc3ODI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8737782?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/dustinbyrne",
|
||||
"html_url": "https://github.com/dustinbyrne",
|
||||
"followers_url": "https://api.github.com/users/dustinbyrne/followers",
|
||||
"following_url": "https://api.github.com/users/dustinbyrne/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/dustinbyrne/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/dustinbyrne/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/dustinbyrne/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/dustinbyrne/orgs",
|
||||
"repos_url": "https://api.github.com/users/dustinbyrne/repos",
|
||||
"events_url": "https://api.github.com/users/dustinbyrne/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/dustinbyrne/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD32IJM4O_vHR",
|
||||
"tag_name": "server-v1.0.3",
|
||||
"target_commitish": "main",
|
||||
"name": "server-v1.0.3",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-10-01T22:55:34Z",
|
||||
"updated_at": "2025-10-01T22:56:14Z",
|
||||
"published_at": "2025-10-01T22:56:14Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-android/tarball/server-v1.0.3",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-android/zipball/server-v1.0.3",
|
||||
"body": "- fix: Events now record SDK info such as `$lib` and `$lib_version` ([#296](https://github.com/PostHog/posthog-android/pull/296))\r\n- fix: SDK requests now assign the expected User-Agent ([#296](https://github.com/PostHog/posthog-android/pull/296))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-android/releases/251291195",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-android/releases/251291195/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-android/releases/251291195/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-android/releases/tag/server-v1.0.2",
|
||||
"id": 251291195,
|
||||
"author": {
|
||||
"login": "dustinbyrne",
|
||||
"id": 8737782,
|
||||
"node_id": "MDQ6VXNlcjg3Mzc3ODI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8737782?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/dustinbyrne",
|
||||
"html_url": "https://github.com/dustinbyrne",
|
||||
"followers_url": "https://api.github.com/users/dustinbyrne/followers",
|
||||
"following_url": "https://api.github.com/users/dustinbyrne/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/dustinbyrne/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/dustinbyrne/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/dustinbyrne/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/dustinbyrne/orgs",
|
||||
"repos_url": "https://api.github.com/users/dustinbyrne/repos",
|
||||
"events_url": "https://api.github.com/users/dustinbyrne/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/dustinbyrne/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD32IJM4O-mY7",
|
||||
"tag_name": "server-v1.0.2",
|
||||
"target_commitish": "main",
|
||||
"name": "server-v1.0.2",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-10-01T01:28:27Z",
|
||||
"updated_at": "2025-10-01T01:29:08Z",
|
||||
"published_at": "2025-10-01T01:29:08Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-android/tarball/server-v1.0.2",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-android/zipball/server-v1.0.2",
|
||||
"body": "- fix: Caching of feature flags occurs in constant time ([#294](https://github.com/PostHog/posthog-android/pull/294))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-android/releases/251272121",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-android/releases/251272121/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-android/releases/251272121/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-android/releases/tag/server-v1.0.1",
|
||||
"id": 251272121,
|
||||
"author": {
|
||||
"login": "dustinbyrne",
|
||||
"id": 8737782,
|
||||
"node_id": "MDQ6VXNlcjg3Mzc3ODI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8737782?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/dustinbyrne",
|
||||
"html_url": "https://github.com/dustinbyrne",
|
||||
"followers_url": "https://api.github.com/users/dustinbyrne/followers",
|
||||
"following_url": "https://api.github.com/users/dustinbyrne/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/dustinbyrne/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/dustinbyrne/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/dustinbyrne/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/dustinbyrne/orgs",
|
||||
"repos_url": "https://api.github.com/users/dustinbyrne/repos",
|
||||
"events_url": "https://api.github.com/users/dustinbyrne/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/dustinbyrne/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD32IJM4O-hu5",
|
||||
"tag_name": "server-v1.0.1",
|
||||
"target_commitish": "main",
|
||||
"name": "server-v1.0.1",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-30T23:06:33Z",
|
||||
"updated_at": "2025-09-30T23:07:13Z",
|
||||
"published_at": "2025-09-30T23:07:13Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-android/tarball/server-v1.0.1",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-android/zipball/server-v1.0.1",
|
||||
"body": "- fix: Support deduplication of `$feature_flag_called` events ([#291](https://github.com/PostHog/posthog-android/pull/291))\r\n- fix: Adds missing `featureFlagCacheSize`, `featureFlagCacheMaxAgeMs` mutators to `PostHogConfig` builder ([#291](https://github.com/PostHog/posthog-android/pull/291))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-android/releases/251270930",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-android/releases/251270930/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-android/releases/251270930/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-android/releases/tag/core-v3.23.1",
|
||||
"id": 251270930,
|
||||
"author": {
|
||||
"login": "dustinbyrne",
|
||||
"id": 8737782,
|
||||
"node_id": "MDQ6VXNlcjg3Mzc3ODI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8737782?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/dustinbyrne",
|
||||
"html_url": "https://github.com/dustinbyrne",
|
||||
"followers_url": "https://api.github.com/users/dustinbyrne/followers",
|
||||
"following_url": "https://api.github.com/users/dustinbyrne/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/dustinbyrne/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/dustinbyrne/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/dustinbyrne/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/dustinbyrne/orgs",
|
||||
"repos_url": "https://api.github.com/users/dustinbyrne/repos",
|
||||
"events_url": "https://api.github.com/users/dustinbyrne/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/dustinbyrne/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD32IJM4O-hcS",
|
||||
"tag_name": "core-v3.23.1",
|
||||
"target_commitish": "main",
|
||||
"name": "core-v3.23.1",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-30T22:55:19Z",
|
||||
"updated_at": "2025-09-30T22:56:16Z",
|
||||
"published_at": "2025-09-30T22:56:16Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-android/tarball/core-v3.23.1",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-android/zipball/core-v3.23.1",
|
||||
"body": "- fix: `PostHogStateless` now deduplicates `$feature_flag_called` events ([#293](https://github.com/PostHog/posthog-android/pull/293))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-android/releases/250919440",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-android/releases/250919440/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-android/releases/250919440/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-android/releases/tag/server-v1.0.0",
|
||||
"id": 250919440,
|
||||
"author": {
|
||||
"login": "dustinbyrne",
|
||||
"id": 8737782,
|
||||
"node_id": "MDQ6VXNlcjg3Mzc3ODI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8737782?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/dustinbyrne",
|
||||
"html_url": "https://github.com/dustinbyrne",
|
||||
"followers_url": "https://api.github.com/users/dustinbyrne/followers",
|
||||
"following_url": "https://api.github.com/users/dustinbyrne/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/dustinbyrne/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/dustinbyrne/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/dustinbyrne/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/dustinbyrne/orgs",
|
||||
"repos_url": "https://api.github.com/users/dustinbyrne/repos",
|
||||
"events_url": "https://api.github.com/users/dustinbyrne/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/dustinbyrne/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD32IJM4O9LoQ",
|
||||
"tag_name": "server-v1.0.0",
|
||||
"target_commitish": "main",
|
||||
"name": "server-v1.0.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-29T19:56:09Z",
|
||||
"updated_at": "2025-09-29T19:57:25Z",
|
||||
"published_at": "2025-09-29T19:57:25Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-android/tarball/server-v1.0.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-android/zipball/server-v1.0.0",
|
||||
"body": "- Initial release ([#288](https://github.com/PostHog/posthog-android/pull/288))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-android/releases/250915148",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-android/releases/250915148/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-android/releases/250915148/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-android/releases/tag/core-v3.23.0",
|
||||
"id": 250915148,
|
||||
"author": {
|
||||
"login": "dustinbyrne",
|
||||
"id": 8737782,
|
||||
"node_id": "MDQ6VXNlcjg3Mzc3ODI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8737782?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/dustinbyrne",
|
||||
"html_url": "https://github.com/dustinbyrne",
|
||||
"followers_url": "https://api.github.com/users/dustinbyrne/followers",
|
||||
"following_url": "https://api.github.com/users/dustinbyrne/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/dustinbyrne/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/dustinbyrne/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/dustinbyrne/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/dustinbyrne/orgs",
|
||||
"repos_url": "https://api.github.com/users/dustinbyrne/repos",
|
||||
"events_url": "https://api.github.com/users/dustinbyrne/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/dustinbyrne/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD32IJM4O9KlM",
|
||||
"tag_name": "core-v3.23.0",
|
||||
"target_commitish": "main",
|
||||
"name": "core-v3.23.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-29T19:39:50Z",
|
||||
"updated_at": "2025-09-29T19:40:38Z",
|
||||
"published_at": "2025-09-29T19:40:38Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-android/tarball/core-v3.23.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-android/zipball/core-v3.23.0",
|
||||
"body": "- feat: `PostHogConfig` now accepts queue and remote config constructors"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-android/releases/250046619",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-android/releases/250046619/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-android/releases/250046619/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-android/releases/tag/3.22.0",
|
||||
"id": 250046619,
|
||||
"author": {
|
||||
"login": "dustinbyrne",
|
||||
"id": 8737782,
|
||||
"node_id": "MDQ6VXNlcjg3Mzc3ODI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8737782?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/dustinbyrne",
|
||||
"html_url": "https://github.com/dustinbyrne",
|
||||
"followers_url": "https://api.github.com/users/dustinbyrne/followers",
|
||||
"following_url": "https://api.github.com/users/dustinbyrne/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/dustinbyrne/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/dustinbyrne/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/dustinbyrne/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/dustinbyrne/orgs",
|
||||
"repos_url": "https://api.github.com/users/dustinbyrne/repos",
|
||||
"events_url": "https://api.github.com/users/dustinbyrne/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/dustinbyrne/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD32IJM4O52ib",
|
||||
"tag_name": "3.22.0",
|
||||
"target_commitish": "main",
|
||||
"name": "3.22.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-25T14:47:42Z",
|
||||
"updated_at": "2025-09-29T19:57:46Z",
|
||||
"published_at": "2025-09-25T15:04:03Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-android/tarball/3.22.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-android/zipball/3.22.0",
|
||||
"body": "- feat: Add a server-side stateless interface, `PostHogStateless` ([#287](https://github.com/PostHog/posthog-android/pull/287))"
|
||||
}
|
||||
]
|
||||
442
dags/tests/fixtures/releases/posthog_flutter_releases.json
vendored
Normal file
@@ -0,0 +1,442 @@
|
||||
[
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/252381053",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/252381053/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-flutter/releases/252381053/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-flutter/releases/tag/5.6.0",
|
||||
"id": 252381053,
|
||||
"author": {
|
||||
"login": "marandaneto",
|
||||
"id": 5731772,
|
||||
"node_id": "MDQ6VXNlcjU3MzE3NzI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5731772?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/marandaneto",
|
||||
"html_url": "https://github.com/marandaneto",
|
||||
"followers_url": "https://api.github.com/users/marandaneto/followers",
|
||||
"following_url": "https://api.github.com/users/marandaneto/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/marandaneto/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/marandaneto/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/marandaneto/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/marandaneto/orgs",
|
||||
"repos_url": "https://api.github.com/users/marandaneto/repos",
|
||||
"events_url": "https://api.github.com/users/marandaneto/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/marandaneto/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOEGNHSM4PCwd9",
|
||||
"tag_name": "5.6.0",
|
||||
"target_commitish": "main",
|
||||
"name": "5.6.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-10-06T11:13:35Z",
|
||||
"updated_at": "2025-10-06T11:14:06Z",
|
||||
"published_at": "2025-10-06T11:14:06Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-flutter/tarball/5.6.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-flutter/zipball/5.6.0",
|
||||
"body": "- feat: surveys use the new response question id format ([#210](https://github.com/PostHog/posthog-flutter/pull/210))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/246693210",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/246693210/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-flutter/releases/246693210/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-flutter/releases/tag/5.5.0",
|
||||
"id": 246693210,
|
||||
"author": {
|
||||
"login": "marandaneto",
|
||||
"id": 5731772,
|
||||
"node_id": "MDQ6VXNlcjU3MzE3NzI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5731772?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/marandaneto",
|
||||
"html_url": "https://github.com/marandaneto",
|
||||
"followers_url": "https://api.github.com/users/marandaneto/followers",
|
||||
"following_url": "https://api.github.com/users/marandaneto/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/marandaneto/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/marandaneto/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/marandaneto/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/marandaneto/orgs",
|
||||
"repos_url": "https://api.github.com/users/marandaneto/repos",
|
||||
"events_url": "https://api.github.com/users/marandaneto/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/marandaneto/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOEGNHSM4OtD1a",
|
||||
"tag_name": "5.5.0",
|
||||
"target_commitish": "main",
|
||||
"name": "5.5.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-12T06:40:55Z",
|
||||
"updated_at": "2025-09-12T06:41:18Z",
|
||||
"published_at": "2025-09-12T06:41:18Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-flutter/tarball/5.5.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-flutter/zipball/5.5.0",
|
||||
"body": "- chore: Android plugin sets compileSdkVersion to flutter.compileSdkVersion instead of hardcoded ([#207](https://github.com/PostHog/posthog-flutter/pull/207))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/245925464",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/245925464/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-flutter/releases/245925464/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-flutter/releases/tag/5.4.3",
|
||||
"id": 245925464,
|
||||
"author": {
|
||||
"login": "marandaneto",
|
||||
"id": 5731772,
|
||||
"node_id": "MDQ6VXNlcjU3MzE3NzI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5731772?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/marandaneto",
|
||||
"html_url": "https://github.com/marandaneto",
|
||||
"followers_url": "https://api.github.com/users/marandaneto/followers",
|
||||
"following_url": "https://api.github.com/users/marandaneto/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/marandaneto/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/marandaneto/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/marandaneto/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/marandaneto/orgs",
|
||||
"repos_url": "https://api.github.com/users/marandaneto/repos",
|
||||
"events_url": "https://api.github.com/users/marandaneto/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/marandaneto/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOEGNHSM4OqIZY",
|
||||
"tag_name": "5.4.3",
|
||||
"target_commitish": "main",
|
||||
"name": "5.4.3",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-09T17:32:00Z",
|
||||
"updated_at": "2025-09-09T17:32:48Z",
|
||||
"published_at": "2025-09-09T17:32:48Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-flutter/tarball/5.4.3",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-flutter/zipball/5.4.3",
|
||||
"body": "- fix: Android back button wasn't cleaning up the Survey resources ([#205](https://github.com/PostHog/posthog-flutter/pull/205))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/244357920",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/244357920/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-flutter/releases/244357920/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-flutter/releases/tag/5.4.2",
|
||||
"id": 244357920,
|
||||
"author": {
|
||||
"login": "marandaneto",
|
||||
"id": 5731772,
|
||||
"node_id": "MDQ6VXNlcjU3MzE3NzI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5731772?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/marandaneto",
|
||||
"html_url": "https://github.com/marandaneto",
|
||||
"followers_url": "https://api.github.com/users/marandaneto/followers",
|
||||
"following_url": "https://api.github.com/users/marandaneto/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/marandaneto/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/marandaneto/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/marandaneto/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/marandaneto/orgs",
|
||||
"repos_url": "https://api.github.com/users/marandaneto/repos",
|
||||
"events_url": "https://api.github.com/users/marandaneto/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/marandaneto/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOEGNHSM4OkJsg",
|
||||
"tag_name": "5.4.2",
|
||||
"target_commitish": "main",
|
||||
"name": "5.4.2",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-03T08:17:11Z",
|
||||
"updated_at": "2025-09-03T08:17:32Z",
|
||||
"published_at": "2025-09-03T08:17:32Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-flutter/tarball/5.4.2",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-flutter/zipball/5.4.2",
|
||||
"body": "- fix: mask TextField widgets automatically if obscureText is enabled (([#204](https://github.com/PostHog/posthog-flutter/pull/204)))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/243503774",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/243503774/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-flutter/releases/243503774/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-flutter/releases/tag/5.4.1",
|
||||
"id": 243503774,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOEGNHSM4Og5Ke",
|
||||
"tag_name": "5.4.1",
|
||||
"target_commitish": "main",
|
||||
"name": "5.4.1",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-29T14:53:11Z",
|
||||
"updated_at": "2025-08-29T14:53:58Z",
|
||||
"published_at": "2025-08-29T14:53:58Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-flutter/tarball/5.4.1",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-flutter/zipball/5.4.1",
|
||||
"body": "- chore: update posthog-ios dependency to min. 3.31.0 (([#202](https://github.com/PostHog/posthog-flutter/pull/202)))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/243148953",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/243148953/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-flutter/releases/243148953/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-flutter/releases/tag/5.4.0",
|
||||
"id": 243148953,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOEGNHSM4OfiiZ",
|
||||
"tag_name": "5.4.0",
|
||||
"target_commitish": "main",
|
||||
"name": "5.4.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-28T11:49:16Z",
|
||||
"updated_at": "2025-08-28T11:50:36Z",
|
||||
"published_at": "2025-08-28T11:50:36Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-flutter/tarball/5.4.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-flutter/zipball/5.4.0",
|
||||
"body": "- feat: surveys for Android ([#198](https://github.com/PostHog/posthog-flutter/pull/198))\r\n - See how to setup in [Surveys docs](https://posthog.com/docs/surveys/installation?tab=Flutter)"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/239641257",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/239641257/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-flutter/releases/239641257/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-flutter/releases/tag/5.3.1",
|
||||
"id": 239641257,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOEGNHSM4OSKKp",
|
||||
"tag_name": "5.3.1",
|
||||
"target_commitish": "main",
|
||||
"name": "5.3.1",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-13T10:55:15Z",
|
||||
"updated_at": "2025-08-13T10:55:49Z",
|
||||
"published_at": "2025-08-13T10:55:49Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-flutter/tarball/5.3.1",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-flutter/zipball/5.3.1",
|
||||
"body": "- fix: don't render HTML content ([#196](https://github.com/PostHog/posthog-flutter/pull/196))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/238963964",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/238963964/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-flutter/releases/238963964/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-flutter/releases/tag/5.3.0",
|
||||
"id": 238963964,
|
||||
"author": {
|
||||
"login": "marandaneto",
|
||||
"id": 5731772,
|
||||
"node_id": "MDQ6VXNlcjU3MzE3NzI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5731772?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/marandaneto",
|
||||
"html_url": "https://github.com/marandaneto",
|
||||
"followers_url": "https://api.github.com/users/marandaneto/followers",
|
||||
"following_url": "https://api.github.com/users/marandaneto/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/marandaneto/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/marandaneto/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/marandaneto/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/marandaneto/orgs",
|
||||
"repos_url": "https://api.github.com/users/marandaneto/repos",
|
||||
"events_url": "https://api.github.com/users/marandaneto/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/marandaneto/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOEGNHSM4OPkz8",
|
||||
"tag_name": "5.3.0",
|
||||
"target_commitish": "main",
|
||||
"name": "5.3.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-11T10:17:48Z",
|
||||
"updated_at": "2025-08-11T10:18:07Z",
|
||||
"published_at": "2025-08-11T10:18:07Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-flutter/tarball/5.3.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-flutter/zipball/5.3.0",
|
||||
"body": "- chore: update languageVersion and apiVersion from 1.6 to 1.8 on Android to be compatible with Kotlin 2.2 ([#193](https://github.com/PostHog/posthog-flutter/pull/193))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/238562157",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/238562157/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-flutter/releases/238562157/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-flutter/releases/tag/5.2.0",
|
||||
"id": 238562157,
|
||||
"author": {
|
||||
"login": "marandaneto",
|
||||
"id": 5731772,
|
||||
"node_id": "MDQ6VXNlcjU3MzE3NzI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5731772?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/marandaneto",
|
||||
"html_url": "https://github.com/marandaneto",
|
||||
"followers_url": "https://api.github.com/users/marandaneto/followers",
|
||||
"following_url": "https://api.github.com/users/marandaneto/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/marandaneto/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/marandaneto/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/marandaneto/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/marandaneto/orgs",
|
||||
"repos_url": "https://api.github.com/users/marandaneto/repos",
|
||||
"events_url": "https://api.github.com/users/marandaneto/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/marandaneto/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOEGNHSM4OOCtt",
|
||||
"tag_name": "5.2.0",
|
||||
"target_commitish": "main",
|
||||
"name": "5.2.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-08T11:19:45Z",
|
||||
"updated_at": "2025-08-08T11:20:18Z",
|
||||
"published_at": "2025-08-08T11:20:18Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-flutter/tarball/5.2.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-flutter/zipball/5.2.0",
|
||||
"body": "- feat: add `isOptOut` method to check if the current user is opted out of data capture. ([#190](https://github.com/PostHog/posthog-flutter/pull/190))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/234169457",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-flutter/releases/234169457/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-flutter/releases/234169457/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-flutter/releases/tag/5.1.0",
|
||||
"id": 234169457,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOEGNHSM4N9SRx",
|
||||
"tag_name": "5.1.0",
|
||||
"target_commitish": "main",
|
||||
"name": "5.1.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-07-22T08:57:44Z",
|
||||
"updated_at": "2025-07-22T15:03:27Z",
|
||||
"published_at": "2025-07-22T09:00:06Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-flutter/tarball/5.1.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-flutter/zipball/5.1.0",
|
||||
"body": "- feat: surveys for iOS ([#188](https://github.com/PostHog/posthog-flutter/pull/188))\r\n\t- See how to setup in [Surveys docs](https://posthog.com/docs/surveys/installation?tab=Flutter)"
|
||||
}
|
||||
]
|
||||
452
dags/tests/fixtures/releases/posthog_go_releases.json
vendored
Normal file
@@ -0,0 +1,452 @@
|
||||
[
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-go/releases/249150942",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-go/releases/249150942/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-go/releases/249150942/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-go/releases/tag/v1.6.10",
|
||||
"id": 249150942,
|
||||
"author": {
|
||||
"login": "andyzzhao",
|
||||
"id": 34008309,
|
||||
"node_id": "MDQ6VXNlcjM0MDA4MzA5",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/34008309?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/andyzzhao",
|
||||
"html_url": "https://github.com/andyzzhao",
|
||||
"followers_url": "https://api.github.com/users/andyzzhao/followers",
|
||||
"following_url": "https://api.github.com/users/andyzzhao/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/andyzzhao/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/andyzzhao/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/andyzzhao/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/andyzzhao/orgs",
|
||||
"repos_url": "https://api.github.com/users/andyzzhao/repos",
|
||||
"events_url": "https://api.github.com/users/andyzzhao/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/andyzzhao/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODnBFYM4O2b3e",
|
||||
"tag_name": "v1.6.10",
|
||||
"target_commitish": "master",
|
||||
"name": "v1.6.10",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-22T20:17:49Z",
|
||||
"updated_at": "2025-09-22T20:23:13Z",
|
||||
"published_at": "2025-09-22T20:23:13Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-go/tarball/v1.6.10",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-go/zipball/v1.6.10",
|
||||
"body": "## What's Changed\r\n* fix: don't sort condition sets with variant overrides to top by @andyzzhao in https://github.com/PostHog/posthog-go/pull/127\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-go/compare/v1.6.8...v1.6.10",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-go/releases/238435487",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-go/releases/238435487/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-go/releases/238435487/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-go/releases/tag/v1.6.2",
|
||||
"id": 238435487,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODnBFYM4ONjyf",
|
||||
"tag_name": "v1.6.2",
|
||||
"target_commitish": "master",
|
||||
"name": "v1.6.2",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-07T20:47:09Z",
|
||||
"updated_at": "2025-08-07T20:48:20Z",
|
||||
"published_at": "2025-08-07T20:48:20Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-go/tarball/v1.6.2",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-go/zipball/v1.6.2",
|
||||
"body": "## What's Changed\r\n* fix(flags): Pass project API key in remote_config requests by @haacked in https://github.com/PostHog/posthog-go/pull/118\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-go/compare/v1.6.1...v1.6.2",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-go/releases/224450943",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-go/releases/224450943/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-go/releases/224450943/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-go/releases/tag/v1.5.12",
|
||||
"id": 224450943,
|
||||
"author": {
|
||||
"login": "orian",
|
||||
"id": 144554,
|
||||
"node_id": "MDQ6VXNlcjE0NDU1NA==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/144554?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/orian",
|
||||
"html_url": "https://github.com/orian",
|
||||
"followers_url": "https://api.github.com/users/orian/followers",
|
||||
"following_url": "https://api.github.com/users/orian/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/orian/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/orian/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/orian/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/orian/orgs",
|
||||
"repos_url": "https://api.github.com/users/orian/repos",
|
||||
"events_url": "https://api.github.com/users/orian/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/orian/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODnBFYM4NYNl_",
|
||||
"tag_name": "v1.5.12",
|
||||
"target_commitish": "master",
|
||||
"name": "v1.5.12",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-06-10T21:00:34Z",
|
||||
"updated_at": "2025-06-10T21:53:30Z",
|
||||
"published_at": "2025-06-10T21:53:30Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-go/tarball/v1.5.12",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-go/zipball/v1.5.12",
|
||||
"body": "## What's Changed\r\n\r\nThis release changes the behavior of the library slightly, it validates the correct endpoint when creating a client.\r\nIt also fixes a bug: a limit of concurrent HTTP requests to be send by a library was broken.\r\n\r\n* chore: move URL parsing errors to init by @orian in https://github.com/PostHog/posthog-go/pull/109\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-go/compare/v1.5.11...v1.5.12",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-go/releases/221758270",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-go/releases/221758270/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-go/releases/221758270/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-go/releases/tag/v1.5.11",
|
||||
"id": 221758270,
|
||||
"author": {
|
||||
"login": "orian",
|
||||
"id": 144554,
|
||||
"node_id": "MDQ6VXNlcjE0NDU1NA==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/144554?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/orian",
|
||||
"html_url": "https://github.com/orian",
|
||||
"followers_url": "https://api.github.com/users/orian/followers",
|
||||
"following_url": "https://api.github.com/users/orian/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/orian/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/orian/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/orian/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/orian/orgs",
|
||||
"repos_url": "https://api.github.com/users/orian/repos",
|
||||
"events_url": "https://api.github.com/users/orian/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/orian/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODnBFYM4NN8M-",
|
||||
"tag_name": "v1.5.11",
|
||||
"target_commitish": "master",
|
||||
"name": "v1.5.11",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-05-29T07:36:55Z",
|
||||
"updated_at": "2025-05-29T08:19:54Z",
|
||||
"published_at": "2025-05-29T08:19:54Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-go/tarball/v1.5.11",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-go/zipball/v1.5.11",
|
||||
"body": "## What's Changed\r\n\r\n* fix: race in accessing feature flags by @orian in https://github.com/PostHog/posthog-go/pull/107\r\n* extended test coverage\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-go/compare/v1.5.9...v1.5.11",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-go/releases/220748197",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-go/releases/220748197/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-go/releases/220748197/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-go/releases/tag/v1.5.9",
|
||||
"id": 220748197,
|
||||
"author": {
|
||||
"login": "orian",
|
||||
"id": 144554,
|
||||
"node_id": "MDQ6VXNlcjE0NDU1NA==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/144554?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/orian",
|
||||
"html_url": "https://github.com/orian",
|
||||
"followers_url": "https://api.github.com/users/orian/followers",
|
||||
"following_url": "https://api.github.com/users/orian/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/orian/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/orian/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/orian/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/orian/orgs",
|
||||
"repos_url": "https://api.github.com/users/orian/repos",
|
||||
"events_url": "https://api.github.com/users/orian/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/orian/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODnBFYM4NKFml",
|
||||
"tag_name": "v1.5.9",
|
||||
"target_commitish": "master",
|
||||
"name": "v1.5.9",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-05-23T22:36:55Z",
|
||||
"updated_at": "2025-05-23T22:41:59Z",
|
||||
"published_at": "2025-05-23T22:41:59Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-go/tarball/v1.5.9",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-go/zipball/v1.5.9",
|
||||
"body": "## Breaking change\r\n\r\nStarting from this version, by default Go library sends `$geoip_disable` property on capture events and `geoip_disable` argument to flags endpoint. This can be overridden by using explicitly setting `Config{DisableGeoIP: &ptr.False}`\r\n\r\n## What's Changed\r\n* fix: $group_key should be override in local eval by @orian in https://github.com/PostHog/posthog-go/pull/105\r\n* feat: add DisableGeoIP option by @orian in https://github.com/PostHog/posthog-go/pull/104\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-go/compare/v1.5.7...v1.5.9",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-go/releases/220119852",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-go/releases/220119852/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-go/releases/220119852/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-go/releases/tag/v1.5.7",
|
||||
"id": 220119852,
|
||||
"author": {
|
||||
"login": "orian",
|
||||
"id": 144554,
|
||||
"node_id": "MDQ6VXNlcjE0NDU1NA==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/144554?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/orian",
|
||||
"html_url": "https://github.com/orian",
|
||||
"followers_url": "https://api.github.com/users/orian/followers",
|
||||
"following_url": "https://api.github.com/users/orian/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/orian/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/orian/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/orian/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/orian/orgs",
|
||||
"repos_url": "https://api.github.com/users/orian/repos",
|
||||
"events_url": "https://api.github.com/users/orian/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/orian/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODnBFYM4NHsMs",
|
||||
"tag_name": "v1.5.7",
|
||||
"target_commitish": "master",
|
||||
"name": "v1.5.7",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-05-21T15:57:25Z",
|
||||
"updated_at": "2025-05-21T15:58:58Z",
|
||||
"published_at": "2025-05-21T15:58:58Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-go/tarball/v1.5.7",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-go/zipball/v1.5.7",
|
||||
"body": "## What's Changed\r\n\r\n* fix: make RolloutPercentage *float64 to match backend by @orian in https://github.com/PostHog/posthog-go/pull/103\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-go/compare/v1.5.6...v1.5.7",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-go/releases/220107258",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-go/releases/220107258/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-go/releases/220107258/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-go/releases/tag/v1.5.6",
|
||||
"id": 220107258,
|
||||
"author": {
|
||||
"login": "orian",
|
||||
"id": 144554,
|
||||
"node_id": "MDQ6VXNlcjE0NDU1NA==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/144554?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/orian",
|
||||
"html_url": "https://github.com/orian",
|
||||
"followers_url": "https://api.github.com/users/orian/followers",
|
||||
"following_url": "https://api.github.com/users/orian/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/orian/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/orian/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/orian/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/orian/orgs",
|
||||
"repos_url": "https://api.github.com/users/orian/repos",
|
||||
"events_url": "https://api.github.com/users/orian/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/orian/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODnBFYM4NHpH6",
|
||||
"tag_name": "v1.5.6",
|
||||
"target_commitish": "master",
|
||||
"name": "v1.5.6",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-05-21T15:08:46Z",
|
||||
"updated_at": "2025-05-21T15:14:36Z",
|
||||
"published_at": "2025-05-21T15:14:36Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-go/tarball/v1.5.6",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-go/zipball/v1.5.6",
|
||||
"body": "## What's Changed\r\n* fix: the local evaluation was not using rollout percentage by @orian in https://github.com/PostHog/posthog-go/pull/102\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-go/compare/v1.5.4...v1.5.6",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-go/releases/218283710",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-go/releases/218283710/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-go/releases/218283710/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-go/releases/tag/v1.5.5",
|
||||
"id": 218283710,
|
||||
"author": {
|
||||
"login": "orian",
|
||||
"id": 144554,
|
||||
"node_id": "MDQ6VXNlcjE0NDU1NA==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/144554?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/orian",
|
||||
"html_url": "https://github.com/orian",
|
||||
"followers_url": "https://api.github.com/users/orian/followers",
|
||||
"following_url": "https://api.github.com/users/orian/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/orian/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/orian/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/orian/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/orian/orgs",
|
||||
"repos_url": "https://api.github.com/users/orian/repos",
|
||||
"events_url": "https://api.github.com/users/orian/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/orian/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODnBFYM4NAr6-",
|
||||
"tag_name": "v1.5.5",
|
||||
"target_commitish": "master",
|
||||
"name": "v1.5.5",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-05-13T14:04:32Z",
|
||||
"updated_at": "2025-05-13T14:05:29Z",
|
||||
"published_at": "2025-05-13T14:05:29Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-go/tarball/v1.5.5",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-go/zipball/v1.5.5",
|
||||
"body": "## What's Changed\r\n* chore: remove own cache implementation, use a thread safe LRU cache by @orian in https://github.com/PostHog/posthog-go/pull/99\r\n\r\n## New Contributors\r\n* @orian made their first contribution in https://github.com/PostHog/posthog-go/pull/99\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-go/compare/v1.5.3...v1.5.5",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-go/releases/213386461",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-go/releases/213386461/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-go/releases/213386461/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-go/releases/tag/v1.4.9",
|
||||
"id": 213386461,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODnBFYM4MuATd",
|
||||
"tag_name": "v1.4.9",
|
||||
"target_commitish": "master",
|
||||
"name": "v1.4.9",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-04-18T19:38:33Z",
|
||||
"updated_at": "2025-04-18T19:40:57Z",
|
||||
"published_at": "2025-04-18T19:40:57Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-go/tarball/v1.4.9",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-go/zipball/v1.4.9",
|
||||
"body": "## What's Changed\r\n\r\n* Allow `condition_index` to be nullable by @haacked in https://github.com/PostHog/posthog-go/pull/93\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-go/compare/v1.4.7...v1.4.9",
|
||||
"mentions_count": 1
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-go/releases/209950833",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-go/releases/209950833/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-go/releases/209950833/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-go/releases/tag/v1.4.7",
|
||||
"id": 209950833,
|
||||
"author": {
|
||||
"login": "haacked",
|
||||
"id": 19977,
|
||||
"node_id": "MDQ6VXNlcjE5OTc3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19977?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/haacked",
|
||||
"html_url": "https://github.com/haacked",
|
||||
"followers_url": "https://api.github.com/users/haacked/followers",
|
||||
"following_url": "https://api.github.com/users/haacked/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/haacked/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/haacked/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/haacked/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/haacked/orgs",
|
||||
"repos_url": "https://api.github.com/users/haacked/repos",
|
||||
"events_url": "https://api.github.com/users/haacked/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/haacked/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODnBFYM4Mg5hx",
|
||||
"tag_name": "v1.4.7",
|
||||
"target_commitish": "master",
|
||||
"name": "v1.4.7",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-04-02T20:36:28Z",
|
||||
"updated_at": "2025-04-02T20:36:54Z",
|
||||
"published_at": "2025-04-02T20:36:54Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-go/tarball/v1.4.7",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-go/zipball/v1.4.7",
|
||||
"body": "## What's Changed\r\n\r\n* chore(flags): Decide v4 support - adds version, id, reason, and requestId to `$feature_flag_called` events by @haacked in https://github.com/PostHog/posthog-go/pull/91\r\n\r\n\r\n**Full Changelog**: https://github.com/PostHog/posthog-go/compare/v1.4.5...v1.4.7",
|
||||
"mentions_count": 1
|
||||
}
|
||||
]
|
||||
456
dags/tests/fixtures/releases/posthog_ios_releases.json
vendored
Normal file
@@ -0,0 +1,456 @@
|
||||
[
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/252017583",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-ios/releases/252017583/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-ios/releases/252017583/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-ios/releases/tag/3.32.0",
|
||||
"id": 252017583,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD15mg84PBXuv",
|
||||
"tag_name": "3.32.0",
|
||||
"target_commitish": "main",
|
||||
"name": "3.32.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-10-03T14:20:55Z",
|
||||
"updated_at": "2025-10-03T14:21:35Z",
|
||||
"published_at": "2025-10-03T14:21:35Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-ios/tarball/3.32.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-ios/zipball/3.32.0",
|
||||
"body": "- feat: iOS surveys use the new response question id format ([#383](https://github.com/PostHog/posthog-ios/pull/383))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/243470681",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-ios/releases/243470681/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-ios/releases/243470681/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-ios/releases/tag/3.31.0",
|
||||
"id": 243470681,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD15mg84OgxFZ",
|
||||
"tag_name": "3.31.0",
|
||||
"target_commitish": "main",
|
||||
"name": "3.31.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-29T12:57:22Z",
|
||||
"updated_at": "2025-08-29T12:57:56Z",
|
||||
"published_at": "2025-08-29T12:57:56Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-ios/tarball/3.31.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-ios/zipball/3.31.0",
|
||||
"body": "- feat: surveys GA ([#381](https://github.com/PostHog/posthog-ios/pull/381))\r\n> Note: Surveys are now enabled by default"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/239422182",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-ios/releases/239422182/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-ios/releases/239422182/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-ios/releases/tag/3.30.1",
|
||||
"id": 239422182,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD15mg84ORUrm",
|
||||
"tag_name": "3.30.1",
|
||||
"target_commitish": "main",
|
||||
"name": "3.30.1",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-12T16:22:14Z",
|
||||
"updated_at": "2025-08-12T16:23:14Z",
|
||||
"published_at": "2025-08-12T16:23:14Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-ios/tarball/3.30.1",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-ios/zipball/3.30.1",
|
||||
"body": "- fix: map missing content type for Surveys ([#377](https://github.com/PostHog/posthog-ios/pull/377))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/235627718",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-ios/releases/235627718/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-ios/releases/235627718/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-ios/releases/tag/3.30.0",
|
||||
"id": 235627718,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD15mg84OC2TG",
|
||||
"tag_name": "3.30.0",
|
||||
"target_commitish": "main",
|
||||
"name": "3.30.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-07-28T12:51:13Z",
|
||||
"updated_at": "2025-07-28T12:51:44Z",
|
||||
"published_at": "2025-07-28T12:51:44Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-ios/tarball/3.30.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-ios/zipball/3.30.0",
|
||||
"body": "- feat: add person and group properties for feature flags ([#373](https://github.com/PostHog/posthog-ios/pull/373))\r\n- feat: support default properties for feature flag evaluation ([#375](https://github.com/PostHog/posthog-ios/pull/375))\r\n"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/232519585",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-ios/releases/232519585/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-ios/releases/232519585/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-ios/releases/tag/3.29.0",
|
||||
"id": 232519585,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD15mg84N2_eh",
|
||||
"tag_name": "3.29.0",
|
||||
"target_commitish": "main",
|
||||
"name": "3.29.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-07-15T12:53:07Z",
|
||||
"updated_at": "2025-07-15T13:12:21Z",
|
||||
"published_at": "2025-07-15T13:12:21Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-ios/tarball/3.29.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-ios/zipball/3.29.0",
|
||||
"body": "- feat: add support for custom survey UI ([#369](https://github.com/PostHog/posthog-ios/pull/369))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/232179212",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-ios/releases/232179212/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-ios/releases/232179212/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-ios/releases/tag/3.28.3",
|
||||
"id": 232179212,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD15mg84N1sYM",
|
||||
"tag_name": "3.28.3",
|
||||
"target_commitish": "main",
|
||||
"name": "3.28.3",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-07-14T10:10:15Z",
|
||||
"updated_at": "2025-07-14T10:23:58Z",
|
||||
"published_at": "2025-07-14T10:23:58Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-ios/tarball/3.28.3",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-ios/zipball/3.28.3",
|
||||
"body": "- fix: don't clear flags on remote config error or if hasFeatureFlags is nil ([#368](https://github.com/PostHog/posthog-ios/pull/368))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/227971024",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-ios/releases/227971024/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-ios/releases/227971024/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-ios/releases/tag/3.28.2",
|
||||
"id": 227971024,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD15mg84Nlo_Q",
|
||||
"tag_name": "3.28.2",
|
||||
"target_commitish": "main",
|
||||
"name": "3.28.2",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-06-26T09:51:29Z",
|
||||
"updated_at": "2025-06-26T10:22:47Z",
|
||||
"published_at": "2025-06-26T10:22:47Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-ios/tarball/3.28.2",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-ios/zipball/3.28.2",
|
||||
"body": "- fix: survey question header padding ([#365](https://github.com/PostHog/posthog-ios/pull/365))\r\n- fix: session replay perforamnce improvements ([#364](https://github.com/PostHog/posthog-ios/pull/364))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/227968670",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-ios/releases/227968670/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-ios/releases/227968670/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-ios/releases/tag/3.28.1",
|
||||
"id": 227968670,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD15mg84Nloae",
|
||||
"tag_name": "3.28.1",
|
||||
"target_commitish": "main",
|
||||
"name": "3.28.1",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-06-23T17:21:39Z",
|
||||
"updated_at": "2025-06-26T10:12:29Z",
|
||||
"published_at": "2025-06-26T10:12:29Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-ios/tarball/3.28.1",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-ios/zipball/3.28.1",
|
||||
"body": "- fix: surveys decoding error ([#363](https://github.com/PostHog/posthog-ios/pull/363))"
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/226509765",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-ios/releases/226509765/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-ios/releases/226509765/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-ios/releases/tag/3.28.0",
|
||||
"id": 226509765,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD15mg84NgEPF",
|
||||
"tag_name": "3.28.0",
|
||||
"target_commitish": "main",
|
||||
"name": "3.28.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-06-19T15:14:13Z",
|
||||
"updated_at": "2025-06-19T17:56:54Z",
|
||||
"published_at": "2025-06-19T17:56:54Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-ios/tarball/3.28.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-ios/zipball/3.28.0",
|
||||
"body": "- feat: add support for beforeSend function to edit or drop events ([#357](https://github.com/PostHog/posthog-ios/pull/357))\r\n - Thanks @wowrumal and @haritowa ❤️",
|
||||
"mentions_count": 2
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/225673519",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-ios/releases/225673519/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-ios/releases/225673519/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-ios/releases/tag/3.27.0",
|
||||
"id": 225673519,
|
||||
"author": {
|
||||
"login": "ioannisj",
|
||||
"id": 183369585,
|
||||
"node_id": "U_kgDOCu3_cQ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/183369585?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ioannisj",
|
||||
"html_url": "https://github.com/ioannisj",
|
||||
"followers_url": "https://api.github.com/users/ioannisj/followers",
|
||||
"following_url": "https://api.github.com/users/ioannisj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ioannisj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ioannisj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ioannisj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ioannisj/orgs",
|
||||
"repos_url": "https://api.github.com/users/ioannisj/repos",
|
||||
"events_url": "https://api.github.com/users/ioannisj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ioannisj/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDOD15mg84Nc4Ev",
|
||||
"tag_name": "3.27.0",
|
||||
"target_commitish": "main",
|
||||
"name": "3.27.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-06-16T19:45:16Z",
|
||||
"updated_at": "2025-06-16T20:09:55Z",
|
||||
"published_at": "2025-06-16T20:09:55Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-ios/tarball/3.27.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-ios/zipball/3.27.0",
|
||||
"body": "- fix: unify storage path for `appGroupIdentifier` across targets ([#356](https://github.com/PostHog/posthog-ios/pull/356))\r\n\t- Thanx @hoppsen ❤️\r\n- fix: do not call flags callback with invalid flags ([#355](https://github.com/PostHog/posthog-ios/pull/355))\r\n- use new `/flags` endpoint instead of `/decide` ([#345](https://github.com/PostHog/posthog-ios/pull/345))",
|
||||
"reactions": {
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-ios/releases/225673519/reactions",
|
||||
"total_count": 1,
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
"laugh": 0,
|
||||
"hooray": 0,
|
||||
"confused": 0,
|
||||
"heart": 1,
|
||||
"rocket": 0,
|
||||
"eyes": 0
|
||||
},
|
||||
"mentions_count": 1
|
||||
}
|
||||
]
|
||||
1102
dags/tests/fixtures/releases/posthog_js_releases.json
vendored
Normal file
442
dags/tests/fixtures/releases/posthog_python_releases.json
vendored
Normal file
@@ -0,0 +1,442 @@
|
||||
[
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-python/releases/249121280",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-python/releases/249121280/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-python/releases/249121280/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-python/releases/tag/v6.7.6",
|
||||
"id": 249121280,
|
||||
"author": {
|
||||
"login": "posthog-bot",
|
||||
"id": 69588470,
|
||||
"node_id": "MDQ6VXNlcjY5NTg4NDcw",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/69588470?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/posthog-bot",
|
||||
"html_url": "https://github.com/posthog-bot",
|
||||
"followers_url": "https://api.github.com/users/posthog-bot/followers",
|
||||
"following_url": "https://api.github.com/users/posthog-bot/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/posthog-bot/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/posthog-bot/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/posthog-bot/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/posthog-bot/orgs",
|
||||
"repos_url": "https://api.github.com/users/posthog-bot/repos",
|
||||
"events_url": "https://api.github.com/users/posthog-bot/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/posthog-bot/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODkV0Dc4O2UoA",
|
||||
"tag_name": "v6.7.6",
|
||||
"target_commitish": "26cfd818afc7e1ab7cc03d3324fdebc477278b40",
|
||||
"name": "6.7.6",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-22T18:10:43Z",
|
||||
"updated_at": "2025-09-22T18:11:17Z",
|
||||
"published_at": "2025-09-22T18:11:17Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-python/tarball/v6.7.6",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-python/zipball/v6.7.6",
|
||||
"body": ""
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-python/releases/247617781",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-python/releases/247617781/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-python/releases/247617781/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-python/releases/tag/v6.7.5",
|
||||
"id": 247617781,
|
||||
"author": {
|
||||
"login": "posthog-bot",
|
||||
"id": 69588470,
|
||||
"node_id": "MDQ6VXNlcjY5NTg4NDcw",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/69588470?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/posthog-bot",
|
||||
"html_url": "https://github.com/posthog-bot",
|
||||
"followers_url": "https://api.github.com/users/posthog-bot/followers",
|
||||
"following_url": "https://api.github.com/users/posthog-bot/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/posthog-bot/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/posthog-bot/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/posthog-bot/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/posthog-bot/orgs",
|
||||
"repos_url": "https://api.github.com/users/posthog-bot/repos",
|
||||
"events_url": "https://api.github.com/users/posthog-bot/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/posthog-bot/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODkV0Dc4Owlj1",
|
||||
"tag_name": "v6.7.5",
|
||||
"target_commitish": "0bb63424723d2f7d1727938b4a80a556b7453747",
|
||||
"name": "6.7.5",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-16T12:40:11Z",
|
||||
"updated_at": "2025-09-16T12:40:40Z",
|
||||
"published_at": "2025-09-16T12:40:40Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-python/tarball/v6.7.5",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-python/zipball/v6.7.5",
|
||||
"body": ""
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-python/releases/245110121",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-python/releases/245110121/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-python/releases/245110121/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-python/releases/tag/v6.7.4",
|
||||
"id": 245110121,
|
||||
"author": {
|
||||
"login": "posthog-bot",
|
||||
"id": 69588470,
|
||||
"node_id": "MDQ6VXNlcjY5NTg4NDcw",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/69588470?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/posthog-bot",
|
||||
"html_url": "https://github.com/posthog-bot",
|
||||
"followers_url": "https://api.github.com/users/posthog-bot/followers",
|
||||
"following_url": "https://api.github.com/users/posthog-bot/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/posthog-bot/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/posthog-bot/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/posthog-bot/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/posthog-bot/orgs",
|
||||
"repos_url": "https://api.github.com/users/posthog-bot/repos",
|
||||
"events_url": "https://api.github.com/users/posthog-bot/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/posthog-bot/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODkV0Dc4OnBVp",
|
||||
"tag_name": "v6.7.4",
|
||||
"target_commitish": "d76bfe6e5be7b4ceb9aa75dfbd44475e37a4efd4",
|
||||
"name": "6.7.4",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-05T15:28:55Z",
|
||||
"updated_at": "2025-09-05T15:29:26Z",
|
||||
"published_at": "2025-09-05T15:29:26Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-python/tarball/v6.7.4",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-python/zipball/v6.7.4",
|
||||
"body": ""
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-python/releases/244879578",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-python/releases/244879578/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-python/releases/244879578/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-python/releases/tag/v6.7.3",
|
||||
"id": 244879578,
|
||||
"author": {
|
||||
"login": "posthog-bot",
|
||||
"id": 69588470,
|
||||
"node_id": "MDQ6VXNlcjY5NTg4NDcw",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/69588470?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/posthog-bot",
|
||||
"html_url": "https://github.com/posthog-bot",
|
||||
"followers_url": "https://api.github.com/users/posthog-bot/followers",
|
||||
"following_url": "https://api.github.com/users/posthog-bot/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/posthog-bot/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/posthog-bot/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/posthog-bot/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/posthog-bot/orgs",
|
||||
"repos_url": "https://api.github.com/users/posthog-bot/repos",
|
||||
"events_url": "https://api.github.com/users/posthog-bot/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/posthog-bot/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODkV0Dc4OmJDa",
|
||||
"tag_name": "v6.7.3",
|
||||
"target_commitish": "b3e21c1c0e8f8fae65a85501ba5c9deb097b8d81",
|
||||
"name": "6.7.3",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-04T18:21:32Z",
|
||||
"updated_at": "2025-09-04T18:22:14Z",
|
||||
"published_at": "2025-09-04T18:22:14Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-python/tarball/v6.7.3",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-python/zipball/v6.7.3",
|
||||
"body": ""
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-python/releases/244565729",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-python/releases/244565729/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-python/releases/244565729/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-python/releases/tag/v6.7.2",
|
||||
"id": 244565729,
|
||||
"author": {
|
||||
"login": "posthog-bot",
|
||||
"id": 69588470,
|
||||
"node_id": "MDQ6VXNlcjY5NTg4NDcw",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/69588470?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/posthog-bot",
|
||||
"html_url": "https://github.com/posthog-bot",
|
||||
"followers_url": "https://api.github.com/users/posthog-bot/followers",
|
||||
"following_url": "https://api.github.com/users/posthog-bot/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/posthog-bot/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/posthog-bot/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/posthog-bot/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/posthog-bot/orgs",
|
||||
"repos_url": "https://api.github.com/users/posthog-bot/repos",
|
||||
"events_url": "https://api.github.com/users/posthog-bot/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/posthog-bot/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODkV0Dc4Ok8bh",
|
||||
"tag_name": "v6.7.2",
|
||||
"target_commitish": "08b11cbf9b3c4d12f30cd13b4d39c7101e868712",
|
||||
"name": "6.7.2",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-03T20:02:38Z",
|
||||
"updated_at": "2025-09-03T20:03:06Z",
|
||||
"published_at": "2025-09-03T20:03:06Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-python/tarball/v6.7.2",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-python/zipball/v6.7.2",
|
||||
"body": ""
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-python/releases/243798223",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-python/releases/243798223/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-python/releases/243798223/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-python/releases/tag/v6.7.1",
|
||||
"id": 243798223,
|
||||
"author": {
|
||||
"login": "posthog-bot",
|
||||
"id": 69588470,
|
||||
"node_id": "MDQ6VXNlcjY5NTg4NDcw",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/69588470?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/posthog-bot",
|
||||
"html_url": "https://github.com/posthog-bot",
|
||||
"followers_url": "https://api.github.com/users/posthog-bot/followers",
|
||||
"following_url": "https://api.github.com/users/posthog-bot/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/posthog-bot/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/posthog-bot/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/posthog-bot/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/posthog-bot/orgs",
|
||||
"repos_url": "https://api.github.com/users/posthog-bot/repos",
|
||||
"events_url": "https://api.github.com/users/posthog-bot/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/posthog-bot/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODkV0Dc4OiBDP",
|
||||
"tag_name": "v6.7.1",
|
||||
"target_commitish": "9f370675d46eaf567cd4c442f8e8b031a0778e2b",
|
||||
"name": "6.7.1",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-09-01T07:13:07Z",
|
||||
"updated_at": "2025-09-01T07:13:38Z",
|
||||
"published_at": "2025-09-01T07:13:38Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-python/tarball/v6.7.1",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-python/zipball/v6.7.1",
|
||||
"body": ""
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-python/releases/242719858",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-python/releases/242719858/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-python/releases/242719858/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-python/releases/tag/v6.7.0",
|
||||
"id": 242719858,
|
||||
"author": {
|
||||
"login": "posthog-bot",
|
||||
"id": 69588470,
|
||||
"node_id": "MDQ6VXNlcjY5NTg4NDcw",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/69588470?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/posthog-bot",
|
||||
"html_url": "https://github.com/posthog-bot",
|
||||
"followers_url": "https://api.github.com/users/posthog-bot/followers",
|
||||
"following_url": "https://api.github.com/users/posthog-bot/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/posthog-bot/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/posthog-bot/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/posthog-bot/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/posthog-bot/orgs",
|
||||
"repos_url": "https://api.github.com/users/posthog-bot/repos",
|
||||
"events_url": "https://api.github.com/users/posthog-bot/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/posthog-bot/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODkV0Dc4Od5xy",
|
||||
"tag_name": "v6.7.0",
|
||||
"target_commitish": "6e00d573f384e5e8231c700262e8367bb82a265f",
|
||||
"name": "6.7.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-26T22:32:04Z",
|
||||
"updated_at": "2025-08-26T22:32:32Z",
|
||||
"published_at": "2025-08-26T22:32:32Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-python/tarball/v6.7.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-python/zipball/v6.7.0",
|
||||
"body": ""
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-python/releases/241530993",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-python/releases/241530993/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-python/releases/241530993/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-python/releases/tag/v6.6.1",
|
||||
"id": 241530993,
|
||||
"author": {
|
||||
"login": "posthog-bot",
|
||||
"id": 69588470,
|
||||
"node_id": "MDQ6VXNlcjY5NTg4NDcw",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/69588470?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/posthog-bot",
|
||||
"html_url": "https://github.com/posthog-bot",
|
||||
"followers_url": "https://api.github.com/users/posthog-bot/followers",
|
||||
"following_url": "https://api.github.com/users/posthog-bot/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/posthog-bot/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/posthog-bot/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/posthog-bot/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/posthog-bot/orgs",
|
||||
"repos_url": "https://api.github.com/users/posthog-bot/repos",
|
||||
"events_url": "https://api.github.com/users/posthog-bot/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/posthog-bot/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODkV0Dc4OZXhx",
|
||||
"tag_name": "v6.6.1",
|
||||
"target_commitish": "fb3844786935fb0788587d37ac607cd9897e8675",
|
||||
"name": "6.6.1",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-21T14:14:27Z",
|
||||
"updated_at": "2025-08-21T14:15:03Z",
|
||||
"published_at": "2025-08-21T14:15:03Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-python/tarball/v6.6.1",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-python/zipball/v6.6.1",
|
||||
"body": ""
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-python/releases/240739318",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-python/releases/240739318/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-python/releases/240739318/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-python/releases/tag/v6.6.0",
|
||||
"id": 240739318,
|
||||
"author": {
|
||||
"login": "posthog-bot",
|
||||
"id": 69588470,
|
||||
"node_id": "MDQ6VXNlcjY5NTg4NDcw",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/69588470?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/posthog-bot",
|
||||
"html_url": "https://github.com/posthog-bot",
|
||||
"followers_url": "https://api.github.com/users/posthog-bot/followers",
|
||||
"following_url": "https://api.github.com/users/posthog-bot/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/posthog-bot/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/posthog-bot/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/posthog-bot/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/posthog-bot/orgs",
|
||||
"repos_url": "https://api.github.com/users/posthog-bot/repos",
|
||||
"events_url": "https://api.github.com/users/posthog-bot/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/posthog-bot/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODkV0Dc4OWWP2",
|
||||
"tag_name": "v6.6.0",
|
||||
"target_commitish": "20b8825bd2b5087f7a0b60eee096e5c690c4be7b",
|
||||
"name": "6.6.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-18T23:10:34Z",
|
||||
"updated_at": "2025-08-18T23:11:08Z",
|
||||
"published_at": "2025-08-18T23:11:08Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-python/tarball/v6.6.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-python/zipball/v6.6.0",
|
||||
"body": ""
|
||||
},
|
||||
{
|
||||
"url": "https://api.github.com/repos/PostHog/posthog-python/releases/238555311",
|
||||
"assets_url": "https://api.github.com/repos/PostHog/posthog-python/releases/238555311/assets",
|
||||
"upload_url": "https://uploads.github.com/repos/PostHog/posthog-python/releases/238555311/assets{?name,label}",
|
||||
"html_url": "https://github.com/PostHog/posthog-python/releases/tag/v6.5.0",
|
||||
"id": 238555311,
|
||||
"author": {
|
||||
"login": "posthog-bot",
|
||||
"id": 69588470,
|
||||
"node_id": "MDQ6VXNlcjY5NTg4NDcw",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/69588470?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/posthog-bot",
|
||||
"html_url": "https://github.com/posthog-bot",
|
||||
"followers_url": "https://api.github.com/users/posthog-bot/followers",
|
||||
"following_url": "https://api.github.com/users/posthog-bot/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/posthog-bot/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/posthog-bot/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/posthog-bot/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/posthog-bot/orgs",
|
||||
"repos_url": "https://api.github.com/users/posthog-bot/repos",
|
||||
"events_url": "https://api.github.com/users/posthog-bot/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/posthog-bot/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"node_id": "RE_kwDODkV0Dc4OOBCv",
|
||||
"tag_name": "v6.5.0",
|
||||
"target_commitish": "818edc281170d1669538b1c0b01920563e0a167b",
|
||||
"name": "6.5.0",
|
||||
"draft": false,
|
||||
"immutable": false,
|
||||
"prerelease": false,
|
||||
"created_at": "2025-08-08T10:44:34Z",
|
||||
"updated_at": "2025-08-08T10:45:08Z",
|
||||
"published_at": "2025-08-08T10:45:08Z",
|
||||
"assets": [
|
||||
|
||||
],
|
||||
"tarball_url": "https://api.github.com/repos/PostHog/posthog-python/tarball/v6.5.0",
|
||||
"zipball_url": "https://api.github.com/repos/PostHog/posthog-python/zipball/v6.5.0",
|
||||
"body": ""
|
||||
}
|
||||
]
|
||||
300
dags/tests/test_sdk_doctor.py
Normal file
@@ -0,0 +1,300 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from dags.sdk_doctor.github_sdk_versions import (
|
||||
fetch_android_sdk_data,
|
||||
fetch_dotnet_sdk_data,
|
||||
fetch_elixir_sdk_data,
|
||||
fetch_flutter_sdk_data,
|
||||
fetch_go_sdk_data,
|
||||
fetch_ios_sdk_data,
|
||||
fetch_node_sdk_data,
|
||||
fetch_php_sdk_data,
|
||||
fetch_python_sdk_data,
|
||||
fetch_react_native_sdk_data,
|
||||
fetch_ruby_sdk_data,
|
||||
fetch_web_sdk_data,
|
||||
)
|
||||
|
||||
# NOTE: Fixtures are defined as they were in October 10, 2025
|
||||
# They can be updated by running the following Python Script:
|
||||
#
|
||||
# ```python
|
||||
# import requests
|
||||
# from pathlib import Path
|
||||
#
|
||||
# FIXTURES = Path(__file__).parent / "fixtures"
|
||||
# CHANGELOGS = FIXTURES / "changelogs"
|
||||
# RELEASES = FIXTURES / "releases"
|
||||
#
|
||||
# changelogs = {
|
||||
# "php_changelog.md": "https://raw.githubusercontent.com/PostHog/posthog-php/master/History.md",
|
||||
# "ruby_changelog.md": "https://raw.githubusercontent.com/PostHog/posthog-ruby/main/CHANGELOG.md",
|
||||
# "elixir_changelog.md": "https://raw.githubusercontent.com/PostHog/posthog-elixir/master/CHANGELOG.md",
|
||||
# }
|
||||
#
|
||||
# releases = {
|
||||
# "posthog_js_releases.json": "https://api.github.com/repos/PostHog/posthog-js/releases?per_page=25",
|
||||
# "posthog_python_releases.json": "https://api.github.com/repos/PostHog/posthog-python/releases?per_page=10",
|
||||
# "posthog_flutter_releases.json": "https://api.github.com/repos/PostHog/posthog-flutter/releases?per_page=10",
|
||||
# "posthog_ios_releases.json": "https://api.github.com/repos/PostHog/posthog-ios/releases?per_page=10",
|
||||
# "posthog_android_releases.json": "https://api.github.com/repos/PostHog/posthog-android/releases?per_page=10",
|
||||
# "posthog_go_releases.json": "https://api.github.com/repos/PostHog/posthog-go/releases?per_page=10",
|
||||
# "dotnet_releases.json": "https://api.github.com/repos/PostHog/posthog-dotnet/releases?per_page=10",
|
||||
# }
|
||||
#
|
||||
# for filename, url in changelogs.items():
|
||||
# print(f"Downloading {filename}...")
|
||||
# r = requests.get(url)
|
||||
# (CHANGELOGS / filename).write_text(r.text)
|
||||
#
|
||||
# for filename, url in releases.items():
|
||||
# print(f"Downloading {filename}...")
|
||||
# r = requests.get(url)
|
||||
# (RELEASES / filename).write_text(r.text)
|
||||
# ```
|
||||
|
||||
FIXTURES_DIR = Path(__file__).parent / "fixtures"
|
||||
CHANGELOGS_DIR = FIXTURES_DIR / "changelogs"
|
||||
RELEASES_DIR = FIXTURES_DIR / "releases"
|
||||
|
||||
|
||||
def load_changelog(filename: str) -> str:
|
||||
"""Load a changelog file from the changelogs directory."""
|
||||
with open(CHANGELOGS_DIR / filename) as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def load_releases(filename: str) -> dict:
|
||||
"""Load a releases JSON file from the releases directory."""
|
||||
with open(RELEASES_DIR / filename) as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
class TestFetchSdkDataBase:
|
||||
def setup_ok_json_mock(self, mock_get, data):
|
||||
response = MagicMock()
|
||||
response.ok = True
|
||||
response.status_code = 200
|
||||
response.json.return_value = data
|
||||
mock_get.side_effect = [response]
|
||||
|
||||
def setup_ok_text_mock(self, mock_get, data):
|
||||
response = MagicMock()
|
||||
response.ok = True
|
||||
response.status_code = 200
|
||||
response.text = data
|
||||
mock_get.side_effect = [response]
|
||||
|
||||
|
||||
class TestFetchWebSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_web_sdk_data_success(self, mock_get):
|
||||
releases_data = load_releases("posthog_js_releases.json")
|
||||
self.setup_ok_json_mock(mock_get, releases_data)
|
||||
|
||||
result = fetch_web_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "1.275.0"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert "1.275.0" in result["releaseDates"]
|
||||
assert result["releaseDates"]["1.275.0"] == "2025-10-10T14:06:17Z"
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_web_sdk_data_request_failure(self, mock_get):
|
||||
response = MagicMock()
|
||||
response.ok = False
|
||||
response.status_code = 404
|
||||
mock_get.side_effect = [response]
|
||||
|
||||
result = fetch_web_sdk_data()
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
class TestFetchPythonSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_python_sdk_data_success(self, mock_get):
|
||||
releases_data = load_releases("posthog_python_releases.json")
|
||||
self.setup_ok_json_mock(mock_get, releases_data)
|
||||
|
||||
result = fetch_python_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "6.7.6"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert "6.7.6" in result["releaseDates"]
|
||||
assert result["releaseDates"]["6.7.6"] == "2025-09-22T18:11:17Z"
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
|
||||
class TestFetchNodeSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_node_sdk_data_success(self, mock_get):
|
||||
releases_data = load_releases("posthog_js_releases.json")
|
||||
self.setup_ok_json_mock(mock_get, releases_data)
|
||||
|
||||
result = fetch_node_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "5.9.5"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
|
||||
class TestFetchReactNativeSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_react_native_sdk_data_success(self, mock_get):
|
||||
releases_data = load_releases("posthog_js_releases.json")
|
||||
self.setup_ok_json_mock(mock_get, releases_data)
|
||||
|
||||
result = fetch_react_native_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "4.9.1"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
|
||||
class TestFetchFlutterSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_flutter_sdk_data_success(self, mock_get):
|
||||
releases_data = load_releases("posthog_flutter_releases.json")
|
||||
self.setup_ok_json_mock(mock_get, releases_data)
|
||||
|
||||
result = fetch_flutter_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "5.6.0"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert "5.6.0" in result["releaseDates"]
|
||||
assert result["releaseDates"]["5.6.0"] == "2025-10-06T11:14:06Z"
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
|
||||
class TestFetchIosSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_ios_sdk_data_success(self, mock_get):
|
||||
releases_data = load_releases("posthog_ios_releases.json")
|
||||
self.setup_ok_json_mock(mock_get, releases_data)
|
||||
|
||||
result = fetch_ios_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "3.32.0"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert "3.32.0" in result["releaseDates"]
|
||||
assert result["releaseDates"]["3.32.0"] == "2025-10-03T14:21:35Z"
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
|
||||
class TestFetchAndroidSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_android_sdk_data_success(self, mock_get):
|
||||
releases_data = load_releases("posthog_android_releases.json")
|
||||
self.setup_ok_json_mock(mock_get, releases_data)
|
||||
|
||||
result = fetch_android_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "3.23.0"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert "3.23.0" in result["releaseDates"]
|
||||
assert result["releaseDates"]["3.23.0"] == "2025-10-06T09:13:27Z"
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
|
||||
class TestFetchGoSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_go_sdk_data_success(self, mock_get):
|
||||
releases_data = load_releases("posthog_go_releases.json")
|
||||
self.setup_ok_json_mock(mock_get, releases_data)
|
||||
|
||||
result = fetch_go_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "1.6.10"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert "1.6.10" in result["releaseDates"]
|
||||
assert result["releaseDates"]["1.6.10"] == "2025-09-22T20:23:13Z"
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
|
||||
class TestFetchPhpSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_php_sdk_data_success(self, mock_get):
|
||||
changelog_content = load_changelog("php_changelog.md")
|
||||
self.setup_ok_text_mock(mock_get, changelog_content)
|
||||
|
||||
result = fetch_php_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "3.7.1"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert "3.7.1" in result["releaseDates"]
|
||||
assert result["releaseDates"]["3.7.1"] == "2025-09-26T00:00:00Z"
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
|
||||
class TestFetchRubySdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_ruby_sdk_data_success(self, mock_get):
|
||||
changelog_content = load_changelog("ruby_changelog.md")
|
||||
self.setup_ok_text_mock(mock_get, changelog_content)
|
||||
|
||||
result = fetch_ruby_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "3.3.2"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert "3.3.2" in result["releaseDates"]
|
||||
assert result["releaseDates"]["3.3.2"] == "2025-09-26T00:00:00Z"
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
|
||||
class TestFetchElixirSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_elixir_sdk_data_success(self, mock_get):
|
||||
changelog_content = load_changelog("elixir_changelog.md")
|
||||
self.setup_ok_text_mock(mock_get, changelog_content)
|
||||
|
||||
result = fetch_elixir_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "2.0.0"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert "2.0.0" in result["releaseDates"]
|
||||
assert result["releaseDates"]["2.0.0"] == "2025-09-30T00:00:00Z"
|
||||
assert mock_get.call_count == 1
|
||||
|
||||
|
||||
class TestFetchDotnetSdkData(TestFetchSdkDataBase):
|
||||
@patch("dags.sdk_doctor.github_sdk_versions.requests.get")
|
||||
def test_fetch_dotnet_sdk_data_success(self, mock_get):
|
||||
releases_data = load_releases("dotnet_releases.json")
|
||||
self.setup_ok_json_mock(mock_get, releases_data)
|
||||
|
||||
result = fetch_dotnet_sdk_data()
|
||||
|
||||
assert result is not None
|
||||
assert result["latestVersion"] == "2.0.1"
|
||||
assert "releaseDates" in result
|
||||
assert len(result["releaseDates"]) > 0
|
||||
assert "2.0.1" in result["releaseDates"]
|
||||
assert result["releaseDates"]["2.0.1"] == "2025-09-28T19:40:53Z"
|
||||
assert mock_get.call_count == 1
|
||||
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 114 KiB |
@@ -33,6 +33,7 @@
|
||||
"typegen:clean": "cd .. && find frontend/src products common -type f -name '*Type.ts' -delete",
|
||||
"typegen:watch": "cd .. && NODE_OPTIONS=\"--max-old-space-size=16384\" kea-typegen watch --delete --show-ts-errors --use-cache",
|
||||
"typegen:write": "cd .. && NODE_OPTIONS=\"--max-old-space-size=16384\" kea-typegen write --delete --show-ts-errors --use-cache",
|
||||
"typegen:write:no-cache": "cd .. && NODE_OPTIONS=\"--max-old-space-size=16384\" kea-typegen write --delete --show-ts-errors",
|
||||
"schema:build:json": "ts-node ./bin/build-schema-json.mjs && prettier --write ./src/queries/schema.json",
|
||||
"test": "SHARD_IDX=${SHARD_INDEX:-1}; SHARD_TOTAL=${SHARD_COUNT:-1}; echo $SHARD_IDX/$SHARD_TOTAL; pnpm build:products && jest --testPathPattern='(frontend/|products/|common/)' --runInBand --forceExit --shard=$SHARD_IDX/$SHARD_TOTAL",
|
||||
"jest": "pnpm build:products && jest",
|
||||
|
||||
@@ -2,12 +2,15 @@ import { Meta, StoryFn } from '@storybook/react'
|
||||
import { useActions } from 'kea'
|
||||
|
||||
import { supportLogic } from 'lib/components/Support/supportLogic'
|
||||
import { FEATURE_FLAGS } from 'lib/constants'
|
||||
import { useOnMountEffect } from 'lib/hooks/useOnMountEffect'
|
||||
import { App } from 'scenes/App'
|
||||
import { urls } from 'scenes/urls'
|
||||
|
||||
import { mswDecorator, useStorybookMocks } from '~/mocks/browser'
|
||||
import organizationCurrent from '~/mocks/fixtures/api/organizations/@current/@current.json'
|
||||
import sdkVersions from '~/mocks/fixtures/api/sdk_versions.json'
|
||||
import teamSdkVersions from '~/mocks/fixtures/api/team_sdk_versions.json'
|
||||
import { SidePanelTab } from '~/types'
|
||||
|
||||
import { sidePanelStateLogic } from './sidePanelStateLogic'
|
||||
@@ -18,8 +21,9 @@ const meta: Meta = {
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
viewMode: 'story',
|
||||
mockDate: '2023-07-04', // To stabilize relative dates
|
||||
mockDate: '2025-10-10', // To stabilize relative dates
|
||||
pageUrl: urls.dashboards(),
|
||||
featureFlags: [FEATURE_FLAGS.SDK_DOCTOR_BETA],
|
||||
testOptions: {
|
||||
includeNavigationInSnapshot: true,
|
||||
},
|
||||
@@ -34,6 +38,10 @@ const meta: Meta = {
|
||||
'/api/projects/:id/batch_exports/': { results: [] },
|
||||
'/api/projects/:id/surveys/': { results: [] },
|
||||
'/api/projects/:id/surveys/responses_count/': { results: [] },
|
||||
'/api/environments/:team_id/exports/': { results: [] },
|
||||
'/api/environments/:team_id/events': { results: [] },
|
||||
'/api/sdk_versions/': sdkVersions,
|
||||
'/api/team_sdk_versions/': teamSdkVersions,
|
||||
},
|
||||
post: {
|
||||
'/api/environments/:team_id/query': {},
|
||||
@@ -70,12 +78,16 @@ export const SidePanelMax: StoryFn = () => {
|
||||
return <BaseTemplate panel={SidePanelTab.Max} />
|
||||
}
|
||||
|
||||
export const SidePanelSdkDoctor: StoryFn = () => {
|
||||
return <BaseTemplate panel={SidePanelTab.SdkDoctor} />
|
||||
}
|
||||
|
||||
export const SidePanelSupportNoEmail: StoryFn = () => {
|
||||
return <BaseTemplate panel={SidePanelTab.Support} />
|
||||
}
|
||||
|
||||
export const SidePanelSupportWithEmail: StoryFn = () => {
|
||||
const { openEmailForm } = useActions(supportLogic)
|
||||
const { openEmailForm, closeEmailForm } = useActions(supportLogic)
|
||||
|
||||
useStorybookMocks({
|
||||
get: {
|
||||
@@ -99,7 +111,10 @@ export const SidePanelSupportWithEmail: StoryFn = () => {
|
||||
},
|
||||
})
|
||||
|
||||
useOnMountEffect(openEmailForm)
|
||||
useOnMountEffect(() => {
|
||||
openEmailForm()
|
||||
return () => closeEmailForm()
|
||||
})
|
||||
|
||||
return <BaseTemplate panel={SidePanelTab.Support} />
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import { SidePanelTab } from '~/types'
|
||||
|
||||
import { SidePanelDocs } from './panels/SidePanelDocs'
|
||||
import { SidePanelMax } from './panels/SidePanelMax'
|
||||
import { SidePanelSdkDoctor, SidePanelSdkDoctorIcon } from './panels/SidePanelSdkDoctor'
|
||||
import { SidePanelSettings } from './panels/SidePanelSettings'
|
||||
import { SidePanelStatus, SidePanelStatusIcon } from './panels/SidePanelStatus'
|
||||
import { SidePanelSupport } from './panels/SidePanelSupport'
|
||||
@@ -106,6 +107,11 @@ export const SIDE_PANEL_TABS: Record<
|
||||
Icon: IconLock,
|
||||
Content: SidePanelAccessControl,
|
||||
},
|
||||
[SidePanelTab.SdkDoctor]: {
|
||||
label: 'SDK Doctor',
|
||||
Icon: SidePanelSdkDoctorIcon,
|
||||
Content: SidePanelSdkDoctor,
|
||||
},
|
||||
}
|
||||
|
||||
const DEFAULT_WIDTH = 512
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
import { useActions, useValues } from 'kea'
|
||||
|
||||
import { IconStethoscope } from '@posthog/icons'
|
||||
import { LemonBanner, LemonButton, LemonTable, LemonTableColumns, LemonTag, Link, Tooltip } from '@posthog/lemon-ui'
|
||||
|
||||
import { TZLabel } from 'lib/components/TZLabel'
|
||||
import { FEATURE_FLAGS } from 'lib/constants'
|
||||
import { IconWithBadge } from 'lib/lemon-ui/icons'
|
||||
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
|
||||
import { inStorybook, inStorybookTestRunner } from 'lib/utils'
|
||||
import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic'
|
||||
|
||||
import { SidePanelPaneHeader } from '../components/SidePanelPaneHeader'
|
||||
import { AugmentedTeamSdkVersionsInfoRelease, type SdkType, sidePanelSdkDoctorLogic } from './sidePanelSdkDoctorLogic'
|
||||
|
||||
const SDK_TYPE_READABLE_NAME: Record<SdkType, string> = {
|
||||
web: 'Web',
|
||||
'posthog-ios': 'iOS',
|
||||
'posthog-android': 'Android',
|
||||
'posthog-node': 'Node.js',
|
||||
'posthog-python': 'Python',
|
||||
'posthog-php': 'PHP',
|
||||
'posthog-ruby': 'Ruby',
|
||||
'posthog-go': 'Go',
|
||||
'posthog-flutter': 'Flutter',
|
||||
'posthog-react-native': 'React Native',
|
||||
'posthog-dotnet': '.NET',
|
||||
'posthog-elixir': 'Elixir',
|
||||
}
|
||||
|
||||
// SDK documentation links mapping
|
||||
const SDK_DOCS_LINKS: Record<SdkType, { releases: string; docs: string }> = {
|
||||
web: {
|
||||
releases: 'https://github.com/PostHog/posthog-js/blob/main/packages/browser/CHANGELOG.md',
|
||||
docs: 'https://posthog.com/docs/libraries/js',
|
||||
},
|
||||
'posthog-ios': {
|
||||
releases: 'https://github.com/PostHog/posthog-ios/releases',
|
||||
docs: 'https://posthog.com/docs/libraries/ios',
|
||||
},
|
||||
'posthog-android': {
|
||||
releases: 'https://github.com/PostHog/posthog-android/releases',
|
||||
docs: 'https://posthog.com/docs/libraries/android',
|
||||
},
|
||||
'posthog-node': {
|
||||
releases: 'https://github.com/PostHog/posthog-js/blob/main/packages/node/CHANGELOG.md',
|
||||
docs: 'https://posthog.com/docs/libraries/node',
|
||||
},
|
||||
'posthog-python': {
|
||||
releases: 'https://github.com/PostHog/posthog-python/releases',
|
||||
docs: 'https://posthog.com/docs/libraries/python',
|
||||
},
|
||||
'posthog-php': {
|
||||
releases: 'https://github.com/PostHog/posthog-php/blob/master/History.md',
|
||||
docs: 'https://posthog.com/docs/libraries/php',
|
||||
},
|
||||
'posthog-ruby': {
|
||||
releases: 'https://github.com/PostHog/posthog-ruby/blob/main/CHANGELOG.md',
|
||||
docs: 'https://posthog.com/docs/libraries/ruby',
|
||||
},
|
||||
'posthog-go': {
|
||||
releases: 'https://github.com/PostHog/posthog-go/releases',
|
||||
docs: 'https://posthog.com/docs/libraries/go',
|
||||
},
|
||||
'posthog-flutter': {
|
||||
releases: 'https://github.com/PostHog/posthog-flutter/releases',
|
||||
docs: 'https://posthog.com/docs/libraries/flutter',
|
||||
},
|
||||
'posthog-react-native': {
|
||||
releases: 'https://github.com/PostHog/posthog-js/blob/main/packages/react-native/CHANGELOG.md',
|
||||
docs: 'https://posthog.com/docs/libraries/react-native',
|
||||
},
|
||||
'posthog-dotnet': {
|
||||
releases: 'https://github.com/PostHog/posthog-dotnet/releases',
|
||||
docs: 'https://posthog.com/docs/libraries/dotnet',
|
||||
},
|
||||
'posthog-elixir': {
|
||||
releases: 'https://github.com/PostHog/posthog-elixir/blob/master/CHANGELOG.md',
|
||||
docs: 'https://posthog.com/docs/libraries/elixir',
|
||||
},
|
||||
}
|
||||
|
||||
const COLUMNS: LemonTableColumns<AugmentedTeamSdkVersionsInfoRelease> = [
|
||||
{
|
||||
title: 'Version',
|
||||
dataIndex: 'version',
|
||||
render: function RenderVersion(_, record) {
|
||||
return (
|
||||
<div className="flex items-center gap-2 justify-end">
|
||||
<code className="text-xs font-mono bg-muted-highlight rounded-sm px-1 py-0.5">
|
||||
{record.version}
|
||||
</code>
|
||||
{record.isOutdated ? (
|
||||
<Tooltip
|
||||
placement="right"
|
||||
title={`Upgrade recommended ${record.daysSinceRelease ? `(${Math.floor(record.daysSinceRelease / 7)} weeks old)` : ''}`}
|
||||
>
|
||||
<LemonTag type="danger" className="shrink-0">
|
||||
Outdated
|
||||
</LemonTag>
|
||||
</Tooltip>
|
||||
) : record.latestVersion && record.version === record.latestVersion ? (
|
||||
<LemonTag type="success" className="shrink-0">
|
||||
Current
|
||||
</LemonTag>
|
||||
) : (
|
||||
<LemonTag type="success" className="shrink-0">
|
||||
Recent
|
||||
</LemonTag>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Last event at',
|
||||
dataIndex: 'maxTimestamp',
|
||||
render: function RenderMaxTimestamp(_, record) {
|
||||
return <TZLabel time={record.maxTimestamp} />
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '# Events in the last 7 days',
|
||||
dataIndex: 'count',
|
||||
render: function RenderCount(_, record) {
|
||||
return <div className="text-xs text-muted-alt">{record.count}</div>
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
export function SidePanelSdkDoctor(): JSX.Element | null {
|
||||
const { sdkVersionsMap, sdkVersionsLoading, teamSdkVersionsLoading, outdatedSdkCount, hasErrors } =
|
||||
useValues(sidePanelSdkDoctorLogic)
|
||||
const { isDev } = useValues(preflightLogic)
|
||||
const { loadTeamSdkVersions, snoozeSdkDoctor } = useActions(sidePanelSdkDoctorLogic)
|
||||
|
||||
const loading = sdkVersionsLoading || teamSdkVersionsLoading
|
||||
|
||||
const { featureFlags } = useValues(featureFlagLogic)
|
||||
|
||||
if (!featureFlags[FEATURE_FLAGS.SDK_DOCTOR_BETA]) {
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
<SidePanelPaneHeader
|
||||
title={
|
||||
<span>
|
||||
SDK Doctor{' '}
|
||||
<LemonTag type="warning" className="ml-1">
|
||||
Beta
|
||||
</LemonTag>
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
<div className="m-2">
|
||||
<LemonBanner type="info">
|
||||
<div>
|
||||
<strong>SDK Doctor is in beta!</strong> It's not enabled in your account yet.
|
||||
</div>
|
||||
</LemonBanner>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
<SidePanelPaneHeader
|
||||
title={
|
||||
<span>
|
||||
SDK Doctor{' '}
|
||||
<LemonTag type="warning" className="ml-1">
|
||||
Beta
|
||||
</LemonTag>
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<LemonButton
|
||||
size="xsmall"
|
||||
type="primary"
|
||||
disabledReason={loading ? 'Scan in progress' : undefined}
|
||||
onClick={() => loadTeamSdkVersions({ forceRefresh: true })}
|
||||
>
|
||||
{loading ? 'Scanning events...' : 'Scan events'}
|
||||
</LemonButton>
|
||||
</SidePanelPaneHeader>
|
||||
|
||||
{/* Explain to devs how they can get the SDK data to show up */}
|
||||
{isDev && !inStorybook() && !inStorybookTestRunner() && (
|
||||
<div className="m-2 mb-4">
|
||||
<LemonBanner type="info">
|
||||
<strong>DEVELOPMENT WARNING!</strong> When running in development, make sure you've run the
|
||||
appropriate Dasgter jobs: <LemonTag>cache_all_team_sdk_versions_job</LemonTag> and{' '}
|
||||
<LemonTag>cache_github_sdk_versions_job</LemonTag>. Data won't be available otherwise.
|
||||
</LemonBanner>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Beta feedback banner */}
|
||||
<div className="m-2">
|
||||
<LemonBanner type="info">
|
||||
<strong>SDK Doctor is in Beta!</strong> Help us improve by sharing your feedback?{' '}
|
||||
<Link to="#panel=support%3Asupport%3Asdk%3Alow%3Atrue">Send feedback</Link>
|
||||
</LemonBanner>
|
||||
</div>
|
||||
|
||||
<div className="p-3">
|
||||
{loading ? null : hasErrors ? (
|
||||
<div className="text-center text-muted p-4">
|
||||
Error loading SDK information. Please try again later.
|
||||
</div>
|
||||
) : Object.keys(sdkVersionsMap).length === 0 ? (
|
||||
<div className="text-center text-muted p-4">
|
||||
No SDK information found. Are you sure you have our SDK installed? You can scan events to get
|
||||
started.
|
||||
</div>
|
||||
) : outdatedSdkCount === 0 ? (
|
||||
<section className="mb-2">
|
||||
<h3>SDK health is good</h3>
|
||||
<LemonBanner type="success" hideIcon={false}>
|
||||
<p className="font-semibold">All caught up! Your SDKs are up to date.</p>
|
||||
<p className="text-sm mt-1">You've got the latest. Nice work keeping everything current.</p>
|
||||
</LemonBanner>
|
||||
</section>
|
||||
) : (
|
||||
<section className="mb-2">
|
||||
<h3>Time for an update!</h3>
|
||||
<LemonBanner
|
||||
type="warning"
|
||||
hideIcon={false}
|
||||
action={{
|
||||
children: 'Snooze warning for 30 days',
|
||||
onClick: () => snoozeSdkDoctor(),
|
||||
}}
|
||||
>
|
||||
<p className="font-semibold">
|
||||
An outdated SDK means you're missing out on bug fixes and enhacements.
|
||||
</p>
|
||||
<p className="text-sm mt-1">Check the links below to get caught up.</p>
|
||||
</LemonBanner>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{Object.keys(sdkVersionsMap).map((sdkType) => (
|
||||
<SdkSection key={sdkType} sdkType={sdkType as SdkType} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const SidePanelSdkDoctorIcon = (props: { className?: string }): JSX.Element => {
|
||||
const { sdkHealth, outdatedSdkCount } = useValues(sidePanelSdkDoctorLogic)
|
||||
|
||||
const title =
|
||||
outdatedSdkCount > 0
|
||||
? 'Outdated SDKs found'
|
||||
: sdkHealth === 'warning'
|
||||
? 'Some SDKs have newer versions available'
|
||||
: 'SDK health is good'
|
||||
|
||||
return (
|
||||
<Tooltip title={title} placement="left">
|
||||
<span {...props}>
|
||||
<IconWithBadge
|
||||
content={sdkHealth !== 'success' && outdatedSdkCount > 0 ? '!' : '✓'}
|
||||
status={outdatedSdkCount > 0 ? 'danger' : sdkHealth}
|
||||
>
|
||||
<IconStethoscope />
|
||||
</IconWithBadge>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
function SdkSection({ sdkType }: { sdkType: SdkType }): JSX.Element {
|
||||
const { sdkVersionsMap, teamSdkVersionsLoading, sdkHealth } = useValues(sidePanelSdkDoctorLogic)
|
||||
|
||||
const sdk = sdkVersionsMap[sdkType]!
|
||||
const links = SDK_DOCS_LINKS[sdkType]
|
||||
const sdkName = SDK_TYPE_READABLE_NAME[sdkType]
|
||||
|
||||
return (
|
||||
<div className="flex flex-col mb-4 p-2">
|
||||
<div className="flex flex-row justify-between items-center gap-2 mb-4">
|
||||
<div>
|
||||
<div className="flex flex-row gap-2">
|
||||
<h3 className="mb-0">{sdkName}</h3>
|
||||
<span>
|
||||
<LemonTag type={sdk.isOutdated ? 'danger' : sdkHealth}>
|
||||
{sdkHealth === 'danger'
|
||||
? 'Critical'
|
||||
: sdk.isOutdated || sdkHealth === 'warning'
|
||||
? 'Outdated'
|
||||
: 'Up to date'}
|
||||
</LemonTag>
|
||||
</span>
|
||||
|
||||
{sdk.isOld && (
|
||||
<LemonTag type="warning" className="shrink-0">
|
||||
Old
|
||||
</LemonTag>
|
||||
)}
|
||||
</div>
|
||||
<small>Current version: {sdk.currentVersion}</small>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row gap-2">
|
||||
<Link to={links.releases} target="_blank" targetBlankIcon>
|
||||
Releases
|
||||
</Link>
|
||||
<Link to={links.docs} target="_blank" targetBlankIcon>
|
||||
Docs
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<LemonTable
|
||||
dataSource={sdk.allReleases}
|
||||
loading={teamSdkVersionsLoading}
|
||||
columns={COLUMNS}
|
||||
size="small"
|
||||
emptyState="No SDK information found. Try scanning recent events."
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,413 @@
|
||||
import { actions, afterMount, kea, listeners, path, reducers, selectors } from 'kea'
|
||||
import { loaders } from 'kea-loaders'
|
||||
|
||||
import { lemonToast } from '@posthog/lemon-ui'
|
||||
|
||||
import api from 'lib/api'
|
||||
import { diffVersions, parseVersion } from 'lib/utils/semver'
|
||||
|
||||
import type { sidePanelSdkDoctorLogicType } from './sidePanelSdkDoctorLogicType'
|
||||
|
||||
// Supported SDK types for version detection and health monitoring
|
||||
export type SdkType =
|
||||
| 'web'
|
||||
| 'posthog-ios'
|
||||
| 'posthog-android'
|
||||
| 'posthog-node'
|
||||
| 'posthog-python'
|
||||
| 'posthog-php'
|
||||
| 'posthog-ruby'
|
||||
| 'posthog-go'
|
||||
| 'posthog-flutter'
|
||||
| 'posthog-react-native'
|
||||
| 'posthog-dotnet'
|
||||
| 'posthog-elixir'
|
||||
|
||||
// Small helper to define what our versions look like
|
||||
export type SdkVersion = `${string}.${string}.${string}`
|
||||
|
||||
// For a given SDK, we want to know the latest version and the release dates of the more recent versions
|
||||
export type SdkVersionInfo = {
|
||||
latestVersion: SdkVersion
|
||||
releaseDates: Record<SdkVersion, string>
|
||||
}
|
||||
|
||||
// For a team we have a map of SDK types to all of the versions we say in recent times
|
||||
// This is what we receive from the backend, we then do some calculations in the UI to determine
|
||||
// what we should be displaying in the UI
|
||||
export type TeamSdkVersionInfo = {
|
||||
lib_version: SdkVersion
|
||||
max_timestamp: string
|
||||
count: number
|
||||
}
|
||||
|
||||
export type TeamSdkVersionsInfo = {
|
||||
[key in SdkType]?: TeamSdkVersionInfo[]
|
||||
}
|
||||
|
||||
// This is the final data used to display in the UI
|
||||
export type AugmentedTeamSdkVersionsInfo = {
|
||||
[key in SdkType]?: {
|
||||
isOutdated: boolean
|
||||
isOld: boolean
|
||||
currentVersion: SdkVersion
|
||||
allReleases: AugmentedTeamSdkVersionsInfoRelease[]
|
||||
}
|
||||
}
|
||||
|
||||
export type AugmentedTeamSdkVersionsInfoRelease = {
|
||||
type: SdkType
|
||||
version: SdkVersion
|
||||
maxTimestamp: string
|
||||
count: number
|
||||
latestVersion: string
|
||||
releaseDate: string | undefined
|
||||
daysSinceRelease: number | undefined
|
||||
isOutdated: boolean
|
||||
isOld: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Overall health status for SDK version monitoring
|
||||
*/
|
||||
export type SdkHealthStatus = 'danger' | 'warning' | 'success'
|
||||
|
||||
/**
|
||||
* SDK Doctor - PostHog SDK Health Monitoring
|
||||
*
|
||||
* Detects installed SDKs and their versions across a team's events.
|
||||
* Provides smart version outdatedness detection.
|
||||
*
|
||||
* Architecture:
|
||||
* - Backend detection: Team SDK detections cached server-side (72h Redis, re-fetched every 6 hours)
|
||||
* - Version checking: Per-SDK GitHub API queries cached server-side (72h Redis, re-fetched every 6 hours)
|
||||
* - Smart semver: Contextual thresholds
|
||||
*/
|
||||
|
||||
const DEVICE_CONTEXT_CONFIG = {
|
||||
mobileSDKs: ['posthog-ios', 'posthog-android', 'posthog-flutter', 'posthog-react-native'] as SdkType[],
|
||||
desktopSDKs: [
|
||||
'web',
|
||||
'posthog-node',
|
||||
'posthog-python',
|
||||
'posthog-php',
|
||||
'posthog-ruby',
|
||||
'posthog-go',
|
||||
'posthog-dotnet',
|
||||
'posthog-elixir',
|
||||
] as SdkType[],
|
||||
ageThresholds: { mobile: 16, desktop: 8 },
|
||||
} as const
|
||||
|
||||
export const sidePanelSdkDoctorLogic = kea<sidePanelSdkDoctorLogicType>([
|
||||
path(['scenes', 'navigation', 'sidepanel', 'sidePanelSdkDoctorLogic']),
|
||||
|
||||
actions({
|
||||
snoozeSdkDoctor: true,
|
||||
}),
|
||||
|
||||
reducers(() => ({
|
||||
snoozedUntil: [
|
||||
null as string | null,
|
||||
{ persist: true },
|
||||
{
|
||||
snoozeSdkDoctor: () => new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
|
||||
},
|
||||
],
|
||||
})),
|
||||
|
||||
loaders(() => ({
|
||||
sdkVersions: [
|
||||
null as Record<SdkType, SdkVersionInfo> | null,
|
||||
{
|
||||
loadSdkVersions: async (): Promise<Record<SdkType, SdkVersionInfo> | null> => {
|
||||
try {
|
||||
const response = await api.get<Record<SdkType, SdkVersionInfo>>('api/sdk_versions/')
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('Error loading SDK versions:', error)
|
||||
return null
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
teamSdkVersions: [
|
||||
null as TeamSdkVersionsInfo | null,
|
||||
{
|
||||
loadTeamSdkVersions: async ({
|
||||
forceRefresh,
|
||||
}: { forceRefresh?: boolean } = {}): Promise<TeamSdkVersionsInfo | null> => {
|
||||
const endpoint =
|
||||
forceRefresh === true ? 'api/team_sdk_versions/?force_refresh=true' : 'api/team_sdk_versions/'
|
||||
|
||||
try {
|
||||
const response = await api.get<{ sdk_versions: TeamSdkVersionsInfo; cached: boolean }>(endpoint)
|
||||
return response.sdk_versions
|
||||
} catch (error) {
|
||||
console.error('Error loading team SDK versions:', error)
|
||||
return null
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
})),
|
||||
|
||||
selectors({
|
||||
sdkVersionsMap: [
|
||||
(s) => [s.sdkVersions, s.teamSdkVersions],
|
||||
(
|
||||
sdkVersions: Record<SdkType, SdkVersionInfo>,
|
||||
teamSdkVersions: TeamSdkVersionsInfo
|
||||
): AugmentedTeamSdkVersionsInfo => {
|
||||
if (!sdkVersions || !teamSdkVersions) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(teamSdkVersions).map(([sdkType, teamSdkVersion]) => {
|
||||
const sdkVersion = sdkVersions[sdkType as SdkType]
|
||||
const releasesInfo = teamSdkVersion.map((version) =>
|
||||
computeAugmentedInfoRelease(sdkType as SdkType, version, sdkVersion)
|
||||
)
|
||||
|
||||
return [
|
||||
sdkType,
|
||||
{
|
||||
isOutdated: releasesInfo[0]!.isOutdated,
|
||||
isOld: releasesInfo[0]!.isOld,
|
||||
currentVersion: sdkVersion.latestVersion,
|
||||
allReleases: releasesInfo,
|
||||
},
|
||||
]
|
||||
})
|
||||
)
|
||||
},
|
||||
],
|
||||
|
||||
outdatedSdkCount: [
|
||||
(s) => [s.sdkVersionsMap],
|
||||
(sdkVersionsMap: AugmentedTeamSdkVersionsInfo): number => {
|
||||
return Object.values(sdkVersionsMap).filter((sdk) => sdk.isOutdated).length
|
||||
},
|
||||
],
|
||||
|
||||
sdkHealth: [
|
||||
(s) => [s.outdatedSdkCount],
|
||||
(outdatedSdkCount: number): SdkHealthStatus => {
|
||||
// If there are any outdated SDKs, mark as warning
|
||||
// If there are 2 or more, mark as critical
|
||||
if (outdatedSdkCount >= 2) {
|
||||
return 'danger'
|
||||
}
|
||||
if (outdatedSdkCount >= 1) {
|
||||
return 'warning'
|
||||
}
|
||||
|
||||
// Else, we're in a healthy state
|
||||
return 'success'
|
||||
},
|
||||
],
|
||||
|
||||
needsAttention: [
|
||||
(s) => [s.sdkHealth, s.snoozedUntil],
|
||||
(sdkHealth: SdkHealthStatus, snoozedUntil: string | null): boolean =>
|
||||
sdkHealth !== 'success' && (snoozedUntil === null || new Date(snoozedUntil) < new Date()),
|
||||
],
|
||||
hasErrors: [
|
||||
(s) => [s.sdkVersions, s.sdkVersionsLoading, s.teamSdkVersions, s.teamSdkVersionsLoading],
|
||||
(
|
||||
sdkVersions: Record<SdkType, SdkVersionInfo> | null,
|
||||
sdkVersionsLoading: boolean,
|
||||
teamSdkVersions: TeamSdkVersionsInfo | null,
|
||||
teamSdkVersionsLoading: boolean
|
||||
): boolean => {
|
||||
return (
|
||||
(!sdkVersionsLoading && sdkVersions === null) ||
|
||||
(!teamSdkVersionsLoading && teamSdkVersions === null)
|
||||
)
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
||||
listeners({
|
||||
snoozeSdkDoctor: () => {
|
||||
lemonToast.success('SDK Doctor snoozed for 30 days')
|
||||
},
|
||||
}),
|
||||
|
||||
afterMount(({ actions }) => {
|
||||
actions.loadTeamSdkVersions()
|
||||
actions.loadSdkVersions()
|
||||
}),
|
||||
])
|
||||
|
||||
/**
|
||||
* Smart semver detection with age-based thresholds.
|
||||
*
|
||||
* This is the core version comparison logic that determines if an SDK version is outdated.
|
||||
* It applies contextual rules based on semantic versioning and release age to avoid false positives.
|
||||
*
|
||||
* Detection thresholds:
|
||||
* - **Grace period**: Versions <7 days old are NEVER flagged (even if major version behind)
|
||||
* - **Major**: Always flag if major version behind (1.x → 2.x) OR >1 year old
|
||||
* - **Minor**: Flag if 3+ minors behind OR >6 months old
|
||||
*
|
||||
* The grace period prevents nagging teams about brand-new releases they haven't had time to upgrade to.
|
||||
* The age-based thresholds catch abandoned projects using very old versions.
|
||||
*
|
||||
* @param type - SDK type to check (e.g., 'web', 'python', 'node')
|
||||
* @param version - Current version string to evaluate
|
||||
* @param latestVersionsData - Version data from GitHub API including:
|
||||
* - latestVersion: Most recent version string
|
||||
* - versions: All versions in descending order
|
||||
* - releaseDates: Map of version -> ISO date for time-based checks
|
||||
* @returns Object containing:
|
||||
* - isOutdated: Whether version should be flagged (uses smart semver logic)
|
||||
* - releasesAhead: Number of releases between current and latest
|
||||
* - latestVersion: The most recent version available
|
||||
* - releaseDate: ISO date when current version was released
|
||||
* - daysSinceRelease: Age of current version in days
|
||||
* - isOld: Whether version is outdated by age alone (for "Old" badge)
|
||||
* - deviceContext: Device platform category (mobile/desktop/mixed)
|
||||
* - error: Error message if version parsing fails
|
||||
*/
|
||||
function computeAugmentedInfoRelease(
|
||||
type: SdkType,
|
||||
version: TeamSdkVersionInfo,
|
||||
sdkVersion: SdkVersionInfo
|
||||
): AugmentedTeamSdkVersionsInfoRelease {
|
||||
try {
|
||||
// Parse versions for comparison
|
||||
const currentVersionParsed = parseVersion(version.lib_version)
|
||||
const latestVersionParsed = parseVersion(sdkVersion.latestVersion)
|
||||
|
||||
// Check if versions differ
|
||||
const diff = diffVersions(latestVersionParsed, currentVersionParsed)
|
||||
|
||||
// Count number of versions behind by estimating based on semantic version difference
|
||||
let releasesBehind = 0
|
||||
if (diff) {
|
||||
if (diff.kind === 'major') {
|
||||
releasesBehind = diff.diff * 100 // Major version differences are significant
|
||||
} else if (diff.kind === 'minor') {
|
||||
releasesBehind = diff.diff * 10 // Minor versions represent normal releases
|
||||
} else if (diff.kind === 'patch') {
|
||||
releasesBehind = diff.diff
|
||||
}
|
||||
}
|
||||
|
||||
// Age-based analysis
|
||||
const deviceContext = determineDeviceContext(type)
|
||||
const releaseDates = sdkVersion.releaseDates
|
||||
const releaseDate: string | undefined = releaseDates[version.lib_version]
|
||||
|
||||
let daysSinceRelease: number | undefined
|
||||
let isOld = false
|
||||
|
||||
if (releaseDate) {
|
||||
daysSinceRelease = calculateVersionAge(releaseDate)
|
||||
const weeksOld = daysSinceRelease / 7
|
||||
|
||||
// Age-based outdated detection depends on mobile/desktop
|
||||
// We're more lenient with mobile versions because it's harder to keep them up to date
|
||||
const ageThreshold =
|
||||
deviceContext === 'desktop'
|
||||
? DEVICE_CONTEXT_CONFIG.ageThresholds.desktop
|
||||
: DEVICE_CONTEXT_CONFIG.ageThresholds.mobile
|
||||
isOld = releasesBehind > 0 && weeksOld > ageThreshold
|
||||
}
|
||||
|
||||
// Grace period: Don't flag versions released <7 days ago (even if major version behind)
|
||||
// This gives our team time to fix any issues with recent releases before we nag them about new releases
|
||||
//
|
||||
// NOTE: If daysSinceRelease is undefined (e.g., failed releases not in GitHub),
|
||||
// we continue with release count logic only - this is intentional
|
||||
let isRecentRelease = false
|
||||
const GRACE_PERIOD_DAYS = 7
|
||||
|
||||
if (daysSinceRelease !== undefined) {
|
||||
isRecentRelease = daysSinceRelease < GRACE_PERIOD_DAYS
|
||||
}
|
||||
|
||||
// Smart version detection based on semver difference
|
||||
let isOutdated = false
|
||||
|
||||
// Apply grace period first - don't flag anything <7 days old
|
||||
if (isRecentRelease) {
|
||||
isOutdated = false
|
||||
} else if (diff) {
|
||||
switch (diff.kind) {
|
||||
case 'major':
|
||||
// Major version behind (1.x → 2.x): Always flag as outdated
|
||||
isOutdated = true
|
||||
break
|
||||
case 'minor':
|
||||
// Minor version behind (1.2.x → 1.5.x): Flag if 3+ minors behind OR >6 months old
|
||||
const sixMonthsInDays = 180
|
||||
const isMinorOutdatedByCount = diff.diff >= 3
|
||||
const isMinorOutdatedByAge = daysSinceRelease !== undefined && daysSinceRelease > sixMonthsInDays
|
||||
isOutdated = isMinorOutdatedByCount || isMinorOutdatedByAge
|
||||
break
|
||||
case 'patch':
|
||||
// Patch version is never outdated
|
||||
isOutdated = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type,
|
||||
version: version.lib_version,
|
||||
maxTimestamp: version.max_timestamp,
|
||||
count: version.count,
|
||||
isOutdated: isOutdated || isOld,
|
||||
isOld, // Returned separately for "Old" badge in UI
|
||||
releaseDate,
|
||||
daysSinceRelease,
|
||||
latestVersion: sdkVersion.latestVersion,
|
||||
}
|
||||
} catch {
|
||||
// If we can't parse the versions, return error state
|
||||
return {
|
||||
type,
|
||||
version: version.lib_version,
|
||||
maxTimestamp: version.max_timestamp,
|
||||
count: version.count,
|
||||
isOutdated: false,
|
||||
isOld: false,
|
||||
releaseDate: undefined,
|
||||
daysSinceRelease: undefined,
|
||||
latestVersion: sdkVersion.latestVersion,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the age of a version in days based on its release date
|
||||
*
|
||||
* @param releaseDate - ISO date string when the version was released
|
||||
* @returns Number of days since the release
|
||||
*/
|
||||
function calculateVersionAge(releaseDate: string): number {
|
||||
const release = new Date(releaseDate)
|
||||
const now = new Date()
|
||||
return Math.floor((now.getTime() - release.getTime()) / (1000 * 60 * 60 * 24))
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the device context (mobile/desktop/mixed) for an SDK type
|
||||
*
|
||||
* @param sdkType - The SDK type to categorize
|
||||
* @returns 'mobile', 'desktop', or 'mixed' based on SDK type
|
||||
*/
|
||||
function determineDeviceContext(sdkType: SdkType): 'mobile' | 'desktop' | 'mixed' {
|
||||
if (DEVICE_CONTEXT_CONFIG.mobileSDKs.includes(sdkType)) {
|
||||
return 'mobile'
|
||||
}
|
||||
if (DEVICE_CONTEXT_CONFIG.desktopSDKs.includes(sdkType)) {
|
||||
return 'desktop'
|
||||
}
|
||||
|
||||
return 'mixed'
|
||||
}
|
||||
@@ -14,11 +14,18 @@ import { sidePanelNotificationsLogic } from '~/layout/navigation-3000/sidepanel/
|
||||
import { AvailableFeature, SidePanelTab } from '~/types'
|
||||
|
||||
import { sidePanelContextLogic } from './panels/sidePanelContextLogic'
|
||||
import { sidePanelSdkDoctorLogic } from './panels/sidePanelSdkDoctorLogic'
|
||||
import { sidePanelStatusLogic } from './panels/sidePanelStatusLogic'
|
||||
import type { sidePanelLogicType } from './sidePanelLogicType'
|
||||
import { sidePanelStateLogic } from './sidePanelStateLogic'
|
||||
|
||||
const ALWAYS_EXTRA_TABS = [SidePanelTab.Settings, SidePanelTab.Activity, SidePanelTab.Status, SidePanelTab.Exports]
|
||||
const ALWAYS_EXTRA_TABS = [
|
||||
SidePanelTab.Settings,
|
||||
SidePanelTab.Activity,
|
||||
SidePanelTab.Status,
|
||||
SidePanelTab.Exports,
|
||||
SidePanelTab.SdkDoctor,
|
||||
]
|
||||
|
||||
const TABS_REQUIRING_A_TEAM = [
|
||||
SidePanelTab.Max,
|
||||
@@ -47,6 +54,8 @@ export const sidePanelLogic = kea<sidePanelLogicType>([
|
||||
['unreadCount'],
|
||||
sidePanelStatusLogic,
|
||||
['status'],
|
||||
sidePanelSdkDoctorLogic,
|
||||
['needsAttention'],
|
||||
userLogic,
|
||||
['hasAvailableFeature'],
|
||||
sidePanelContextLogic,
|
||||
@@ -99,6 +108,10 @@ export const sidePanelLogic = kea<sidePanelLogicType>([
|
||||
tabs.push(SidePanelTab.Exports)
|
||||
tabs.push(SidePanelTab.Settings)
|
||||
|
||||
if (featureFlags[FEATURE_FLAGS.SDK_DOCTOR_BETA]) {
|
||||
tabs.push(SidePanelTab.SdkDoctor)
|
||||
}
|
||||
|
||||
if (isCloudOrDev) {
|
||||
tabs.push(SidePanelTab.Status)
|
||||
}
|
||||
@@ -117,6 +130,7 @@ export const sidePanelLogic = kea<sidePanelLogicType>([
|
||||
s.sidePanelOpen,
|
||||
s.unreadCount,
|
||||
s.status,
|
||||
s.needsAttention,
|
||||
s.hasAvailableFeature,
|
||||
s.shouldShowActivationTab,
|
||||
],
|
||||
@@ -126,6 +140,7 @@ export const sidePanelLogic = kea<sidePanelLogicType>([
|
||||
sidePanelOpen,
|
||||
unreadCount,
|
||||
status,
|
||||
needsAttention,
|
||||
hasAvailableFeature,
|
||||
shouldShowActivationTab
|
||||
): SidePanelTab[] => {
|
||||
@@ -146,6 +161,10 @@ export const sidePanelLogic = kea<sidePanelLogicType>([
|
||||
return true
|
||||
}
|
||||
|
||||
if (tab === SidePanelTab.SdkDoctor && needsAttention) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (tab === SidePanelTab.Activation && !shouldShowActivationTab) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -227,6 +227,7 @@ export const FEATURE_FLAGS = {
|
||||
EXPERIMENT_INTERVAL_TIMESERIES: 'experiments-interval-timeseries', // owner: @jurajmajerik #team-experiments
|
||||
EXPERIMENTAL_DASHBOARD_ITEM_RENDERING: 'experimental-dashboard-item-rendering', // owner: @thmsobrmlr #team-product-analytics
|
||||
PATHS_V2: 'paths-v2', // owner: @thmsobrmlr #team-product-analytics
|
||||
SDK_DOCTOR_BETA: 'sdk-doctor-beta', // owner: @slshults
|
||||
ONBOARDING_DATA_WAREHOUSE_FOR_PRODUCT_ANALYTICS: 'onboarding-data-warehouse-for-product-analytics', // owner: @joshsny
|
||||
DELAYED_LOADING_ANIMATION: 'delayed-loading-animation', // owner: @raquelmsmith
|
||||
WEB_ANALYTICS_PAGE_REPORTS: 'web-analytics-page-reports', // owner: @lricoy #team-web-analytics
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface LemonBannerProps {
|
||||
*/
|
||||
hideIcon?: boolean
|
||||
square?: boolean
|
||||
icon?: React.ReactNode
|
||||
}
|
||||
|
||||
/** Generic alert message. */
|
||||
@@ -39,6 +40,7 @@ export function LemonBanner({
|
||||
dismissKey = '',
|
||||
hideIcon,
|
||||
square = false,
|
||||
icon,
|
||||
}: LemonBannerProps): JSX.Element | null {
|
||||
const logic = lemonBannerLogic({ dismissKey })
|
||||
const { isDismissed } = useValues(logic)
|
||||
@@ -67,7 +69,9 @@ export function LemonBanner({
|
||||
>
|
||||
<div className="flex items-center gap-2 grow @md:!px-1">
|
||||
{!hideIcon &&
|
||||
(type === 'warning' || type === 'error' ? (
|
||||
(icon ? (
|
||||
icon
|
||||
) : type === 'warning' || type === 'error' ? (
|
||||
<IconWarning className={clsx('LemonBanner__icon', hideIcon !== false && 'hidden @md:!block')} />
|
||||
) : (
|
||||
<IconInfo className={clsx('LemonBanner__icon', hideIcon !== false && 'hidden @md:!block')} />
|
||||
|
||||
256
frontend/src/mocks/fixtures/api/sdk_versions.json
Normal file
@@ -0,0 +1,256 @@
|
||||
{
|
||||
"web": {
|
||||
"latestVersion": "1.275.1",
|
||||
"releaseDates": {
|
||||
"1.275.1": "2025-10-10T16:34:38Z",
|
||||
"1.275.0": "2025-10-10T14:06:17Z",
|
||||
"1.274.3": "2025-10-10T01:48:12Z",
|
||||
"1.274.2": "2025-10-10T00:20:33Z",
|
||||
"1.274.1": "2025-10-09T12:03:05Z",
|
||||
"1.274.0": "2025-10-09T09:24:34Z",
|
||||
"1.273.1": "2025-10-08T09:14:09Z",
|
||||
"1.273.0": "2025-10-07T16:00:49Z",
|
||||
"1.272.1": "2025-10-07T13:41:22Z",
|
||||
"1.272.0": "2025-10-06T21:32:53Z",
|
||||
"1.271.0": "2025-10-06T05:27:08Z",
|
||||
"1.270.1": "2025-10-03T16:39:20Z",
|
||||
"1.270.0": "2025-10-03T09:57:05Z"
|
||||
}
|
||||
},
|
||||
"posthog-ios": {
|
||||
"latestVersion": "3.32.0",
|
||||
"releaseDates": {
|
||||
"3.32.0": "2025-10-03T14:21:35Z",
|
||||
"3.31.0": "2025-08-29T12:57:56Z",
|
||||
"3.30.1": "2025-08-12T16:23:14Z",
|
||||
"3.30.0": "2025-07-28T12:51:44Z",
|
||||
"3.29.0": "2025-07-15T13:12:21Z",
|
||||
"3.28.3": "2025-07-14T10:23:58Z",
|
||||
"3.28.2": "2025-06-26T10:22:47Z",
|
||||
"3.28.1": "2025-06-26T10:12:29Z",
|
||||
"3.28.0": "2025-06-19T17:56:54Z",
|
||||
"3.27.0": "2025-06-16T20:09:55Z",
|
||||
"3.26.2": "2025-06-03T19:46:14Z",
|
||||
"3.26.1": "2025-05-30T11:37:37Z",
|
||||
"3.26.0": "2025-05-21T05:28:11Z",
|
||||
"3.25.1": "2025-05-13T10:06:26Z",
|
||||
"3.25.0": "2025-04-30T06:27:32Z",
|
||||
"3.24.3": "2025-04-29T10:03:37Z",
|
||||
"3.24.2": "2025-04-25T06:48:39Z",
|
||||
"3.24.1": "2025-04-23T11:11:07Z",
|
||||
"3.24.0": "2025-04-17T15:26:03Z",
|
||||
"3.23.0": "2025-04-14T08:59:14Z",
|
||||
"3.22.1": "2025-04-10T09:26:19Z",
|
||||
"3.22.0": "2025-04-09T09:19:50Z",
|
||||
"3.21.0": "2025-03-28T08:49:07Z",
|
||||
"3.20.1": "2025-03-13T09:05:35Z",
|
||||
"3.20.0": "2025-03-04T07:04:48Z",
|
||||
"3.19.9": "2025-02-28T07:24:29Z",
|
||||
"3.19.8": "2025-02-26T14:26:45Z",
|
||||
"3.19.7": "2025-02-20T12:04:31Z",
|
||||
"3.19.6": "2025-02-18T11:17:05Z",
|
||||
"3.19.5": "2025-02-11T08:21:52Z"
|
||||
}
|
||||
},
|
||||
"posthog-android": {
|
||||
"latestVersion": "3.23.0",
|
||||
"releaseDates": {
|
||||
"3.23.0": "2025-10-06T09:13:27Z"
|
||||
}
|
||||
},
|
||||
"posthog-node": {
|
||||
"latestVersion": "5.9.5",
|
||||
"releaseDates": {
|
||||
"5.9.5": "2025-10-09T12:03:23Z",
|
||||
"5.9.4": "2025-10-09T09:25:00Z",
|
||||
"5.9.3": "2025-10-06T23:33:26Z"
|
||||
}
|
||||
},
|
||||
"posthog-python": {
|
||||
"latestVersion": "6.7.6",
|
||||
"releaseDates": {
|
||||
"6.7.6": "2025-09-22T18:11:17Z",
|
||||
"6.7.5": "2025-09-16T12:40:40Z",
|
||||
"6.7.4": "2025-09-05T15:29:26Z",
|
||||
"6.7.3": "2025-09-04T18:22:14Z",
|
||||
"6.7.2": "2025-09-03T20:03:06Z",
|
||||
"6.7.1": "2025-09-01T07:13:38Z",
|
||||
"6.7.0": "2025-08-26T22:32:32Z",
|
||||
"6.6.1": "2025-08-21T14:15:03Z",
|
||||
"6.6.0": "2025-08-18T23:11:08Z",
|
||||
"6.5.0": "2025-08-08T10:45:08Z",
|
||||
"6.4.1": "2025-08-06T21:18:10Z",
|
||||
"6.4.0": "2025-08-05T19:33:41Z",
|
||||
"6.3.4": "2025-08-05T18:03:17Z",
|
||||
"6.3.3": "2025-08-02T00:33:33Z",
|
||||
"6.3.2": "2025-07-31T21:14:13Z",
|
||||
"6.3.1": "2025-07-23T09:52:26Z",
|
||||
"6.3.0": "2025-07-22T22:21:24Z",
|
||||
"6.2.1": "2025-07-22T06:54:26Z",
|
||||
"6.1.1": "2025-07-16T19:54:33Z",
|
||||
"6.1.0": "2025-07-10T15:04:06Z",
|
||||
"6.0.4": "2025-07-09T14:06:51Z",
|
||||
"6.0.3": "2025-07-07T07:14:13Z",
|
||||
"6.0.2": "2025-07-02T19:21:55Z",
|
||||
"6.0.1": "2025-07-01T12:27:28Z",
|
||||
"6.0.0": "2025-06-27T11:57:29Z",
|
||||
"5.4.0": "2025-06-20T23:19:27Z",
|
||||
"5.3.0": "2025-06-19T14:38:45Z",
|
||||
"5.2.0": "2025-06-19T13:48:10Z",
|
||||
"5.1.0": "2025-06-18T16:28:02Z",
|
||||
"5.0.0": "2025-06-16T15:39:23Z"
|
||||
}
|
||||
},
|
||||
"posthog-php": {
|
||||
"latestVersion": "3.7.1",
|
||||
"releaseDates": {
|
||||
"3.7.1": "2025-09-26T00:00:00Z",
|
||||
"3.7.0": "2025-08-26T00:00:00Z",
|
||||
"3.6.0": "2025-04-30T00:00:00Z",
|
||||
"3.5.0": "2025-04-17T00:00:00Z",
|
||||
"3.4.0": "2025-04-15T00:00:00Z",
|
||||
"3.3.5": "2025-03-26T00:00:00Z",
|
||||
"3.3.4": "2025-03-11T00:00:00Z",
|
||||
"3.3.3": "2025-02-28T00:00:00Z",
|
||||
"3.3.2": "2024-04-03T00:00:00Z",
|
||||
"3.3.1": "2024-03-22T00:00:00Z",
|
||||
"3.3.0": "2024-03-13T00:00:00Z",
|
||||
"3.2.2": "2024-03-11T00:00:00Z",
|
||||
"3.2.1": "2024-01-26T00:00:00Z",
|
||||
"3.2.0": "2024-01-10T00:00:00Z",
|
||||
"3.1.0": "2024-01-10T00:00:00Z",
|
||||
"3.0.8": "2023-09-25T00:00:00Z",
|
||||
"3.0.7": "2023-08-31T00:00:00Z",
|
||||
"3.0.6": "2023-07-04T00:00:00Z",
|
||||
"3.0.5": "2023-06-16T00:00:00Z",
|
||||
"3.0.4": "2023-05-19T00:00:00Z",
|
||||
"3.0.3": "2023-03-21T00:00:00Z",
|
||||
"3.0.2": "2023-03-08T00:00:00Z",
|
||||
"3.0.1": "2022-12-09T00:00:00Z",
|
||||
"3.0.0": "2022-08-15T00:00:00Z",
|
||||
"2.1.1": "2022-01-21T00:00:00Z",
|
||||
"2.1.0": "2021-10-28T00:00:00Z",
|
||||
"2.0.6": "2021-10-05T00:00:00Z",
|
||||
"2.0.5": "2021-07-13T00:00:00Z",
|
||||
"2.0.4": "2021-07-08T00:00:00Z",
|
||||
"2.0.3": "2021-07-08T00:00:00Z",
|
||||
"2.0.2": "2021-07-08T00:00:00Z",
|
||||
"2.0.1": "2021-06-11T00:00:00Z",
|
||||
"2.0.0": "2021-05-22T00:00:00Z"
|
||||
}
|
||||
},
|
||||
"posthog-ruby": {
|
||||
"latestVersion": "3.3.2",
|
||||
"releaseDates": {
|
||||
"3.3.2": "2025-09-26T00:00:00Z",
|
||||
"3.3.1": "2025-09-26T00:00:00Z",
|
||||
"3.3.0": "2025-09-23T00:00:00Z",
|
||||
"3.2.0": "2025-08-26T00:00:00Z",
|
||||
"3.1.2": "2025-08-26T00:00:00Z",
|
||||
"3.1.1": "2025-08-06T00:00:00Z",
|
||||
"3.1.0": "2025-08-06T00:00:00Z",
|
||||
"3.0.1": "2025-05-20T00:00:00Z",
|
||||
"3.0.0": "2025-05-20T00:00:00Z",
|
||||
"2.6.0": "2025-02-13T00:00:00Z",
|
||||
"2.5.1": "2024-12-19T00:00:00Z",
|
||||
"2.5.0": "2024-03-15T00:00:00Z",
|
||||
"2.4.3": "2024-02-29T00:00:00Z",
|
||||
"2.4.2": "2024-01-26T00:00:00Z"
|
||||
}
|
||||
},
|
||||
"posthog-go": {
|
||||
"latestVersion": "1.6.10",
|
||||
"releaseDates": {
|
||||
"1.6.10": "2025-09-22T20:23:13Z",
|
||||
"1.6.2": "2025-08-07T20:48:20Z",
|
||||
"1.5.12": "2025-06-10T21:53:30Z",
|
||||
"1.5.11": "2025-05-29T08:19:54Z",
|
||||
"1.5.9": "2025-05-23T22:41:59Z",
|
||||
"1.5.7": "2025-05-21T15:58:58Z",
|
||||
"1.5.6": "2025-05-21T15:14:36Z",
|
||||
"1.5.5": "2025-05-13T14:05:29Z",
|
||||
"1.4.9": "2025-04-18T19:40:57Z",
|
||||
"1.4.7": "2025-04-02T20:36:54Z",
|
||||
"1.2.1": "2024-08-08T00:05:34Z"
|
||||
}
|
||||
},
|
||||
"posthog-flutter": {
|
||||
"latestVersion": "5.6.0",
|
||||
"releaseDates": {
|
||||
"5.6.0": "2025-10-06T11:14:06Z",
|
||||
"5.5.0": "2025-09-12T06:41:18Z",
|
||||
"5.4.3": "2025-09-09T17:32:48Z",
|
||||
"5.4.2": "2025-09-03T08:17:32Z",
|
||||
"5.4.1": "2025-08-29T14:53:58Z",
|
||||
"5.4.0": "2025-08-28T11:50:36Z",
|
||||
"5.3.1": "2025-08-13T10:55:49Z",
|
||||
"5.3.0": "2025-08-11T10:18:07Z",
|
||||
"5.2.0": "2025-08-08T11:20:18Z",
|
||||
"5.1.0": "2025-07-22T09:00:06Z",
|
||||
"5.0.0": "2025-05-05T07:19:13Z",
|
||||
"4.11.0": "2025-04-24T15:36:41Z",
|
||||
"4.10.8": "2025-04-10T11:21:47Z",
|
||||
"4.10.7": "2025-04-09T12:22:32Z",
|
||||
"4.10.6": "2025-04-09T11:09:35Z",
|
||||
"4.10.5": "2025-04-08T08:57:18Z",
|
||||
"4.10.4": "2025-03-01T07:35:43Z",
|
||||
"4.10.3": "2025-02-21T11:40:07Z",
|
||||
"4.10.2": "2025-02-06T15:11:44Z",
|
||||
"4.10.1": "2025-02-05T17:18:05Z",
|
||||
"4.10.0": "2025-01-16T10:50:55Z",
|
||||
"4.9.4": "2025-01-13T12:49:23Z",
|
||||
"4.9.3": "2025-01-09T07:37:06Z",
|
||||
"4.9.2": "2025-01-08T09:48:46Z",
|
||||
"4.9.1": "2025-01-07T10:29:02Z",
|
||||
"4.9.0": "2024-12-18T14:39:22Z",
|
||||
"4.8.0": "2024-12-13T10:54:10Z",
|
||||
"4.7.1": "2024-12-09T12:02:12Z",
|
||||
"4.7.0": "2024-12-03T15:00:19Z",
|
||||
"4.6.0": "2024-10-03T07:49:06Z"
|
||||
}
|
||||
},
|
||||
"posthog-react-native": {
|
||||
"latestVersion": "4.9.1",
|
||||
"releaseDates": {
|
||||
"4.9.1": "2025-10-09T12:03:43Z",
|
||||
"4.9.0": "2025-10-09T11:10:55Z",
|
||||
"4.8.1": "2025-10-09T09:25:07Z",
|
||||
"4.8.0": "2025-10-07T11:36:46Z"
|
||||
}
|
||||
},
|
||||
"posthog-dotnet": {
|
||||
"latestVersion": "2.0.1",
|
||||
"releaseDates": {
|
||||
"2.0.1": "2025-09-28T19:40:53Z",
|
||||
"2.0.0": "2025-08-26T22:21:03Z",
|
||||
"1.0.8": "2025-08-07T22:20:48Z",
|
||||
"1.0.7": "2025-07-21T15:27:43Z",
|
||||
"1.0.6": "2025-07-10T21:07:11Z",
|
||||
"1.0.5": "2025-04-04T21:35:05Z",
|
||||
"1.0.4": "2025-03-24T21:59:52Z",
|
||||
"1.0.3": "2025-03-05T23:41:51Z",
|
||||
"1.0.2": "2025-03-05T02:43:18Z",
|
||||
"1.0.1": "2025-02-27T19:33:13Z",
|
||||
"1.0.0": "2025-02-24T18:26:38Z"
|
||||
}
|
||||
},
|
||||
"posthog-elixir": {
|
||||
"latestVersion": "2.0.0",
|
||||
"releaseDates": {
|
||||
"2.0.0": "2025-09-30T00:00:00Z",
|
||||
"1.1.0": "2025-07-01T00:00:00Z",
|
||||
"1.0.3": "2025-06-02T00:00:00Z",
|
||||
"1.0.2": "2025-04-17T00:00:00Z",
|
||||
"1.0.1": "2025-04-17T00:00:00Z",
|
||||
"1.0.0": "2025-04-17T00:00:00Z",
|
||||
"0.4.4": "2025-04-14T00:00:00Z",
|
||||
"0.4.3": "2025-04-14T00:00:00Z",
|
||||
"0.4.2": "2025-03-27T00:00:00Z",
|
||||
"0.4.1": "2025-03-12T00:00:00Z",
|
||||
"0.4.0": "2025-02-11T00:00:00Z",
|
||||
"0.3.0": "2025-01-09T00:00:00Z",
|
||||
"0.2.0": "2024-05-04T00:00:00Z",
|
||||
"0.1.0": "2020-06-06T00:00:00Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
24
frontend/src/mocks/fixtures/api/team_sdk_versions.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"sdk_versions": {
|
||||
"posthog-python": [
|
||||
{
|
||||
"lib_version": "6.7.4",
|
||||
"max_timestamp": "2025-10-11 21:07:24.248000+00:00",
|
||||
"count": 180
|
||||
}
|
||||
],
|
||||
"web": [
|
||||
{
|
||||
"lib_version": "1.274.2",
|
||||
"max_timestamp": "2025-10-11 21:08:04.526000+00:00",
|
||||
"count": 1562
|
||||
},
|
||||
{
|
||||
"lib_version": "1.274.1",
|
||||
"max_timestamp": "2025-10-09 23:51:41.925000+00:00",
|
||||
"count": 133
|
||||
}
|
||||
]
|
||||
},
|
||||
"cached": true
|
||||
}
|
||||
@@ -71,14 +71,14 @@ export function HeatmapsBrowserNoPageSelected(): JSX.Element {
|
||||
return <App />
|
||||
}
|
||||
|
||||
export const HeatmapsBrowserWithUnauthorizedPageSelected: Story = {
|
||||
parameters: {
|
||||
pageUrl: urls.heatmaps('pageURL=https://random.example.com'),
|
||||
},
|
||||
}
|
||||
|
||||
export const HeatmapsBrowserWithPageSelected: Story = {
|
||||
parameters: {
|
||||
pageUrl: urls.heatmaps('pageURL=https://example.com&heatmapPalette=red&heatmapFilters={"type"%3A"mousemove"}'),
|
||||
},
|
||||
}
|
||||
|
||||
export const HeatmapsBrowserWithUnauthorizedPageSelected: Story = {
|
||||
parameters: {
|
||||
pageUrl: urls.heatmaps('pageURL=https://random.example.com'),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -5246,6 +5246,7 @@ export enum SidePanelTab {
|
||||
Status = 'status',
|
||||
Exports = 'exports',
|
||||
AccessControl = 'access-control',
|
||||
SdkDoctor = 'sdk-doctor',
|
||||
}
|
||||
|
||||
export interface ProductPricingTierSubrows {
|
||||
|
||||
50
posthog/api/github_sdk_versions.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import json
|
||||
from typing import cast
|
||||
|
||||
from django.http import JsonResponse
|
||||
|
||||
import structlog
|
||||
import posthoganalytics
|
||||
from rest_framework import exceptions
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.request import Request
|
||||
|
||||
from posthog.exceptions_capture import capture_exception
|
||||
from posthog.models.user import User
|
||||
from posthog.redis import get_client
|
||||
|
||||
from dags.sdk_doctor.github_sdk_versions import SDK_TYPES
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
@api_view(["GET"])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def github_sdk_versions(request: Request) -> JsonResponse:
|
||||
"""
|
||||
Serve cached GitHub SDK version data for SDK Doctor.
|
||||
Data is cached by Dagster job that runs every 6 hours.
|
||||
Protected by sdk-doctor-beta feature flag.
|
||||
"""
|
||||
user = cast(User, request.user)
|
||||
if not posthoganalytics.feature_enabled("sdk-doctor-beta", str(user.distinct_id)):
|
||||
raise exceptions.ValidationError("SDK Doctor is not enabled for this user")
|
||||
|
||||
redis_client = get_client()
|
||||
response = {}
|
||||
for sdk_type in SDK_TYPES:
|
||||
cache_key = f"github:sdk_versions:{sdk_type}"
|
||||
cached_data = redis_client.get(cache_key)
|
||||
if cached_data:
|
||||
try:
|
||||
data = json.loads(cached_data.decode("utf-8") if isinstance(cached_data, bytes) else cached_data)
|
||||
response[sdk_type] = data
|
||||
except (json.JSONDecodeError, AttributeError) as e:
|
||||
logger.warning(f"[SDK Doctor] Cache corrupted for {sdk_type}", error=str(e))
|
||||
capture_exception(e, {"sdk_type": sdk_type, "cache_key": cache_key})
|
||||
else:
|
||||
logger.warning(f"[SDK Doctor] {sdk_type} SDK info not found in cache")
|
||||
response[sdk_type] = {"error": "SDK data not available. Please try again later."}
|
||||
|
||||
return JsonResponse(response)
|
||||
77
posthog/api/team_sdk_versions.py
Normal file
@@ -0,0 +1,77 @@
|
||||
import json
|
||||
from typing import cast
|
||||
|
||||
from django.http import JsonResponse
|
||||
|
||||
import structlog
|
||||
import posthoganalytics
|
||||
from rest_framework import exceptions
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.request import Request
|
||||
|
||||
from posthog.exceptions_capture import capture_exception
|
||||
from posthog.models.team import Team
|
||||
from posthog.models.user import User
|
||||
from posthog.redis import get_client
|
||||
|
||||
from dags.sdk_doctor.team_sdk_versions import get_and_cache_team_sdk_versions
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
@api_view(["GET"])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def team_sdk_versions(request: Request) -> JsonResponse:
|
||||
"""
|
||||
Serve team SDK versions. Data is cached by Dagster job (runs every 6 hours).
|
||||
Supports force_refresh=true for on-demand detection.
|
||||
Protected by sdk-doctor-beta feature flag.
|
||||
"""
|
||||
user = cast(User, request.user)
|
||||
|
||||
if not posthoganalytics.feature_enabled("sdk-doctor-beta", str(user.distinct_id)):
|
||||
raise exceptions.ValidationError("SDK Doctor is not enabled for this user")
|
||||
|
||||
team_id = cast(Team, user.team).id
|
||||
raw_force_refresh = request.GET.get("force_refresh", "")
|
||||
force_refresh = raw_force_refresh.lower() == "true"
|
||||
|
||||
redis_client = get_client()
|
||||
cache_key = f"sdk_versions:team:{team_id}"
|
||||
|
||||
logger.info(
|
||||
f"[SDK Doctor] Team {team_id} SDK versions requested",
|
||||
team_id=team_id,
|
||||
force_refresh=force_refresh,
|
||||
raw_force_refresh=raw_force_refresh,
|
||||
cache_key=cache_key,
|
||||
)
|
||||
|
||||
if not force_refresh:
|
||||
cached_data = redis_client.get(cache_key)
|
||||
if cached_data:
|
||||
try:
|
||||
sdk_versions = json.loads(
|
||||
cached_data.decode("utf-8") if isinstance(cached_data, bytes) else cached_data
|
||||
)
|
||||
logger.info(f"[SDK Doctor] Team {team_id} SDK versions successfully read from cache")
|
||||
return JsonResponse({"sdk_versions": sdk_versions, "cached": True}, safe=False)
|
||||
except (json.JSONDecodeError, AttributeError) as e:
|
||||
logger.warning(f"[SDK Doctor] Cache corrupted for team {team_id}", error=str(e))
|
||||
capture_exception(e)
|
||||
else:
|
||||
logger.info(f"[SDK Doctor] Force refresh requested for team {team_id}, bypassing cache")
|
||||
|
||||
logger.info(f"[SDK Doctor] Team {team_id} SDK versions not found in cache, querying ClickHouse")
|
||||
try:
|
||||
sdk_versions = get_and_cache_team_sdk_versions(team_id, redis_client)
|
||||
if sdk_versions is not None:
|
||||
return JsonResponse({"sdk_versions": sdk_versions, "cached": False}, safe=False)
|
||||
else:
|
||||
logger.error(f"[SDK Doctor] No data received from ClickHouse for team {team_id}")
|
||||
return JsonResponse({"error": "Failed to get SDK versions. Please try again later."}, status=500)
|
||||
except Exception as e:
|
||||
logger.exception(f"[SDK Doctor] Failed to get SDK versions for team {team_id}")
|
||||
capture_exception(e)
|
||||
return JsonResponse({"error": "Failed to get SDK versions. Please try again later."}, status=500)
|
||||
@@ -37,6 +37,7 @@ TYPE_CONVERSION_FUNCTIONS: dict[str, HogQLFunctionMeta] = {
|
||||
"reinterpretAsFloat64": HogQLFunctionMeta("reinterpretAsFloat64", 1, 1),
|
||||
"reinterpretAsUUID": HogQLFunctionMeta("reinterpretAsUUID", 1, 1),
|
||||
"toInt": HogQLFunctionMeta("accurateCastOrNull", 1, 1, suffix_args=[ast.Constant(value="Int64")]),
|
||||
"toIntOrZero": HogQLFunctionMeta("toInt64OrZero", 1, 1, signatures=[((StringType(),), IntegerType())]),
|
||||
"_toInt8": HogQLFunctionMeta("toInt8", 1, 1),
|
||||
"_toInt16": HogQLFunctionMeta("toInt16", 1, 1),
|
||||
"_toInt32": HogQLFunctionMeta("toInt32", 1, 1),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Tests for team access token cache functionality.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.core.cache import cache
|
||||
@@ -1132,6 +1133,7 @@ class TestUpdateUserAuthenticationCache(TestCase):
|
||||
assert not PersonalAPIKey.objects.filter(user_id=user_to_delete.id).exists(), "User's keys should be deleted"
|
||||
assert PersonalAPIKey.objects.filter(user_id=user_to_keep.id).exists(), "Other user's keys should remain"
|
||||
|
||||
@pytest.mark.skip(reason="Flaky in CI, works fine locally")
|
||||
def test_update_user_authentication_cache_handles_warm_cache_failures(self):
|
||||
"""Test function handles individual cache warming failures gracefully."""
|
||||
import logging
|
||||
@@ -1685,6 +1687,7 @@ class TestSignalHandlerCacheWarming(TestCase):
|
||||
except Exception as e:
|
||||
raise AssertionError(f"Should handle orphaned team references gracefully, but raised: {e}")
|
||||
|
||||
@pytest.mark.skip(reason="Flaky in CI, works fine locally")
|
||||
def test_signal_handlers_handle_cache_warming_failures(self):
|
||||
"""Test that signal handlers handle cache warming failures gracefully."""
|
||||
import logging
|
||||
|
||||
@@ -30,9 +30,11 @@ from posthog.api import (
|
||||
uploaded_media,
|
||||
user,
|
||||
)
|
||||
from posthog.api.github_sdk_versions import github_sdk_versions
|
||||
from posthog.api.query import progress
|
||||
from posthog.api.slack import slack_interactivity_callback
|
||||
from posthog.api.survey import public_survey_page, surveys
|
||||
from posthog.api.team_sdk_versions import team_sdk_versions
|
||||
from posthog.api.utils import hostname_in_allowed_url_list
|
||||
from posthog.api.web_experiment import web_experiments
|
||||
from posthog.api.zendesk_orgcheck import ensure_zendesk_organization
|
||||
@@ -169,6 +171,8 @@ urlpatterns = [
|
||||
path("api/environments/<int:team_id>/query/<str:query_uuid>/progress", progress),
|
||||
path("api/unsubscribe", unsubscribe.unsubscribe),
|
||||
path("api/alerts/github", github.SecretAlert.as_view()),
|
||||
path("api/sdk_versions/", github_sdk_versions),
|
||||
path("api/team_sdk_versions/", team_sdk_versions),
|
||||
opt_slash_path("api/support/ensure-zendesk-organization", csrf_exempt(ensure_zendesk_organization)),
|
||||
path("api/", include(router.urls)),
|
||||
path("", include(tf_urls)),
|
||||
|
||||