UNPKG

semantic-release-npm-workspaces-monorepo

Version:
112 lines (111 loc) 4.77 kB
import fs from 'fs/promises'; import { generatePackageSettings, SETTINGS } from '../settings.js'; import fetchRetry from 'fetch-retry'; import { readCacheStorage } from '../storage.js'; import semver from 'semver'; import * as simpleGit from 'simple-git'; import micromatch from 'micromatch'; import path from 'path'; const nodeFetchWithRetry = fetchRetry(fetch); const FETCH_RETRY_OPTIONS = { retries: 3, retryDelay: 1000, }; export default class UpdatePackages { constructor(packagePath, _packages) { this._packages = _packages; this._packageJSONPath = path.join(packagePath, 'package.json'); const relativePath = path.relative(process.cwd(), packagePath); this.settings = generatePackageSettings(relativePath); } async _updateVersions(data = {}) { for (const key in data) { if (this._packages.includes(key)) { const { version, isPrerelease } = await UpdatePackages.getLatestVersion(key, this.settings); data[key] = this.useVersionTemplate(data[key], version, isPrerelease); } } } async _readPackageJson() { this._originalPackageContent = await fs .readFile(this._packageJSONPath, 'utf-8') .then(JSON.parse); this.packageContent = structuredClone(this._originalPackageContent); } async savePackageJson(content = this.packageContent) { await fs.writeFile(this._packageJSONPath, JSON.stringify(content, null, 2)); } async restoreOriginalPackageJson() { await this.savePackageJson(this._originalPackageContent); } async updateDeps() { await this._readPackageJson(); await this._updateVersions(this.packageContent.dependencies); await this._updateVersions(this.packageContent.devDependencies); } static async getLatestVersion(packageName, settings = SETTINGS) { const cache = await readCacheStorage(); const cacheVersion = cache[packageName]; const branchInfo = await this.findBranchInfo(settings); const isPrereleaseChannel = Boolean(branchInfo?.prerelease); if (cacheVersion) { console.log('Cache version for', packageName, 'is', cacheVersion); return { version: cacheVersion, isPrerelease: isPrereleaseChannel, }; } else { console.log('Cache version for', packageName, 'is not found'); } try { const packageSearch = await nodeFetchWithRetry(`${settings.registry}/${packageName}`, FETCH_RETRY_OPTIONS); const packageSearchJson = await packageSearch.json(); const versions = packageSearchJson['dist-tags']; const template = typeof branchInfo?.prerelease === 'string' ? branchInfo.prerelease : branchInfo?.channel || ''; const channelNameReplaced = template.replaceAll('${name}', branchInfo?.name || '') || branchInfo?.name || ''; if (isPrereleaseChannel) { const prereleaseVersion = versions[channelNameReplaced]; if (prereleaseVersion) { return { version: prereleaseVersion, isPrerelease: true, }; } } return { version: versions[channelNameReplaced] ?? versions.latest, isPrerelease: false, }; } catch (error) { console.error(`Failed to get version from NPM for ${packageName}: ${error.message}`); return { version: '0.0.1', isPrerelease: false, }; } } useVersionTemplate(templateVersion, toVersion, isPrerelease = false) { if (isPrerelease && this.settings.preReleaseVersionTemplate) { return this.settings.preReleaseVersionTemplate.replace('${version}', toVersion); } const originalVersion = (semver.coerce(templateVersion, { includePrerelease: true }) || templateVersion).toString(); return templateVersion.replace(originalVersion, toVersion); } static async findBranchInfo(settings = SETTINGS) { const ciBranch = process.env.CI_COMMIT_BRANCH || process.env.GITHUB_REF_NAME || process.env.CIRCLE_BRANCH || process.env.TRAVIS_BRANCH || process.env.BITBUCKET_BRANCH; const branch = (this._cacheCurrentBranch ??= ciBranch || (await simpleGit.simpleGit().branch()).current); return settings.release.branches.find(x => typeof x === 'object' && micromatch.isMatch(branch, x.name)); } }