diff --git a/lib/__tests__/apk-parser.test.ts b/lib/__tests__/apk-parser.test.ts index c351ac0..c2cc8d3 100644 --- a/lib/__tests__/apk-parser.test.ts +++ b/lib/__tests__/apk-parser.test.ts @@ -1,60 +1,69 @@ -import { parseApkFilename, detectEnvironment } from '../apk-parser'; +import { parseApkFilename, detectEnvironment, getApkTabs } from '../apk-parser'; describe('parseApkFilename', () => { - it('should parse APK with environment suffix', () => { - const result = parseApkFilename('ft_timeshift_0_42_57ef3a60d.apk'); - expect(result.environment).toBe('dev'); - expect(result.commit).toBe('57ef3a60d'); + it('should parse product APK (no environment)', () => { + const result = parseApkFilename('ft_0_44_bfeddf2d0.apk', '0_44'); + expect(result.environment).toBe('product'); + expect(result.commit).toBe('bfeddf2d0'); expect(result.isValid).toBe(true); }); - it('should parse APK without environment (product)', () => { - const result = parseApkFilename('ft_0_42_ff9ff3441.apk'); - expect(result.environment).toBe('product'); - expect(result.commit).toBe('ff9ff3441'); + it('should parse dev APK', () => { + const result = parseApkFilename('ft_dev_0_44_bfeddf2d0.apk', '0_44'); + expect(result.environment).toBe('dev'); + expect(result.commit).toBe('bfeddf2d0'); expect(result.isValid).toBe(true); }); it('should parse sandbox APK', () => { - const result = parseApkFilename('ft_sandbox_0_42_57ef3a60d.apk'); + const result = parseApkFilename('ft_sandbox_0_44_bfeddf2d0.apk', '0_44'); expect(result.environment).toBe('sandbox'); - expect(result.commit).toBe('57ef3a60d'); + expect(result.commit).toBe('bfeddf2d0'); expect(result.isValid).toBe(true); }); - it('should handle invalid format', () => { - const result = parseApkFilename('invalid_filename.apk'); - expect(result.environment).toBe('product'); + it('should map unknown environment to other', () => { + const result = parseApkFilename('ft_lan_0_44_bfeddf2d0.apk', '0_44'); + expect(result.environment).toBe('other'); + expect(result.commit).toBe('bfeddf2d0'); + }); + + it('should map timeshift to other', () => { + const result = parseApkFilename('ft_timeshift_0_42_57ef3a60d.apk', '0_42'); + expect(result.environment).toBe('other'); + }); + + it('should handle invalid format without commit', () => { + const result = parseApkFilename('ft_dev_0_44.apk', '0_44'); + expect(result.environment).toBe('dev'); expect(result.commit).toBeNull(); expect(result.isValid).toBe(false); }); - it('should handle missing commit ID', () => { - const result = parseApkFilename('ft_dev_0_42.apk'); - expect(result.environment).toBe('dev'); + it('should handle completely invalid filename', () => { + const result = parseApkFilename('invalid_filename.apk', '0_44'); + expect(result.environment).toBe('other'); expect(result.commit).toBeNull(); expect(result.isValid).toBe(false); }); }); describe('detectEnvironment', () => { - it('should detect dev environment', () => { - expect(detectEnvironment('ft_timeshift_0_42_57ef3a60d.apk')).toBe('dev'); + it('should detect product when no underscore in prefix', () => { + expect(detectEnvironment('ft', ['dev', 'sandbox'])).toBe('product'); }); - it('should detect sandbox environment', () => { - expect(detectEnvironment('ft_sandbox_0_42_57ef3a60d.apk')).toBe('sandbox'); + it('should detect configured environment', () => { + expect(detectEnvironment('ft_dev', ['dev', 'sandbox'])).toBe('dev'); + expect(detectEnvironment('ft_sandbox', ['dev', 'sandbox'])).toBe('sandbox'); }); - it('should detect product environment (no suffix)', () => { - expect(detectEnvironment('ft_0_42_ff9ff3441.apk')).toBe('product'); + it('should return other for unconfigured environment', () => { + expect(detectEnvironment('ft_lan', ['dev', 'sandbox'])).toBe('other'); + expect(detectEnvironment('ft_timeshift', ['dev', 'sandbox'])).toBe('other'); }); - it('should detect lan environment', () => { - expect(detectEnvironment('ft_lan_0_42_57ef3a60d.apk')).toBe('dev'); - }); - - it('should return other for unknown environments', () => { - expect(detectEnvironment('ft_unknown_0_42_57ef3a60d.apk')).toBe('other'); + it('should return other for empty prefix', () => { + expect(detectEnvironment('', ['dev', 'sandbox'])).toBe('other'); }); }); diff --git a/lib/apk-parser.ts b/lib/apk-parser.ts index fd6a712..66f65bd 100644 --- a/lib/apk-parser.ts +++ b/lib/apk-parser.ts @@ -1,4 +1,6 @@ -export type ApkEnvironment = 'dev' | 'sandbox' | 'product' | 'other'; +import { APK_TABS } from './constants'; + +export type ApkEnvironment = 'product' | 'dev' | 'sandbox' | 'other'; export interface ParsedApkMetadata { environment: ApkEnvironment; @@ -6,37 +8,55 @@ export interface ParsedApkMetadata { isValid: boolean; } -// Environment mapping based on filename patterns -const ENVIRONMENT_MAP: Record = { - 'timeshift': 'dev', - 'lan': 'dev', - 'dev': 'dev', - 'sandbox': 'sandbox', -}; +export function getApkTabs(): string[] { + return APK_TABS; +} -export function detectEnvironment(filename: string): ApkEnvironment { - // Pattern: ft_[environment]_version_commit.apk - // Extract the environment segment (alphabetic only) between first and second underscores - const match = filename.match(/^ft_([a-z]+)_/i); +export function detectEnvironment(prefix: string, configuredTabs: string[]): ApkEnvironment { + // Empty prefix → other + if (!prefix) { + return 'other'; + } - if (!match) { - // No environment suffix, default to product + // No underscore means product (e.g., "ft") + if (!prefix.includes('_')) { return 'product'; } - const env = match[1].toLowerCase(); - return ENVIRONMENT_MAP[env] || 'other'; + // Extract environment from last segment after underscore + const lastUnderscoreIndex = prefix.lastIndexOf('_'); + const env = prefix.substring(lastUnderscoreIndex + 1); + + // Check if environment is configured + if (configuredTabs.includes(env)) { + return env as ApkEnvironment; + } + + return 'other'; } -export function parseApkFilename(filename: string): ParsedApkMetadata { - const environment = detectEnvironment(filename); +export function parseApkFilename(filename: string, version: string): ParsedApkMetadata { + // Use version as delimiter (with leading underscore) + const delimiter = `_${version}`; + const delimiterIndex = filename.indexOf(delimiter); + + let prefix: string; + if (delimiterIndex > 0) { + prefix = filename.substring(0, delimiterIndex); + } else { + // Fallback: can't find version delimiter + prefix = ''; + } + + const environment = detectEnvironment(prefix, APK_TABS); + + // Extract commit ID const commitMatch = filename.match(/([a-f0-9]{7,})\.apk$/); const commit = commitMatch ? commitMatch[1] : null; - const isValid = commit !== null; return { environment, commit, - isValid, + isValid: commit !== null, }; }