UNPKG

tdpw

Version:

CLI tool for uploading Playwright test reports to TestDino platform with TestDino storage support

197 lines 7.54 kB
"use strict"; /** * Cache ID detection utilities for cache functionality * Cache ID format: <ciProvider>_<repoName>_<branch> * Example: gh_playwright-tests_main */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CacheIdDetector = void 0; const tslib_1 = require("tslib"); const git_1 = require("../collectors/git"); const ci_1 = require("../collectors/ci"); const crypto_1 = tslib_1.__importDefault(require("crypto")); /** * Service for detecting and generating cache IDs */ class CacheIdDetector { /** * Detect cache ID and related metadata from environment. * Format: <ciProvider>_<repoName>_<branch> * Supports custom cache ID via TESTDINO_CACHE_ID env var or --cache-id flag. * Supports custom branch and commit via --branch and --commit flags. */ static async detectCacheId(customCacheId, customBranch, customCommit) { try { // Check for custom cache ID (highest priority) const envCustomId = process.env.TESTDINO_CACHE_ID; if (customCacheId || envCustomId) { const finalCustomId = customCacheId || envCustomId || 'unknown'; // Still need git/ci metadata for commit, pipelineId, etc. const metadata = await this.collectMetadata(); return { cacheId: finalCustomId, pipelineId: metadata.pipelineId, commit: customCommit || metadata.commit, branch: customBranch || metadata.branch, repository: metadata.repository, ciProvider: metadata.ciProvider, source: 'custom', }; } // Auto-detect cache ID from environment return await this.generateCacheId(customBranch, customCommit); } catch (error) { console.warn('⚠️ Cache ID detection failed:', error instanceof Error ? error.message : 'Unknown error'); // Fallback to basic cache ID return { cacheId: `local_unknown_${this.generateHash('fallback', 6)}`, pipelineId: 'unknown', commit: customCommit || 'unknown', branch: customBranch || 'unknown', repository: 'unknown/unknown', ciProvider: 'local', source: 'local', }; } } /** * Collect metadata from Git and CI collectors */ static async collectMetadata() { const gitCollector = new git_1.GitCollector(process.cwd()); const gitMetadata = await gitCollector.getMetadata(); const ciMetadata = ci_1.CiCollector.collect(); return { commit: gitMetadata.commit?.hash || 'unknown', branch: gitMetadata.branch || 'unknown', repository: gitMetadata.repository?.name || 'unknown/unknown', pipelineId: ciMetadata.pipeline.id || 'unknown', ciProvider: ciMetadata.provider || 'unknown', }; } /** * Generate cache ID from environment * Format: <ciProvider>_<repoName>_<branch> */ static async generateCacheId(customBranch, customCommit) { const metadata = await this.collectMetadata(); // Use custom values if provided, otherwise use detected values const finalBranch = customBranch || metadata.branch; const finalCommit = customCommit || metadata.commit; // Extract repo name (without owner) let repoName = this.extractRepoName(metadata.repository); // If repo name is unknown, add hash and warn user if (repoName === 'unknown') { const hash = this.generateHash('unknown', 6); repoName = `unknown${hash}`; console.warn('⚠️ Repository name could not be detected'); console.warn('💡 Use a Git repository or set TESTDINO_CACHE_ID explicitly'); console.warn(` Generated cache ID: ${repoName}`); } // Get CI provider prefix const ciPrefix = this.getCIProviderPrefix(metadata.ciProvider); // Sanitize branch name for cache ID const sanitizedBranch = this.sanitizeComponent(finalBranch); // Build cache ID const cacheId = `${ciPrefix}_${repoName}_${sanitizedBranch}`; return { cacheId, pipelineId: metadata.pipelineId, commit: finalCommit, branch: finalBranch, // Original unsanitized branch repository: metadata.repository, ciProvider: metadata.ciProvider, source: metadata.ciProvider === 'unknown' ? 'local' : 'ci', }; } /** * Extract repository name from full repo string * "owner/repo" → "repo" */ static extractRepoName(fullRepo) { if (!fullRepo || fullRepo === 'unknown/unknown') { return 'unknown'; } const parts = fullRepo.split('/'); return parts[parts.length - 1] || 'unknown'; } /** * Get CI provider prefix for cache ID */ static getCIProviderPrefix(provider) { const prefixes = { 'github-actions': 'gh', 'gitlab-ci': 'gl', jenkins: 'jenkins', 'azure-devops': 'az', circleci: 'circle', unknown: 'local', }; return prefixes[provider] || 'local'; } /** * Sanitize component for cache ID (remove special characters) */ static sanitizeComponent(component) { return component .toLowerCase() .replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric with dash .replace(/^-+|-+$/g, '') // Trim dashes .substring(0, 50); // Max 50 chars } /** * Generate hash from string */ static generateHash(input, length) { const hash = crypto_1.default .createHash('sha256') .update(input + Date.now()) .digest('hex'); return hash.substring(0, length); } /** * Validate cache ID format */ static validateCacheId(cacheId) { if (!cacheId || typeof cacheId !== 'string') { return false; } // Allow reasonable length and characters (underscores and dashes) return (cacheId.length >= 5 && cacheId.length <= 150 && /^[a-zA-Z0-9\-_]+$/.test(cacheId)); } /** * Get cache context information for logging using existing collectors */ static async getCacheContext() { try { const cacheIdInfo = await this.detectCacheId(); return { // Cache identification cacheId: cacheIdInfo.cacheId, pipelineId: cacheIdInfo.pipelineId, commit: cacheIdInfo.commit, branch: cacheIdInfo.branch, repository: cacheIdInfo.repository, ciProvider: cacheIdInfo.ciProvider, source: cacheIdInfo.source, }; } catch (_error) { // Fallback to basic detection if detection fails return { cacheId: 'unknown', pipelineId: 'unknown', commit: 'unknown', branch: 'unknown', repository: 'unknown', ciProvider: 'local', source: 'local', }; } } } exports.CacheIdDetector = CacheIdDetector; //# sourceMappingURL=build-detector.js.map