Skip to content

feat: Semantic Versioning suppport in Audience Evaluation #213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Sep 15, 2020

Conversation

yasirfolio3
Copy link
Contributor

Summary

  • add greater than or equal and less than or equal for numbers
  • add semantic version match types.

@coveralls
Copy link

coveralls commented Aug 28, 2020

Coverage Status

Coverage decreased (-0.1%) to 98.156% when pulling 7ac685a on yasir/sem-ver into 543a8e3 on master.

Copy link
Contributor

@oakbani oakbani left a comment

Choose a reason for hiding this comment

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

Some changes requested.

protected function semverEqualEvaluator($condition)
{
$comparison = $this->semverEvaluator($condition);
if ($comparison !== null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit. Will be more readable if you do:
if ($comparison === null) { return null } return $comparison === 0
For all others too


public function testSemVerGTMatcherReturnsFalseWhenAttributeValueIsLessThanOrEqualToConditionValue()
{
$customAttrConditionEvaluator = new CustomAttributeConditionEvaluator(
Copy link
Contributor

Choose a reason for hiding this comment

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

nit. define the condition inside this method just like you have done below. testSemVerGTMatcherReturnsTrueWhenAttributeValueIsGreaterThanConditionValueBeta()

$invalidValues = ["-", ".", "..", "+", "+test", " ", "2 .3. 0", "2.",
".2.2", "3.7.2.2", "3.x", ",", "+build-prerelease"];

foreach ($invalidValues as $val) {
Copy link
Contributor

Choose a reason for hiding this comment

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

can you write the above tests in a for loop just like you have done here?
seta custom error message and send it to assert call as last argument.

@oakbani oakbani changed the title feature: add semantic version types feat: Semantic Versioning suppport in Audience Evaluation Sep 4, 2020
Copy link
Contributor

@oakbani oakbani left a comment

Choose a reason for hiding this comment

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

Rather than creating SemVersionConditionEvaluator as a separate class and creating it's instance on every evaluation call. Make method inside SemVerionEvaluator static. And directly use them from different evaluator methods. Pass logger as a param to compare_version static method. And move string validation to compare_version method as well.

compare_version should get (target_version, user_version, logger)

$conditionValue = $condition['value'];
$userValue = isset($this->userAttributes[$conditionName]) ? $this->userAttributes[$conditionName] : null;

if (!Validator::validateNonEmptyString($conditionValue)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

$userValue should be checked here instead of $conditionValue. And a unit test written if not already.

private function toInt($str)
{
if (is_numeric($str)) {
return intval($str);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can directly use PHP intVal method. https://www.php.net/manual/en/function.intval.php

The integer value of var on success, or 0 on failure. Empty arrays return 0, non-empty arrays return 1.

}

/**
* checks if string contains prerelease seperator before build separator.
Copy link
Contributor

Choose a reason for hiding this comment

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

Checks if given string is a prerelease version?

prerelease seperator before build separator. is an implementation detail that should come as a comment inside code.

/**
* checks if string contains prerelease seperator before build separator.
*
* @param string $str value to be checked.
Copy link
Contributor

Choose a reason for hiding this comment

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

let's rename $str to $version

*
* @param string $str value to be checked.
*
* @return bool true if prerelease seperator comes first.
Copy link
Contributor

Choose a reason for hiding this comment

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

true if given version is a prerelease

* @return null|array array if provided string was successfully split,
* null if any issues occured.
*/
protected function splitSemanticVersion($targetedVersion)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit.rename to $version. This method doesn't know if it's targeted or userVersion

$targetSuffix = array();

if ($this->isPreRelease($targetedVersion) || $this->isBuild($targetedVersion)) {
$targetParts = explode($this->isPreRelease($targetPrefix) ? self::PRE_RELEASE_SEPARATOR : self::BUILD_SEPARATOR, $targetedVersion, 2);
Copy link
Contributor

Choose a reason for hiding this comment

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

$this->isPreRelease($targetPrefix) ? self::PRE_RELEASE_SEPARATOR : self::BUILD_SEPARATOR assign this to a variable before use. Readability.

if ($targetedVersionParts === null) {
return null;
}
$versionParts = $this->splitSemanticVersion($this->condition);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit. rename userVersionParts


// Up to the precision of targetedVersion, expect version to match exactly.
for ($i = 0; $i < count($targetedVersionParts); $i++) {
if (count($versionParts) <= $i) {
Copy link
Contributor

Choose a reason for hiding this comment

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

count($versionParts) assign this to a variable at top and resuse

// Up to the precision of targetedVersion, expect version to match exactly.
for ($i = 0; $i < count($targetedVersionParts); $i++) {
if (count($versionParts) <= $i) {
// even if they are equal at this point. if the target is a prerelease then it must be greater than the pre release.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit. looks like there is something wrong with this comment.

@yasirfolio3 yasirfolio3 requested a review from oakbani September 4, 2020 10:32
Copy link
Contributor

@oakbani oakbani left a comment

Choose a reason for hiding this comment

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

Looks good.

@@ -143,15 +143,13 @@ protected function semverEvaluator($condition)
$conditionValue = $condition['value'];
$userValue = isset($this->userAttributes[$conditionName]) ? $this->userAttributes[$conditionName] : null;

if (!Validator::validateNonEmptyString($conditionValue)) {
if (!Validator::validateNonEmptyString($conditionValue) || !Validator::validateNonEmptyString($userValue)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

just remove the check for conditionValue. We assume that we get string semantic version value from the datafile/backend.
And in case of bad condition value, the error message being logged is misleading.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit.
Modify doc string of this method to returns result of SemVersionConditionEvaluator::compareVersion for given target and user versions.

Copy link
Contributor

@oakbani oakbani left a comment

Choose a reason for hiding this comment

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

@yasirfolio3 Code Optimization

$targetSuffix = array();

if (self::isPreRelease($version) || self::isBuild($version)) {
$separator = self::isPreRelease($targetPrefix) ? self::PRE_RELEASE_SEPARATOR : self::BUILD_SEPARATOR;
Copy link
Contributor

Choose a reason for hiding this comment

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

self::isPreRelease($targetPrefix)
nit. do this once
if (self::isPreRelease)
$separator = ...
elseif(self::isBuild)
$separator = ...

if (!self::isPreRelease($targetedVersion) && self::isPreRelease($userVersion)) {
return -1;
}
return 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

assign self::isPreRelease($targetedVersion) and self::isPreRelease($userVersion) to variables at the top of this method. And reuse them at all places.

@yasirfolio3 yasirfolio3 marked this pull request as ready for review September 8, 2020 15:15
@yasirfolio3 yasirfolio3 requested a review from a team as a code owner September 8, 2020 15:15
Comment on lines 81 to 83
return array(self::EXACT_MATCH_TYPE, self::EXISTS_MATCH_TYPE, self::GREATER_THAN_MATCH_TYPE, self::GREATER_THAN_EQUAL_TO_MATCH_TYPE,
self::LESS_THAN_MATCH_TYPE, self::LESS_THAN_EQUAL_TO_MATCH_TYPE, self::SUBSTRING_MATCH_TYPE, self::SEMVER_EQ,
self::SEMVER_GT, self::SEMVER_GE, self::SEMVER_LT, self::SEMVER_LE);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be made nicer by having these on separate lines and alphabetized.

$evaluatorsByMatchType[self::SUBSTRING_MATCH_TYPE] = 'substringEvaluator';
$evaluatorsByMatchType[self::SEMVER_EQ] = 'semverEqualEvaluator';
Copy link
Contributor

Choose a reason for hiding this comment

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

nit. Alphabetize.

@@ -109,6 +125,33 @@ protected function isValueTypeValidForExactConditions($value)
return false;
}

/**
* returns result of SemVersionConditionEvaluator::compareVersion for given target and user versions.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit. Returns

Comment on lines 133 to 135
* @return null|int 0 if user's semver attribute is equal to the semver condition value,
* 1 if user's semver attribute is greater than the semver condition value,
* -1 if user's semver attribute is less than the semver condition value,
Copy link
Contributor

Choose a reason for hiding this comment

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

User has a version attribute. Semver is a specification.

*
* @param object $condition
*
* @return boolean true if user's semver attribute is greater than the semver condition value,
Copy link
Contributor

Choose a reason for hiding this comment

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

nit. version attribute. Please update at all places.

/**
* compares targeted version with the provided user version.
*
* @param object $targetedVersion
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't the versions string?

*
* @return bool true if given version is a build.
*/
private static function isBuild($version)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit. isBuildVersion

*
* @return bool true if given version is a prerelease.
*/
private static function isPreRelease($version)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit. isPreReleaseVersion

* @param string $userVersion
* @param object $logger
*
* @return null|int 0 if user's semver attribute is equal to the semver condition value,
Copy link
Contributor

Choose a reason for hiding this comment

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

nit. user's attribute or user's version attribute

Copy link
Contributor

Choose a reason for hiding this comment

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

Please apply this feedback throughout the PR.

* @param string $userVersion
* @param object $logger
*
* @return null|int 0 if user's semver attribute is equal to the semver condition value,
Copy link
Contributor

Choose a reason for hiding this comment

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

Please apply this feedback throughout the PR.

Copy link
Contributor

@msohailhussain msohailhussain left a comment

Choose a reason for hiding this comment

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

lgtm

@mikeproeng37 mikeproeng37 merged commit d0c6f5e into master Sep 15, 2020
@mikeproeng37 mikeproeng37 deleted the yasir/sem-ver branch September 15, 2020 04:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants