Skip to content

Commit 66494b5

Browse files
feat: implement pre-release guard functionality with tests
1 parent d3fa73c commit 66494b5

File tree

4 files changed

+62
-1
lines changed

4 files changed

+62
-1
lines changed

docs/tasks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ Use Context7 MCP for up to date documentation.
139139
If already at latest, set `skipped_reason=already_latest`.
140140
Verify: Second run produces skip.
141141

142-
17. [ ] **Pre-release guard**
142+
17. [x] **Pre-release guard**
143143
Default off. Enabled by `include_prerelease=true`.
144144
Verify: Tests confirm behavior.
145145

src/versioning/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ export type { PythonOrgFallbackOptions, PythonOrgVersion } from './python-org-fa
66

77
export { fetchRunnerAvailability } from './runner-availability';
88
export type { RunnerAvailability, RunnerAvailabilityOptions } from './runner-availability';
9+
10+
export { enforcePreReleaseGuard } from './pre-release-guard';
11+
export type { PreReleaseGuardResult } from './pre-release-guard';
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import semver from 'semver';
2+
3+
export interface PreReleaseGuardResult {
4+
allowed: boolean;
5+
reason?: 'pre_release_guarded';
6+
}
7+
8+
export function enforcePreReleaseGuard(
9+
includePrerelease: boolean,
10+
version: string | null,
11+
): PreReleaseGuardResult {
12+
if (version === null) {
13+
return { allowed: true };
14+
}
15+
16+
const parsed = semver.parse(version, { includePrerelease: true, loose: true });
17+
if (!parsed) {
18+
return { allowed: true };
19+
}
20+
21+
const isPreRelease = parsed.prerelease.length > 0;
22+
if (isPreRelease && !includePrerelease) {
23+
return { allowed: false, reason: 'pre_release_guarded' };
24+
}
25+
26+
return { allowed: true };
27+
}

tests/pre-release-guard.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { enforcePreReleaseGuard } from '../src/versioning';
4+
5+
describe('enforcePreReleaseGuard', () => {
6+
it('blocks pre-release versions when flag is false', () => {
7+
const result = enforcePreReleaseGuard(false, '3.13.0-rc.1');
8+
9+
expect(result.allowed).toBe(false);
10+
expect(result.reason).toBe('pre_release_guarded');
11+
});
12+
13+
it('allows pre-release versions when flag is true', () => {
14+
const result = enforcePreReleaseGuard(true, '3.13.0-rc.1');
15+
16+
expect(result.allowed).toBe(true);
17+
expect(result.reason).toBeUndefined();
18+
});
19+
20+
it('allows stable versions regardless of flag', () => {
21+
const result = enforcePreReleaseGuard(false, '3.13.2');
22+
23+
expect(result.allowed).toBe(true);
24+
});
25+
26+
it('allows when version is null', () => {
27+
const result = enforcePreReleaseGuard(false, null);
28+
29+
expect(result.allowed).toBe(true);
30+
});
31+
});

0 commit comments

Comments
 (0)