Skip to content

Commit 17c0bf7

Browse files
chore: refactor semver checking to be more robust
1 parent 118f260 commit 17c0bf7

File tree

2 files changed

+73
-34
lines changed

2 files changed

+73
-34
lines changed

packages/test/src/test-flags.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,15 @@ test('OpenTelemetryHandleSignalInterceptorInsertYield enabled by version', (t) =
1414
{ version: '1.14.0', expected: false },
1515
];
1616
for (const { version, expected } of cases) {
17-
const actual = SdkFlags.OpenTelemetryHandleSignalInterceptorInsertYield.alternativeConditions![0]!({
17+
const alternativeCondition = (ctx: { info: WorkflowInfo; sdkVersion: string | undefined }) => {
18+
for (const cond of SdkFlags.OpenTelemetryHandleSignalInterceptorInsertYield.alternativeConditions!) {
19+
if (cond(ctx)) {
20+
return true;
21+
}
22+
}
23+
return false;
24+
};
25+
const actual = alternativeCondition({
1826
info: {} as WorkflowInfo,
1927
sdkVersion: version,
2028
});

packages/workflow/src/flags.ts

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ export const SdkFlags = {
5656
*
5757
* @since Introduced in 1.13.2.
5858
*/
59-
OpenTelemetryHandleSignalInterceptorInsertYield: defineFlag(3, false, [affectedOtelInterceptorVersion]),
59+
OpenTelemetryHandleSignalInterceptorInsertYield: defineFlag(3, false, [
60+
isBetween({ major: 1, minor: 11, patch: 3 }, { major: 1, minor: 13, patch: 2 }),
61+
]),
6062
} as const;
6163

6264
function defineFlag(id: number, def: boolean, alternativeConditions?: AltConditionFn[]): SdkFlag {
@@ -88,36 +90,65 @@ function buildIdSdkVersionMatches(version: RegExp): AltConditionFn {
8890
return ({ info }) => info.currentBuildId != null && regex.test(info.currentBuildId); // eslint-disable-line deprecation/deprecation
8991
}
9092

91-
function affectedOtelInterceptorVersion({ sdkVersion }: { sdkVersion?: string }): boolean {
92-
if (!sdkVersion) {
93-
return false;
94-
}
95-
const [major, minor, patchAndTags] = sdkVersion.split('.', 3);
96-
if (major !== '1') return false;
97-
98-
// Semver allows for additional tags to be appended to the version
99-
let patch;
100-
try {
101-
const patchDigits = /[0-9]+/.exec(patchAndTags)?.[0];
102-
patch = patchDigits ? Number.parseInt(patchDigits) : null;
103-
} catch {
104-
// This shouldn't ever happen, but we are conservative here and avoid throwing when checking a flag.
105-
patch = null;
106-
}
107-
108-
switch (minor) {
109-
case '11':
110-
// 1.11.3 was the last release that didn't inject a yield point
111-
// If for some reason we are unable to parse the patch version, assume it isn't affected
112-
return Boolean(patch && patch > 3);
113-
case '12':
114-
// Every 1.12 release requires a yield
115-
return true;
116-
case '13':
117-
// 1.13.2 will be the first release since 1.11.3 that doesn't have a yield point in `handleSignal`
118-
// If for some reason we are unable to parse the patch version, assume it isn't affected
119-
return Boolean(patch && patch < 2);
120-
default:
121-
return false;
122-
}
93+
type SemVer = {
94+
major: number;
95+
minor: number;
96+
patch: number;
97+
};
98+
99+
function parseSemver(version: string): SemVer | undefined {
100+
const matches = version.match(/(\d+)\.(\d+)\.(\d+)/);
101+
if (!matches) return undefined;
102+
const [full, major, minor, patch] = matches.map((digits) => {
103+
try {
104+
return Number.parseInt(digits);
105+
} catch {
106+
return undefined;
107+
}
108+
});
109+
if (major === undefined || minor === undefined || patch === undefined)
110+
throw new Error(`full: ${full}, parts: ${major}.${minor}.${patch}`);
111+
if (major === undefined || minor === undefined || patch === undefined) return undefined;
112+
return {
113+
major,
114+
minor,
115+
patch,
116+
};
117+
}
118+
119+
function compareSemver(a: SemVer, b: SemVer): -1 | 0 | 1 {
120+
if (a.major < b.major) return -1;
121+
if (a.major > b.major) return 1;
122+
if (a.minor < b.minor) return -1;
123+
if (a.minor > b.minor) return 1;
124+
if (a.patch < b.patch) return -1;
125+
if (a.patch > b.patch) return 1;
126+
return 0;
127+
}
128+
129+
function isCompared(compare: SemVer, comparison: -1 | 0 | 1): AltConditionFn {
130+
return ({ sdkVersion }) => {
131+
if (!sdkVersion) throw new Error('no sdk version');
132+
if (!sdkVersion) return false;
133+
const version = parseSemver(sdkVersion);
134+
if (!version) throw new Error(`no version for ${sdkVersion}`);
135+
if (!version) return false;
136+
return compareSemver(compare, version) === comparison;
137+
};
138+
}
139+
140+
function isBefore(compare: SemVer): AltConditionFn {
141+
return isCompared(compare, 1);
142+
}
143+
144+
function isEqual(compare: SemVer): AltConditionFn {
145+
return isCompared(compare, 0);
146+
}
147+
148+
function isAfter(compare: SemVer): AltConditionFn {
149+
return isCompared(compare, -1);
150+
}
151+
152+
function isBetween(lowEnd: SemVer, highEnd: SemVer): AltConditionFn {
153+
return (ctx) => isAfter(lowEnd)(ctx) && isBefore(highEnd)(ctx);
123154
}

0 commit comments

Comments
 (0)