feat(flags): support semver comparisons in user_blast_radius#44596
feat(flags): support semver comparisons in user_blast_radius#44596
user_blast_radius#44596Conversation
…' into feat/support-semver-comparisons-in-user-blast-radius
user_blast_radius
| @@ -349,6 +360,7 @@ export const allOperatorsMapping: Record<string, string> = { | |||
| ...cohortOperatorMap, | |||
| ...featureFlagOperatorMap, | |||
| ...cleanedPathOperatorMap, | |||
| ...semverOperatorMap, | |||
There was a problem hiding this comment.
these changes aren't relevant yet, since we're not making UI changes, but they'll matter soon. They're good to have for all of these schema validation changes.
| elif operator == PropertyOperator.SEMVER_EQ: | ||
| return ast.CompareOperation( | ||
| op=ast.CompareOperationOp.Eq, | ||
| left=ast.Call(name="sortableSemver", args=[expr]), |
There was a problem hiding this comment.
an important thing to note here is that we're using the sortableSemver hogQL function to implement the data extraction, but this method does not support all of valid semver, e.g. things like 1.0.0-alpha.1 aren't supported. I'll make this change in a future PR; just trying to get the broad strokes down here.
There was a problem hiding this comment.
1 issue found across 8 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="posthog/hogql/property.py">
<violation number="1" location="posthog/hogql/property.py:343">
P1: Caret operator doesn't handle 0.x.y versions per semver spec. According to semver, `^0.2.3` should mean `>=0.2.3 <0.3.0` (not `<1.0.0`), and `^0.0.3` should mean `>=0.0.3 <0.0.4`. The current implementation always bumps major version, which will cause incorrect feature flag targeting for pre-1.0 software versions.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
…f github.com:PostHog/posthog into feat/support-semver-comparisons-in-user-blast-radius
haacked
left a comment
There was a problem hiding this comment.
Nice work!
Some non-blocking comments.
Would like to see more tests of edge cases in order to document what behavior we expect with values like these.
0.0.0- minimal version1.2.3-alpha- We don't support it yet, but want to document what should happenv1.2.31.2.3- (leading space)1.2.3- (trailing space)01.02.03- (Should be same as 1.2.3 even though I believe it violates Semver spec)1.2.3.4- Too many version numbers. These are common in .NET land though1..2.3- empty component1.2.3.- trailing dot.1.2.3- leading dot1.-2.3- negative version part (invalid semver)
posthog/hogql/property.py
Outdated
| if len(parts) < 2: | ||
| raise ValueError("Invalid semver format") |
There was a problem hiding this comment.
We might want to consider 1.0 as 1.0.0 down the road.
Also, if someone does pass 1.0.0-alpha.1 have we already stripped out the -alpha.1 by this point?
posthog/hogql/property.py
Outdated
| major = parts[0] | ||
| minor = parts[1] if len(parts) > 1 else "0" | ||
| patch = parts[2] if len(parts) > 2 else "0" |
There was a problem hiding this comment.
This parsing does what I described earlier by treating 1.0 as 1.0.0. Would it make sense to have a standard function to do this parsing and return the parts?
| ), | ||
| ] | ||
| ) | ||
| elif operator == PropertyOperator.SEMVER_CARET: |
There was a problem hiding this comment.
Each of the three range operators (tilde, caret, wildcard) does these 4 steps:
- Validate input type
- Parse version parts
- Calculate bounds
- Return the same AST structure
Maybe extract that into a helper method?
| op = ast.CompareOperationOp.NotIn if operator == PropertyOperator.NOT_IN else ast.CompareOperationOp.In | ||
| return ast.CompareOperation(op=op, left=expr, right=ast.Array(exprs=[ast.Constant(value=v) for v in value])) | ||
| elif operator == PropertyOperator.SEMVER_EQ: | ||
| return ast.CompareOperation( |
There was a problem hiding this comment.
The range operators all validate the input type:
if not isinstance(value, str):
raise QueryError("Semver operators require a string value")Would it make sense to have the basic operators also do this so errors are consistent rather than dependent on whatever sortableSemver does?
Greptile's behavior is changing!From now on, if a review finishes with no comments, we will not post an additional "statistics" comment to confirm that our review found nothing to comment on. However, you can confirm that we reviewed your changes in the status check section. This feature can be toggled off in your Code Review Settings by deselecting "Create a status check for each PR". |
What's Being ChangedThe PR introduces comprehensive semver comparison operators that follow the semantic versioning specification:
The changes span multiple layers:
How It WorksThe implementation leverages ClickHouse's existing The code includes proper semver parsing with support for pre-release suffixes, missing version components, and follows semver specification edge cases (e.g., Test Coverage
The testing strategy follows the custom rule of preferring parameterized tests where appropriate, with clear documentation of expected behavior. Potential Issues
Confidence Score: 4/5The implementation is well-structured and comprehensive with excellent test coverage. The risk level is moderate due to the complexity of the HogQL integration and potential for schema synchronization issues, but the foundational nature of the change and thorough testing provide good confidence in the implementation. |
Problem
We're building SemVer targeting for feature flags, so the first thing we need to do is make sure that the
user_blast_radiusfunction can correctly evaluate potential rollouts that have semver operators. This change should be no-op, as we don't support creating flags with semver operators yet, but this is just laying the groundwork, tinkering with some hogQL, and keeping the PR footprint small.Changes
-
semver_eq,semver_gt,semver_gte,semver_lt,semver_lte-
semver_tilde(~1.2.3 matches >=1.2.3 <1.3.0)-
semver_caret(^1.2.3 matches >=1.2.3 <2.0.0)-
semver_wildcard(1.2.* matches >=1.2.0 <1.3.0)- Implemented all 8 operators using the existing sortableSemver function
- Added proper error handling with QueryError
- Fixed edge case bug for empty wildcard patterns
- Integration tests in posthog/api/test/test_feature_flag.py:8362-8615
- Unit tests in posthog/hogql/test/test_property.py:1084-1172
- All 4 semver tests pass (2 unit + 2 integration)
- All 24 blast radius tests pass
- Human-readable labels for all operators
Publish to changelog?
no